mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Registry: add a reusable function registry (#17047)
This commit is contained in:
parent
5151b8ce07
commit
c194ae1ba5
@ -2,6 +2,7 @@ export * from './data';
|
||||
export * from './dataLink';
|
||||
export * from './logs';
|
||||
export * from './navModel';
|
||||
export * from './select';
|
||||
export * from './time';
|
||||
export * from './threshold';
|
||||
export * from './utils';
|
||||
|
10
packages/grafana-data/src/types/select.ts
Normal file
10
packages/grafana-data/src/types/select.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Used in select elements
|
||||
*/
|
||||
export interface SelectableValue<T = any> {
|
||||
label?: string;
|
||||
value?: T;
|
||||
imgUrl?: string;
|
||||
description?: string;
|
||||
[key: string]: any;
|
||||
}
|
@ -1,6 +1,14 @@
|
||||
import { getFieldReducers, ReducerID, reduceField } from './index';
|
||||
import { fieldReducers, ReducerID, reduceField } from './fieldReducer';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { DataFrame } from '../types/data';
|
||||
|
||||
/**
|
||||
* Run a reducer and get back the value
|
||||
*/
|
||||
function reduce(series: DataFrame, fieldIndex: number, id: string): any {
|
||||
return reduceField({ series, fieldIndex, reducers: [id] })[id];
|
||||
}
|
||||
|
||||
describe('Stats Calculators', () => {
|
||||
const basicTable = {
|
||||
@ -9,29 +17,16 @@ describe('Stats Calculators', () => {
|
||||
};
|
||||
|
||||
it('should load all standard stats', () => {
|
||||
const names = [
|
||||
ReducerID.sum,
|
||||
ReducerID.max,
|
||||
ReducerID.min,
|
||||
ReducerID.logmin,
|
||||
ReducerID.mean,
|
||||
ReducerID.last,
|
||||
ReducerID.first,
|
||||
ReducerID.count,
|
||||
ReducerID.range,
|
||||
ReducerID.diff,
|
||||
ReducerID.step,
|
||||
ReducerID.delta,
|
||||
// ReducerID.allIsZero,
|
||||
// ReducerID.allIsNull,
|
||||
];
|
||||
const stats = getFieldReducers(names);
|
||||
expect(stats.length).toBe(names.length);
|
||||
for (const id of Object.keys(ReducerID)) {
|
||||
const reducer = fieldReducers.getIfExists(id);
|
||||
const found = reducer ? reducer.id : '<NOT FOUND>';
|
||||
expect(found).toEqual(id);
|
||||
}
|
||||
});
|
||||
|
||||
it('should fail to load unknown stats', () => {
|
||||
const names = ['not a stat', ReducerID.max, ReducerID.min, 'also not a stat'];
|
||||
const stats = getFieldReducers(names);
|
||||
const stats = fieldReducers.list(names);
|
||||
expect(stats.length).toBe(2);
|
||||
|
||||
const found = stats.map(v => v.id);
|
||||
@ -92,6 +87,34 @@ describe('Stats Calculators', () => {
|
||||
expect(stats.delta).toEqual(300);
|
||||
});
|
||||
|
||||
it('consistenly check allIsNull/allIsZero', () => {
|
||||
const empty = {
|
||||
fields: [{ name: 'A' }],
|
||||
rows: [],
|
||||
};
|
||||
const allNull = ({
|
||||
fields: [{ name: 'A' }],
|
||||
rows: [null, null, null, null],
|
||||
} as unknown) as DataFrame;
|
||||
const allNull2 = {
|
||||
fields: [{ name: 'A' }],
|
||||
rows: [[null], [null], [null], [null]],
|
||||
};
|
||||
const allZero = {
|
||||
fields: [{ name: 'A' }],
|
||||
rows: [[0], [0], [0], [0]],
|
||||
};
|
||||
|
||||
expect(reduce(empty, 0, ReducerID.allIsNull)).toEqual(true);
|
||||
expect(reduce(allNull, 0, ReducerID.allIsNull)).toEqual(true);
|
||||
expect(reduce(allNull2, 0, ReducerID.allIsNull)).toEqual(true);
|
||||
|
||||
expect(reduce(empty, 0, ReducerID.allIsZero)).toEqual(false);
|
||||
expect(reduce(allNull, 0, ReducerID.allIsZero)).toEqual(false);
|
||||
expect(reduce(allNull2, 0, ReducerID.allIsZero)).toEqual(false);
|
||||
expect(reduce(allZero, 0, ReducerID.allIsZero)).toEqual(true);
|
||||
});
|
||||
|
||||
it('consistent results for first/last value with null', () => {
|
||||
const info = [
|
||||
{
|
||||
|
@ -1,7 +1,8 @@
|
||||
// Libraries
|
||||
import isNumber from 'lodash/isNumber';
|
||||
|
||||
import { DataFrame, NullValueMode } from '../types/index';
|
||||
import { DataFrame, NullValueMode } from '../types';
|
||||
import { Registry, RegistryItem } from './registry';
|
||||
|
||||
export enum ReducerID {
|
||||
sum = 'sum',
|
||||
@ -34,38 +35,13 @@ export interface FieldCalcs {
|
||||
// Internal function
|
||||
type FieldReducer = (data: DataFrame, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean) => FieldCalcs;
|
||||
|
||||
export interface FieldReducerInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
alias?: string; // optional secondary key. 'avg' vs 'mean', 'total' vs 'sum'
|
||||
|
||||
export interface FieldReducerInfo extends RegistryItem {
|
||||
// Internal details
|
||||
emptyInputResult?: any; // typically null, but some things like 'count' & 'sum' should be zero
|
||||
standard: boolean; // The most common stats can all be calculated in a single pass
|
||||
reduce?: FieldReducer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ids list of stat names or null to get all of them
|
||||
*/
|
||||
export function getFieldReducers(ids?: string[]): FieldReducerInfo[] {
|
||||
if (ids === null || ids === undefined) {
|
||||
if (!hasBuiltIndex) {
|
||||
getById(ReducerID.mean);
|
||||
}
|
||||
return listOfStats;
|
||||
}
|
||||
|
||||
return ids.reduce((list, id) => {
|
||||
const stat = getById(id);
|
||||
if (stat) {
|
||||
list.push(stat);
|
||||
}
|
||||
return list;
|
||||
}, new Array<FieldReducerInfo>());
|
||||
}
|
||||
|
||||
interface ReduceFieldOptions {
|
||||
series: DataFrame;
|
||||
fieldIndex: number;
|
||||
@ -83,7 +59,7 @@ export function reduceField(options: ReduceFieldOptions): FieldCalcs {
|
||||
return {};
|
||||
}
|
||||
|
||||
const queue = getFieldReducers(reducers);
|
||||
const queue = fieldReducers.list(reducers);
|
||||
|
||||
// Return early for empty series
|
||||
// This lets the concrete implementations assume at least one row
|
||||
@ -122,122 +98,107 @@ export function reduceField(options: ReduceFieldOptions): FieldCalcs {
|
||||
//
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// private registry of all stats
|
||||
interface TableStatIndex {
|
||||
[id: string]: FieldReducerInfo;
|
||||
}
|
||||
|
||||
const listOfStats: FieldReducerInfo[] = [];
|
||||
const index: TableStatIndex = {};
|
||||
let hasBuiltIndex = false;
|
||||
|
||||
function getById(id: string): FieldReducerInfo | undefined {
|
||||
if (!hasBuiltIndex) {
|
||||
[
|
||||
{
|
||||
id: ReducerID.lastNotNull,
|
||||
name: 'Last (not null)',
|
||||
description: 'Last non-null value',
|
||||
standard: true,
|
||||
alias: 'current',
|
||||
reduce: calculateLastNotNull,
|
||||
},
|
||||
{
|
||||
id: ReducerID.last,
|
||||
name: 'Last',
|
||||
description: 'Last Value',
|
||||
standard: true,
|
||||
reduce: calculateLast,
|
||||
},
|
||||
{ id: ReducerID.first, name: 'First', description: 'First Value', standard: true, reduce: calculateFirst },
|
||||
{
|
||||
id: ReducerID.firstNotNull,
|
||||
name: 'First (not null)',
|
||||
description: 'First non-null value',
|
||||
standard: true,
|
||||
reduce: calculateFirstNotNull,
|
||||
},
|
||||
{ id: ReducerID.min, name: 'Min', description: 'Minimum Value', standard: true },
|
||||
{ id: ReducerID.max, name: 'Max', description: 'Maximum Value', standard: true },
|
||||
{ id: ReducerID.mean, name: 'Mean', description: 'Average Value', standard: true, alias: 'avg' },
|
||||
{
|
||||
id: ReducerID.sum,
|
||||
name: 'Total',
|
||||
description: 'The sum of all values',
|
||||
emptyInputResult: 0,
|
||||
standard: true,
|
||||
alias: 'total',
|
||||
},
|
||||
{
|
||||
id: ReducerID.count,
|
||||
name: 'Count',
|
||||
description: 'Number of values in response',
|
||||
emptyInputResult: 0,
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.range,
|
||||
name: 'Range',
|
||||
description: 'Difference between minimum and maximum values',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.delta,
|
||||
name: 'Delta',
|
||||
description: 'Cumulative change in value',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.step,
|
||||
name: 'Step',
|
||||
description: 'Minimum interval between values',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.diff,
|
||||
name: 'Difference',
|
||||
description: 'Difference between first and last values',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.logmin,
|
||||
name: 'Min (above zero)',
|
||||
description: 'Used for log min scale',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.changeCount,
|
||||
name: 'Change Count',
|
||||
description: 'Number of times the value changes',
|
||||
standard: false,
|
||||
reduce: calculateChangeCount,
|
||||
},
|
||||
{
|
||||
id: ReducerID.distinctCount,
|
||||
name: 'Distinct Count',
|
||||
description: 'Number of distinct values',
|
||||
standard: false,
|
||||
reduce: calculateDistinctCount,
|
||||
},
|
||||
].forEach(info => {
|
||||
const { id, alias } = info;
|
||||
if (index.hasOwnProperty(id)) {
|
||||
console.warn('Duplicate Stat', id, info, index);
|
||||
}
|
||||
index[id] = info;
|
||||
if (alias) {
|
||||
if (index.hasOwnProperty(alias)) {
|
||||
console.warn('Duplicate Stat (alias)', alias, info, index);
|
||||
}
|
||||
index[alias] = info;
|
||||
}
|
||||
listOfStats.push(info);
|
||||
});
|
||||
hasBuiltIndex = true;
|
||||
}
|
||||
|
||||
return index[id];
|
||||
}
|
||||
export const fieldReducers = new Registry<FieldReducerInfo>(() => [
|
||||
{
|
||||
id: ReducerID.lastNotNull,
|
||||
name: 'Last (not null)',
|
||||
description: 'Last non-null value',
|
||||
standard: true,
|
||||
alias: 'current',
|
||||
reduce: calculateLastNotNull,
|
||||
},
|
||||
{
|
||||
id: ReducerID.last,
|
||||
name: 'Last',
|
||||
description: 'Last Value',
|
||||
standard: true,
|
||||
reduce: calculateLast,
|
||||
},
|
||||
{ id: ReducerID.first, name: 'First', description: 'First Value', standard: true, reduce: calculateFirst },
|
||||
{
|
||||
id: ReducerID.firstNotNull,
|
||||
name: 'First (not null)',
|
||||
description: 'First non-null value',
|
||||
standard: true,
|
||||
reduce: calculateFirstNotNull,
|
||||
},
|
||||
{ id: ReducerID.min, name: 'Min', description: 'Minimum Value', standard: true },
|
||||
{ id: ReducerID.max, name: 'Max', description: 'Maximum Value', standard: true },
|
||||
{ id: ReducerID.mean, name: 'Mean', description: 'Average Value', standard: true, alias: 'avg' },
|
||||
{
|
||||
id: ReducerID.sum,
|
||||
name: 'Total',
|
||||
description: 'The sum of all values',
|
||||
emptyInputResult: 0,
|
||||
standard: true,
|
||||
alias: 'total',
|
||||
},
|
||||
{
|
||||
id: ReducerID.count,
|
||||
name: 'Count',
|
||||
description: 'Number of values in response',
|
||||
emptyInputResult: 0,
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.range,
|
||||
name: 'Range',
|
||||
description: 'Difference between minimum and maximum values',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.delta,
|
||||
name: 'Delta',
|
||||
description: 'Cumulative change in value',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.step,
|
||||
name: 'Step',
|
||||
description: 'Minimum interval between values',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.diff,
|
||||
name: 'Difference',
|
||||
description: 'Difference between first and last values',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.logmin,
|
||||
name: 'Min (above zero)',
|
||||
description: 'Used for log min scale',
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.allIsZero,
|
||||
name: 'All Zeros',
|
||||
description: 'All values are zero',
|
||||
emptyInputResult: false,
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.allIsNull,
|
||||
name: 'All Nulls',
|
||||
description: 'All values are null',
|
||||
emptyInputResult: true,
|
||||
standard: true,
|
||||
},
|
||||
{
|
||||
id: ReducerID.changeCount,
|
||||
name: 'Change Count',
|
||||
description: 'Number of times the value changes',
|
||||
standard: false,
|
||||
reduce: calculateChangeCount,
|
||||
},
|
||||
{
|
||||
id: ReducerID.distinctCount,
|
||||
name: 'Distinct Count',
|
||||
description: 'Number of distinct values',
|
||||
standard: false,
|
||||
reduce: calculateDistinctCount,
|
||||
},
|
||||
]);
|
||||
|
||||
function doStandardCalcs(data: DataFrame, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs {
|
||||
const calcs = {
|
||||
@ -253,7 +214,7 @@ function doStandardCalcs(data: DataFrame, fieldIndex: number, ignoreNulls: boole
|
||||
count: 0,
|
||||
nonNullCount: 0,
|
||||
allIsNull: true,
|
||||
allIsZero: false,
|
||||
allIsZero: true,
|
||||
range: null,
|
||||
diff: null,
|
||||
delta: 0,
|
||||
@ -264,7 +225,7 @@ function doStandardCalcs(data: DataFrame, fieldIndex: number, ignoreNulls: boole
|
||||
} as FieldCalcs;
|
||||
|
||||
for (let i = 0; i < data.rows.length; i++) {
|
||||
let currentValue = data.rows[i][fieldIndex];
|
||||
let currentValue = data.rows[i] ? data.rows[i][fieldIndex] : null;
|
||||
if (i === 0) {
|
||||
calcs.first = currentValue;
|
||||
}
|
||||
@ -350,6 +311,10 @@ function doStandardCalcs(data: DataFrame, fieldIndex: number, ignoreNulls: boole
|
||||
calcs.mean = calcs.sum! / calcs.nonNullCount;
|
||||
}
|
||||
|
||||
if (calcs.allIsNull) {
|
||||
calcs.allIsZero = false;
|
||||
}
|
||||
|
||||
if (calcs.max !== null && calcs.min !== null) {
|
||||
calcs.range = calcs.max - calcs.min;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
export * from './string';
|
||||
export * from './registry';
|
||||
export * from './markdown';
|
||||
export * from './processDataFrame';
|
||||
export * from './csv';
|
||||
|
134
packages/grafana-data/src/utils/registry.ts
Normal file
134
packages/grafana-data/src/utils/registry.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import { SelectableValue } from '../types/select';
|
||||
|
||||
export interface RegistryItem {
|
||||
id: string; // Unique Key -- saved in configs
|
||||
name: string; // Display Name, can change without breaking configs
|
||||
description: string;
|
||||
aliasIds?: string[]; // when the ID changes, we may want backwards compatibility ('current' => 'last')
|
||||
|
||||
/**
|
||||
* Some extensions should not be user selectable
|
||||
* like: 'all' and 'any' matchers;
|
||||
*/
|
||||
excludeFromPicker?: boolean;
|
||||
}
|
||||
|
||||
interface RegistrySelectInfo {
|
||||
options: Array<SelectableValue<string>>;
|
||||
current: Array<SelectableValue<string>>;
|
||||
}
|
||||
|
||||
export class Registry<T extends RegistryItem> {
|
||||
private ordered: T[] = [];
|
||||
private byId = new Map<string, T>();
|
||||
private initalized = false;
|
||||
|
||||
constructor(private init?: () => T[]) {}
|
||||
|
||||
getIfExists(id: string | undefined): T | undefined {
|
||||
if (!this.initalized) {
|
||||
if (this.init) {
|
||||
for (const ext of this.init()) {
|
||||
this.register(ext);
|
||||
}
|
||||
}
|
||||
this.sort();
|
||||
this.initalized = true;
|
||||
}
|
||||
if (id) {
|
||||
return this.byId.get(id);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
get(id: string): T {
|
||||
const v = this.getIfExists(id);
|
||||
if (!v) {
|
||||
throw new Error('Undefined: ' + id);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
selectOptions(current?: string[], filter?: (ext: T) => boolean): RegistrySelectInfo {
|
||||
if (!this.initalized) {
|
||||
this.getIfExists('xxx'); // will trigger init
|
||||
}
|
||||
|
||||
const select = {
|
||||
options: [],
|
||||
current: [],
|
||||
} as RegistrySelectInfo;
|
||||
|
||||
const currentIds: any = {};
|
||||
if (current) {
|
||||
for (const id of current) {
|
||||
currentIds[id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const ext of this.ordered) {
|
||||
if (ext.excludeFromPicker) {
|
||||
continue;
|
||||
}
|
||||
if (filter && !filter(ext)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const option = {
|
||||
value: ext.id,
|
||||
label: ext.name,
|
||||
description: ext.description,
|
||||
};
|
||||
|
||||
select.options.push(option);
|
||||
if (currentIds[ext.id]) {
|
||||
select.current.push(option);
|
||||
}
|
||||
}
|
||||
return select;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of values by ID, or all values if not specified
|
||||
*/
|
||||
list(ids?: any[]): T[] {
|
||||
if (ids) {
|
||||
const found: T[] = [];
|
||||
for (const id of ids) {
|
||||
const v = this.getIfExists(id);
|
||||
if (v) {
|
||||
found.push(v);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
if (!this.initalized) {
|
||||
this.getIfExists('xxx'); // will trigger init
|
||||
}
|
||||
return [...this.ordered]; // copy of everythign just in case
|
||||
}
|
||||
|
||||
register(ext: T) {
|
||||
if (this.byId.has(ext.id)) {
|
||||
throw new Error('Duplicate Key:' + ext.id);
|
||||
}
|
||||
this.byId.set(ext.id, ext);
|
||||
this.ordered.push(ext);
|
||||
|
||||
if (ext.aliasIds) {
|
||||
for (const alias of ext.aliasIds) {
|
||||
if (!this.byId.has(alias)) {
|
||||
this.byId.set(alias, ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.initalized) {
|
||||
this.sort();
|
||||
}
|
||||
}
|
||||
|
||||
private sort() {
|
||||
// TODO sort the list
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { SelectOptionItem } from '../Select/Select';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import { ButtonSelect } from '../Select/ButtonSelect';
|
||||
|
||||
@ -23,7 +23,7 @@ export class RefreshPicker extends PureComponent<Props> {
|
||||
super(props);
|
||||
}
|
||||
|
||||
intervalsToOptions = (intervals: string[] | undefined): Array<SelectOptionItem<string>> => {
|
||||
intervalsToOptions = (intervals: string[] | undefined): Array<SelectableValue<string>> => {
|
||||
const intervalsOrDefault = intervals || defaultIntervals;
|
||||
const options = intervalsOrDefault
|
||||
.filter(str => str !== '')
|
||||
@ -37,7 +37,7 @@ export class RefreshPicker extends PureComponent<Props> {
|
||||
return options;
|
||||
};
|
||||
|
||||
onChangeSelect = (item: SelectOptionItem<string>) => {
|
||||
onChangeSelect = (item: SelectableValue<string>) => {
|
||||
const { onIntervalChanged } = this.props;
|
||||
if (onIntervalChanged) {
|
||||
// @ts-ignore
|
||||
|
@ -4,7 +4,7 @@ import { action } from '@storybook/addon-actions';
|
||||
import { withKnobs, object, text } from '@storybook/addon-knobs';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { UseState } from '../../utils/storybook/UseState';
|
||||
import { SelectOptionItem } from './Select';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { ButtonSelect } from './ButtonSelect';
|
||||
|
||||
const ButtonSelectStories = storiesOf('UI/Select/ButtonSelect', module);
|
||||
@ -12,9 +12,9 @@ const ButtonSelectStories = storiesOf('UI/Select/ButtonSelect', module);
|
||||
ButtonSelectStories.addDecorator(withCenteredStory).addDecorator(withKnobs);
|
||||
|
||||
ButtonSelectStories.add('default', () => {
|
||||
const intialState: SelectOptionItem<string> = { label: 'A label', value: 'A value' };
|
||||
const value = object<SelectOptionItem<string>>('Selected Value:', intialState);
|
||||
const options = object<Array<SelectOptionItem<string>>>('Options:', [
|
||||
const intialState: SelectableValue<string> = { label: 'A label', value: 'A value' };
|
||||
const value = object<SelectableValue<string>>('Selected Value:', intialState);
|
||||
const options = object<Array<SelectableValue<string>>>('Options:', [
|
||||
intialState,
|
||||
{ label: 'Another label', value: 'Another value' },
|
||||
]);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { PureComponent, ReactElement } from 'react';
|
||||
import Select, { SelectOptionItem } from './Select';
|
||||
import Select from './Select';
|
||||
import { PopperContent } from '../Tooltip/PopperController';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
interface ButtonComponentProps {
|
||||
label: ReactElement | string | undefined;
|
||||
@ -30,13 +31,13 @@ const ButtonComponent = (buttonProps: ButtonComponentProps) => (props: any) => {
|
||||
|
||||
export interface Props<T> {
|
||||
className: string | undefined;
|
||||
options: Array<SelectOptionItem<T>>;
|
||||
value?: SelectOptionItem<T>;
|
||||
options: Array<SelectableValue<T>>;
|
||||
value?: SelectableValue<T>;
|
||||
label?: ReactElement | string;
|
||||
iconClass?: string;
|
||||
components?: any;
|
||||
maxMenuHeight?: number;
|
||||
onChange: (item: SelectOptionItem<T>) => void;
|
||||
onChange: (item: SelectableValue<T>) => void;
|
||||
tooltipContent?: PopperContent<any>;
|
||||
isMenuOpen?: boolean;
|
||||
onOpenMenu?: () => void;
|
||||
@ -45,7 +46,7 @@ export interface Props<T> {
|
||||
}
|
||||
|
||||
export class ButtonSelect<T> extends PureComponent<Props<T>> {
|
||||
onChange = (item: SelectOptionItem<T>) => {
|
||||
onChange = (item: SelectableValue<T>) => {
|
||||
const { onChange } = this.props;
|
||||
onChange(item);
|
||||
};
|
||||
|
@ -19,23 +19,16 @@ import resetSelectStyles from './resetSelectStyles';
|
||||
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
|
||||
import { PopperContent } from '../Tooltip/PopperController';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
|
||||
export interface SelectOptionItem<T> {
|
||||
label?: string;
|
||||
value?: T;
|
||||
imgUrl?: string;
|
||||
description?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
export interface CommonProps<T> {
|
||||
defaultValue?: any;
|
||||
getOptionLabel?: (item: SelectOptionItem<T>) => string;
|
||||
getOptionValue?: (item: SelectOptionItem<T>) => string;
|
||||
onChange: (item: SelectOptionItem<T>) => {} | void;
|
||||
getOptionLabel?: (item: SelectableValue<T>) => string;
|
||||
getOptionValue?: (item: SelectableValue<T>) => string;
|
||||
onChange: (item: SelectableValue<T>) => {} | void;
|
||||
placeholder?: string;
|
||||
width?: number;
|
||||
value?: SelectOptionItem<T>;
|
||||
value?: SelectableValue<T>;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
isSearchable?: boolean;
|
||||
@ -57,12 +50,12 @@ export interface CommonProps<T> {
|
||||
}
|
||||
|
||||
export interface SelectProps<T> extends CommonProps<T> {
|
||||
options: Array<SelectOptionItem<T>>;
|
||||
options: Array<SelectableValue<T>>;
|
||||
}
|
||||
|
||||
interface AsyncProps<T> extends CommonProps<T> {
|
||||
defaultOptions: boolean;
|
||||
loadOptions: (query: string) => Promise<Array<SelectOptionItem<T>>>;
|
||||
loadOptions: (query: string) => Promise<Array<SelectableValue<T>>>;
|
||||
loadingMessage?: () => string;
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,10 @@ import { interval, Subscription, Subject, of, NEVER } from 'rxjs';
|
||||
import { tap, switchMap } from 'rxjs/operators';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { stringToMs } from '@grafana/data';
|
||||
import { stringToMs, SelectableValue } from '@grafana/data';
|
||||
import { isLive } from '../RefreshPicker/RefreshPicker';
|
||||
import { SelectOptionItem } from '../Select/Select';
|
||||
|
||||
export function getIntervalFromString(strInterval: string): SelectOptionItem<number> {
|
||||
export function getIntervalFromString(strInterval: string): SelectableValue<number> {
|
||||
return {
|
||||
label: strInterval,
|
||||
value: stringToMs(strInterval),
|
||||
|
@ -8,10 +8,10 @@ import { StatsPicker } from '../StatsPicker/StatsPicker';
|
||||
|
||||
// Types
|
||||
import { FieldDisplayOptions, DEFAULT_FIELD_DISPLAY_VALUES_LIMIT } from '../../utils/fieldDisplay';
|
||||
import Select, { SelectOptionItem } from '../Select/Select';
|
||||
import { Field, ReducerID, toNumberString, toIntegerOrUndefined } from '@grafana/data';
|
||||
import Select from '../Select/Select';
|
||||
import { Field, ReducerID, toNumberString, toIntegerOrUndefined, SelectableValue } from '@grafana/data';
|
||||
|
||||
const showOptions: Array<SelectOptionItem<boolean>> = [
|
||||
const showOptions: Array<SelectableValue<boolean>> = [
|
||||
{
|
||||
value: true,
|
||||
label: 'All Values',
|
||||
@ -31,7 +31,7 @@ export interface Props {
|
||||
}
|
||||
|
||||
export class FieldDisplayEditor extends PureComponent<Props> {
|
||||
onShowValuesChange = (item: SelectOptionItem<boolean>) => {
|
||||
onShowValuesChange = (item: SelectableValue<boolean>) => {
|
||||
const val = item.value === true;
|
||||
this.props.onChange({ ...this.props.value, values: val });
|
||||
};
|
||||
|
@ -7,8 +7,7 @@ import { FormLabel } from '../FormLabel/FormLabel';
|
||||
import { UnitPicker } from '../UnitPicker/UnitPicker';
|
||||
|
||||
// Types
|
||||
import { toIntegerOrUndefined, Field } from '@grafana/data';
|
||||
import { SelectOptionItem } from '../Select/Select';
|
||||
import { toIntegerOrUndefined, Field, SelectableValue } from '@grafana/data';
|
||||
|
||||
import { VAR_SERIES_NAME, VAR_FIELD_NAME, VAR_CALC, VAR_CELL_PREFIX } from '../../utils/fieldDisplay';
|
||||
|
||||
@ -54,7 +53,7 @@ export const FieldPropertiesEditor: React.FC<Props> = ({ value, onChange, showMi
|
||||
[value.max, onChange]
|
||||
);
|
||||
|
||||
const onUnitChange = (unit: SelectOptionItem<string>) => {
|
||||
const onUnitChange = (unit: SelectableValue<string>) => {
|
||||
onChange({ ...value, unit: unit.value });
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,7 @@ import omit from 'lodash/omit';
|
||||
|
||||
import { VizOrientation, PanelModel } from '../../types/panel';
|
||||
import { FieldDisplayOptions } from '../../utils/fieldDisplay';
|
||||
import { Field, getFieldReducers, Threshold, sortThresholds } from '@grafana/data';
|
||||
import { Field, fieldReducers, Threshold, sortThresholds } from '@grafana/data';
|
||||
|
||||
export interface SingleStatBaseOptions {
|
||||
fieldOptions: FieldDisplayOptions;
|
||||
@ -48,7 +48,10 @@ export const sharedSingleStatMigrationCheck = (panel: PanelModel<SingleStatBaseO
|
||||
|
||||
// Make sure the stats have a valid name
|
||||
if (valueOptions.stat) {
|
||||
fieldOptions.calcs = getFieldReducers([valueOptions.stat]).map(s => s.id);
|
||||
const reducer = fieldReducers.get(valueOptions.stat);
|
||||
if (reducer) {
|
||||
fieldOptions.calcs = [reducer.id];
|
||||
}
|
||||
}
|
||||
|
||||
field.min = old.minValue;
|
||||
|
@ -5,8 +5,7 @@ import difference from 'lodash/difference';
|
||||
|
||||
import { Select } from '../index';
|
||||
|
||||
import { getFieldReducers } from '@grafana/data';
|
||||
import { SelectOptionItem } from '../Select/Select';
|
||||
import { fieldReducers, SelectableValue } from '@grafana/data';
|
||||
|
||||
interface Props {
|
||||
placeholder?: string;
|
||||
@ -34,7 +33,7 @@ export class StatsPicker extends PureComponent<Props> {
|
||||
checkInput = () => {
|
||||
const { stats, allowMultiple, defaultStat, onChange } = this.props;
|
||||
|
||||
const current = getFieldReducers(stats);
|
||||
const current = fieldReducers.list(stats);
|
||||
if (current.length !== stats.length) {
|
||||
const found = current.map(v => v.id);
|
||||
const notFound = difference(stats, found);
|
||||
@ -54,7 +53,7 @@ export class StatsPicker extends PureComponent<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
onSelectionChange = (item: SelectOptionItem<string>) => {
|
||||
onSelectionChange = (item: SelectableValue<string>) => {
|
||||
const { onChange } = this.props;
|
||||
if (isArray(item)) {
|
||||
onChange(item.map(v => v.value));
|
||||
@ -65,24 +64,16 @@ export class StatsPicker extends PureComponent<Props> {
|
||||
|
||||
render() {
|
||||
const { width, stats, allowMultiple, defaultStat, placeholder } = this.props;
|
||||
const options = getFieldReducers().map(s => {
|
||||
return {
|
||||
value: s.id,
|
||||
label: s.name,
|
||||
description: s.description,
|
||||
};
|
||||
});
|
||||
|
||||
const value: Array<SelectOptionItem<string>> = options.filter(option => stats.find(stat => option.value === stat));
|
||||
|
||||
const select = fieldReducers.selectOptions(stats);
|
||||
return (
|
||||
<Select
|
||||
width={width}
|
||||
value={value}
|
||||
value={select.current}
|
||||
isClearable={!defaultStat}
|
||||
isMulti={allowMultiple}
|
||||
isSearchable={true}
|
||||
options={options}
|
||||
options={select.options}
|
||||
placeholder={placeholder}
|
||||
onChange={this.onSelectionChange}
|
||||
/>
|
||||
|
@ -13,8 +13,7 @@ import { rangeUtil } from '@grafana/data';
|
||||
import { rawToTimeRange } from './time';
|
||||
|
||||
// Types
|
||||
import { TimeRange, TimeOption, TimeZone, TIME_FORMAT } from '@grafana/data';
|
||||
import { SelectOptionItem } from '../Select/Select';
|
||||
import { TimeRange, TimeOption, TimeZone, TIME_FORMAT, SelectableValue } from '@grafana/data';
|
||||
|
||||
export interface Props {
|
||||
value: TimeRange;
|
||||
@ -77,7 +76,7 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
isCustomOpen: false,
|
||||
};
|
||||
|
||||
mapTimeOptionsToSelectOptionItems = (selectOptions: TimeOption[]) => {
|
||||
mapTimeOptionsToSelectableValues = (selectOptions: TimeOption[]) => {
|
||||
const options = selectOptions.map(timeOption => {
|
||||
return {
|
||||
label: timeOption.display,
|
||||
@ -93,7 +92,7 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
return options;
|
||||
};
|
||||
|
||||
onSelectChanged = (item: SelectOptionItem<TimeOption>) => {
|
||||
onSelectChanged = (item: SelectableValue<TimeOption>) => {
|
||||
const { onChange, timeZone } = this.props;
|
||||
|
||||
if (item.value && item.value.from === 'custom') {
|
||||
@ -122,7 +121,7 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
render() {
|
||||
const { selectOptions: selectTimeOptions, value, onMoveBackward, onMoveForward, onZoom, timeZone } = this.props;
|
||||
const { isCustomOpen } = this.state;
|
||||
const options = this.mapTimeOptionsToSelectOptionItems(selectTimeOptions);
|
||||
const options = this.mapTimeOptionsToSelectableValues(selectTimeOptions);
|
||||
const currentOption = options.find(item => isTimeOptionEqualToTimeRange(item.value, value));
|
||||
const rangeString = rangeUtil.describeTimeRange(value.raw);
|
||||
|
||||
|
@ -9,7 +9,7 @@ export * from './Button/Button';
|
||||
export { ButtonVariant } from './Button/AbstractButton';
|
||||
|
||||
// Select
|
||||
export { Select, AsyncSelect, SelectOptionItem } from './Select/Select';
|
||||
export { Select, AsyncSelect } from './Select/Select';
|
||||
export { IndicatorsContainer } from './Select/IndicatorsContainer';
|
||||
export { NoOptionsMessage } from './Select/NoOptionsMessage';
|
||||
export { default as resetSelectStyles } from './Select/resetSelectStyles';
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { Component } from 'react';
|
||||
import { UserPicker } from 'app/core/components/Select/UserPicker';
|
||||
import { TeamPicker, Team } from 'app/core/components/Select/TeamPicker';
|
||||
import { Select, SelectOptionItem } from '@grafana/ui';
|
||||
import { Select } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { User } from 'app/types';
|
||||
import {
|
||||
dashboardPermissionLevels,
|
||||
@ -61,7 +62,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
|
||||
this.setState({ teamId: team && !Array.isArray(team) ? team.id : 0 });
|
||||
};
|
||||
|
||||
onPermissionChanged = (permission: SelectOptionItem<PermissionLevel>) => {
|
||||
onPermissionChanged = (permission: SelectableValue<PermissionLevel>) => {
|
||||
this.setState({ permission: permission.value });
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Select, SelectOptionItem } from '@grafana/ui';
|
||||
import { Select } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl';
|
||||
import { FolderInfo } from 'app/types';
|
||||
|
||||
@ -39,7 +40,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export default class PermissionsListItem extends PureComponent<Props> {
|
||||
onPermissionChanged = (option: SelectOptionItem<PermissionLevel>) => {
|
||||
onPermissionChanged = (option: SelectableValue<PermissionLevel>) => {
|
||||
this.props.onPermissionChanged(this.props.item, option.value);
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,8 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Components
|
||||
import { Select, SelectOptionItem } from '@grafana/ui';
|
||||
import { Select } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
// Types
|
||||
import { DataSourceSelectItem } from '@grafana/ui';
|
||||
@ -28,7 +29,7 @@ export class DataSourcePicker extends PureComponent<Props> {
|
||||
super(props);
|
||||
}
|
||||
|
||||
onChange = (item: SelectOptionItem<string>) => {
|
||||
onChange = (item: SelectableValue<string>) => {
|
||||
const ds = this.props.datasources.find(ds => ds.name === item.value);
|
||||
this.props.onChange(ds);
|
||||
};
|
||||
|
@ -1,12 +1,13 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Select, SelectOptionItem } from '@grafana/ui';
|
||||
import { Select } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Variable } from 'app/types/templates';
|
||||
|
||||
export interface Props {
|
||||
onChange: (value: string) => void;
|
||||
options: Array<SelectOptionItem<string>>;
|
||||
options: Array<SelectableValue<string>>;
|
||||
isSearchable: boolean;
|
||||
value: string;
|
||||
placeholder?: string;
|
||||
@ -15,7 +16,7 @@ export interface Props {
|
||||
}
|
||||
|
||||
interface State {
|
||||
options: Array<SelectOptionItem<string>>;
|
||||
options: Array<SelectableValue<string>>;
|
||||
}
|
||||
|
||||
export class MetricSelect extends React.Component<Props, State> {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { Select, GrafanaTheme, ThemeContext, SelectOptionItem } from '@grafana/ui';
|
||||
import { Select, GrafanaTheme, ThemeContext } from '@grafana/ui';
|
||||
import { css, cx } from 'emotion';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
const getStyles = (theme: GrafanaTheme) => ({
|
||||
keyValueContainer: css`
|
||||
@ -33,7 +34,7 @@ export const AdHocFilter: React.FunctionComponent<Props> = props => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const styles = getStyles(theme);
|
||||
|
||||
const onChange = (changeType: ChangeType) => (item: SelectOptionItem<string>) => {
|
||||
const onChange = (changeType: ChangeType) => (item: SelectableValue<string>) => {
|
||||
const { onKeyChanged, onValueChanged, onOperatorChanged } = props;
|
||||
switch (changeType) {
|
||||
case ChangeType.Key:
|
||||
|
@ -3,8 +3,8 @@ import { connect } from 'react-redux';
|
||||
import { hot } from 'react-hot-loader';
|
||||
|
||||
import { ExploreId, ExploreMode } from 'app/types/explore';
|
||||
import { DataSourceSelectItem, SelectOptionItem } from '@grafana/ui';
|
||||
import { RawTimeRange, TimeZone, TimeRange, LoadingState } from '@grafana/data';
|
||||
import { DataSourceSelectItem } from '@grafana/ui';
|
||||
import { RawTimeRange, TimeZone, TimeRange, LoadingState, SelectableValue } from '@grafana/data';
|
||||
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
||||
import { StoreState } from 'app/types/store';
|
||||
import {
|
||||
@ -67,8 +67,8 @@ interface StateProps {
|
||||
selectedDatasource: DataSourceSelectItem;
|
||||
splitted: boolean;
|
||||
refreshInterval: string;
|
||||
supportedModeOptions: Array<SelectOptionItem<ExploreMode>>;
|
||||
selectedModeOption: SelectOptionItem<ExploreMode>;
|
||||
supportedModeOptions: Array<SelectableValue<ExploreMode>>;
|
||||
selectedModeOption: SelectableValue<ExploreMode>;
|
||||
hasLiveOption: boolean;
|
||||
isLive: boolean;
|
||||
}
|
||||
@ -258,7 +258,7 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps
|
||||
const hasLiveOption =
|
||||
datasourceInstance && datasourceInstance.meta && datasourceInstance.meta.streaming ? true : false;
|
||||
|
||||
const supportedModeOptions: Array<SelectOptionItem<ExploreMode>> = [];
|
||||
const supportedModeOptions: Array<SelectableValue<ExploreMode>> = [];
|
||||
let selectedModeOption = null;
|
||||
for (const supportedMode of supportedModes) {
|
||||
switch (supportedMode) {
|
||||
|
@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
|
||||
import { TeamMember, TeamPermissionLevel } from '../../types';
|
||||
import { getMockTeamMember } from './__mocks__/teamMocks';
|
||||
import { TeamMemberRow, Props } from './TeamMemberRow';
|
||||
import { SelectOptionItem } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
@ -80,7 +80,7 @@ describe('Functions', () => {
|
||||
};
|
||||
const { instance } = setup({ member });
|
||||
const permission = TeamPermissionLevel.Admin;
|
||||
const item: SelectOptionItem<TeamPermissionLevel> = { value: permission };
|
||||
const item: SelectableValue<TeamPermissionLevel> = { value: permission };
|
||||
const expectedTeamMemeber = { ...member, permission };
|
||||
|
||||
instance.onPermissionChange(item, member);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { DeleteButton, Select, SelectOptionItem } from '@grafana/ui';
|
||||
import { DeleteButton, Select } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
import { TeamMember, teamsPermissionLevels, TeamPermissionLevel } from 'app/types';
|
||||
import { WithFeatureToggle } from 'app/core/components/WithFeatureToggle';
|
||||
@ -27,7 +28,7 @@ export class TeamMemberRow extends PureComponent<Props> {
|
||||
this.props.removeTeamMember(member.userId);
|
||||
}
|
||||
|
||||
onPermissionChange = (item: SelectOptionItem<TeamPermissionLevel>, member: TeamMember) => {
|
||||
onPermissionChange = (item: SelectableValue<TeamPermissionLevel>, member: TeamMember) => {
|
||||
const permission = item.value;
|
||||
const updatedTeamMember = { ...member, permission };
|
||||
|
||||
|
@ -5,8 +5,8 @@ import React, { PureComponent } from 'react';
|
||||
import { InputDatasource, describeDataFrame } from './InputDatasource';
|
||||
import { InputQuery, InputOptions } from './types';
|
||||
|
||||
import { FormLabel, Select, QueryEditorProps, SelectOptionItem, TableInputCSV } from '@grafana/ui';
|
||||
import { DataFrame, toCSV } from '@grafana/data';
|
||||
import { FormLabel, Select, QueryEditorProps, TableInputCSV } from '@grafana/ui';
|
||||
import { DataFrame, toCSV, SelectableValue } from '@grafana/data';
|
||||
|
||||
type Props = QueryEditorProps<InputDatasource, InputQuery, InputOptions>;
|
||||
|
||||
@ -30,7 +30,7 @@ export class InputQueryEditor extends PureComponent<Props, State> {
|
||||
this.setState({ text });
|
||||
}
|
||||
|
||||
onSourceChange = (item: SelectOptionItem<string>) => {
|
||||
onSourceChange = (item: SelectableValue<string>) => {
|
||||
const { datasource, query, onChange, onRunQuery } = this.props;
|
||||
let data: DataFrame[] | undefined = undefined;
|
||||
if (item.value === 'panel') {
|
||||
|
@ -1,9 +1,6 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Components
|
||||
// import { Select, SelectOptionItem } from '@grafana/ui';
|
||||
|
||||
// Types
|
||||
import { QueryEditorProps } from '@grafana/ui';
|
||||
import { LokiDatasource } from '../datasource';
|
||||
@ -37,7 +34,7 @@ export class LokiQueryEditor extends PureComponent<Props> {
|
||||
// });
|
||||
// };
|
||||
//
|
||||
// onFormatChanged = (option: SelectOptionItem) => {
|
||||
// onFormatChanged = (option: SelectableValue) => {
|
||||
// this.props.onChange({
|
||||
// ...this.state.query,
|
||||
// resultFormat: option.value,
|
||||
@ -47,7 +44,7 @@ export class LokiQueryEditor extends PureComponent<Props> {
|
||||
render() {
|
||||
// const { query } = this.state;
|
||||
// const { datasource } = this.props;
|
||||
// const formatOptions: SelectOptionItem[] = [
|
||||
// const formatOptions: SelectableValue[] = [
|
||||
// { label: 'Time Series', value: 'time_series' },
|
||||
// { label: 'Table', value: 'table' },
|
||||
// ];
|
||||
|
@ -2,33 +2,32 @@ import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Types
|
||||
import { FormLabel, Select, SelectOptionItem, Switch } from '@grafana/ui';
|
||||
import { QueryEditorProps, DataSourceStatus } from '@grafana/ui';
|
||||
import { FormLabel, Select, Switch, QueryEditorProps, DataSourceStatus } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
import { PrometheusDatasource } from '../datasource';
|
||||
import { PromQuery, PromOptions } from '../types';
|
||||
|
||||
import PromQueryField from './PromQueryField';
|
||||
import PromLink from './PromLink';
|
||||
|
||||
export type Props = QueryEditorProps<PrometheusDatasource, PromQuery, PromOptions>;
|
||||
|
||||
const FORMAT_OPTIONS: Array<SelectOptionItem<string>> = [
|
||||
const FORMAT_OPTIONS: Array<SelectableValue<string>> = [
|
||||
{ label: 'Time series', value: 'time_series' },
|
||||
{ label: 'Table', value: 'table' },
|
||||
{ label: 'Heatmap', value: 'heatmap' },
|
||||
];
|
||||
|
||||
const INTERVAL_FACTOR_OPTIONS: Array<SelectOptionItem<number>> = _.map([1, 2, 3, 4, 5, 10], (value: number) => ({
|
||||
const INTERVAL_FACTOR_OPTIONS: Array<SelectableValue<number>> = _.map([1, 2, 3, 4, 5, 10], (value: number) => ({
|
||||
value,
|
||||
label: '1/' + value,
|
||||
}));
|
||||
|
||||
interface State {
|
||||
legendFormat: string;
|
||||
formatOption: SelectOptionItem<string>;
|
||||
formatOption: SelectableValue<string>;
|
||||
interval: string;
|
||||
intervalFactorOption: SelectOptionItem<number>;
|
||||
intervalFactorOption: SelectableValue<number>;
|
||||
instant: boolean;
|
||||
}
|
||||
|
||||
@ -58,7 +57,7 @@ export class PromQueryEditor extends PureComponent<Props, State> {
|
||||
this.query.expr = query.expr;
|
||||
};
|
||||
|
||||
onFormatChange = (option: SelectOptionItem<string>) => {
|
||||
onFormatChange = (option: SelectableValue<string>) => {
|
||||
this.query.format = option.value;
|
||||
this.setState({ formatOption: option }, this.onRunQuery);
|
||||
};
|
||||
@ -75,7 +74,7 @@ export class PromQueryEditor extends PureComponent<Props, State> {
|
||||
this.setState({ interval });
|
||||
};
|
||||
|
||||
onIntervalFactorChange = (option: SelectOptionItem<number>) => {
|
||||
onIntervalFactorChange = (option: SelectableValue<number>) => {
|
||||
this.query.intervalFactor = option.value;
|
||||
this.setState({ intervalFactorOption: option }, this.onRunQuery);
|
||||
};
|
||||
|
@ -3,12 +3,12 @@ import _ from 'lodash';
|
||||
|
||||
import { MetricSelect } from 'app/core/components/Select/MetricSelect';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { SelectOptionItem } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
export interface Props {
|
||||
onChange: (perSeriesAligner: any) => void;
|
||||
templateSrv: TemplateSrv;
|
||||
alignOptions: Array<SelectOptionItem<string>>;
|
||||
alignOptions: Array<SelectableValue<string>>;
|
||||
perSeriesAligner: string;
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,7 @@ import { Help } from './Help';
|
||||
import { StackdriverQuery, MetricDescriptor } from '../types';
|
||||
import { getAlignmentPickerData } from '../functions';
|
||||
import StackdriverDatasource from '../datasource';
|
||||
import { SelectOptionItem } from '@grafana/ui';
|
||||
import { TimeSeries } from '@grafana/data';
|
||||
import { TimeSeries, SelectableValue } from '@grafana/data';
|
||||
|
||||
export interface Props {
|
||||
onQueryChange: (target: StackdriverQuery) => void;
|
||||
@ -26,7 +25,7 @@ export interface Props {
|
||||
}
|
||||
|
||||
interface State extends StackdriverQuery {
|
||||
alignOptions: Array<SelectOptionItem<string>>;
|
||||
alignOptions: Array<SelectableValue<string>>;
|
||||
lastQuery: string;
|
||||
lastQueryError: string;
|
||||
[key: string]: any;
|
||||
|
@ -6,7 +6,8 @@ import _ from 'lodash';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
|
||||
// Components
|
||||
import { FormLabel, Select, SelectOptionItem } from '@grafana/ui';
|
||||
import { FormLabel, Select } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
// Types
|
||||
import { QueryEditorProps } from '@grafana/ui';
|
||||
@ -40,7 +41,7 @@ export class QueryEditor extends PureComponent<Props> {
|
||||
this.setState({ scenarioList: scenarioList, current: current });
|
||||
}
|
||||
|
||||
onScenarioChange = (item: SelectOptionItem<string>) => {
|
||||
onScenarioChange = (item: SelectableValue<string>) => {
|
||||
this.props.onChange({
|
||||
...this.props.query,
|
||||
scenarioId: item.value,
|
||||
|
@ -1,17 +1,18 @@
|
||||
import { VizOrientation, SelectOptionItem, SingleStatBaseOptions } from '@grafana/ui';
|
||||
import { VizOrientation, SingleStatBaseOptions } from '@grafana/ui';
|
||||
import { standardGaugeFieldOptions } from '../gauge/types';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
export interface BarGaugeOptions extends SingleStatBaseOptions {
|
||||
displayMode: 'basic' | 'lcd' | 'gradient';
|
||||
}
|
||||
|
||||
export const displayModes: Array<SelectOptionItem<string>> = [
|
||||
export const displayModes: Array<SelectableValue<string>> = [
|
||||
{ value: 'gradient', label: 'Gradient' },
|
||||
{ value: 'lcd', label: 'Retro LCD' },
|
||||
{ value: 'basic', label: 'Basic' },
|
||||
];
|
||||
|
||||
export const orientationOptions: Array<SelectOptionItem<VizOrientation>> = [
|
||||
export const orientationOptions: Array<SelectableValue<VizOrientation>> = [
|
||||
{ value: VizOrientation.Horizontal, label: 'Horizontal' },
|
||||
{ value: VizOrientation.Vertical, label: 'Vertical' },
|
||||
];
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Field, getFieldReducers } from '@grafana/data';
|
||||
import { PanelModel } from '@grafana/ui';
|
||||
import { Field, fieldReducers } from '@grafana/data';
|
||||
import { PanelModel, FieldDisplayOptions } from '@grafana/ui';
|
||||
import { GaugeOptions } from './types';
|
||||
import {
|
||||
sharedSingleStatMigrationCheck,
|
||||
migrateOldThresholds,
|
||||
} from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
|
||||
import { FieldDisplayOptions } from '@grafana/ui/src/utils/fieldDisplay';
|
||||
|
||||
export const gaugePanelMigrationCheck = (panel: PanelModel<GaugeOptions>): Partial<GaugeOptions> => {
|
||||
if (!panel.options) {
|
||||
@ -33,7 +32,7 @@ export const gaugePanelMigrationCheck = (panel: PanelModel<GaugeOptions>): Parti
|
||||
|
||||
// Make sure the stats have a valid name
|
||||
if (valueOptions.stat) {
|
||||
fieldOptions.calcs = getFieldReducers([valueOptions.stat]).map(s => s.id);
|
||||
fieldOptions.calcs = [fieldReducers.get(valueOptions.stat).id];
|
||||
}
|
||||
field.min = old.minValue;
|
||||
field.max = old.maxValue;
|
||||
|
@ -2,10 +2,11 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Components
|
||||
import { FormLabel, Select, PanelOptionsGroup, SelectOptionItem } from '@grafana/ui';
|
||||
import { FormLabel, Select, PanelOptionsGroup } from '@grafana/ui';
|
||||
|
||||
// Types
|
||||
import { SingleStatOptions } from './types';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
const labelWidth = 6;
|
||||
|
||||
@ -20,13 +21,13 @@ const fontSizeOptions = percents.map(v => {
|
||||
});
|
||||
|
||||
export class FontSizeEditor extends PureComponent<Props> {
|
||||
setPrefixFontSize = (v: SelectOptionItem<string>) =>
|
||||
setPrefixFontSize = (v: SelectableValue<string>) =>
|
||||
this.props.onChange({ ...this.props.options, prefixFontSize: v.value });
|
||||
|
||||
setValueFontSize = (v: SelectOptionItem<string>) =>
|
||||
setValueFontSize = (v: SelectableValue<string>) =>
|
||||
this.props.onChange({ ...this.props.options, valueFontSize: v.value });
|
||||
|
||||
setPostfixFontSize = (v: SelectOptionItem<string>) =>
|
||||
setPostfixFontSize = (v: SelectableValue<string>) =>
|
||||
this.props.onChange({ ...this.props.options, postfixFontSize: v.value });
|
||||
|
||||
render() {
|
||||
|
@ -2,19 +2,20 @@
|
||||
import React, { PureComponent, ChangeEvent } from 'react';
|
||||
|
||||
// Components
|
||||
import { PanelEditorProps, PanelOptionsGroup, Select, SelectOptionItem } from '@grafana/ui';
|
||||
import { PanelEditorProps, PanelOptionsGroup, Select } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
// Types
|
||||
import { TextOptions, TextMode } from './types';
|
||||
|
||||
export class TextPanelEditor extends PureComponent<PanelEditorProps<TextOptions>> {
|
||||
modes: Array<SelectOptionItem<TextMode>> = [
|
||||
modes: Array<SelectableValue<TextMode>> = [
|
||||
{ value: 'markdown', label: 'Markdown' },
|
||||
{ value: 'text', label: 'Text' },
|
||||
{ value: 'html', label: 'HTML' },
|
||||
];
|
||||
|
||||
onModeChange = (item: SelectOptionItem<TextMode>) =>
|
||||
onModeChange = (item: SelectableValue<TextMode>) =>
|
||||
this.props.onOptionsChange({ ...this.props.options, mode: item.value });
|
||||
|
||||
onContentChange = (evt: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
|
Loading…
Reference in New Issue
Block a user