diff --git a/packages/grafana-data/src/field/fieldOverrides.ts b/packages/grafana-data/src/field/fieldOverrides.ts index 96d7d403644..c3a64d496ae 100644 --- a/packages/grafana-data/src/field/fieldOverrides.ts +++ b/packages/grafana-data/src/field/fieldOverrides.ts @@ -1,5 +1,5 @@ import { isNumber, set, unset, get, cloneDeep } from 'lodash'; -import { useMemo, useRef } from 'react'; +import { createContext, useContext, useMemo, useRef } from 'react'; import { usePrevious } from 'react-use'; import { ThresholdsMode, VariableFormatID } from '@grafana/schema'; @@ -583,13 +583,14 @@ export function useFieldOverrides( data: PanelData | undefined, timeZone: string, theme: GrafanaTheme2, - replace: InterpolateFunction, - dataLinkPostProcessor?: DataLinkPostProcessor + replace: InterpolateFunction ): PanelData | undefined { const fieldConfigRegistry = plugin?.fieldConfigRegistry; const structureRev = useRef(0); const prevSeries = usePrevious(data?.series); + const { dataLinkPostProcessor } = useDataLinksContext(); + return useMemo(() => { if (!fieldConfigRegistry || !fieldConfig || !data) { return; @@ -650,3 +651,15 @@ export function getFieldDataContextClone(frame: DataFrame, field: Field, fieldSc return { value: { frame, field, data: [frame] } }; } + +/** + * @internal + */ +export const DataLinksContext = createContext<{ + dataLinkPostProcessor: DataLinkPostProcessor; +}>({ dataLinkPostProcessor: defaultInternalLinkPostProcessor }); + +/** + * @internal + */ +export const useDataLinksContext = () => useContext(DataLinksContext); diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index 6dcc5a186e6..269dba30b62 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -150,6 +150,8 @@ export { applyRawFieldOverrides, useFieldOverrides, getFieldDataContextClone, + DataLinksContext, + useDataLinksContext, } from './field/fieldOverrides'; export { getFieldDisplayValuesProxy } from './field/getFieldDisplayValuesProxy'; export { diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts b/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts index 97ddb007235..a9d5334925a 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts +++ b/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts @@ -96,6 +96,7 @@ export interface PanelContext { /** * Optional supplier for internal data links. If not provided a link pointing to Explore will be generated. * @internal + * @deprecated Please use DataLinksContext instead. This property will be removed in next major. */ dataLinkPostProcessor?: DataLinkPostProcessor; } diff --git a/public/app/features/explore/CustomContainer.tsx b/public/app/features/explore/CustomContainer.tsx index 26cf7dd14f4..ab5bc4117d4 100644 --- a/public/app/features/explore/CustomContainer.tsx +++ b/public/app/features/explore/CustomContainer.tsx @@ -1,6 +1,6 @@ -import { DataFrame, EventBus, LoadingState, SplitOpen, TimeRange } from '@grafana/data'; +import { DataFrame, DataLinksContext, EventBus, LoadingState, SplitOpen, TimeRange } from '@grafana/data'; import { PanelRenderer } from '@grafana/runtime'; -import { PanelChrome, PanelContext, PanelContextProvider } from '@grafana/ui'; +import { PanelChrome } from '@grafana/ui'; import { getPanelPluginMeta } from '../plugins/importPanelPlugin'; @@ -18,29 +18,13 @@ export interface Props { eventBus: EventBus; } -export function CustomContainer({ - width, - height, - timeZone, - state, - pluginId, - frames, - timeRange, - splitOpenFn, - eventBus, -}: Props) { +export function CustomContainer({ width, height, timeZone, state, pluginId, frames, timeRange, splitOpenFn }: Props) { const plugin = getPanelPluginMeta(pluginId); const dataLinkPostProcessor = useExploreDataLinkPostProcessor(splitOpenFn, timeRange); - const panelContext: PanelContext = { - dataLinkPostProcessor, - eventBus, - eventsScope: 'explore', - }; - return ( - + {(innerWidth, innerHeight) => ( )} - + ); } diff --git a/public/app/features/explore/Graph/ExploreGraph.tsx b/public/app/features/explore/Graph/ExploreGraph.tsx index e4dedb3f76c..6c5ccbba57c 100644 --- a/public/app/features/explore/Graph/ExploreGraph.tsx +++ b/public/app/features/explore/Graph/ExploreGraph.tsx @@ -8,6 +8,7 @@ import { createFieldConfigRegistry, DashboardCursorSync, DataFrame, + DataLinksContext, EventBus, FieldColorModeId, FieldConfigSource, @@ -121,9 +122,8 @@ export function ExploreGraph({ replaceVariables: (value) => value, // We don't need proper replace here as it is only used in getLinks and we use getFieldLinks theme, fieldConfigRegistry, - dataLinkPostProcessor, }); - }, [fieldConfigRegistry, data, timeZone, theme, styledFieldConfig, dataLinkPostProcessor]); + }, [fieldConfigRegistry, data, timeZone, theme, styledFieldConfig]); const annotationsWithConfig = useMemo(() => { return applyFieldOverrides({ @@ -171,7 +171,6 @@ export function ExploreGraph({ onToggleSeriesVisibility(label: string, mode: SeriesVisibilityChangeMode) { setFieldConfig(seriesVisibilityConfigFactory(label, mode, fieldConfig, data)); }, - dataLinkPostProcessor, }; function toggleLegend(name: string | undefined, mode: SeriesVisibilityChangeMode) { @@ -204,23 +203,25 @@ export function ExploreGraph({ ); return ( - - - + + + + + ); } diff --git a/public/app/features/panel/components/PanelRenderer.tsx b/public/app/features/panel/components/PanelRenderer.tsx index 74b9b295be2..fb99e39041a 100644 --- a/public/app/features/panel/components/PanelRenderer.tsx +++ b/public/app/features/panel/components/PanelRenderer.tsx @@ -11,7 +11,7 @@ import { } from '@grafana/data'; import { Trans } from '@grafana/i18n'; import { getTemplateSrv, PanelRendererProps } from '@grafana/runtime'; -import { ErrorBoundaryAlert, usePanelContext, useTheme2 } from '@grafana/ui'; +import { ErrorBoundaryAlert, useTheme2 } from '@grafana/ui'; import { appEvents } from 'app/core/core'; import { importPanelPlugin, syncGetPanelPlugin } from '../../plugins/importPanelPlugin'; @@ -39,16 +39,7 @@ export function PanelRenderer

(prop const [plugin, setPlugin] = useState(syncGetPanelPlugin(pluginId)); const [error, setError] = useState(); const optionsWithDefaults = useOptionDefaults(plugin, options, fieldConfig); - const { dataLinkPostProcessor } = usePanelContext(); - const dataWithOverrides = useFieldOverrides( - plugin, - optionsWithDefaults?.fieldConfig, - data, - timeZone, - theme, - replace, - dataLinkPostProcessor - ); + const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults?.fieldConfig, data, timeZone, theme, replace); useEffect(() => { // If we already have a plugin and it's correct one do nothing diff --git a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx index 3f261b56876..cb17a7792fd 100644 --- a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx +++ b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx @@ -4,7 +4,7 @@ import { useMemo, useState } from 'react'; import uPlot from 'uplot'; -import { Field, getDisplayProcessor, PanelProps } from '@grafana/data'; +import { Field, getDisplayProcessor, PanelProps, useDataLinksContext } from '@grafana/data'; import { PanelDataErrorView } from '@grafana/runtime'; import { DashboardCursorSync, TooltipDisplayMode } from '@grafana/schema'; import { @@ -50,11 +50,12 @@ export const CandlestickPanel = ({ onThresholdsChange, canEditThresholds, showThresholds, - dataLinkPostProcessor, eventBus, canExecuteActions, } = usePanelContext(); + const { dataLinkPostProcessor } = useDataLinksContext(); + const userCanExecuteActions = useMemo(() => canExecuteActions?.() ?? false, [canExecuteActions]); const theme = useTheme2(); diff --git a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx index d1369a79508..30ed5965a63 100644 --- a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx +++ b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from 'react'; -import { DashboardCursorSync, PanelProps } from '@grafana/data'; +import { DashboardCursorSync, PanelProps, useDataLinksContext } from '@grafana/data'; import { PanelDataErrorView } from '@grafana/runtime'; import { AxisPlacement, @@ -47,8 +47,9 @@ export const StateTimelinePanel = ({ // temp range set for adding new annotation set by TooltipPlugin2, consumed by AnnotationPlugin2 const [newAnnotationRange, setNewAnnotationRange] = useState(null); - const { sync, eventsScope, canAddAnnotations, dataLinkPostProcessor, eventBus, canExecuteActions } = - usePanelContext(); + const { sync, eventsScope, canAddAnnotations, eventBus, canExecuteActions } = usePanelContext(); + + const { dataLinkPostProcessor } = useDataLinksContext(); const userCanExecuteActions = useMemo(() => canExecuteActions?.() ?? false, [canExecuteActions]); const cursorSync = sync?.() ?? DashboardCursorSync.Off; diff --git a/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx b/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx index be38b2a81f1..bfa2dbdcf99 100644 --- a/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx +++ b/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from 'react'; -import { DashboardCursorSync, PanelProps } from '@grafana/data'; +import { DashboardCursorSync, PanelProps, useDataLinksContext } from '@grafana/data'; import { Trans } from '@grafana/i18n'; import { PanelDataErrorView } from '@grafana/runtime'; import { @@ -48,7 +48,8 @@ export const StatusHistoryPanel = ({ // temp range set for adding new annotation set by TooltipPlugin2, consumed by AnnotationPlugin2 const [newAnnotationRange, setNewAnnotationRange] = useState(null); - const { sync, eventsScope, canAddAnnotations, dataLinkPostProcessor, eventBus } = usePanelContext(); + const { sync, eventsScope, canAddAnnotations, eventBus } = usePanelContext(); + const { dataLinkPostProcessor } = useDataLinksContext(); const cursorSync = sync?.() ?? DashboardCursorSync.Off; const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations()); diff --git a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx index 92ba4d3f97b..bc198392c05 100644 --- a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx +++ b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx @@ -7,6 +7,7 @@ import { DataFrame, alignTimeRangeCompareData, shouldAlignTimeCompare, + useDataLinksContext, FieldType, } from '@grafana/data'; import { PanelDataErrorView } from '@grafana/runtime'; @@ -46,11 +47,12 @@ export const TimeSeriesPanel = ({ onThresholdsChange, canEditThresholds, showThresholds, - dataLinkPostProcessor, eventBus, canExecuteActions, } = usePanelContext(); + const { dataLinkPostProcessor } = useDataLinksContext(); + const userCanExecuteActions = useMemo(() => canExecuteActions?.() ?? false, [canExecuteActions]); // Vertical orientation is not available for users through config. // It is simplified version of horizontal time series panel and it does not support all plugins. diff --git a/public/app/plugins/panel/trend/TrendPanel.tsx b/public/app/plugins/panel/trend/TrendPanel.tsx index d5a7cff51d3..ecfaff896e0 100644 --- a/public/app/plugins/panel/trend/TrendPanel.tsx +++ b/public/app/plugins/panel/trend/TrendPanel.tsx @@ -8,9 +8,10 @@ import { FieldType, PanelProps, TimeRange, + useDataLinksContext, } from '@grafana/data'; import { config, PanelDataErrorView } from '@grafana/runtime'; -import { KeyboardPlugin, TooltipDisplayMode, usePanelContext, TooltipPlugin2 } from '@grafana/ui'; +import { KeyboardPlugin, TooltipDisplayMode, TooltipPlugin2 } from '@grafana/ui'; import { TooltipHoverMode } from '@grafana/ui/internal'; import { XYFieldMatchers } from 'app/core/components/GraphNG/types'; import { preparePlotFrame } from 'app/core/components/GraphNG/utils'; @@ -33,7 +34,7 @@ export const TrendPanel = ({ replaceVariables, id, }: PanelProps) => { - const { dataLinkPostProcessor } = usePanelContext(); + const { dataLinkPostProcessor } = useDataLinksContext(); // Need to fallback to first number field if no xField is set in options otherwise panel crashes 😬 const trendXFieldName = options.xField ?? data.series[0]?.fields.find((field) => field.type === FieldType.number)?.name;