mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
FieldConfig: Add support for Actions (#92874)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
parent
165ca3b4e8
commit
f9f85131a9
@ -1,3 +1,4 @@
|
|||||||
|
import { Action } from '../../types/action';
|
||||||
import { Field } from '../../types/dataFrame';
|
import { Field } from '../../types/dataFrame';
|
||||||
import { DataLink } from '../../types/dataLink';
|
import { DataLink } from '../../types/dataLink';
|
||||||
import { FieldOverrideContext } from '../../types/fieldOverrides';
|
import { FieldOverrideContext } from '../../types/fieldOverrides';
|
||||||
@ -59,6 +60,15 @@ export const dataLinksOverrideProcessor = (
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const actionsOverrideProcessor = (
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
value: any,
|
||||||
|
_context: FieldOverrideContext,
|
||||||
|
_settings?: DataLinksFieldConfigSettings
|
||||||
|
): Action[] => {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
export interface ValueMappingFieldConfigSettings {}
|
export interface ValueMappingFieldConfigSettings {}
|
||||||
|
|
||||||
export const valueMappingsOverrideProcessor = (
|
export const valueMappingsOverrideProcessor = (
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { HideSeriesConfig } from '@grafana/schema';
|
import { HideSeriesConfig } from '@grafana/schema';
|
||||||
|
|
||||||
import { ScopedVars } from './ScopedVars';
|
import { ScopedVars } from './ScopedVars';
|
||||||
|
import { Action } from './action';
|
||||||
import { QueryResultBase, Labels, NullValueMode } from './data';
|
import { QueryResultBase, Labels, NullValueMode } from './data';
|
||||||
import { DataLink, LinkModel } from './dataLink';
|
import { DataLink, LinkModel } from './dataLink';
|
||||||
import { DecimalCount, DisplayProcessor, DisplayValue, DisplayValueAlignmentFactors } from './displayValue';
|
import { DecimalCount, DisplayProcessor, DisplayValue, DisplayValueAlignmentFactors } from './displayValue';
|
||||||
@ -98,6 +99,8 @@ export interface FieldConfig<TOptions = any> {
|
|||||||
// The behavior when clicking on a result
|
// The behavior when clicking on a result
|
||||||
links?: DataLink[];
|
links?: DataLink[];
|
||||||
|
|
||||||
|
actions?: Action[];
|
||||||
|
|
||||||
// Alternative to empty string
|
// Alternative to empty string
|
||||||
noValue?: string;
|
noValue?: string;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ func TestList(t *testing.T) {
|
|||||||
|
|
||||||
res, err := List(ctx, "items", nil, Pagination{Limit: 2}, func(ctx context.Context, ns claims.NamespaceInfo, p Pagination) (*ListResponse[item], error) {
|
res, err := List(ctx, "items", nil, Pagination{Limit: 2}, func(ctx context.Context, ns claims.NamespaceInfo, p Pagination) (*ListResponse[item], error) {
|
||||||
return &ListResponse[item]{
|
return &ListResponse[item]{
|
||||||
Items: []item{item{"1"}, item{"2"}},
|
Items: []item{{"1"}, {"2"}},
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -47,7 +47,7 @@ func TestList(t *testing.T) {
|
|||||||
})
|
})
|
||||||
res, err := List(ctx, "items", a, Pagination{Limit: 2}, func(ctx context.Context, ns claims.NamespaceInfo, p Pagination) (*ListResponse[item], error) {
|
res, err := List(ctx, "items", a, Pagination{Limit: 2}, func(ctx context.Context, ns claims.NamespaceInfo, p Pagination) (*ListResponse[item], error) {
|
||||||
return &ListResponse[item]{
|
return &ListResponse[item]{
|
||||||
Items: []item{item{"1"}, item{"2"}},
|
Items: []item{{"1"}, {"2"}},
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -70,13 +70,13 @@ func TestList(t *testing.T) {
|
|||||||
res, err := List(ctx, "items", a, Pagination{Limit: 2}, func(ctx context.Context, ns claims.NamespaceInfo, p Pagination) (*ListResponse[item], error) {
|
res, err := List(ctx, "items", a, Pagination{Limit: 2}, func(ctx context.Context, ns claims.NamespaceInfo, p Pagination) (*ListResponse[item], error) {
|
||||||
if called {
|
if called {
|
||||||
return &ListResponse[item]{
|
return &ListResponse[item]{
|
||||||
Items: []item{item{"3"}},
|
Items: []item{{"3"}},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
called = true
|
called = true
|
||||||
return &ListResponse[item]{
|
return &ListResponse[item]{
|
||||||
Items: []item{item{"1"}, item{"2"}},
|
Items: []item{{"1"}, {"2"}},
|
||||||
Continue: 3,
|
Continue: 3,
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
|
15
public/app/core/components/OptionsUI/actions.tsx
Normal file
15
public/app/core/components/OptionsUI/actions.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Action, DataLinksFieldConfigSettings, StandardEditorProps, VariableSuggestionsScope } from '@grafana/data';
|
||||||
|
import { ActionsInlineEditor } from 'app/features/actions/ActionsInlineEditor';
|
||||||
|
|
||||||
|
type Props = StandardEditorProps<Action[], DataLinksFieldConfigSettings>;
|
||||||
|
|
||||||
|
export const ActionsValueEditor = ({ value, onChange, context }: Props) => {
|
||||||
|
return (
|
||||||
|
<ActionsInlineEditor
|
||||||
|
actions={value}
|
||||||
|
onChange={onChange}
|
||||||
|
data={context.data}
|
||||||
|
getSuggestions={() => (context.getSuggestions ? context.getSuggestions(VariableSuggestionsScope.Values) : [])}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -26,7 +26,10 @@ import {
|
|||||||
displayNameOverrideProcessor,
|
displayNameOverrideProcessor,
|
||||||
FieldNamePickerConfigSettings,
|
FieldNamePickerConfigSettings,
|
||||||
booleanOverrideProcessor,
|
booleanOverrideProcessor,
|
||||||
|
Action,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
|
import { actionsOverrideProcessor } from '@grafana/data/src/field/overrides/processors';
|
||||||
|
import { config } from '@grafana/runtime';
|
||||||
import { FieldConfig } from '@grafana/schema';
|
import { FieldConfig } from '@grafana/schema';
|
||||||
import { RadioButtonGroup, TimeZonePicker, Switch } from '@grafana/ui';
|
import { RadioButtonGroup, TimeZonePicker, Switch } from '@grafana/ui';
|
||||||
import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldNamePicker';
|
import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldNamePicker';
|
||||||
@ -34,6 +37,7 @@ import { ThresholdsValueEditor } from 'app/features/dimensions/editors/Threshold
|
|||||||
import { ValueMappingsEditor } from 'app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor';
|
import { ValueMappingsEditor } from 'app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor';
|
||||||
|
|
||||||
import { DashboardPicker, DashboardPickerOptions } from './DashboardPicker';
|
import { DashboardPicker, DashboardPickerOptions } from './DashboardPicker';
|
||||||
|
import { ActionsValueEditor } from './actions';
|
||||||
import { ColorValueEditor, ColorValueEditorSettings } from './color';
|
import { ColorValueEditor, ColorValueEditorSettings } from './color';
|
||||||
import { FieldColorEditor } from './fieldColor';
|
import { FieldColorEditor } from './fieldColor';
|
||||||
import { DataLinksValueEditor } from './links';
|
import { DataLinksValueEditor } from './links';
|
||||||
@ -143,6 +147,13 @@ export const getAllOptionEditors = () => {
|
|||||||
editor: DataLinksValueEditor,
|
editor: DataLinksValueEditor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const actions: StandardEditorsRegistryItem<Action[]> = {
|
||||||
|
id: 'actions',
|
||||||
|
name: 'Actions',
|
||||||
|
description: 'Allows defining actions',
|
||||||
|
editor: ActionsValueEditor,
|
||||||
|
};
|
||||||
|
|
||||||
const statsPicker: StandardEditorsRegistryItem<string[], StatsPickerConfigSettings> = {
|
const statsPicker: StandardEditorsRegistryItem<string[], StatsPickerConfigSettings> = {
|
||||||
id: 'stats-picker',
|
id: 'stats-picker',
|
||||||
name: 'Stats Picker',
|
name: 'Stats Picker',
|
||||||
@ -194,6 +205,7 @@ export const getAllOptionEditors = () => {
|
|||||||
select,
|
select,
|
||||||
unit,
|
unit,
|
||||||
links,
|
links,
|
||||||
|
actions,
|
||||||
statsPicker,
|
statsPicker,
|
||||||
strings,
|
strings,
|
||||||
timeZone,
|
timeZone,
|
||||||
@ -336,6 +348,8 @@ export const getAllStandardFieldConfigs = () => {
|
|||||||
category,
|
category,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const dataLinksCategory = config.featureToggles.vizActions ? 'Data links and actions' : 'Data links';
|
||||||
|
|
||||||
const links: FieldConfigPropertyItem<FieldConfig, DataLink[], StringFieldConfigSettings> = {
|
const links: FieldConfigPropertyItem<FieldConfig, DataLink[], StringFieldConfigSettings> = {
|
||||||
id: 'links',
|
id: 'links',
|
||||||
path: 'links',
|
path: 'links',
|
||||||
@ -347,10 +361,26 @@ export const getAllStandardFieldConfigs = () => {
|
|||||||
placeholder: '-',
|
placeholder: '-',
|
||||||
},
|
},
|
||||||
shouldApply: () => true,
|
shouldApply: () => true,
|
||||||
category: ['Data links'],
|
category: [dataLinksCategory],
|
||||||
getItemsCount: (value) => (value ? value.length : 0),
|
getItemsCount: (value) => (value ? value.length : 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const actions: FieldConfigPropertyItem<FieldConfig, Action[], StringFieldConfigSettings> = {
|
||||||
|
id: 'actions',
|
||||||
|
path: 'actions',
|
||||||
|
name: 'Actions',
|
||||||
|
editor: standardEditorsRegistry.get('actions').editor,
|
||||||
|
override: standardEditorsRegistry.get('actions').editor,
|
||||||
|
process: actionsOverrideProcessor,
|
||||||
|
settings: {
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
shouldApply: () => true,
|
||||||
|
category: [dataLinksCategory],
|
||||||
|
getItemsCount: (value) => (value ? value.length : 0),
|
||||||
|
showIf: () => config.featureToggles.vizActions,
|
||||||
|
};
|
||||||
|
|
||||||
const color: FieldConfigPropertyItem<FieldConfig, FieldColor | undefined, FieldColorConfigSettings> = {
|
const color: FieldConfigPropertyItem<FieldConfig, FieldColor | undefined, FieldColorConfigSettings> = {
|
||||||
id: 'color',
|
id: 'color',
|
||||||
path: 'color',
|
path: 'color',
|
||||||
@ -415,5 +445,19 @@ export const getAllStandardFieldConfigs = () => {
|
|||||||
category,
|
category,
|
||||||
};
|
};
|
||||||
|
|
||||||
return [unit, min, max, fieldMinMax, decimals, displayName, color, noValue, links, mappings, thresholds, filterable];
|
return [
|
||||||
|
unit,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
fieldMinMax,
|
||||||
|
decimals,
|
||||||
|
displayName,
|
||||||
|
color,
|
||||||
|
noValue,
|
||||||
|
links,
|
||||||
|
actions,
|
||||||
|
mappings,
|
||||||
|
thresholds,
|
||||||
|
filterable,
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
@ -221,6 +221,7 @@ export const SuggestionsInput = ({
|
|||||||
{...inputProps}
|
{...inputProps}
|
||||||
ref={handleRef as unknown as React.RefObject<HTMLTextAreaElement>}
|
ref={handleRef as unknown as React.RefObject<HTMLTextAreaElement>}
|
||||||
autoFocus={autoFocus}
|
autoFocus={autoFocus}
|
||||||
|
rows={5}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,16 +24,7 @@ const charWidth = measureText('M', UPLOT_AXIS_FONT_SIZE).width;
|
|||||||
const toRads = Math.PI / 180;
|
const toRads = Math.PI / 180;
|
||||||
|
|
||||||
export const BarChartPanel = (props: PanelProps<Options>) => {
|
export const BarChartPanel = (props: PanelProps<Options>) => {
|
||||||
const {
|
const { data, options, fieldConfig, width, height, timeZone, id, replaceVariables } = props;
|
||||||
data,
|
|
||||||
options,
|
|
||||||
fieldConfig,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
timeZone,
|
|
||||||
id,
|
|
||||||
// replaceVariables
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
// will need this if joining on time to re-create data links
|
// will need this if joining on time to re-create data links
|
||||||
// const { dataLinkPostProcessor } = usePanelContext();
|
// const { dataLinkPostProcessor } = usePanelContext();
|
||||||
@ -177,6 +168,7 @@ export const BarChartPanel = (props: PanelProps<Options>) => {
|
|||||||
sortOrder={options.tooltip.sort}
|
sortOrder={options.tooltip.sort}
|
||||||
isPinned={isPinned}
|
isPinned={isPinned}
|
||||||
maxHeight={options.tooltip.maxHeight}
|
maxHeight={options.tooltip.maxHeight}
|
||||||
|
replaceVariables={replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -306,6 +306,7 @@ export const CandlestickPanel = ({
|
|||||||
isPinned={isPinned}
|
isPinned={isPinned}
|
||||||
annotate={enableAnnotationCreation ? annotate : undefined}
|
annotate={enableAnnotationCreation ? annotate : undefined}
|
||||||
maxHeight={options.tooltip.maxHeight}
|
maxHeight={options.tooltip.maxHeight}
|
||||||
|
replaceVariables={replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -219,6 +219,7 @@ export const HeatmapPanel = ({
|
|||||||
annotate={enableAnnotationCreation ? annotate : undefined}
|
annotate={enableAnnotationCreation ? annotate : undefined}
|
||||||
maxHeight={options.tooltip.maxHeight}
|
maxHeight={options.tooltip.maxHeight}
|
||||||
maxWidth={options.tooltip.maxWidth}
|
maxWidth={options.tooltip.maxWidth}
|
||||||
|
replaceVariables={replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -3,11 +3,13 @@ import * as React from 'react';
|
|||||||
import uPlot from 'uplot';
|
import uPlot from 'uplot';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ActionModel,
|
||||||
DataFrameType,
|
DataFrameType,
|
||||||
Field,
|
Field,
|
||||||
FieldType,
|
FieldType,
|
||||||
formattedValueToString,
|
formattedValueToString,
|
||||||
getFieldDisplayName,
|
getFieldDisplayName,
|
||||||
|
InterpolateFunction,
|
||||||
LinkModel,
|
LinkModel,
|
||||||
PanelData,
|
PanelData,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
@ -16,14 +18,14 @@ import { TooltipDisplayMode, useTheme2 } from '@grafana/ui';
|
|||||||
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
||||||
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
||||||
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
||||||
|
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
|
||||||
import { ColorIndicator, ColorPlacement, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
import { ColorIndicator, ColorPlacement, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
||||||
import { ColorScale } from 'app/core/components/ColorScale/ColorScale';
|
import { ColorScale } from 'app/core/components/ColorScale/ColorScale';
|
||||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||||
import { isHeatmapCellsDense, readHeatmapRowsCustomMeta } from 'app/features/transformers/calculateHeatmap/heatmap';
|
import { isHeatmapCellsDense, readHeatmapRowsCustomMeta } from 'app/features/transformers/calculateHeatmap/heatmap';
|
||||||
import { DataHoverView } from 'app/features/visualization/data-hover/DataHoverView';
|
import { DataHoverView } from 'app/features/visualization/data-hover/DataHoverView';
|
||||||
|
|
||||||
import { VizTooltipWrapper } from '../../../../../packages/grafana-ui/src/components/VizTooltip/VizTooltipWrapper';
|
import { getDataLinks, getFieldActions } from '../status-history/utils';
|
||||||
import { getDataLinks } from '../status-history/utils';
|
|
||||||
import { isTooltipScrollable } from '../timeseries/utils';
|
import { isTooltipScrollable } from '../timeseries/utils';
|
||||||
|
|
||||||
import { HeatmapData } from './fields';
|
import { HeatmapData } from './fields';
|
||||||
@ -43,6 +45,7 @@ interface HeatmapTooltipProps {
|
|||||||
annotate?: () => void;
|
annotate?: () => void;
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
|
replaceVariables: InterpolateFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HeatmapTooltip = (props: HeatmapTooltipProps) => {
|
export const HeatmapTooltip = (props: HeatmapTooltipProps) => {
|
||||||
@ -73,6 +76,7 @@ const HeatmapHoverCell = ({
|
|||||||
annotate,
|
annotate,
|
||||||
maxHeight,
|
maxHeight,
|
||||||
maxWidth,
|
maxWidth,
|
||||||
|
replaceVariables,
|
||||||
}: HeatmapTooltipProps) => {
|
}: HeatmapTooltipProps) => {
|
||||||
const index = dataIdxs[1]!;
|
const index = dataIdxs[1]!;
|
||||||
const data = dataRef.current;
|
const data = dataRef.current;
|
||||||
@ -291,6 +295,7 @@ const HeatmapHoverCell = ({
|
|||||||
|
|
||||||
if (isPinned) {
|
if (isPinned) {
|
||||||
let links: Array<LinkModel<Field>> = [];
|
let links: Array<LinkModel<Field>> = [];
|
||||||
|
let actions: Array<ActionModel<Field>> = [];
|
||||||
|
|
||||||
const linksField = data.series?.fields[yValueIdx + 1];
|
const linksField = data.series?.fields[yValueIdx + 1];
|
||||||
|
|
||||||
@ -301,9 +306,11 @@ const HeatmapHoverCell = ({
|
|||||||
if (visible && hasLinks) {
|
if (visible && hasLinks) {
|
||||||
links = getDataLinks(linksField, xValueIdx);
|
links = getDataLinks(linksField, xValueIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actions = getFieldActions(data.series!, linksField, replaceVariables);
|
||||||
}
|
}
|
||||||
|
|
||||||
footer = <VizTooltipFooter dataLinks={links} annotate={annotate} />;
|
footer = <VizTooltipFooter dataLinks={links} annotate={annotate} actions={actions} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
let can = useRef<HTMLCanvasElement>(null);
|
let can = useRef<HTMLCanvasElement>(null);
|
||||||
|
@ -5,10 +5,10 @@ import { SortOrder, TooltipDisplayMode } from '@grafana/schema/dist/esm/common/c
|
|||||||
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
||||||
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
||||||
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
||||||
|
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
|
||||||
import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
||||||
import { getContentItems } from '@grafana/ui/src/components/VizTooltip/utils';
|
import { getContentItems } from '@grafana/ui/src/components/VizTooltip/utils';
|
||||||
|
|
||||||
import { VizTooltipWrapper } from '../../../../../packages/grafana-ui/src/components/VizTooltip/VizTooltipWrapper';
|
|
||||||
import { getDataLinks } from '../status-history/utils';
|
import { getDataLinks } from '../status-history/utils';
|
||||||
import { isTooltipScrollable } from '../timeseries/utils';
|
import { isTooltipScrollable } from '../timeseries/utils';
|
||||||
|
|
||||||
|
@ -198,6 +198,7 @@ export const StateTimelinePanel = ({
|
|||||||
annotate={enableAnnotationCreation ? annotate : undefined}
|
annotate={enableAnnotationCreation ? annotate : undefined}
|
||||||
withDuration={true}
|
withDuration={true}
|
||||||
maxHeight={options.tooltip.maxHeight}
|
maxHeight={options.tooltip.maxHeight}
|
||||||
|
replaceVariables={replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -6,12 +6,12 @@ import { TooltipDisplayMode } from '@grafana/ui';
|
|||||||
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
||||||
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
||||||
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
||||||
|
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
|
||||||
import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
||||||
import { getContentItems } from '@grafana/ui/src/components/VizTooltip/utils';
|
import { getContentItems } from '@grafana/ui/src/components/VizTooltip/utils';
|
||||||
import { findNextStateIndex, fmtDuration } from 'app/core/components/TimelineChart/utils';
|
import { findNextStateIndex, fmtDuration } from 'app/core/components/TimelineChart/utils';
|
||||||
|
|
||||||
import { VizTooltipWrapper } from '../../../../../packages/grafana-ui/src/components/VizTooltip/VizTooltipWrapper';
|
import { getDataLinks, getFieldActions } from '../status-history/utils';
|
||||||
import { getDataLinks } from '../status-history/utils';
|
|
||||||
import { TimeSeriesTooltipProps } from '../timeseries/TimeSeriesTooltip';
|
import { TimeSeriesTooltipProps } from '../timeseries/TimeSeriesTooltip';
|
||||||
import { isTooltipScrollable } from '../timeseries/utils';
|
import { isTooltipScrollable } from '../timeseries/utils';
|
||||||
|
|
||||||
@ -31,6 +31,7 @@ export const StateTimelineTooltip2 = ({
|
|||||||
timeRange,
|
timeRange,
|
||||||
withDuration,
|
withDuration,
|
||||||
maxHeight,
|
maxHeight,
|
||||||
|
replaceVariables,
|
||||||
}: StateTimelineTooltip2Props) => {
|
}: StateTimelineTooltip2Props) => {
|
||||||
const xField = series.fields[0];
|
const xField = series.fields[0];
|
||||||
|
|
||||||
@ -70,8 +71,9 @@ export const StateTimelineTooltip2 = ({
|
|||||||
const field = series.fields[seriesIdx];
|
const field = series.fields[seriesIdx];
|
||||||
const dataIdx = dataIdxs[seriesIdx]!;
|
const dataIdx = dataIdxs[seriesIdx]!;
|
||||||
const links = getDataLinks(field, dataIdx);
|
const links = getDataLinks(field, dataIdx);
|
||||||
|
const actions = getFieldActions(series, field, replaceVariables!);
|
||||||
|
|
||||||
footer = <VizTooltipFooter dataLinks={links} annotate={annotate} />;
|
footer = <VizTooltipFooter dataLinks={links} annotate={annotate} actions={actions} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerItem: VizTooltipItem = {
|
const headerItem: VizTooltipItem = {
|
||||||
|
@ -130,6 +130,7 @@ export const StatusHistoryPanel = ({
|
|||||||
annotate={enableAnnotationCreation ? annotate : undefined}
|
annotate={enableAnnotationCreation ? annotate : undefined}
|
||||||
withDuration={false}
|
withDuration={false}
|
||||||
maxHeight={options.tooltip.maxHeight}
|
maxHeight={options.tooltip.maxHeight}
|
||||||
|
replaceVariables={replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import { Field, LinkModel } from '@grafana/data';
|
import { ActionModel, Field, InterpolateFunction, LinkModel } from '@grafana/data';
|
||||||
|
import { DataFrame } from '@grafana/data/';
|
||||||
|
import { config } from '@grafana/runtime';
|
||||||
|
import { getActions } from 'app/features/actions/utils';
|
||||||
|
|
||||||
export const getDataLinks = (field: Field, rowIdx: number) => {
|
export const getDataLinks = (field: Field, rowIdx: number) => {
|
||||||
const links: Array<LinkModel<Field>> = [];
|
const links: Array<LinkModel<Field>> = [];
|
||||||
@ -20,3 +23,31 @@ export const getDataLinks = (field: Field, rowIdx: number) => {
|
|||||||
|
|
||||||
return links;
|
return links;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getFieldActions = (dataFrame: DataFrame, field: Field, replaceVars: InterpolateFunction) => {
|
||||||
|
if (!config.featureToggles?.vizActions) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const actions: Array<ActionModel<Field>> = [];
|
||||||
|
const actionLookup = new Set<string>();
|
||||||
|
|
||||||
|
const actionsModel = getActions(
|
||||||
|
dataFrame,
|
||||||
|
field,
|
||||||
|
field.state!.scopedVars!,
|
||||||
|
replaceVars,
|
||||||
|
field.config.actions ?? [],
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
actionsModel.forEach((action) => {
|
||||||
|
const key = `${action.title}`;
|
||||||
|
if (!actionLookup.has(key)) {
|
||||||
|
actions.push(action);
|
||||||
|
actionLookup.add(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
};
|
||||||
|
@ -131,6 +131,7 @@ export const TimeSeriesPanel = ({
|
|||||||
isPinned={isPinned}
|
isPinned={isPinned}
|
||||||
annotate={enableAnnotationCreation ? annotate : undefined}
|
annotate={enableAnnotationCreation ? annotate : undefined}
|
||||||
maxHeight={options.tooltip.maxHeight}
|
maxHeight={options.tooltip.maxHeight}
|
||||||
|
replaceVariables={replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { DataFrame, Field, FieldType, formattedValueToString } from '@grafana/data';
|
import { DataFrame, Field, FieldType, formattedValueToString, InterpolateFunction } from '@grafana/data';
|
||||||
import { SortOrder, TooltipDisplayMode } from '@grafana/schema/dist/esm/common/common.gen';
|
import { SortOrder, TooltipDisplayMode } from '@grafana/schema/dist/esm/common/common.gen';
|
||||||
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
||||||
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
||||||
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
||||||
|
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
|
||||||
import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
||||||
import { getContentItems } from '@grafana/ui/src/components/VizTooltip/utils';
|
import { getContentItems } from '@grafana/ui/src/components/VizTooltip/utils';
|
||||||
|
|
||||||
import { VizTooltipWrapper } from '../../../../../packages/grafana-ui/src/components/VizTooltip/VizTooltipWrapper';
|
import { getDataLinks, getFieldActions } from '../status-history/utils';
|
||||||
import { getDataLinks } from '../status-history/utils';
|
|
||||||
import { fmt } from '../xychart/utils';
|
import { fmt } from '../xychart/utils';
|
||||||
|
|
||||||
import { isTooltipScrollable } from './utils';
|
import { isTooltipScrollable } from './utils';
|
||||||
@ -36,6 +35,8 @@ export interface TimeSeriesTooltipProps {
|
|||||||
|
|
||||||
annotate?: () => void;
|
annotate?: () => void;
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
|
|
||||||
|
replaceVariables?: InterpolateFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TimeSeriesTooltip = ({
|
export const TimeSeriesTooltip = ({
|
||||||
@ -48,6 +49,7 @@ export const TimeSeriesTooltip = ({
|
|||||||
isPinned,
|
isPinned,
|
||||||
annotate,
|
annotate,
|
||||||
maxHeight,
|
maxHeight,
|
||||||
|
replaceVariables,
|
||||||
}: TimeSeriesTooltipProps) => {
|
}: TimeSeriesTooltipProps) => {
|
||||||
const xField = series.fields[0];
|
const xField = series.fields[0];
|
||||||
const xVal = formattedValueToString(xField.display!(xField.values[dataIdxs[0]!]));
|
const xVal = formattedValueToString(xField.display!(xField.values[dataIdxs[0]!]));
|
||||||
@ -77,8 +79,9 @@ export const TimeSeriesTooltip = ({
|
|||||||
const field = series.fields[seriesIdx];
|
const field = series.fields[seriesIdx];
|
||||||
const dataIdx = dataIdxs[seriesIdx]!;
|
const dataIdx = dataIdxs[seriesIdx]!;
|
||||||
const links = getDataLinks(field, dataIdx);
|
const links = getDataLinks(field, dataIdx);
|
||||||
|
const actions = getFieldActions(series, field, replaceVariables!);
|
||||||
|
|
||||||
footer = <VizTooltipFooter dataLinks={links} annotate={annotate} />;
|
footer = <VizTooltipFooter dataLinks={links} actions={actions} annotate={annotate} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerItem: VizTooltipItem | null = xField.config.custom?.hideFrom?.tooltip
|
const headerItem: VizTooltipItem | null = xField.config.custom?.hideFrom?.tooltip
|
||||||
@ -101,10 +104,3 @@ export const TimeSeriesTooltip = ({
|
|||||||
</VizTooltipWrapper>
|
</VizTooltipWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getStyles = () => ({
|
|
||||||
wrapper: css({
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
@ -130,6 +130,7 @@ export const TrendPanel = ({
|
|||||||
sortOrder={options.tooltip.sort}
|
sortOrder={options.tooltip.sort}
|
||||||
isPinned={isPinned}
|
isPinned={isPinned}
|
||||||
maxHeight={options.tooltip.maxHeight}
|
maxHeight={options.tooltip.maxHeight}
|
||||||
|
replaceVariables={replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -5,9 +5,9 @@ import { alpha } from '@grafana/data/src/themes/colorManipulator';
|
|||||||
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
||||||
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
||||||
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
||||||
|
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
|
||||||
import { ColorIndicator, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
import { ColorIndicator, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
||||||
|
|
||||||
import { VizTooltipWrapper } from '../../../../../packages/grafana-ui/src/components/VizTooltip/VizTooltipWrapper';
|
|
||||||
import { getDataLinks } from '../status-history/utils';
|
import { getDataLinks } from '../status-history/utils';
|
||||||
|
|
||||||
import { Options } from './panelcfg.gen';
|
import { Options } from './panelcfg.gen';
|
||||||
|
@ -122,6 +122,7 @@ export const XYChartPanel2 = (props: Props2) => {
|
|||||||
dismiss={dismiss}
|
dismiss={dismiss}
|
||||||
isPinned={isPinned}
|
isPinned={isPinned}
|
||||||
seriesIdx={seriesIdx!}
|
seriesIdx={seriesIdx!}
|
||||||
|
replaceVariables={props.replaceVariables}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { DataFrame } from '@grafana/data';
|
import { DataFrame, InterpolateFunction } from '@grafana/data';
|
||||||
import { alpha } from '@grafana/data/src/themes/colorManipulator';
|
import { alpha } from '@grafana/data/src/themes/colorManipulator';
|
||||||
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
|
||||||
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
|
||||||
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
|
||||||
|
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
|
||||||
import { ColorIndicator, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
import { ColorIndicator, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
|
||||||
|
|
||||||
import { VizTooltipWrapper } from '../../../../../../packages/grafana-ui/src/components/VizTooltip/VizTooltipWrapper';
|
import { getDataLinks, getFieldActions } from '../../status-history/utils';
|
||||||
import { getDataLinks } from '../../status-history/utils';
|
|
||||||
|
|
||||||
import { XYSeries } from './types2';
|
import { XYSeries } from './types2';
|
||||||
import { fmt } from './utils';
|
import { fmt } from './utils';
|
||||||
@ -20,6 +20,7 @@ export interface Props {
|
|||||||
dismiss: () => void;
|
dismiss: () => void;
|
||||||
data: DataFrame[];
|
data: DataFrame[];
|
||||||
xySeries: XYSeries[];
|
xySeries: XYSeries[];
|
||||||
|
replaceVariables: InterpolateFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stripSeriesName(fieldName: string, seriesName: string) {
|
function stripSeriesName(fieldName: string, seriesName: string) {
|
||||||
@ -30,7 +31,7 @@ function stripSeriesName(fieldName: string, seriesName: string) {
|
|||||||
return fieldName;
|
return fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const XYChartTooltip = ({ dataIdxs, seriesIdx, data, xySeries, dismiss, isPinned }: Props) => {
|
export const XYChartTooltip = ({ dataIdxs, seriesIdx, data, xySeries, dismiss, isPinned, replaceVariables }: Props) => {
|
||||||
const rowIndex = dataIdxs.find((idx) => idx !== null)!;
|
const rowIndex = dataIdxs.find((idx) => idx !== null)!;
|
||||||
|
|
||||||
const series = xySeries[seriesIdx! - 1];
|
const series = xySeries[seriesIdx! - 1];
|
||||||
@ -94,8 +95,10 @@ export const XYChartTooltip = ({ dataIdxs, seriesIdx, data, xySeries, dismiss, i
|
|||||||
|
|
||||||
if (isPinned && seriesIdx != null) {
|
if (isPinned && seriesIdx != null) {
|
||||||
const links = getDataLinks(yField, rowIndex);
|
const links = getDataLinks(yField, rowIndex);
|
||||||
|
const yFieldFrame = data.find((frame) => frame.fields.includes(yField))!;
|
||||||
|
const actions = getFieldActions(yFieldFrame, yField, replaceVariables);
|
||||||
|
|
||||||
footer = <VizTooltipFooter dataLinks={links} />;
|
footer = <VizTooltipFooter dataLinks={links} actions={actions} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user