Annotations: VizActions support in annotation tooltips (#112141)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
co-authored by
Leon Sorokin
parent
5aef57af73
commit
fcf7aa5e2f
@@ -321,6 +321,7 @@ export const CandlestickPanel = ({
|
||||
/>
|
||||
)}
|
||||
<AnnotationsPlugin2
|
||||
replaceVariables={replaceVariables}
|
||||
annotations={data.annotations ?? []}
|
||||
config={uplotConfig}
|
||||
timeZone={timeZone}
|
||||
|
||||
@@ -230,6 +230,7 @@ export const HeatmapPanel = ({
|
||||
/>
|
||||
)}
|
||||
<AnnotationsPlugin2
|
||||
replaceVariables={replaceVariables}
|
||||
annotations={data.annotations ?? []}
|
||||
config={builder}
|
||||
timeZone={timeZone}
|
||||
|
||||
@@ -151,6 +151,7 @@ export const StateTimelinePanel = ({
|
||||
)}
|
||||
{alignedFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
|
||||
<AnnotationsPlugin2
|
||||
replaceVariables={replaceVariables}
|
||||
annotations={data.annotations ?? []}
|
||||
config={builder}
|
||||
timeZone={timeZone}
|
||||
|
||||
@@ -164,6 +164,7 @@ export const StatusHistoryPanel = ({
|
||||
)}
|
||||
{alignedFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
|
||||
<AnnotationsPlugin2
|
||||
replaceVariables={replaceVariables}
|
||||
annotations={data.annotations ?? []}
|
||||
config={builder}
|
||||
timeZone={timeZone}
|
||||
|
||||
@@ -22,8 +22,6 @@ export const getDataLinks = (field: Field, rowIdx: number) => {
|
||||
return links;
|
||||
};
|
||||
|
||||
export const getAllFrameActions = (dataFrame: DataFrame) => {};
|
||||
|
||||
export const getFieldActions = (
|
||||
dataFrame: DataFrame,
|
||||
field: Field,
|
||||
@@ -31,19 +29,22 @@ export const getFieldActions = (
|
||||
rowIndex: number
|
||||
) => {
|
||||
const actions: Array<ActionModel<Field>> = [];
|
||||
const actionLookup = new Set<string>();
|
||||
|
||||
const actionsModel = getActions(dataFrame, field, field.state!.scopedVars!, replaceVars, field.config.actions ?? [], {
|
||||
valueRowIndex: rowIndex,
|
||||
});
|
||||
if (field.state?.scopedVars) {
|
||||
const actionLookup = new Set<string>();
|
||||
|
||||
actionsModel.forEach((action) => {
|
||||
const key = `${action.title}`;
|
||||
if (!actionLookup.has(key)) {
|
||||
actions.push(action);
|
||||
actionLookup.add(key);
|
||||
}
|
||||
});
|
||||
const actionsModel = getActions(dataFrame, field, field.state.scopedVars, replaceVars, field.config.actions ?? [], {
|
||||
valueRowIndex: rowIndex,
|
||||
});
|
||||
|
||||
actionsModel.forEach((action) => {
|
||||
const key = `${action.title}`;
|
||||
if (!actionLookup.has(key)) {
|
||||
actions.push(action);
|
||||
actionLookup.add(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return actions;
|
||||
};
|
||||
|
||||
@@ -191,6 +191,7 @@ export const TimeSeriesPanel = ({
|
||||
{!isVerticallyOriented && (
|
||||
<>
|
||||
<AnnotationsPlugin2
|
||||
replaceVariables={replaceVariables}
|
||||
annotations={data.annotations ?? []}
|
||||
config={uplotConfig}
|
||||
timeZone={timeZone}
|
||||
|
||||
@@ -5,9 +5,16 @@ import { createPortal } from 'react-dom';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
import { arrayToDataFrame, colorManipulator, DataFrame, DataTopic } from '@grafana/data';
|
||||
import { arrayToDataFrame, colorManipulator, DataFrame, DataTopic, InterpolateFunction } from '@grafana/data';
|
||||
import { TimeZone } from '@grafana/schema';
|
||||
import { DEFAULT_ANNOTATION_COLOR, getPortalContainer, UPlotConfigBuilder, useStyles2, useTheme2 } from '@grafana/ui';
|
||||
import {
|
||||
DEFAULT_ANNOTATION_COLOR,
|
||||
getPortalContainer,
|
||||
UPlotConfigBuilder,
|
||||
usePanelContext,
|
||||
useStyles2,
|
||||
useTheme2,
|
||||
} from '@grafana/ui';
|
||||
|
||||
import { AnnotationMarker2 } from './annotations2/AnnotationMarker2';
|
||||
|
||||
@@ -24,6 +31,7 @@ interface AnnotationsPluginProps {
|
||||
newRange: TimeRange2 | null;
|
||||
setNewRange: (newRage: TimeRange2 | null) => void;
|
||||
canvasRegionRendering?: boolean;
|
||||
replaceVariables: InterpolateFunction;
|
||||
}
|
||||
|
||||
// TODO: batch by color, use Path2D objects
|
||||
@@ -62,6 +70,7 @@ export const AnnotationsPlugin2 = ({
|
||||
config,
|
||||
newRange,
|
||||
setNewRange,
|
||||
replaceVariables,
|
||||
canvasRegionRendering = true,
|
||||
}: AnnotationsPluginProps) => {
|
||||
const [plot, setPlot] = useState<uPlot>();
|
||||
@@ -73,6 +82,9 @@ export const AnnotationsPlugin2 = ({
|
||||
|
||||
const [_, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||
|
||||
const { canExecuteActions } = usePanelContext();
|
||||
const userCanExecuteActions = canExecuteActions?.() ?? false;
|
||||
|
||||
const annos = useMemo(() => {
|
||||
let annos = annotations.filter(
|
||||
(frame) => frame.name !== 'exemplar' && frame.length > 0 && frame.fields.some((f) => f.name === 'time')
|
||||
@@ -258,6 +270,8 @@ export const AnnotationsPlugin2 = ({
|
||||
key={`${frameIdx}:${i}`}
|
||||
exitWipEdit={isWip ? exitWipEdit : null}
|
||||
portalRoot={portalRoot}
|
||||
canExecuteActions={userCanExecuteActions}
|
||||
replaceVariables={replaceVariables}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import { useState } from 'react';
|
||||
import * as React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import { DataFrame, GrafanaTheme2, LinkModel } from '@grafana/data';
|
||||
import { ActionModel, DataFrame, GrafanaTheme2, InterpolateFunction, LinkModel } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { TimeZone } from '@grafana/schema';
|
||||
import { floatingUtils, useStyles2 } from '@grafana/ui';
|
||||
import { getDataLinks } from 'app/plugins/panel/status-history/utils';
|
||||
import { getDataLinks, getFieldActions } from 'app/plugins/panel/status-history/utils';
|
||||
|
||||
import { AnnotationEditor2 } from './AnnotationEditor2';
|
||||
import { AnnotationTooltip2 } from './AnnotationTooltip2';
|
||||
@@ -23,6 +23,8 @@ interface AnnoBoxProps {
|
||||
timeZone: TimeZone;
|
||||
exitWipEdit?: null | (() => void);
|
||||
portalRoot: HTMLElement;
|
||||
canExecuteActions: boolean;
|
||||
replaceVariables: InterpolateFunction;
|
||||
}
|
||||
|
||||
const STATE_DEFAULT = 0;
|
||||
@@ -38,6 +40,8 @@ export const AnnotationMarker2 = ({
|
||||
exitWipEdit,
|
||||
timeZone,
|
||||
portalRoot,
|
||||
replaceVariables,
|
||||
canExecuteActions,
|
||||
}: AnnoBoxProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const placement = 'bottom';
|
||||
@@ -52,10 +56,15 @@ export const AnnotationMarker2 = ({
|
||||
});
|
||||
|
||||
const links: LinkModel[] = [];
|
||||
const actions: ActionModel[] = [];
|
||||
|
||||
if (STATE_HOVERED) {
|
||||
frame.fields.forEach((field) => {
|
||||
links.push(...getDataLinks(field, annoIdx));
|
||||
|
||||
if (canExecuteActions) {
|
||||
actions.push(...getFieldActions(frame, field, replaceVariables, annoIdx));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,6 +76,7 @@ export const AnnotationMarker2 = ({
|
||||
timeZone={timeZone}
|
||||
onEdit={() => setState(STATE_EDITING)}
|
||||
links={links}
|
||||
actions={actions}
|
||||
/>
|
||||
) : state === STATE_EDITING ? (
|
||||
<AnnotationEditor2
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { css } from '@emotion/css';
|
||||
import * as React from 'react';
|
||||
|
||||
import { GrafanaTheme2, dateTimeFormat, systemDateFormats, textUtil, LinkModel } from '@grafana/data';
|
||||
import { GrafanaTheme2, dateTimeFormat, systemDateFormats, textUtil, LinkModel, ActionModel } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { Stack, IconButton, Tag, usePanelContext, useStyles2 } from '@grafana/ui';
|
||||
import { VizTooltipFooter } from '@grafana/ui/internal';
|
||||
@@ -13,11 +13,12 @@ interface Props {
|
||||
timeZone: string;
|
||||
onEdit: () => void;
|
||||
links?: LinkModel[];
|
||||
actions?: ActionModel[];
|
||||
}
|
||||
|
||||
const retFalse = () => false;
|
||||
|
||||
export const AnnotationTooltip2 = ({ annoVals, annoIdx, timeZone, onEdit, links = [] }: Props) => {
|
||||
export const AnnotationTooltip2 = ({ annoVals, annoIdx, timeZone, onEdit, links = [], actions = [] }: Props) => {
|
||||
const annoId = annoVals.id?.[annoIdx];
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
@@ -110,7 +111,7 @@ export const AnnotationTooltip2 = ({ annoVals, annoIdx, timeZone, onEdit, links
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{links.length > 0 && <VizTooltipFooter dataLinks={links} />}
|
||||
{(links.length > 0 || actions.length > 0) && <VizTooltipFooter dataLinks={links} actions={actions} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user