-
Notifications
You must be signed in to change notification settings - Fork 11.7k
/
Dimensions.tsx
113 lines (98 loc) · 3.36 KB
/
Dimensions.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { isEqual } from 'lodash';
import React, { useMemo, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorList } from '@grafana/experimental';
import { CloudWatchDatasource } from '../../datasource';
import { Dimensions as DimensionsType, MetricStat } from '../../types';
import { FilterItem } from './FilterItem';
export interface Props {
metricStat: MetricStat;
onChange: (dimensions: DimensionsType) => void;
datasource: CloudWatchDatasource;
dimensionKeys: Array<SelectableValue<string>>;
disableExpressions: boolean;
}
export interface DimensionFilterCondition {
key?: string;
operator?: string;
value?: string;
}
const dimensionsToFilterConditions = (dimensions: DimensionsType | undefined) =>
Object.entries(dimensions ?? {}).reduce<DimensionFilterCondition[]>((acc, [key, value]) => {
if (!value) {
return acc;
}
// Previously, we only appended to the `acc`umulated dimensions if the value was a string.
// However, Cloudwatch can present dimensions with single-value arrays, e.g.
// k: FunctionName
// v: ['MyLambdaFunction']
// in which case we grab the single-value from the Array and use that as the value.
let v = '';
if (typeof value === 'string') {
v = value;
} else if (Array.isArray(value) && typeof value[0] === 'string') {
v = value[0];
}
if (!v) {
return acc;
}
const filter = {
key: key,
value: v,
operator: '=',
};
return [...acc, filter];
}, []);
const filterConditionsToDimensions = (filters: DimensionFilterCondition[]) => {
return filters.reduce<DimensionsType>((acc, { key, value }) => {
if (key && value) {
return { ...acc, [key]: value };
}
return acc;
}, {});
};
export const Dimensions = ({ metricStat, datasource, dimensionKeys, disableExpressions, onChange }: Props) => {
const dimensionFilters = useMemo(() => dimensionsToFilterConditions(metricStat.dimensions), [metricStat.dimensions]);
const [items, setItems] = useState<DimensionFilterCondition[]>(dimensionFilters);
const onDimensionsChange = (newItems: Array<Partial<DimensionFilterCondition>>) => {
setItems(newItems);
// The onChange event should only be triggered in the case there is a complete dimension object.
// So when a new key is added that does not yet have a value, it should not trigger an onChange event.
const newDimensions = filterConditionsToDimensions(newItems);
if (!isEqual(newDimensions, metricStat.dimensions)) {
onChange(newDimensions);
}
};
return (
<EditorList
items={items}
onChange={onDimensionsChange}
renderItem={makeRenderFilter(datasource, metricStat, dimensionKeys, disableExpressions)}
/>
);
};
function makeRenderFilter(
datasource: CloudWatchDatasource,
metricStat: MetricStat,
dimensionKeys: Array<SelectableValue<string>>,
disableExpressions: boolean
) {
function renderFilter(
item: DimensionFilterCondition,
onChange: (item: DimensionFilterCondition) => void,
onDelete: () => void
) {
return (
<FilterItem
filter={item}
onChange={(item) => onChange(item)}
datasource={datasource}
metricStat={metricStat}
disableExpressions={disableExpressions}
dimensionKeys={dimensionKeys}
onDelete={onDelete}
/>
);
}
return renderFilter;
}