diff --git a/devenv/dev-dashboards/panel-histogram/histogram_tests.json b/devenv/dev-dashboards/panel-histogram/histogram_tests.json index 60ca7a6302b..0c75888c4a3 100644 --- a/devenv/dev-dashboards/panel-histogram/histogram_tests.json +++ b/devenv/dev-dashboards/panel-histogram/histogram_tests.json @@ -341,7 +341,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, "custom": { "align": "auto", @@ -436,7 +436,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, "custom": { "align": "auto", @@ -523,7 +523,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, "custom": { "fillOpacity": 20, @@ -608,7 +608,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, "custom": { "fillOpacity": 20, @@ -693,7 +693,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, "custom": { "fillOpacity": 20, @@ -778,7 +778,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, "custom": { "fillOpacity": 80, @@ -845,7 +845,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, "custom": { "fillOpacity": 80, diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx index fd302ee3287..a6e3fcf1e5e 100644 --- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx +++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx @@ -28,7 +28,7 @@ export const VizTooltipContent = ({ const scrollableStyle: CSSProperties = scrollable ? { maxHeight: maxHeight, - overflowY: 'scroll', + overflowY: 'auto', } : {}; diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx index f08e075a8ac..956b634cd57 100644 --- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx +++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx @@ -47,7 +47,7 @@ export const VizTooltipRow = ({ maxHeight: 55, whiteSpace: 'wrap', wordBreak: 'break-word', - overflowY: 'scroll', + overflowY: 'auto', } : { whiteSpace: 'wrap', diff --git a/public/app/plugins/panel/histogram/Histogram.tsx b/public/app/plugins/panel/histogram/Histogram.tsx index 0a042b1afa7..517069b2d94 100644 --- a/public/app/plugins/panel/histogram/Histogram.tsx +++ b/public/app/plugins/panel/histogram/Histogram.tsx @@ -46,7 +46,7 @@ export interface HistogramProps extends Themeable2 { structureRev?: number; // a number that will change when the frames[] structure changes legend: VizLegendOptions; rawSeries?: DataFrame[]; - children?: (builder: UPlotConfigBuilder, frame: DataFrame) => React.ReactNode; + children?: (builder: UPlotConfigBuilder, frame: DataFrame, xMinOnlyFrame: DataFrame) => React.ReactNode; } export function getBucketSize(frame: DataFrame) { @@ -283,6 +283,7 @@ interface State { alignedData: AlignedData; alignedFrame: DataFrame; config?: UPlotConfigBuilder; + xMinOnlyFrame: DataFrame; } export class Histogram extends React.Component { @@ -295,12 +296,14 @@ export class Histogram extends React.Component { const { alignedFrame } = props; const config = withConfig ? prepConfig(alignedFrame, this.props.theme) : this.state.config!; - const alignedData = preparePlotData(config, xMinOnlyFrame(alignedFrame)); + const xMinOnly = xMinOnlyFrame(alignedFrame); + const alignedData = preparePlotData(config, xMinOnly); return { alignedFrame, alignedData, config, + xMinOnlyFrame: xMinOnly, }; } @@ -347,7 +350,7 @@ export class Histogram extends React.Component { {(vizWidth: number, vizHeight: number) => ( - {children ? children(config, alignedFrame) : null} + {children ? children(config, alignedFrame, this.state.xMinOnlyFrame) : null} )} diff --git a/public/app/plugins/panel/histogram/HistogramPanel.tsx b/public/app/plugins/panel/histogram/HistogramPanel.tsx index fddee1297d6..d0355b5524b 100644 --- a/public/app/plugins/panel/histogram/HistogramPanel.tsx +++ b/public/app/plugins/panel/histogram/HistogramPanel.tsx @@ -2,9 +2,11 @@ import React, { useMemo } from 'react'; import { PanelProps, buildHistogram, getHistogramFields } from '@grafana/data'; import { histogramFieldsToFrame } from '@grafana/data/src/transformations/transformers/histogram'; -import { useTheme2 } from '@grafana/ui'; +import { TooltipDisplayMode, TooltipPlugin2, useTheme2 } from '@grafana/ui'; +import { TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2'; import { Histogram, getBucketSize } from './Histogram'; +import { HistogramTooltip } from './HistogramTooltip'; import { Options } from './panelcfg.gen'; type Props = PanelProps; @@ -67,8 +69,34 @@ export const HistogramPanel = ({ data, options, width, height }: Props) => { bucketSize={bucketSize} bucketCount={options.bucketCount} > - {(config, alignedFrame) => { - return null; // ; + {(builder, alignedFrame, xMinOnlyFrame) => { + return ( + <> + {options.tooltip.mode !== TooltipDisplayMode.None && ( + { + return ( + + ); + }} + maxWidth={options.tooltip.maxWidth} + /> + )} + + ); }} ); diff --git a/public/app/plugins/panel/histogram/HistogramTooltip.tsx b/public/app/plugins/panel/histogram/HistogramTooltip.tsx new file mode 100644 index 00000000000..e61b243d395 --- /dev/null +++ b/public/app/plugins/panel/histogram/HistogramTooltip.tsx @@ -0,0 +1,95 @@ +import { css } from '@emotion/css'; +import React, { ReactNode, useMemo } from 'react'; + +import { DataFrame, formattedValueToString } from '@grafana/data'; +import { SortOrder, TooltipDisplayMode } from '@grafana/schema/dist/esm/common/common.gen'; +import { useStyles2 } from '@grafana/ui'; +import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent'; +import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter'; +import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader'; +import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types'; +import { getContentItems } from '@grafana/ui/src/components/VizTooltip/utils'; + +import { getDataLinks } from '../status-history/utils'; +import { isTooltipScrollable } from '../timeseries/utils'; + +export interface HistogramTooltipProps { + // aligned series frame + series: DataFrame; + xMinOnlyFrame: DataFrame; + + // hovered points + dataIdxs: Array; + // closest/hovered series + seriesIdx?: number | null; + mode?: TooltipDisplayMode; + sortOrder?: SortOrder; + + isPinned: boolean; + maxHeight?: number; +} + +export const HistogramTooltip = ({ + series, + xMinOnlyFrame, + dataIdxs, + seriesIdx, + mode = TooltipDisplayMode.Single, + sortOrder = SortOrder.None, + isPinned, + maxHeight, +}: HistogramTooltipProps) => { + const styles = useStyles2(getStyles); + + const xMinField = series.fields[0]; + const xMaxField = series.fields[1]; + + // use the formatter from other bucket bound if none is defined + const { display: xMinDisp } = xMinField.config.unit != null ? xMinField : xMaxField; + const { display: xMaxDisp } = xMaxField.config.unit != null ? xMaxField : xMinField; + + const xMinVal = formattedValueToString(xMinDisp!(xMinField.values[dataIdxs[0]!])); + const xMaxVal = formattedValueToString(xMaxDisp!(xMaxField.values[dataIdxs[1]!])); + + const headerItem: VizTooltipItem | null = xMinField.config.custom?.hideFrom?.tooltip + ? null + : { + label: 'Bucket', + value: `${xMinVal} - ${xMaxVal}`, + }; + + const contentItems = useMemo( + () => getContentItems(xMinOnlyFrame.fields, xMinField, dataIdxs, seriesIdx, mode, sortOrder), + [xMinOnlyFrame.fields, xMinField, dataIdxs, seriesIdx, mode, sortOrder] + ); + + let footer: ReactNode; + + if (isPinned && seriesIdx != null) { + const field = series.fields[seriesIdx]; + const dataIdx = dataIdxs[seriesIdx]!; + const links = getDataLinks(field, dataIdx); + + footer = ; + } + + return ( +
+ {headerItem != null && } + + {footer} +
+ ); +}; + +export const getStyles = () => ({ + wrapper: css({ + display: 'flex', + flexDirection: 'column', + }), +}); diff --git a/public/app/plugins/panel/histogram/module.tsx b/public/app/plugins/panel/histogram/module.tsx index 7bea3f036aa..c73870cf739 100644 --- a/public/app/plugins/panel/histogram/module.tsx +++ b/public/app/plugins/panel/histogram/module.tsx @@ -66,7 +66,7 @@ export const plugin = new PanelPlugin(HistogramPanel) showIf: (opts, data) => !originalDataHasHistogram(data), }); - // commonOptionsBuilder.addTooltipOptions(builder); + commonOptionsBuilder.addTooltipOptions(builder); commonOptionsBuilder.addLegendOptions(builder); }) .useFieldConfig({