@centreon/ui 23.10.75 → 23.10.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Graph/LineChart/BasicComponents/Lines/RegularLines/index.tsx +5 -5
- package/src/Graph/LineChart/BasicComponents/Lines/StackedLines/index.tsx +5 -3
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/useScaleThreshold.ts +3 -3
- package/src/Graph/LineChart/BasicComponents/Lines/index.tsx +5 -5
- package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx +5 -5
- package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/models.ts +1 -1
- package/src/Graph/LineChart/Legend/index.tsx +7 -7
- package/src/Graph/LineChart/Legend/useInteractiveValues.ts +10 -10
- package/src/Graph/LineChart/Legend/useLegend.ts +16 -18
- package/src/Graph/common/timeSeries/index.test.ts +38 -23
- package/src/Graph/common/timeSeries/index.ts +19 -17
- package/src/Graph/common/timeSeries/models.ts +3 -1
- package/src/InputField/Select/Autocomplete/Connected/index.tsx +7 -2
- package/src/InputField/Select/Autocomplete/Multi/index.tsx +18 -11
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +9 -6
- package/src/TimePeriods/CustomTimePeriod/SimpleCustomTimePeriod.tsx +28 -0
- package/src/TimePeriods/index.stories.tsx +15 -0
- package/src/api/useGraphQuery/index.ts +52 -27
- package/src/api/useGraphQuery/models.ts +9 -8
- package/src/index.ts +3 -0
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ interface Props {
|
|
|
16
16
|
graphHeight: number;
|
|
17
17
|
highlight?: boolean;
|
|
18
18
|
lineColor: string;
|
|
19
|
-
|
|
19
|
+
metric_id: number;
|
|
20
20
|
shapeAreaClosed?: Record<string, unknown>;
|
|
21
21
|
shapeLinePath?: Record<string, unknown>;
|
|
22
22
|
timeSeries: Array<TimeValue>;
|
|
@@ -30,7 +30,7 @@ const RegularLine = ({
|
|
|
30
30
|
filled,
|
|
31
31
|
timeSeries,
|
|
32
32
|
highlight,
|
|
33
|
-
|
|
33
|
+
metric_id,
|
|
34
34
|
lineColor,
|
|
35
35
|
unit,
|
|
36
36
|
yScale,
|
|
@@ -43,13 +43,13 @@ const RegularLine = ({
|
|
|
43
43
|
const props = {
|
|
44
44
|
curve,
|
|
45
45
|
data: timeSeries,
|
|
46
|
-
defined: (value): boolean => !isNil(value[
|
|
46
|
+
defined: (value): boolean => !isNil(value[metric_id]),
|
|
47
47
|
opacity: 1,
|
|
48
48
|
stroke: lineColor,
|
|
49
49
|
strokeWidth: !highlight ? 1 : 2,
|
|
50
50
|
unit,
|
|
51
51
|
x: (timeValue): number => xScale(getTime(timeValue)) as number,
|
|
52
|
-
y: (timeValue): number => yScale(prop(
|
|
52
|
+
y: (timeValue): number => yScale(prop(metric_id, timeValue)) ?? null
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
if (filled) {
|
|
@@ -57,7 +57,7 @@ const RegularLine = ({
|
|
|
57
57
|
<Shape.AreaClosed<TimeValue>
|
|
58
58
|
fill={getFillColor({ areaColor, transparency })}
|
|
59
59
|
fillRule="nonzero"
|
|
60
|
-
key={
|
|
60
|
+
key={metric_id}
|
|
61
61
|
y0={Math.min(yScale(0), graphHeight)}
|
|
62
62
|
yScale={yScale}
|
|
63
63
|
{...props}
|
|
@@ -32,11 +32,13 @@ const StackLines = ({
|
|
|
32
32
|
data={timeSeries}
|
|
33
33
|
defined={(d): boolean => {
|
|
34
34
|
return pipe(
|
|
35
|
-
map(prop('
|
|
36
|
-
|
|
35
|
+
map(prop('metric_id')) as unknown as (
|
|
36
|
+
displayedLines
|
|
37
|
+
) => Array<string>,
|
|
38
|
+
all((metric_id) => pipe(path(['data', metric_id]), isNil, not)(d))
|
|
37
39
|
)(lines);
|
|
38
40
|
}}
|
|
39
|
-
keys={map(prop('
|
|
41
|
+
keys={map(prop('metric_id'), lines)}
|
|
40
42
|
x={(d): number => xScale(getTime(d.data)) ?? 0}
|
|
41
43
|
y0={(d): number => yScale(d[0]) ?? 0}
|
|
42
44
|
y1={(d): number => yScale(d[1]) ?? 0}
|
|
@@ -53,21 +53,21 @@ const useScaleThreshold = ({
|
|
|
53
53
|
const [, secondUnit, thirdUnit] = getUnits(lines);
|
|
54
54
|
|
|
55
55
|
const {
|
|
56
|
-
|
|
56
|
+
metric_id: metricY1,
|
|
57
57
|
unit: unitY1,
|
|
58
58
|
invert: invertY1,
|
|
59
59
|
lineColor: lineColorY1
|
|
60
60
|
} = lineUpper;
|
|
61
61
|
|
|
62
62
|
const {
|
|
63
|
-
|
|
63
|
+
metric_id: metricY0,
|
|
64
64
|
unit: unitY0,
|
|
65
65
|
invert: invertY0,
|
|
66
66
|
lineColor: lineColorY0
|
|
67
67
|
} = lineLower;
|
|
68
68
|
|
|
69
69
|
const {
|
|
70
|
-
|
|
70
|
+
metric_id: metricOrigin,
|
|
71
71
|
unit: unitYOrigin,
|
|
72
72
|
invert: invertYOrigin
|
|
73
73
|
} = lineOrigin;
|
|
@@ -129,14 +129,14 @@ const Lines = ({
|
|
|
129
129
|
{displayAreaRegularLines
|
|
130
130
|
? regularLines.map(
|
|
131
131
|
({
|
|
132
|
-
metric,
|
|
133
132
|
areaColor,
|
|
134
133
|
transparency,
|
|
135
134
|
lineColor,
|
|
136
135
|
filled,
|
|
137
136
|
unit,
|
|
138
137
|
highlight,
|
|
139
|
-
invert
|
|
138
|
+
invert,
|
|
139
|
+
metric_id
|
|
140
140
|
}) => {
|
|
141
141
|
const [, secondUnit, thirdUnit] = getUnits(
|
|
142
142
|
regularLines as Array<Line>
|
|
@@ -151,12 +151,12 @@ const Lines = ({
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
return (
|
|
154
|
-
<g key={
|
|
154
|
+
<g key={metric_id}>
|
|
155
155
|
{displayGuidingLines && (
|
|
156
156
|
<RegularAnchorPoint
|
|
157
157
|
areaColor={areaColor}
|
|
158
158
|
lineColor={lineColor}
|
|
159
|
-
|
|
159
|
+
metric_id={metric_id}
|
|
160
160
|
timeSeries={timeSeries}
|
|
161
161
|
transparency={transparency}
|
|
162
162
|
xScale={xScale}
|
|
@@ -170,7 +170,7 @@ const Lines = ({
|
|
|
170
170
|
graphHeight={height}
|
|
171
171
|
highlight={highlight}
|
|
172
172
|
lineColor={lineColor}
|
|
173
|
-
|
|
173
|
+
metric_id={metric_id}
|
|
174
174
|
timeSeries={timeSeries}
|
|
175
175
|
transparency={transparency}
|
|
176
176
|
unit={unit}
|
|
@@ -11,7 +11,7 @@ import AnchorPoint from '.';
|
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
13
|
lineColor: string;
|
|
14
|
-
|
|
14
|
+
metric_id: number;
|
|
15
15
|
timeSeries: Array<TimeValue>;
|
|
16
16
|
xScale: ScaleTime<number, number>;
|
|
17
17
|
yScale: ScaleLinear<number, number>;
|
|
@@ -21,18 +21,18 @@ const getYAnchorPoint = ({
|
|
|
21
21
|
timeTick,
|
|
22
22
|
timeSeries,
|
|
23
23
|
yScale,
|
|
24
|
-
|
|
24
|
+
metric_id
|
|
25
25
|
}: GetYAnchorPoint): number => {
|
|
26
26
|
const index = bisectDate(getDates(timeSeries), timeTick);
|
|
27
27
|
const timeValue = timeSeries[index];
|
|
28
28
|
|
|
29
|
-
return yScale(prop(
|
|
29
|
+
return yScale(prop(metric_id, timeValue) as number);
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
const RegularAnchorPoint = ({
|
|
33
33
|
xScale,
|
|
34
34
|
yScale,
|
|
35
|
-
|
|
35
|
+
metric_id,
|
|
36
36
|
timeSeries,
|
|
37
37
|
lineColor
|
|
38
38
|
}: Props): JSX.Element | null => {
|
|
@@ -48,7 +48,7 @@ const RegularAnchorPoint = ({
|
|
|
48
48
|
const xAnchorPoint = xScale(timeTick);
|
|
49
49
|
|
|
50
50
|
const yAnchorPoint = getYAnchorPoint({
|
|
51
|
-
|
|
51
|
+
metric_id,
|
|
52
52
|
timeSeries,
|
|
53
53
|
timeTick,
|
|
54
54
|
yScale
|
|
@@ -69,25 +69,25 @@ const MainLegend = ({
|
|
|
69
69
|
value
|
|
70
70
|
}) || 'N/A';
|
|
71
71
|
|
|
72
|
-
const selectMetric = ({ event,
|
|
72
|
+
const selectMetric = ({ event, metric_id }): void => {
|
|
73
73
|
if (!toggable) {
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
if (event.ctrlKey || event.metaKey) {
|
|
78
|
-
toggleMetricLine(
|
|
78
|
+
toggleMetricLine(metric_id);
|
|
79
79
|
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
selectMetricLine(
|
|
83
|
+
selectMetricLine(metric_id);
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
return (
|
|
87
87
|
<div className={classes.legend}>
|
|
88
88
|
<div className={classes.items}>
|
|
89
89
|
{displayedLines.map((line) => {
|
|
90
|
-
const { color,
|
|
90
|
+
const { color, display, highlight, metric_id } = line;
|
|
91
91
|
|
|
92
92
|
const markerColor = display
|
|
93
93
|
? color
|
|
@@ -119,9 +119,9 @@ const MainLegend = ({
|
|
|
119
119
|
highlight ? classes.highlight : classes.normal,
|
|
120
120
|
toggable && classes.toggable
|
|
121
121
|
)}
|
|
122
|
-
key={
|
|
123
|
-
onClick={(event): void => selectMetric({ event,
|
|
124
|
-
onMouseEnter={(): void => highlightLine(
|
|
122
|
+
key={metric_id}
|
|
123
|
+
onClick={(event): void => selectMetric({ event, metric_id })}
|
|
124
|
+
onMouseEnter={(): void => highlightLine(metric_id)}
|
|
125
125
|
onMouseLeave={(): void => clearHighlight()}
|
|
126
126
|
>
|
|
127
127
|
<LegendMarker color={markerColor} disabled={!display} />
|
|
@@ -43,34 +43,34 @@ const useInteractiveValues = ({
|
|
|
43
43
|
equals(item.timeTick, timeValue?.timeTick)
|
|
44
44
|
);
|
|
45
45
|
|
|
46
|
-
const getMetricsToDisplay = (): Array<
|
|
46
|
+
const getMetricsToDisplay = (): Array<number> => {
|
|
47
47
|
if (isNil(graphTimeValue)) {
|
|
48
48
|
return [];
|
|
49
49
|
}
|
|
50
50
|
const metricsData = getMetrics(graphTimeValue as TimeValue);
|
|
51
51
|
|
|
52
|
-
const metricsToDisplay = metricsData.filter((
|
|
53
|
-
const line = getLineForMetric({ lines,
|
|
52
|
+
const metricsToDisplay = metricsData.filter((metric_id) => {
|
|
53
|
+
const line = getLineForMetric({ lines, metric_id: Number(metric_id) });
|
|
54
54
|
|
|
55
|
-
return !isNil(graphTimeValue[
|
|
55
|
+
return !isNil(graphTimeValue[metric_id]) && !isNil(line);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
return metricsToDisplay;
|
|
58
|
+
return metricsToDisplay.map(Number);
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
const metrics = useMemo(() => getMetricsToDisplay(), [graphTimeValue]);
|
|
62
62
|
|
|
63
63
|
const getFormattedMetricData = (
|
|
64
|
-
|
|
64
|
+
metric_id: number
|
|
65
65
|
): FormattedMetricData | null => {
|
|
66
66
|
if (isNil(graphTimeValue)) {
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
|
-
const value = graphTimeValue[
|
|
69
|
+
const value = graphTimeValue[metric_id] as number;
|
|
70
70
|
|
|
71
71
|
const { color, name, unit } = getLineForMetric({
|
|
72
72
|
lines,
|
|
73
|
-
|
|
73
|
+
metric_id
|
|
74
74
|
}) as Line;
|
|
75
75
|
|
|
76
76
|
const formattedValue = formatMetricValue({
|
|
@@ -88,9 +88,9 @@ const useInteractiveValues = ({
|
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
const getFormattedValue = (line: Line): string | undefined | null => {
|
|
91
|
-
const
|
|
91
|
+
const metric_id = find(equals(line.metric_id), metrics);
|
|
92
92
|
|
|
93
|
-
return
|
|
93
|
+
return metric_id ? getFormattedMetricData(metric_id)?.formattedValue : null;
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
return { getFormattedValue };
|
|
@@ -11,18 +11,16 @@ import {
|
|
|
11
11
|
prop,
|
|
12
12
|
propEq,
|
|
13
13
|
reject,
|
|
14
|
-
sortBy
|
|
15
|
-
compose,
|
|
16
|
-
toLower
|
|
14
|
+
sortBy
|
|
17
15
|
} from 'ramda';
|
|
18
16
|
|
|
19
17
|
import { Line } from '../../common/timeSeries/models';
|
|
20
18
|
|
|
21
19
|
interface LegendActions {
|
|
22
20
|
clearHighlight: () => void;
|
|
23
|
-
highlightLine: (
|
|
24
|
-
selectMetricLine: (
|
|
25
|
-
toggleMetricLine: (
|
|
21
|
+
highlightLine: (metric_id: number) => void;
|
|
22
|
+
selectMetricLine: (metric_id: number) => void;
|
|
23
|
+
toggleMetricLine: (metric_id: number) => void;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
interface Props {
|
|
@@ -32,26 +30,26 @@ interface Props {
|
|
|
32
30
|
|
|
33
31
|
const useLegend = ({ lines, setLinesGraph }: Props): LegendActions => {
|
|
34
32
|
const displayedLines = reject(propEq('display', false), lines);
|
|
35
|
-
const getLineByMetric = (
|
|
36
|
-
find(propEq('
|
|
33
|
+
const getLineByMetric = (metric_id: number): Line =>
|
|
34
|
+
find(propEq('metric_id', metric_id), lines) as Line;
|
|
37
35
|
|
|
38
|
-
const toggleMetricLine = (
|
|
39
|
-
const line = getLineByMetric(
|
|
36
|
+
const toggleMetricLine = (metric_id): void => {
|
|
37
|
+
const line = getLineByMetric(metric_id);
|
|
40
38
|
|
|
41
39
|
setLinesGraph([
|
|
42
|
-
...reject(propEq('
|
|
40
|
+
...reject(propEq('metric_id', metric_id), lines),
|
|
43
41
|
{ ...line, display: !line.display }
|
|
44
42
|
]);
|
|
45
43
|
};
|
|
46
44
|
|
|
47
|
-
const highlightLine = (
|
|
45
|
+
const highlightLine = (metric_id): void => {
|
|
48
46
|
const fadedLines = map((line) => ({ ...line, highlight: false }), lines);
|
|
49
47
|
const data = [
|
|
50
|
-
...reject(propEq('
|
|
51
|
-
{ ...getLineByMetric(
|
|
48
|
+
...reject(propEq('metric_id', metric_id), fadedLines),
|
|
49
|
+
{ ...getLineByMetric(metric_id), highlight: true }
|
|
52
50
|
];
|
|
53
51
|
|
|
54
|
-
const sortedData = sortBy(
|
|
52
|
+
const sortedData = sortBy(prop('metric_id'), data);
|
|
55
53
|
|
|
56
54
|
setLinesGraph(sortedData);
|
|
57
55
|
};
|
|
@@ -60,8 +58,8 @@ const useLegend = ({ lines, setLinesGraph }: Props): LegendActions => {
|
|
|
60
58
|
setLinesGraph(map((line) => ({ ...line, highlight: undefined }), lines));
|
|
61
59
|
};
|
|
62
60
|
|
|
63
|
-
const selectMetricLine = (
|
|
64
|
-
const metricLine = getLineByMetric(
|
|
61
|
+
const selectMetricLine = (metric_id: number): void => {
|
|
62
|
+
const metricLine = getLineByMetric(metric_id);
|
|
65
63
|
|
|
66
64
|
const isLineDisplayed = pipe(head, equals(metricLine))(displayedLines);
|
|
67
65
|
const isOnlyLineDisplayed =
|
|
@@ -99,7 +97,7 @@ const useLegend = ({ lines, setLinesGraph }: Props): LegendActions => {
|
|
|
99
97
|
|
|
100
98
|
const newLines = lines.map((line) => ({
|
|
101
99
|
...line,
|
|
102
|
-
display: find(propEq('
|
|
100
|
+
display: find(propEq('metric_id', line.metric_id), lines)?.display ?? true
|
|
103
101
|
}));
|
|
104
102
|
|
|
105
103
|
setLinesGraph(newLines);
|
|
@@ -24,6 +24,7 @@ describe('timeSeries', () => {
|
|
|
24
24
|
legend: 'Round-Trip-Time Average (ms)',
|
|
25
25
|
maximum_value: 1.5,
|
|
26
26
|
metric: 'rta',
|
|
27
|
+
metric_id: 1,
|
|
27
28
|
minimum_value: 0.5,
|
|
28
29
|
unit: 'ms'
|
|
29
30
|
},
|
|
@@ -43,6 +44,7 @@ describe('timeSeries', () => {
|
|
|
43
44
|
legend: 'Time (ms)',
|
|
44
45
|
maximum_value: 1.5,
|
|
45
46
|
metric: 'time',
|
|
47
|
+
metric_id: 2,
|
|
46
48
|
minimum_value: 0.5,
|
|
47
49
|
unit: 'ms'
|
|
48
50
|
},
|
|
@@ -62,6 +64,7 @@ describe('timeSeries', () => {
|
|
|
62
64
|
legend: 'Average duration (ms)',
|
|
63
65
|
maximum_value: 1.5,
|
|
64
66
|
metric: 'avgDuration',
|
|
67
|
+
metric_id: 3,
|
|
65
68
|
minimum_value: 0.5,
|
|
66
69
|
unit: 'ms'
|
|
67
70
|
},
|
|
@@ -81,6 +84,7 @@ describe('timeSeries', () => {
|
|
|
81
84
|
legend: 'Duration (ms)',
|
|
82
85
|
maximum_value: 1.5,
|
|
83
86
|
metric: 'duration',
|
|
87
|
+
metric_id: 4,
|
|
84
88
|
minimum_value: 0.5,
|
|
85
89
|
unit: 'ms'
|
|
86
90
|
},
|
|
@@ -100,6 +104,7 @@ describe('timeSeries', () => {
|
|
|
100
104
|
legend: 'Packet Loss (%)',
|
|
101
105
|
maximum_value: 1.5,
|
|
102
106
|
metric: 'packet_loss',
|
|
107
|
+
metric_id: 5,
|
|
103
108
|
minimum_value: 0.5,
|
|
104
109
|
unit: '%'
|
|
105
110
|
}
|
|
@@ -111,19 +116,19 @@ describe('timeSeries', () => {
|
|
|
111
116
|
it('returns the time series for the given graph data', () => {
|
|
112
117
|
expect(timeSeries.getTimeSeries(graphData)).toEqual([
|
|
113
118
|
{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
1: 0,
|
|
120
|
+
2: 0.5,
|
|
121
|
+
3: 6,
|
|
122
|
+
4: 12,
|
|
123
|
+
5: 0,
|
|
119
124
|
timeTick: '2020-11-05T10:35:00Z'
|
|
120
125
|
},
|
|
121
126
|
{
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
1: 1,
|
|
128
|
+
2: 3,
|
|
129
|
+
3: 4,
|
|
130
|
+
4: 25,
|
|
131
|
+
5: 1,
|
|
127
132
|
timeTick: '2020-11-05T10:40:00Z'
|
|
128
133
|
}
|
|
129
134
|
]);
|
|
@@ -139,17 +144,17 @@ describe('timeSeries', () => {
|
|
|
139
144
|
|
|
140
145
|
expect(timeSeries.getTimeSeries(graphDataWithLowerLimit)).toEqual([
|
|
141
146
|
{
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
2: 0.5,
|
|
148
|
+
3: 6,
|
|
149
|
+
4: 12,
|
|
145
150
|
timeTick: '2020-11-05T10:35:00Z'
|
|
146
151
|
},
|
|
147
152
|
{
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
1: 1,
|
|
154
|
+
2: 3,
|
|
155
|
+
3: 4,
|
|
156
|
+
4: 25,
|
|
157
|
+
5: 1,
|
|
153
158
|
timeTick: '2020-11-05T10:40:00Z'
|
|
154
159
|
}
|
|
155
160
|
]);
|
|
@@ -171,6 +176,7 @@ describe('timeSeries', () => {
|
|
|
171
176
|
lineColor: 'black',
|
|
172
177
|
maximum_value: 1.5,
|
|
173
178
|
metric: 'rta',
|
|
179
|
+
metric_id: 1,
|
|
174
180
|
minimum_value: 0.5,
|
|
175
181
|
name: 'Round-Trip-Time Average (ms)',
|
|
176
182
|
stackOrder: null,
|
|
@@ -189,6 +195,7 @@ describe('timeSeries', () => {
|
|
|
189
195
|
lineColor: 'blue',
|
|
190
196
|
maximum_value: 1.5,
|
|
191
197
|
metric: 'time',
|
|
198
|
+
metric_id: 2,
|
|
192
199
|
minimum_value: 0.5,
|
|
193
200
|
name: 'Time (ms)',
|
|
194
201
|
stackOrder: null,
|
|
@@ -207,6 +214,7 @@ describe('timeSeries', () => {
|
|
|
207
214
|
lineColor: 'red',
|
|
208
215
|
maximum_value: 1.5,
|
|
209
216
|
metric: 'avgDuration',
|
|
217
|
+
metric_id: 3,
|
|
210
218
|
minimum_value: 0.5,
|
|
211
219
|
name: 'Average duration (ms)',
|
|
212
220
|
stackOrder: 2,
|
|
@@ -225,6 +233,7 @@ describe('timeSeries', () => {
|
|
|
225
233
|
lineColor: 'yellow',
|
|
226
234
|
maximum_value: 1.5,
|
|
227
235
|
metric: 'duration',
|
|
236
|
+
metric_id: 4,
|
|
228
237
|
minimum_value: 0.5,
|
|
229
238
|
name: 'Duration (ms)',
|
|
230
239
|
stackOrder: 1,
|
|
@@ -243,6 +252,7 @@ describe('timeSeries', () => {
|
|
|
243
252
|
lineColor: 'yellow',
|
|
244
253
|
maximum_value: 1.5,
|
|
245
254
|
metric: 'packet_loss',
|
|
255
|
+
metric_id: 5,
|
|
246
256
|
minimum_value: 0.5,
|
|
247
257
|
name: 'Packet Loss (%)',
|
|
248
258
|
stackOrder: null,
|
|
@@ -300,7 +310,7 @@ describe('timeSeries', () => {
|
|
|
300
310
|
it('returns the line corresponding to the given metrics', () => {
|
|
301
311
|
const lines = timeSeries.getLineData(graphData);
|
|
302
312
|
|
|
303
|
-
expect(timeSeries.getLineForMetric({ lines,
|
|
313
|
+
expect(timeSeries.getLineForMetric({ lines, metric_id: 1 })).toEqual({
|
|
304
314
|
areaColor: 'transparent',
|
|
305
315
|
average_value: 1,
|
|
306
316
|
color: 'black',
|
|
@@ -312,6 +322,7 @@ describe('timeSeries', () => {
|
|
|
312
322
|
lineColor: 'black',
|
|
313
323
|
maximum_value: 1.5,
|
|
314
324
|
metric: 'rta',
|
|
325
|
+
metric_id: 1,
|
|
315
326
|
minimum_value: 0.5,
|
|
316
327
|
name: 'Round-Trip-Time Average (ms)',
|
|
317
328
|
stackOrder: null,
|
|
@@ -369,6 +380,7 @@ describe('timeSeries', () => {
|
|
|
369
380
|
lineColor: 'yellow',
|
|
370
381
|
maximum_value: 1.5,
|
|
371
382
|
metric: 'duration',
|
|
383
|
+
metric_id: 4,
|
|
372
384
|
minimum_value: 0.5,
|
|
373
385
|
name: 'Duration (ms)',
|
|
374
386
|
stackOrder: 1,
|
|
@@ -387,6 +399,7 @@ describe('timeSeries', () => {
|
|
|
387
399
|
lineColor: 'red',
|
|
388
400
|
maximum_value: 1.5,
|
|
389
401
|
metric: 'avgDuration',
|
|
402
|
+
metric_id: 3,
|
|
390
403
|
minimum_value: 0.5,
|
|
391
404
|
name: 'Average duration (ms)',
|
|
392
405
|
stackOrder: 2,
|
|
@@ -423,13 +436,13 @@ describe('timeSeries', () => {
|
|
|
423
436
|
})
|
|
424
437
|
).toEqual([
|
|
425
438
|
{
|
|
426
|
-
|
|
427
|
-
|
|
439
|
+
3: 6,
|
|
440
|
+
4: 12,
|
|
428
441
|
timeTick: '2020-11-05T10:35:00Z'
|
|
429
442
|
},
|
|
430
443
|
{
|
|
431
|
-
|
|
432
|
-
|
|
444
|
+
3: 4,
|
|
445
|
+
4: 25,
|
|
433
446
|
timeTick: '2020-11-05T10:40:00Z'
|
|
434
447
|
}
|
|
435
448
|
]);
|
|
@@ -453,6 +466,7 @@ describe('timeSeries', () => {
|
|
|
453
466
|
lineColor: 'yellow',
|
|
454
467
|
maximum_value: 1.5,
|
|
455
468
|
metric: 'duration',
|
|
469
|
+
metric_id: 4,
|
|
456
470
|
minimum_value: 0.5,
|
|
457
471
|
name: 'Duration (ms)',
|
|
458
472
|
stackOrder: 1,
|
|
@@ -480,6 +494,7 @@ describe('timeSeries', () => {
|
|
|
480
494
|
lineColor: 'red',
|
|
481
495
|
maximum_value: 1.5,
|
|
482
496
|
metric: 'avgDuration',
|
|
497
|
+
metric_id: 3,
|
|
483
498
|
minimum_value: 0.5,
|
|
484
499
|
name: 'Average duration (ms)',
|
|
485
500
|
stackOrder: 2,
|
|
@@ -70,9 +70,9 @@ const toTimeTickValue = (
|
|
|
70
70
|
timeIndex: number
|
|
71
71
|
): TimeValue => {
|
|
72
72
|
const getMetricsForIndex = (): Omit<TimeValue, 'timeTick'> => {
|
|
73
|
-
const addMetricForTimeIndex = (acc, {
|
|
73
|
+
const addMetricForTimeIndex = (acc, { metric_id, data }): TimeValue => ({
|
|
74
74
|
...acc,
|
|
75
|
-
[
|
|
75
|
+
[metric_id]: data[timeIndex]
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
return reduce(addMetricForTimeIndex, {} as TimeValue, metrics);
|
|
@@ -116,7 +116,8 @@ const toLine = ({
|
|
|
116
116
|
unit,
|
|
117
117
|
average_value,
|
|
118
118
|
minimum_value,
|
|
119
|
-
maximum_value
|
|
119
|
+
maximum_value,
|
|
120
|
+
metric_id
|
|
120
121
|
}: Metric): Line => ({
|
|
121
122
|
areaColor: ds_data.ds_color_area,
|
|
122
123
|
average_value,
|
|
@@ -129,6 +130,7 @@ const toLine = ({
|
|
|
129
130
|
lineColor: ds_data.ds_color_line,
|
|
130
131
|
maximum_value,
|
|
131
132
|
metric,
|
|
133
|
+
metric_id,
|
|
132
134
|
minimum_value,
|
|
133
135
|
name: legend,
|
|
134
136
|
stackOrder: equals(ds_data.ds_stack, '1')
|
|
@@ -153,8 +155,8 @@ const getMetrics = (timeValue: TimeValue): Array<string> =>
|
|
|
153
155
|
|
|
154
156
|
const getValueForMetric =
|
|
155
157
|
(timeValue: TimeValue) =>
|
|
156
|
-
(
|
|
157
|
-
prop(
|
|
158
|
+
(metric_id: number): number =>
|
|
159
|
+
prop(metric_id, timeValue) as number;
|
|
158
160
|
|
|
159
161
|
const getUnits = (lines: Array<Line>): Array<string> =>
|
|
160
162
|
pipe(map(prop('unit')), uniq)(lines);
|
|
@@ -170,15 +172,15 @@ const getMetricValuesForUnit = ({
|
|
|
170
172
|
timeSeries,
|
|
171
173
|
unit
|
|
172
174
|
}: ValuesForUnitProps): Array<number> => {
|
|
173
|
-
const getTimeSeriesValuesForMetric = (
|
|
175
|
+
const getTimeSeriesValuesForMetric = (metric_id): Array<number> =>
|
|
174
176
|
map(
|
|
175
|
-
(timeValue) => getValueForMetric(timeValue)(
|
|
177
|
+
(timeValue) => getValueForMetric(timeValue)(metric_id),
|
|
176
178
|
timeSeries
|
|
177
179
|
) as Array<number>;
|
|
178
180
|
|
|
179
181
|
return pipe(
|
|
180
182
|
filter(propEq('unit', unit)) as (line) => Array<Line>,
|
|
181
|
-
map(prop('
|
|
183
|
+
map(prop('metric_id')),
|
|
182
184
|
map(getTimeSeriesValuesForMetric),
|
|
183
185
|
flatten,
|
|
184
186
|
reject(isNil)
|
|
@@ -194,14 +196,14 @@ const getDates = (timeSeries: Array<TimeValue>): Array<Date> => {
|
|
|
194
196
|
|
|
195
197
|
interface LineForMetricProps {
|
|
196
198
|
lines: Array<Line>;
|
|
197
|
-
|
|
199
|
+
metric_id: number;
|
|
198
200
|
}
|
|
199
201
|
|
|
200
202
|
const getLineForMetric = ({
|
|
201
203
|
lines,
|
|
202
|
-
|
|
204
|
+
metric_id
|
|
203
205
|
}: LineForMetricProps): Line | undefined =>
|
|
204
|
-
find(propEq('
|
|
206
|
+
find(propEq('metric_id', metric_id), lines);
|
|
205
207
|
|
|
206
208
|
interface LinesTimeSeries {
|
|
207
209
|
lines: Array<Line>;
|
|
@@ -222,11 +224,11 @@ const getStackedMetricValues = ({
|
|
|
222
224
|
lines,
|
|
223
225
|
timeSeries
|
|
224
226
|
}: LinesTimeSeries): Array<number> => {
|
|
225
|
-
const getTimeSeriesValuesForMetric = (
|
|
226
|
-
map((timeValue) => getValueForMetric(timeValue)(
|
|
227
|
+
const getTimeSeriesValuesForMetric = (metric_id): Array<number> =>
|
|
228
|
+
map((timeValue) => getValueForMetric(timeValue)(metric_id), timeSeries);
|
|
227
229
|
|
|
228
230
|
const metricsValues = pipe(
|
|
229
|
-
map(prop('
|
|
231
|
+
map(prop('metric_id')) as (metric) => Array<number>,
|
|
230
232
|
map(getTimeSeriesValuesForMetric) as () => Array<Array<number>>
|
|
231
233
|
)(lines as Array<Line>);
|
|
232
234
|
|
|
@@ -279,14 +281,14 @@ const getTimeSeriesForLines = ({
|
|
|
279
281
|
lines,
|
|
280
282
|
timeSeries
|
|
281
283
|
}: LinesTimeSeries): Array<TimeValue> => {
|
|
282
|
-
const metrics = map(prop('
|
|
284
|
+
const metrics = map(prop('metric_id'), lines);
|
|
283
285
|
|
|
284
286
|
return map(
|
|
285
287
|
({ timeTick, ...metricsValue }): TimeValue => ({
|
|
286
288
|
...reduce(
|
|
287
|
-
(acc,
|
|
289
|
+
(acc, metric_id): Omit<TimeValue, 'timePick'> => ({
|
|
288
290
|
...acc,
|
|
289
|
-
[
|
|
291
|
+
[metric_id]: metricsValue[metric_id]
|
|
290
292
|
}),
|
|
291
293
|
{},
|
|
292
294
|
metrics
|
|
@@ -21,6 +21,7 @@ export interface Metric {
|
|
|
21
21
|
legend: string;
|
|
22
22
|
maximum_value: number | null;
|
|
23
23
|
metric: string;
|
|
24
|
+
metric_id: number;
|
|
24
25
|
minimum_value: number | null;
|
|
25
26
|
unit: string;
|
|
26
27
|
warning_high_threshold: number | null;
|
|
@@ -30,7 +31,7 @@ export interface Metric {
|
|
|
30
31
|
type TimeSeries = { timeTick: string };
|
|
31
32
|
|
|
32
33
|
export type TimeValue = TimeSeries & {
|
|
33
|
-
[field:
|
|
34
|
+
[field: number]: number;
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export interface Line {
|
|
@@ -45,6 +46,7 @@ export interface Line {
|
|
|
45
46
|
lineColor: string;
|
|
46
47
|
maximum_value: number | null;
|
|
47
48
|
metric: string;
|
|
49
|
+
metric_id: number;
|
|
48
50
|
minimum_value: number | null;
|
|
49
51
|
name: string;
|
|
50
52
|
stackOrder: number | null;
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
pipe,
|
|
11
11
|
not,
|
|
12
12
|
has,
|
|
13
|
-
omit
|
|
13
|
+
omit,
|
|
14
|
+
uniqBy
|
|
14
15
|
} from 'ramda';
|
|
15
16
|
|
|
16
17
|
import { CircularProgress, useTheme } from '@mui/material';
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
import useFetchQuery from '../../../../api/useFetchQuery';
|
|
31
32
|
|
|
32
33
|
export interface ConnectedAutoCompleteFieldProps<TData> {
|
|
34
|
+
allowUniqOption?: boolean;
|
|
33
35
|
conditionField?: keyof SelectEntry;
|
|
34
36
|
field: string;
|
|
35
37
|
getEndpoint: ({ search, page }) => string;
|
|
@@ -57,6 +59,7 @@ const ConnectedAutocompleteField = (
|
|
|
57
59
|
getRequestHeaders,
|
|
58
60
|
displayOptionThumbnail,
|
|
59
61
|
queryKey,
|
|
62
|
+
allowUniqOption,
|
|
60
63
|
...props
|
|
61
64
|
}: ConnectedAutoCompleteFieldProps<TData> &
|
|
62
65
|
Omit<AutocompleteFieldProps, 'options'>): JSX.Element => {
|
|
@@ -305,7 +308,9 @@ const ConnectedAutocompleteField = (
|
|
|
305
308
|
filterOptions={(opt): SelectEntry => opt}
|
|
306
309
|
loading={isFetching}
|
|
307
310
|
open={optionsOpen}
|
|
308
|
-
options={
|
|
311
|
+
options={
|
|
312
|
+
allowUniqOption ? uniqBy(getRenderedOptionText, options) : options
|
|
313
|
+
}
|
|
309
314
|
renderOption={renderOptions}
|
|
310
315
|
onChange={(_, value) => setAutocompleteChangedValue(value)}
|
|
311
316
|
onClose={(): void => setOptionsOpen(false)}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { includes, map, prop, reject } from 'ramda';
|
|
2
2
|
import { makeStyles } from 'tss-react/mui';
|
|
3
3
|
|
|
4
|
-
import { Chip, ChipProps } from '@mui/material';
|
|
4
|
+
import { Chip, ChipProps, Tooltip } from '@mui/material';
|
|
5
5
|
import { UseAutocompleteProps } from '@mui/material/useAutocomplete';
|
|
6
6
|
|
|
7
7
|
import Autocomplete, { Props as AutocompleteProps } from '..';
|
|
@@ -34,6 +34,7 @@ export interface Props
|
|
|
34
34
|
> {
|
|
35
35
|
chipProps?: ChipProps;
|
|
36
36
|
disableSortedOptions?: boolean;
|
|
37
|
+
getOptionTooltipLabel?: (option) => string;
|
|
37
38
|
getTagLabel?: (option) => string;
|
|
38
39
|
optionProperty?: string;
|
|
39
40
|
}
|
|
@@ -45,6 +46,7 @@ const MultiAutocompleteField = ({
|
|
|
45
46
|
optionProperty = 'name',
|
|
46
47
|
getOptionLabel = (option): string => option.name,
|
|
47
48
|
getTagLabel = (option): string => option[optionProperty],
|
|
49
|
+
getOptionTooltipLabel,
|
|
48
50
|
chipProps,
|
|
49
51
|
...props
|
|
50
52
|
}: Props): JSX.Element => {
|
|
@@ -52,17 +54,22 @@ const MultiAutocompleteField = ({
|
|
|
52
54
|
|
|
53
55
|
const renderTags = (renderedValue, getTagProps): Array<JSX.Element> =>
|
|
54
56
|
renderedValue.map((option, index) => (
|
|
55
|
-
<
|
|
56
|
-
classes={{
|
|
57
|
-
deleteIcon: classes.deleteIcon,
|
|
58
|
-
root: classes.tag
|
|
59
|
-
}}
|
|
57
|
+
<Tooltip
|
|
60
58
|
key={option.id}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
placement="top"
|
|
60
|
+
title={getOptionTooltipLabel?.(option)}
|
|
61
|
+
>
|
|
62
|
+
<Chip
|
|
63
|
+
classes={{
|
|
64
|
+
deleteIcon: classes.deleteIcon,
|
|
65
|
+
root: classes.tag
|
|
66
|
+
}}
|
|
67
|
+
label={getTagLabel(option)}
|
|
68
|
+
size="medium"
|
|
69
|
+
{...getTagProps({ index })}
|
|
70
|
+
{...chipProps}
|
|
71
|
+
/>
|
|
72
|
+
</Tooltip>
|
|
66
73
|
));
|
|
67
74
|
|
|
68
75
|
const getLimitTagsText = (more): JSX.Element => <Option>{`+${more}`}</Option>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useAtomValue } from 'jotai';
|
|
2
2
|
import { makeStyles } from 'tss-react/mui';
|
|
3
3
|
import { equals } from 'ramda';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
4
5
|
|
|
5
6
|
import { Typography } from '@mui/material';
|
|
6
7
|
import { LocalizationProvider } from '@mui/x-date-pickers';
|
|
@@ -34,6 +35,7 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
34
35
|
textAlign: 'left'
|
|
35
36
|
},
|
|
36
37
|
row: {
|
|
38
|
+
alignItems: 'center',
|
|
37
39
|
display: 'flex',
|
|
38
40
|
flexDirection: 'row',
|
|
39
41
|
gap: theme.spacing(1)
|
|
@@ -63,11 +65,12 @@ const PickerDateWithLabel = ({
|
|
|
63
65
|
direction = PickersStartEndDateDirection.column
|
|
64
66
|
}: PropsPickersDateWithLabel): JSX.Element => {
|
|
65
67
|
const { classes, cx } = useStyles();
|
|
68
|
+
const { t } = useTranslation();
|
|
66
69
|
const isRow = equals(direction, PickersStartEndDateDirection.row);
|
|
67
70
|
|
|
68
71
|
return (
|
|
69
72
|
<div aria-label={label} className={cx({ [classes.row]: isRow })}>
|
|
70
|
-
<Typography component={isRow ? 'div' : 'p'}>{label}</Typography>
|
|
73
|
+
<Typography component={isRow ? 'div' : 'p'}>{t(label)}</Typography>
|
|
71
74
|
<DateTimePickerInput
|
|
72
75
|
changeDate={changeDate}
|
|
73
76
|
date={date}
|
|
@@ -106,10 +109,10 @@ const PickersStartEndDate = ({
|
|
|
106
109
|
const { locale } = useAtomValue(userAtom);
|
|
107
110
|
const error = useAtomValue(errorTimePeriodAtom);
|
|
108
111
|
|
|
109
|
-
const maxStart = rangeStartDate?.max;
|
|
112
|
+
const maxStart = rangeStartDate?.max || endDate;
|
|
110
113
|
const minStart = rangeStartDate?.min;
|
|
111
114
|
const maxEnd = rangeEndDate?.max;
|
|
112
|
-
const minEnd = rangeEndDate?.min;
|
|
115
|
+
const minEnd = rangeEndDate?.min || startDate;
|
|
113
116
|
|
|
114
117
|
const styleContainer = equals(direction, PickersStartEndDateDirection.column)
|
|
115
118
|
? classes.verticalDirection
|
|
@@ -132,7 +135,7 @@ const PickersStartEndDate = ({
|
|
|
132
135
|
direction={direction}
|
|
133
136
|
disabled={disabled?.isDisabledStartPicker}
|
|
134
137
|
label="From"
|
|
135
|
-
maxDate={maxStart}
|
|
138
|
+
maxDate={maxStart || undefined}
|
|
136
139
|
minDate={minStart}
|
|
137
140
|
property={CustomTimePeriodProperty.start}
|
|
138
141
|
/>
|
|
@@ -141,9 +144,9 @@ const PickersStartEndDate = ({
|
|
|
141
144
|
date={endDate}
|
|
142
145
|
direction={direction}
|
|
143
146
|
disabled={disabled?.isDisabledEndPicker}
|
|
144
|
-
label="
|
|
147
|
+
label="to"
|
|
145
148
|
maxDate={maxEnd}
|
|
146
|
-
minDate={minEnd}
|
|
149
|
+
minDate={minEnd || undefined}
|
|
147
150
|
property={CustomTimePeriodProperty.end}
|
|
148
151
|
/>
|
|
149
152
|
</div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import PickersStartEndDate from './PopoverCustomTimePeriod/PickersStartEndDate';
|
|
2
|
+
import {
|
|
3
|
+
AcceptDateProps,
|
|
4
|
+
PickersStartEndDateDirection
|
|
5
|
+
} from './PopoverCustomTimePeriod/models';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
changeDate: (props: AcceptDateProps) => void;
|
|
9
|
+
endDate: Date;
|
|
10
|
+
startDate: Date;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const SimpleCustomTimePeriod = ({
|
|
14
|
+
startDate,
|
|
15
|
+
endDate,
|
|
16
|
+
changeDate
|
|
17
|
+
}: Props): JSX.Element => {
|
|
18
|
+
return (
|
|
19
|
+
<PickersStartEndDate
|
|
20
|
+
changeDate={changeDate}
|
|
21
|
+
direction={PickersStartEndDateDirection.row}
|
|
22
|
+
endDate={endDate}
|
|
23
|
+
startDate={startDate}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default SimpleCustomTimePeriod;
|
|
@@ -4,6 +4,7 @@ import dayjs from 'dayjs';
|
|
|
4
4
|
import Switch from '@mui/material/Switch';
|
|
5
5
|
|
|
6
6
|
import { dateFormat } from './models';
|
|
7
|
+
import SimpleCustomTimePeriod from './CustomTimePeriod/SimpleCustomTimePeriod';
|
|
7
8
|
|
|
8
9
|
import TimePeriod from '.';
|
|
9
10
|
|
|
@@ -16,10 +17,16 @@ export default meta;
|
|
|
16
17
|
|
|
17
18
|
type Story = StoryObj<typeof TimePeriod>;
|
|
18
19
|
|
|
20
|
+
type StorySimpleTimePeriod = StoryObj<typeof SimpleCustomTimePeriod>;
|
|
21
|
+
|
|
19
22
|
const Template: Story = {
|
|
20
23
|
render: (args) => <TimePeriod {...args} />
|
|
21
24
|
};
|
|
22
25
|
|
|
26
|
+
const TemplateWithSimpleTimePeriod: StorySimpleTimePeriod = {
|
|
27
|
+
render: (args) => <SimpleCustomTimePeriod {...args} />
|
|
28
|
+
};
|
|
29
|
+
|
|
23
30
|
const TemplateWithExternalComponent: Story = {
|
|
24
31
|
render: (args) => (
|
|
25
32
|
<TimePeriod {...args} renderExternalComponent={<Switch />} />
|
|
@@ -96,3 +103,11 @@ export const WithExternalComponent: Story = {
|
|
|
96
103
|
...TemplateWithExternalComponent,
|
|
97
104
|
argTypes
|
|
98
105
|
};
|
|
106
|
+
|
|
107
|
+
export const SimpleTimePeriod: StorySimpleTimePeriod = {
|
|
108
|
+
...TemplateWithSimpleTimePeriod,
|
|
109
|
+
args: {
|
|
110
|
+
endDate: dayjs(Date.now()).toDate(),
|
|
111
|
+
startDate: dayjs(Date.now()).subtract(29, 'day').toDate()
|
|
112
|
+
}
|
|
113
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { equals,
|
|
1
|
+
import { equals, has, isEmpty, pluck } from 'ramda';
|
|
2
2
|
import dayjs from 'dayjs';
|
|
3
3
|
|
|
4
|
-
import { LineChartData, useFetchQuery } from '../..';
|
|
4
|
+
import { LineChartData, buildListingEndpoint, useFetchQuery } from '../..';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { Resource, WidgetResourceType } from './models';
|
|
7
7
|
|
|
8
8
|
interface CustomTimePeriod {
|
|
9
9
|
end: string;
|
|
@@ -12,8 +12,9 @@ interface CustomTimePeriod {
|
|
|
12
12
|
|
|
13
13
|
interface UseMetricsQueryProps {
|
|
14
14
|
baseEndpoint: string;
|
|
15
|
-
metrics: Array<
|
|
15
|
+
metrics: Array<string>;
|
|
16
16
|
refreshInterval?: number | false;
|
|
17
|
+
resources?: Array<Resource>;
|
|
17
18
|
timePeriod?: {
|
|
18
19
|
end?: string | null;
|
|
19
20
|
start?: string | null;
|
|
@@ -25,7 +26,7 @@ interface UseMetricsQueryState {
|
|
|
25
26
|
end: string;
|
|
26
27
|
graphData: LineChartData | undefined;
|
|
27
28
|
isGraphLoading: boolean;
|
|
28
|
-
|
|
29
|
+
isMetricsEmpty: boolean;
|
|
29
30
|
start: string;
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -51,21 +52,28 @@ interface PerformanceGraphData extends Omit<LineChartData, 'global'> {
|
|
|
51
52
|
base: number;
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
const resourceTypeQueryParameter = {
|
|
56
|
+
[WidgetResourceType.host]: 'host.id',
|
|
57
|
+
[WidgetResourceType.hostCategory]: 'hostcategory.id',
|
|
58
|
+
[WidgetResourceType.hostGroup]: 'hostgroup.id',
|
|
59
|
+
[WidgetResourceType.service]: 'service.name'
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const areResourcesFullfilled = (value: Array<Resource>): boolean =>
|
|
63
|
+
value?.every(
|
|
64
|
+
({ resourceType, resources }) =>
|
|
65
|
+
!isEmpty(resourceType) && !isEmpty(resources)
|
|
66
|
+
);
|
|
67
|
+
|
|
54
68
|
const useGraphQuery = ({
|
|
55
69
|
metrics,
|
|
70
|
+
resources = [],
|
|
56
71
|
baseEndpoint,
|
|
57
72
|
timePeriod = {
|
|
58
73
|
timePeriodType: 1
|
|
59
74
|
},
|
|
60
75
|
refreshInterval = false
|
|
61
76
|
}: UseMetricsQueryProps): UseMetricsQueryState => {
|
|
62
|
-
const metricIds = pipe(
|
|
63
|
-
pluck('metrics'),
|
|
64
|
-
flatten,
|
|
65
|
-
pluck('id'),
|
|
66
|
-
join(',')
|
|
67
|
-
)(metrics);
|
|
68
|
-
|
|
69
77
|
const timePeriodToUse = equals(timePeriod?.timePeriodType, -1)
|
|
70
78
|
? {
|
|
71
79
|
end: timePeriod.end,
|
|
@@ -73,27 +81,44 @@ const useGraphQuery = ({
|
|
|
73
81
|
}
|
|
74
82
|
: timePeriod?.timePeriodType;
|
|
75
83
|
|
|
84
|
+
const startAndEnd = isCustomTimePeriod(timePeriodToUse)
|
|
85
|
+
? (timePeriodToUse as CustomTimePeriod)
|
|
86
|
+
: getStartEndFromTimePeriod(timePeriodToUse as number);
|
|
87
|
+
|
|
88
|
+
const definedMetrics = metrics.filter((metric) => metric);
|
|
89
|
+
|
|
76
90
|
const {
|
|
77
91
|
data: graphData,
|
|
78
92
|
isFetching,
|
|
79
93
|
isLoading
|
|
80
94
|
} = useFetchQuery<PerformanceGraphData>({
|
|
81
95
|
getEndpoint: () => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
const endpoint = buildListingEndpoint({
|
|
97
|
+
baseEndpoint,
|
|
98
|
+
parameters: {
|
|
99
|
+
search: {
|
|
100
|
+
lists: resources.map((resource) => ({
|
|
101
|
+
field: resourceTypeQueryParameter[resource.resourceType],
|
|
102
|
+
values: equals(resource.resourceType, 'service')
|
|
103
|
+
? pluck('name', resource.resources)
|
|
104
|
+
: pluck('id', resource.resources)
|
|
105
|
+
}))
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return `${endpoint}&start=${startAndEnd.start}&end=${
|
|
111
|
+
startAndEnd.end
|
|
112
|
+
}&metric_names=[${definedMetrics.join(',')}]`;
|
|
93
113
|
},
|
|
94
|
-
getQueryKey: () => [
|
|
114
|
+
getQueryKey: () => [
|
|
115
|
+
'graph',
|
|
116
|
+
JSON.stringify(definedMetrics),
|
|
117
|
+
JSON.stringify(resources),
|
|
118
|
+
timePeriod
|
|
119
|
+
],
|
|
95
120
|
queryOptions: {
|
|
96
|
-
enabled: !isEmpty(
|
|
121
|
+
enabled: areResourcesFullfilled(resources) && !isEmpty(definedMetrics),
|
|
97
122
|
refetchInterval: refreshInterval,
|
|
98
123
|
suspense: false
|
|
99
124
|
}
|
|
@@ -117,8 +142,8 @@ const useGraphQuery = ({
|
|
|
117
142
|
return {
|
|
118
143
|
end,
|
|
119
144
|
graphData: formattedGraphData,
|
|
120
|
-
isGraphLoading: isFetching || (isLoading && !isEmpty(
|
|
121
|
-
|
|
145
|
+
isGraphLoading: isFetching || (isLoading && !isEmpty(definedMetrics)),
|
|
146
|
+
isMetricsEmpty: isEmpty(definedMetrics),
|
|
122
147
|
start
|
|
123
148
|
};
|
|
124
149
|
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
id: number;
|
|
3
|
-
name: string;
|
|
4
|
-
}
|
|
1
|
+
import { SelectEntry } from '../..';
|
|
5
2
|
|
|
6
|
-
interface
|
|
7
|
-
|
|
3
|
+
export interface Resource {
|
|
4
|
+
resourceType: string;
|
|
5
|
+
resources: Array<SelectEntry>;
|
|
8
6
|
}
|
|
9
7
|
|
|
10
|
-
export
|
|
11
|
-
|
|
8
|
+
export enum WidgetResourceType {
|
|
9
|
+
host = 'host',
|
|
10
|
+
hostCategory = 'host-category',
|
|
11
|
+
hostGroup = 'host-group',
|
|
12
|
+
service = 'service'
|
|
12
13
|
}
|
package/src/index.ts
CHANGED
|
@@ -147,3 +147,6 @@ export * from './Dashboard';
|
|
|
147
147
|
export * from './Graph';
|
|
148
148
|
export type { LineChartData } from './Graph/common/models';
|
|
149
149
|
export * from './Graph/common/timeSeries';
|
|
150
|
+
|
|
151
|
+
export { default as TimePeriods } from './TimePeriods';
|
|
152
|
+
export { default as SimpleCustomTimePeriod } from './TimePeriods/CustomTimePeriod/SimpleCustomTimePeriod';
|