Commit 428b4ae5 by Hugo Häggmark Committed by GitHub

Stat/Gauge/BarGauge: shows default cursor when missing links (#24284)

* Stat/Gauge/BarGauge: shows default cursor when missing links

* Stat/Gauge/BarGauge: shows default cursor when missing links

* Refactor: changes after PR comments
parent 9b1c0455
......@@ -7,6 +7,7 @@ import {
DataFrame,
DisplayValue,
DisplayValueAlignmentFactors,
Field,
FieldConfig,
FieldConfigSource,
FieldType,
......@@ -80,6 +81,7 @@ export interface FieldDisplay {
colIndex?: number; // The field column index
rowIndex?: number; // only filled in when the value is from a row (ie, not a reduction)
getLinks?: () => LinkModel[];
hasLinks: boolean;
}
export interface GetFieldDisplayValuesOptions {
......@@ -168,6 +170,7 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
valueRowIndex: j,
})
: () => [],
hasLinks: hasLinks(field),
});
if (values.length >= limit) {
......@@ -210,6 +213,7 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
calculatedValue: displayValue,
})
: () => [],
hasLinks: hasLinks(field),
});
}
}
......@@ -227,6 +231,10 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
return values;
};
export function hasLinks(field: Field): boolean {
return field.config?.links?.length ? field.config.links.length > 0 : false;
}
export function getDisplayValueAlignmentFactors(values: FieldDisplay[]): DisplayValueAlignmentFactors {
const info: DisplayValueAlignmentFactors = {
title: '',
......@@ -287,6 +295,7 @@ function createNoValuesFieldDisplay(options: GetFieldDisplayValuesOptions): Fiel
numeric: 0,
color: display.color,
},
hasLinks: false,
};
}
......
......@@ -5,15 +5,16 @@ import { linkModelToContextMenuItems } from '../../utils/dataLinks';
import { css } from 'emotion';
interface DataLinksContextMenuProps {
children: (props: { openMenu?: React.MouseEventHandler<HTMLElement>; targetClassName?: string }) => JSX.Element;
links?: () => LinkModel[];
children: (props: DataLinksContextMenuApi) => JSX.Element;
links: () => LinkModel[];
}
export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ children, links }) => {
if (!links) {
return children({});
}
export interface DataLinksContextMenuApi {
openMenu?: React.MouseEventHandler<HTMLElement>;
targetClassName?: string;
}
export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ children, links }) => {
const getDataLinksContextMenuItems = () => {
return [{ items: linkModelToContextMenuItems(links), label: 'Data links' }];
};
......
......@@ -149,6 +149,7 @@ describe('getLinksFromLogsField', () => {
rowIndex,
colIndex,
display: field.display!(field.values.get(rowIndex)),
hasLinks: true,
};
const supplier = getFieldLinksSupplier(fieldDisp);
......
// Libraries
import React, { PureComponent } from 'react';
// Services & Utils
import { config } from 'app/core/config';
import { BarGauge, VizRepeater, VizRepeaterRenderValueProps, DataLinksContextMenu } from '@grafana/ui';
import { BarGaugeOptions } from './types';
import {
getFieldDisplayValues,
DisplayValueAlignmentFactors,
FieldDisplay,
PanelProps,
getDisplayValueAlignmentFactors,
DisplayValueAlignmentFactors,
getFieldDisplayValues,
PanelProps,
} from '@grafana/data';
import { BarGauge, DataLinksContextMenu, VizRepeater, VizRepeaterRenderValueProps } from '@grafana/ui';
import { config } from 'app/core/config';
import { BarGaugeOptions } from './types';
import { DataLinksContextMenuApi } from '@grafana/ui/src/components/DataLinks/DataLinksContextMenu';
export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
renderValue = (valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>): JSX.Element => {
renderComponent = (
valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>,
menuProps: DataLinksContextMenuApi
): JSX.Element => {
const { options } = this.props;
const { value, alignmentFactors, orientation, width, height } = valueProps;
const { field, display, view, colIndex } = value;
const { openMenu, targetClassName } = menuProps;
return (
<BarGauge
value={display}
width={width}
height={height}
orientation={orientation}
field={field}
display={view?.getFieldDisplayProcessor(colIndex)}
theme={config.theme}
itemSpacing={this.getItemSpacing()}
displayMode={options.displayMode}
onClick={openMenu}
className={targetClassName}
alignmentFactors={alignmentFactors}
showUnfilled={options.showUnfilled}
/>
);
};
renderValue = (valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>): JSX.Element => {
const { value } = valueProps;
const { hasLinks, getLinks } = value;
if (!hasLinks) {
return this.renderComponent(valueProps, {});
}
return (
<DataLinksContextMenu links={value.getLinks}>
{({ openMenu, targetClassName }) => {
return (
<BarGauge
value={display}
width={width}
height={height}
orientation={orientation}
field={field}
display={view?.getFieldDisplayProcessor(colIndex)}
theme={config.theme}
itemSpacing={this.getItemSpacing()}
displayMode={options.displayMode}
onClick={openMenu}
className={targetClassName}
alignmentFactors={alignmentFactors}
showUnfilled={options.showUnfilled}
/>
);
<DataLinksContextMenu links={getLinks}>
{api => {
return this.renderComponent(valueProps, api);
}}
</DataLinksContextMenu>
);
......
// Libraries
import React, { PureComponent } from 'react';
import { FieldDisplay, getFieldDisplayValues, PanelProps, VizOrientation } from '@grafana/data';
import { DataLinksContextMenu, Gauge, VizRepeater, VizRepeaterRenderValueProps } from '@grafana/ui';
import { DataLinksContextMenuApi } from '@grafana/ui/src/components/DataLinks/DataLinksContextMenu';
// Services & Utils
import { config } from 'app/core/config';
// Components
import { Gauge, DataLinksContextMenu, VizRepeater, VizRepeaterRenderValueProps } from '@grafana/ui';
// Types
import { GaugeOptions } from './types';
import { FieldDisplay, getFieldDisplayValues, VizOrientation, PanelProps } from '@grafana/data';
export class GaugePanel extends PureComponent<PanelProps<GaugeOptions>> {
renderValue = (valueProps: VizRepeaterRenderValueProps<FieldDisplay>): JSX.Element => {
renderComponent = (
valueProps: VizRepeaterRenderValueProps<FieldDisplay>,
menuProps: DataLinksContextMenuApi
): JSX.Element => {
const { options } = this.props;
const { value, width, height } = valueProps;
const { field, display } = value;
const { openMenu, targetClassName } = menuProps;
return (
<Gauge
value={display}
width={width}
height={height}
field={field}
showThresholdLabels={options.showThresholdLabels}
showThresholdMarkers={options.showThresholdMarkers}
theme={config.theme}
onClick={openMenu}
className={targetClassName}
/>
);
};
renderValue = (valueProps: VizRepeaterRenderValueProps<FieldDisplay>): JSX.Element => {
const { value } = valueProps;
const { getLinks, hasLinks } = value;
if (!hasLinks) {
return this.renderComponent(valueProps, {});
}
return (
<DataLinksContextMenu links={value.getLinks}>
{({ openMenu, targetClassName }) => {
return (
<Gauge
value={display}
width={width}
height={height}
field={field}
showThresholdLabels={options.showThresholdLabels}
showThresholdMarkers={options.showThresholdMarkers}
theme={config.theme}
onClick={openMenu}
className={targetClassName}
/>
);
<DataLinksContextMenu links={getLinks}>
{api => {
return this.renderComponent(valueProps, api);
}}
</DataLinksContextMenu>
);
......
......@@ -24,21 +24,22 @@ import ReactDOM from 'react-dom';
import { GraphLegendProps, Legend } from './Legend/Legend';
import { GraphCtrl } from './module';
import { ContextMenuGroup, ContextMenuItem, graphTimeFormatter, graphTimeFormat } from '@grafana/ui';
import { provideTheme, getCurrentTheme } from 'app/core/utils/ConfigProvider';
import { ContextMenuGroup, ContextMenuItem, graphTimeFormat, graphTimeFormatter } from '@grafana/ui';
import { getCurrentTheme, provideTheme } from 'app/core/utils/ConfigProvider';
import {
toUtc,
LinkModelSupplier,
DataFrame,
DataFrameView,
getValueFormat,
FieldDisplay,
FieldType,
formattedValueToString,
getDisplayProcessor,
getFlotPairsConstant,
PanelEvents,
formattedValueToString,
FieldType,
DataFrame,
getTimeField,
getValueFormat,
hasLinks,
LinkModelSupplier,
PanelEvents,
toUtc,
} from '@grafana/data';
import { GraphContextMenuCtrl } from './GraphContextMenuCtrl';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
......@@ -259,7 +260,8 @@ class GraphElement {
const dataIndex = this.getDataIndexWithNullValuesCorrection(item, dataFrame);
let links: any[] = this.panel.options.dataLinks || [];
if (field.config.links && field.config.links.length) {
const hasLinksValue = hasLinks(field);
if (hasLinksValue) {
// Append the configured links to the panel datalinks
links = [...links, ...field.config.links];
}
......@@ -280,6 +282,7 @@ class GraphElement {
rowIndex: dataIndex,
colIndex: item.series.fieldIndex,
field: fieldConfig,
hasLinks: hasLinksValue,
})
: undefined;
}
......
// Libraries
import React, { PureComponent } from 'react';
// Utils & Services
import { config } from 'app/core/config';
// Types
import { StatPanelOptions } from './types';
import {
VizRepeater,
VizRepeaterRenderValueProps,
BigValue,
DataLinksContextMenu,
BigValueSparkline,
BigValueGraphMode,
BigValueSparkline,
DataLinksContextMenu,
VizRepeater,
VizRepeaterRenderValueProps,
} from '@grafana/ui';
import {
PanelProps,
getFieldDisplayValues,
DisplayValueAlignmentFactors,
FieldDisplay,
ReducerID,
getDisplayValueAlignmentFactors,
DisplayValueAlignmentFactors,
getFieldDisplayValues,
PanelProps,
ReducerID,
} from '@grafana/data';
import { config } from 'app/core/config';
import { StatPanelOptions } from './types';
import { DataLinksContextMenuApi } from '@grafana/ui/src/components/DataLinks/DataLinksContextMenu';
export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
renderValue = (valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>): JSX.Element => {
renderComponent = (
valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>,
menuProps: DataLinksContextMenuApi
): JSX.Element => {
const { timeRange, options } = this.props;
const { value, alignmentFactors, width, height } = valueProps;
const { openMenu, targetClassName } = menuProps;
let sparkline: BigValueSparkline | undefined;
if (value.sparkline) {
......@@ -46,23 +46,33 @@ export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
}
return (
<DataLinksContextMenu links={value.getLinks}>
{({ openMenu, targetClassName }) => {
return (
<BigValue
value={value.display}
sparkline={sparkline}
colorMode={options.colorMode}
graphMode={options.graphMode}
justifyMode={options.justifyMode}
alignmentFactors={alignmentFactors}
width={width}
height={height}
theme={config.theme}
onClick={openMenu}
className={targetClassName}
/>
);
<BigValue
value={value.display}
sparkline={sparkline}
colorMode={options.colorMode}
graphMode={options.graphMode}
justifyMode={options.justifyMode}
alignmentFactors={alignmentFactors}
width={width}
height={height}
theme={config.theme}
onClick={openMenu}
className={targetClassName}
/>
);
};
renderValue = (valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>): JSX.Element => {
const { value } = valueProps;
const { getLinks, hasLinks } = value;
if (!hasLinks) {
return this.renderComponent(valueProps, {});
}
return (
<DataLinksContextMenu links={getLinks}>
{api => {
return this.renderComponent(valueProps, api);
}}
</DataLinksContextMenu>
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment