You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

229 lines
6.6 KiB

import { IconPosition, Icon, Condition } from 'types';
import { GrafanaTheme, SelectableValue, StandardEditorProps } from '@grafana/data';
import {
Button,
HorizontalGroup,
IconButton,
Input,
RadioButtonGroup,
Slider,
stylesFactory,
ThemeContext,
} from '@grafana/ui';
import { FieldNamePicker } from '../../grafana/MatchersUI/FieldNamePicker';
import { css } from 'emotion';
import React from 'react';
import * as _ from 'lodash';
const positionOptions: Array<SelectableValue<IconPosition>> = [
{
label: 'Upper-Left',
value: IconPosition.UPPER_LEFT,
},
{
label: 'Middle',
value: IconPosition.MIDDLE,
},
{
label: 'Upper-Right',
value: IconPosition.UPPER_RIGHT,
},
];
const conditionOptions: Array<SelectableValue<Condition>> = [
{
label: '>=',
value: Condition.GREATER_OR_EQUAL,
},
{
label: '>',
value: Condition.GREATER,
},
{
label: '=',
value: Condition.EQUAL,
},
{
label: '<',
value: Condition.LESS,
},
{
label: '<=',
value: Condition.LESS_OR_EQUAL,
},
];
const DEFAULT_ICON: Icon = {
position: IconPosition.UPPER_LEFT,
url: '',
size: 40,
metrics: [],
conditions: [],
values: [],
};
const fieldNamePickerSettings = {
settings: { width: 24 },
} as any;
export function IconsEditor({ onChange, value, context }: StandardEditorProps<Icon[]>) {
const icons = value;
const addIcon = () => {
onChange(_.concat(icons, _.cloneDeep(DEFAULT_ICON)));
};
const removeIcon = (idx: number) => {
onChange(_.filter(icons, (icon, iconIdx) => iconIdx !== idx));
};
const addCondition = (iconIdx: number) => {
icons[iconIdx].conditions.push(Condition.GREATER_OR_EQUAL);
icons[iconIdx].metrics.push('');
icons[iconIdx].values.push(0);
onChange(icons);
};
const removeCondition = (iconIdx: number, conditionIdx: number) => {
icons[iconIdx].conditions.splice(conditionIdx, 1);
icons[iconIdx].metrics.splice(conditionIdx, 1);
icons[iconIdx].values.splice(conditionIdx, 1);
onChange(icons);
};
const onIconFieldChange = (iconIdx: number, field: keyof Icon, value: any) => {
// @ts-ignore
icons[iconIdx][field] = value;
onChange(icons);
};
const onConditionChange = (iconIdx: number, conditionIdx: number, field: keyof Icon, value: any) => {
// @ts-ignore
icons[iconIdx][field][conditionIdx] = value;
onChange(icons);
};
return (
<ThemeContext.Consumer>
{(theme) => {
const styles = getStyles(theme.v1);
return (
<div>
<div className={styles.icons}>
{icons.map((icon, iconIdx) => {
return (
<div key={iconIdx} className={styles.icon}>
<IconButton name="trash-alt" onClick={() => removeIcon(iconIdx)} tooltip="Delete Icon"></IconButton>
<div className={styles.row}>
<Input
type="url"
placeholder="Image URL"
value={icon.url}
onChange={(evt) => onIconFieldChange(iconIdx, 'url', (evt.target as any).value)}
/>
</div>
<RadioButtonGroup
value={icon.position}
options={positionOptions}
onChange={(newVal) => onIconFieldChange(iconIdx, 'position', newVal)}
/>
<div className={styles.slider}>
<Slider
value={icon.size}
min={1}
max={100}
step={1}
onAfterChange={(newVal) => onIconFieldChange(iconIdx, 'size', newVal)}
/>
</div>
{icon.conditions.map((condition, conditionIdx) => {
return (
<div key={conditionIdx} className={styles.condition}>
<HorizontalGroup key={conditionIdx}>
<FieldNamePicker
context={context}
value={icon.metrics[conditionIdx]}
onChange={(newVal: any) => onConditionChange(iconIdx, conditionIdx, 'metrics', newVal)}
item={fieldNamePickerSettings}
/>
<RadioButtonGroup
value={icon.conditions[conditionIdx]}
options={conditionOptions}
onChange={(newVal) => onConditionChange(iconIdx, conditionIdx, 'conditions', newVal)}
/>
<Input
placeholder="value"
value={icon.values[conditionIdx]}
onChange={(evt) =>
onConditionChange(iconIdx, conditionIdx, 'values', (evt.target as any).value)
}
/>
<IconButton
name="trash-alt"
onClick={() => removeCondition(iconIdx, conditionIdx)}
tooltip="Delete Condition"
></IconButton>
</HorizontalGroup>
</div>
);
})}
<Button variant="secondary" onClick={() => addCondition(iconIdx)}>
Add Condition
</Button>
</div>
);
})}
</div>
<Button variant="secondary" onClick={addIcon}>
Add Icon
</Button>
</div>
);
}}
</ThemeContext.Consumer>
);
}
interface IconsEditorStyles {
icons: string;
icon: string;
condition: string;
slider: string;
row: string;
}
const getStyles = stylesFactory((theme: GrafanaTheme): IconsEditorStyles => {
return {
icons: css`
display: flex;
flex-direction: column;
margin-bottom: ${theme.spacing.formSpacingBase * 2}px;
`,
icon: css`
margin-bottom: ${theme.spacing.sm};
border-bottom: 1px solid ${theme.colors.panelBorder};
padding-bottom: ${theme.spacing.formSpacingBase * 2}px;
&:last-child {
margin-bottom: 0;
}
`,
condition: css`
margin-bottom: ${theme.spacing.xxs};
`,
slider: css`
padding-bottom: ${theme.spacing.xxs};
`,
row: css`
margin-bottom: ${theme.spacing.sm};
`,
};
});