mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Refactor: Make SelectOptionItem a generic type to enable select value typing (#16718)
* Make SelectOptionItem a generic type to enable select value typing * TS ignores added because of optional value on Select items (it's no longer any)
This commit is contained in:
@@ -33,15 +33,16 @@ export class RefreshPicker extends PureComponent<Props> {
|
||||
return false;
|
||||
};
|
||||
|
||||
intervalsToOptions = (intervals: string[] = defaultIntervals): SelectOptionItem[] => {
|
||||
intervalsToOptions = (intervals: string[] = defaultIntervals): Array<SelectOptionItem<string>> => {
|
||||
const options = intervals.map(interval => ({ label: interval, value: interval }));
|
||||
options.unshift(offOption);
|
||||
return options;
|
||||
};
|
||||
|
||||
onChangeSelect = (item: SelectOptionItem) => {
|
||||
onChangeSelect = (item: SelectOptionItem<string>) => {
|
||||
const { onIntervalChanged } = this.props;
|
||||
if (onIntervalChanged) {
|
||||
// @ts-ignore
|
||||
onIntervalChanged(item.value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,9 +12,9 @@ const ButtonSelectStories = storiesOf('UI/Select/ButtonSelect', module);
|
||||
ButtonSelectStories.addDecorator(withCenteredStory).addDecorator(withKnobs);
|
||||
|
||||
ButtonSelectStories.add('default', () => {
|
||||
const intialState: SelectOptionItem = { label: 'A label', value: 'A value' };
|
||||
const value = object<SelectOptionItem>('Selected Value:', intialState);
|
||||
const options = object<SelectOptionItem[]>('Options:', [
|
||||
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:', [
|
||||
intialState,
|
||||
{ label: 'Another label', value: 'Another value' },
|
||||
]);
|
||||
|
||||
@@ -27,23 +27,23 @@ const ButtonComponent = (buttonProps: ButtonComponentProps) => (props: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
export interface Props {
|
||||
export interface Props<T> {
|
||||
className: string | undefined;
|
||||
options: SelectOptionItem[];
|
||||
value: SelectOptionItem;
|
||||
options: Array<SelectOptionItem<T>>;
|
||||
value: SelectOptionItem<T>;
|
||||
label?: string;
|
||||
iconClass?: string;
|
||||
components?: any;
|
||||
maxMenuHeight?: number;
|
||||
onChange: (item: SelectOptionItem) => void;
|
||||
onChange: (item: SelectOptionItem<T>) => void;
|
||||
tooltipContent?: PopperContent<any>;
|
||||
isMenuOpen?: boolean;
|
||||
onOpenMenu?: () => void;
|
||||
onCloseMenu?: () => void;
|
||||
}
|
||||
|
||||
export class ButtonSelect extends PureComponent<Props> {
|
||||
onChange = (item: SelectOptionItem) => {
|
||||
export class ButtonSelect<T> extends PureComponent<Props<T>> {
|
||||
onChange = (item: SelectOptionItem<T>) => {
|
||||
const { onChange } = this.props;
|
||||
onChange(item);
|
||||
};
|
||||
|
||||
@@ -20,22 +20,22 @@ import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
|
||||
import { PopperContent } from '@grafana/ui/src/components/Tooltip/PopperController';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
export interface SelectOptionItem {
|
||||
export interface SelectOptionItem<T> {
|
||||
label?: string;
|
||||
value?: any;
|
||||
value?: T;
|
||||
imgUrl?: string;
|
||||
description?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface CommonProps {
|
||||
export interface CommonProps<T> {
|
||||
defaultValue?: any;
|
||||
getOptionLabel?: (item: SelectOptionItem) => string;
|
||||
getOptionValue?: (item: SelectOptionItem) => string;
|
||||
onChange: (item: SelectOptionItem) => {} | void;
|
||||
getOptionLabel?: (item: SelectOptionItem<T>) => string;
|
||||
getOptionValue?: (item: SelectOptionItem<T>) => string;
|
||||
onChange: (item: SelectOptionItem<T>) => {} | void;
|
||||
placeholder?: string;
|
||||
width?: number;
|
||||
value?: SelectOptionItem;
|
||||
value?: SelectOptionItem<T>;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
isSearchable?: boolean;
|
||||
@@ -55,13 +55,13 @@ export interface CommonProps {
|
||||
onCloseMenu?: () => void;
|
||||
}
|
||||
|
||||
export interface SelectProps {
|
||||
options: SelectOptionItem[];
|
||||
export interface SelectProps<T> {
|
||||
options: Array<SelectOptionItem<T>>;
|
||||
}
|
||||
|
||||
interface AsyncProps {
|
||||
interface AsyncProps<T> {
|
||||
defaultOptions: boolean;
|
||||
loadOptions: (query: string) => Promise<SelectOptionItem[]>;
|
||||
loadOptions: (query: string) => Promise<Array<SelectOptionItem<T>>>;
|
||||
loadingMessage?: () => string;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export const MenuList = (props: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
export class Select extends PureComponent<CommonProps & SelectProps> {
|
||||
export class Select<T> extends PureComponent<CommonProps<T> & SelectProps<T>> {
|
||||
static defaultProps = {
|
||||
width: null,
|
||||
className: '',
|
||||
@@ -201,7 +201,7 @@ export class Select extends PureComponent<CommonProps & SelectProps> {
|
||||
}
|
||||
}
|
||||
|
||||
export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
|
||||
export class AsyncSelect<T> extends PureComponent<CommonProps<T> & AsyncProps<T>> {
|
||||
static defaultProps = {
|
||||
width: null,
|
||||
className: '',
|
||||
|
||||
@@ -18,39 +18,40 @@ import { SingleStatValueOptions } from './shared';
|
||||
const labelWidth = 6;
|
||||
|
||||
export interface Props {
|
||||
options: SingleStatValueOptions;
|
||||
value: SingleStatValueOptions;
|
||||
onChange: (valueOptions: SingleStatValueOptions) => void;
|
||||
}
|
||||
|
||||
export class SingleStatValueEditor extends PureComponent<Props> {
|
||||
onUnitChange = (unit: SelectOptionItem) => this.props.onChange({ ...this.props.options, unit: unit.value });
|
||||
// @ts-ignore
|
||||
onUnitChange = (unit: SelectOptionItem<string>) => this.props.onChange({ ...this.props.value, unit: unit.value });
|
||||
|
||||
onStatsChange = (stats: string[]) => {
|
||||
const stat = stats[0] || StatID.mean;
|
||||
this.props.onChange({ ...this.props.options, stat });
|
||||
this.props.onChange({ ...this.props.value, stat });
|
||||
};
|
||||
|
||||
onDecimalChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!isNaN(parseInt(event.target.value, 10))) {
|
||||
this.props.onChange({
|
||||
...this.props.options,
|
||||
...this.props.value,
|
||||
decimals: parseInt(event.target.value, 10),
|
||||
});
|
||||
} else {
|
||||
this.props.onChange({
|
||||
...this.props.options,
|
||||
...this.props.value,
|
||||
decimals: null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onPrefixChange = (event: ChangeEvent<HTMLInputElement>) =>
|
||||
this.props.onChange({ ...this.props.options, prefix: event.target.value });
|
||||
this.props.onChange({ ...this.props.value, prefix: event.target.value });
|
||||
onSuffixChange = (event: ChangeEvent<HTMLInputElement>) =>
|
||||
this.props.onChange({ ...this.props.options, suffix: event.target.value });
|
||||
this.props.onChange({ ...this.props.value, suffix: event.target.value });
|
||||
|
||||
render() {
|
||||
const { stat, unit, decimals, prefix, suffix } = this.props.options;
|
||||
const { stat, unit, decimals, prefix, suffix } = this.props.value;
|
||||
|
||||
let decimalsString = '';
|
||||
if (decimals !== null && decimals !== undefined && Number.isFinite(decimals as number)) {
|
||||
|
||||
@@ -54,12 +54,12 @@ export class StatsPicker extends PureComponent<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
onSelectionChange = (item: SelectOptionItem) => {
|
||||
onSelectionChange = (item: SelectOptionItem<string>) => {
|
||||
const { onChange } = this.props;
|
||||
if (isArray(item)) {
|
||||
onChange(item.map(v => v.value));
|
||||
} else {
|
||||
onChange([item.value]);
|
||||
onChange(item.value ? [item.value] : []);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ export class StatsPicker extends PureComponent<Props> {
|
||||
};
|
||||
});
|
||||
|
||||
const value: SelectOptionItem[] = options.filter(option => stats.find(stat => option.value === stat));
|
||||
const value: Array<SelectOptionItem<string>> = options.filter(option => stats.find(stat => option.value === stat));
|
||||
|
||||
return (
|
||||
<Select
|
||||
|
||||
@@ -231,8 +231,10 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
];
|
||||
};
|
||||
|
||||
onSelectChanged = (item: SelectOptionItem) => {
|
||||
onSelectChanged = (item: SelectOptionItem<TimeOption>) => {
|
||||
const { isTimezoneUtc, onChange, timezone } = this.props;
|
||||
|
||||
// @ts-ignore
|
||||
onChange(mapTimeOptionToTimeRange(item.value, isTimezoneUtc, timezone));
|
||||
};
|
||||
|
||||
@@ -264,6 +266,7 @@ export class TimePicker extends PureComponent<Props, State> {
|
||||
const options = this.mapTimeOptionsToSelectOptionItems(selectTimeOptions);
|
||||
const rangeString = mapTimeRangeToRangeString(value);
|
||||
const isAbsolute = moment.isMoment(value.raw.to);
|
||||
|
||||
return (
|
||||
<div className="time-picker">
|
||||
<div className="time-picker-buttons">
|
||||
|
||||
@@ -126,6 +126,7 @@ export default class MappingRow extends PureComponent<Props, State> {
|
||||
isSearchable={false}
|
||||
options={mappingOptions}
|
||||
value={mappingOptions.find(o => o.value === type)}
|
||||
// @ts-ignore
|
||||
onChange={type => this.onMappingTypeChange(type.value)}
|
||||
width={7}
|
||||
/>
|
||||
|
||||
@@ -43,7 +43,7 @@ export function stringToMs(str: string): number {
|
||||
}
|
||||
}
|
||||
|
||||
export function getIntervalFromString(strInterval: string): SelectOptionItem {
|
||||
export function getIntervalFromString(strInterval: string): SelectOptionItem<number> {
|
||||
return {
|
||||
label: strInterval,
|
||||
value: stringToMs(strInterval),
|
||||
|
||||
Reference in New Issue
Block a user