mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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
This commit is contained in:
parent
9b1c0455c4
commit
428b4ae565
@ -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 interface DataLinksContextMenuApi {
|
||||
openMenu?: React.MouseEventHandler<HTMLElement>;
|
||||
targetClassName?: string;
|
||||
}
|
||||
|
||||
export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ children, links }) => {
|
||||
if (!links) {
|
||||
return children({});
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -1,45 +1,58 @@
|
||||
// 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,
|
||||
FieldDisplay,
|
||||
PanelProps,
|
||||
getDisplayValueAlignmentFactors,
|
||||
DisplayValueAlignmentFactors,
|
||||
FieldDisplay,
|
||||
getDisplayValueAlignmentFactors,
|
||||
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 (
|
||||
<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}
|
||||
/>
|
||||
);
|
||||
<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={getLinks}>
|
||||
{api => {
|
||||
return this.renderComponent(valueProps, api);
|
||||
}}
|
||||
</DataLinksContextMenu>
|
||||
);
|
||||
|
@ -1,38 +1,48 @@
|
||||
// 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 (
|
||||
<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}
|
||||
/>
|
||||
);
|
||||
<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={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;
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Utils & Services
|
||||
import { config } from 'app/core/config';
|
||||
|
||||
// Types
|
||||
import { StatPanelOptions } from './types';
|
||||
import {
|
||||
BigValue,
|
||||
BigValueGraphMode,
|
||||
BigValueSparkline,
|
||||
DataLinksContextMenu,
|
||||
VizRepeater,
|
||||
VizRepeaterRenderValueProps,
|
||||
BigValue,
|
||||
DataLinksContextMenu,
|
||||
BigValueSparkline,
|
||||
BigValueGraphMode,
|
||||
} from '@grafana/ui';
|
||||
|
||||
import {
|
||||
PanelProps,
|
||||
getFieldDisplayValues,
|
||||
FieldDisplay,
|
||||
ReducerID,
|
||||
getDisplayValueAlignmentFactors,
|
||||
DisplayValueAlignmentFactors,
|
||||
FieldDisplay,
|
||||
getDisplayValueAlignmentFactors,
|
||||
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>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user