@centreon/ui 25.3.0 → 25.3.2
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/BarChart/BarChart.cypress.spec.tsx +2 -2
- package/src/Graph/BarChart/BarChart.stories.tsx +39 -0
- package/src/Graph/BarChart/BarStack.tsx +8 -2
- package/src/Graph/BarChart/ResponsiveBarChart.tsx +10 -8
- package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +41 -24
- package/src/Graph/Chart/BasicComponents/Lines/index.tsx +22 -37
- package/src/Graph/Chart/Chart.cypress.spec.tsx +104 -31
- package/src/Graph/Chart/Chart.stories.tsx +24 -2
- package/src/Graph/Chart/Chart.tsx +23 -18
- package/src/Graph/Chart/index.tsx +2 -0
- package/src/Graph/Chart/models.ts +4 -3
- package/src/Graph/Tree/Tree.stories.tsx +4 -1
- package/src/Graph/common/Axes/index.tsx +1 -1
- package/src/Graph/common/BaseChart/AdditionalLine.tsx +37 -0
- package/src/Graph/common/BaseChart/BaseChart.tsx +5 -1
- package/src/Graph/common/BaseChart/Header/index.tsx +5 -7
- package/src/Graph/common/BaseChart/Header/useHeaderStyles.ts +5 -1
- package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +9 -2
- package/src/Graph/common/models.ts +7 -0
- package/src/Graph/common/timeSeries/index.ts +1 -1
- package/src/Graph/common/utils.ts +22 -1
- package/src/Graph/mockedData/lastDayWithNullValues.json +6 -40
- package/src/Graph/mockedData/pingService.json +3 -3
- package/src/api/useGraphQuery/index.ts +3 -1
package/package.json
CHANGED
|
@@ -83,7 +83,7 @@ describe('Bar chart', () => {
|
|
|
83
83
|
cy.contains('20').should('be.visible');
|
|
84
84
|
cy.contains(':40 AM').should('be.visible');
|
|
85
85
|
|
|
86
|
-
cy.findByTestId('stacked-bar-3-0-0.
|
|
86
|
+
cy.findByTestId('stacked-bar-3-0-0.08084').should('be.visible');
|
|
87
87
|
|
|
88
88
|
cy.makeSnapshot();
|
|
89
89
|
});
|
|
@@ -96,7 +96,7 @@ describe('Bar chart', () => {
|
|
|
96
96
|
cy.contains('20').should('be.visible');
|
|
97
97
|
cy.contains(':40 AM').should('be.visible');
|
|
98
98
|
|
|
99
|
-
cy.findByTestId('stacked-bar-3-0-0.
|
|
99
|
+
cy.findByTestId('stacked-bar-3-0-0.08084').should('be.visible');
|
|
100
100
|
|
|
101
101
|
cy.makeSnapshot();
|
|
102
102
|
});
|
|
@@ -195,6 +195,45 @@ export const customBarStyle: Story = {
|
|
|
195
195
|
render: Template
|
|
196
196
|
};
|
|
197
197
|
|
|
198
|
+
export const customBarStyleForABar: Story = {
|
|
199
|
+
args: {
|
|
200
|
+
...defaultArgs,
|
|
201
|
+
barStyle: [
|
|
202
|
+
{
|
|
203
|
+
opacity: 0.5,
|
|
204
|
+
radius: 0.5,
|
|
205
|
+
metricId: 10
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
opacity: 0.2,
|
|
209
|
+
radius: 0.3,
|
|
210
|
+
metricId: 1
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
},
|
|
214
|
+
render: Template
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const customBarStyleForABarStacked: Story = {
|
|
218
|
+
args: {
|
|
219
|
+
...defaultArgs,
|
|
220
|
+
data: dataPingServiceStacked,
|
|
221
|
+
barStyle: [
|
|
222
|
+
{
|
|
223
|
+
opacity: 0.5,
|
|
224
|
+
radius: 0.5,
|
|
225
|
+
metricId: 10
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
opacity: 0.2,
|
|
229
|
+
radius: 0.3,
|
|
230
|
+
metricId: 1
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
render: Template
|
|
235
|
+
};
|
|
236
|
+
|
|
198
237
|
export const mixedStacked: Story = {
|
|
199
238
|
args: {
|
|
200
239
|
...defaultArgs,
|
|
@@ -5,6 +5,7 @@ import { BarRounded } from '@visx/shape';
|
|
|
5
5
|
import { dec, equals, gt, pick } from 'ramda';
|
|
6
6
|
|
|
7
7
|
import { BarGroupBar, SeriesPoint, StackKey } from '@visx/shape/lib/types';
|
|
8
|
+
import { getStyle } from '../common/utils';
|
|
8
9
|
import { BarStyle } from './models';
|
|
9
10
|
import { UseBarStackProps, useBarStack } from './useBarStack';
|
|
10
11
|
|
|
@@ -112,6 +113,11 @@ const BarStack = ({
|
|
|
112
113
|
[isHorizontal ? 'top' : 'right']: shouldApplyRadiusOnTop
|
|
113
114
|
};
|
|
114
115
|
|
|
116
|
+
const style = getStyle({
|
|
117
|
+
style: barStyle,
|
|
118
|
+
metricId: Number(bar.key)
|
|
119
|
+
}) as BarStyle;
|
|
120
|
+
|
|
115
121
|
return (
|
|
116
122
|
<BarRounded
|
|
117
123
|
{...barRoundedProps}
|
|
@@ -133,8 +139,8 @@ const BarStack = ({
|
|
|
133
139
|
neutralValue
|
|
134
140
|
})}
|
|
135
141
|
key={`bar-stack-${barStack.index}-${bar.index}`}
|
|
136
|
-
opacity={
|
|
137
|
-
radius={barWidth *
|
|
142
|
+
opacity={style?.opacity || 1}
|
|
143
|
+
radius={style?.radius ? barWidth * style.radius : 0}
|
|
138
144
|
width={isHorizontal ? barWidth : Math.abs(bar.width)}
|
|
139
145
|
x={
|
|
140
146
|
isHorizontal
|
|
@@ -87,14 +87,15 @@ const ResponsiveBarChart = ({
|
|
|
87
87
|
secondUnit
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
const { legendRef, graphWidth, graphHeight } =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
const { legendRef, graphWidth, graphHeight, titleRef } =
|
|
91
|
+
useComputeBaseChartDimensions({
|
|
92
|
+
hasSecondUnit: Boolean(secondUnit),
|
|
93
|
+
height,
|
|
94
|
+
legendDisplay: legend?.display,
|
|
95
|
+
legendPlacement: legend?.placement,
|
|
96
|
+
width,
|
|
97
|
+
maxAxisCharacters: maxRightAxisCharacters || maxLeftAxisCharacters
|
|
98
|
+
});
|
|
98
99
|
|
|
99
100
|
const thresholdValues = flatten([
|
|
100
101
|
pluck('value', thresholds?.warning || []),
|
|
@@ -192,6 +193,7 @@ const ResponsiveBarChart = ({
|
|
|
192
193
|
lines={linesGraph}
|
|
193
194
|
setLines={setLinesGraph}
|
|
194
195
|
title={title}
|
|
196
|
+
titleRef={titleRef}
|
|
195
197
|
>
|
|
196
198
|
<Tooltip
|
|
197
199
|
classes={{
|
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import { Shape } from '@visx/visx';
|
|
2
2
|
import { ScaleLinear, ScaleTime } from 'd3-scale';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
path,
|
|
5
|
+
all,
|
|
6
|
+
equals,
|
|
7
|
+
isNil,
|
|
8
|
+
map,
|
|
9
|
+
not,
|
|
10
|
+
nth,
|
|
11
|
+
pipe,
|
|
12
|
+
prop,
|
|
13
|
+
type
|
|
14
|
+
} from 'ramda';
|
|
4
15
|
|
|
5
16
|
import { getDates, getTime } from '../../../../common/timeSeries';
|
|
6
17
|
import { Line, TimeValue } from '../../../../common/timeSeries/models';
|
|
7
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
getPointRadius,
|
|
20
|
+
getStrokeDashArray,
|
|
21
|
+
getStyle
|
|
22
|
+
} from '../../../../common/utils';
|
|
8
23
|
import StackedAnchorPoint, {
|
|
9
24
|
getYAnchorPoint
|
|
10
25
|
} from '../../../InteractiveComponents/AnchorPoint/StackedAnchorPoint';
|
|
11
26
|
import { StackValue } from '../../../InteractiveComponents/AnchorPoint/models';
|
|
12
27
|
import { getCurveFactory, getFillColor } from '../../../common';
|
|
28
|
+
import { LineStyle } from '../../../models';
|
|
13
29
|
import Point from '../Point';
|
|
14
30
|
|
|
15
31
|
interface Props {
|
|
@@ -26,6 +42,7 @@ interface Props {
|
|
|
26
42
|
timeSeries: Array<TimeValue>;
|
|
27
43
|
xScale: ScaleTime<number, number>;
|
|
28
44
|
yScale: ScaleLinear<number, number>;
|
|
45
|
+
lineStyle: LineStyle | Array<LineStyle>;
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
const StackLines = ({
|
|
@@ -34,19 +51,13 @@ const StackLines = ({
|
|
|
34
51
|
yScale,
|
|
35
52
|
xScale,
|
|
36
53
|
displayAnchor,
|
|
37
|
-
|
|
38
|
-
showPoints,
|
|
39
|
-
showArea,
|
|
40
|
-
areaTransparency,
|
|
41
|
-
lineWidth,
|
|
42
|
-
dashLength,
|
|
43
|
-
dashOffset,
|
|
44
|
-
dotOffset
|
|
54
|
+
lineStyle
|
|
45
55
|
}: Props): JSX.Element => {
|
|
46
|
-
const curveType = getCurveFactory(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
const curveType = getCurveFactory(
|
|
57
|
+
(equals(type(lineStyle), 'Array')
|
|
58
|
+
? lineStyle?.[0].curve
|
|
59
|
+
: lineStyle?.curve) || 'linear'
|
|
60
|
+
);
|
|
50
61
|
return (
|
|
51
62
|
<Shape.AreaStack
|
|
52
63
|
curve={curveType}
|
|
@@ -69,15 +80,21 @@ const StackLines = ({
|
|
|
69
80
|
const { areaColor, transparency, lineColor, highlight, metric_id } =
|
|
70
81
|
nth(index, lines) as Line;
|
|
71
82
|
|
|
72
|
-
const
|
|
83
|
+
const style = getStyle({
|
|
84
|
+
style: lineStyle,
|
|
85
|
+
metricId: metric_id
|
|
86
|
+
}) as LineStyle;
|
|
87
|
+
const formattedLineWidth = style?.lineWidth ?? 2;
|
|
88
|
+
|
|
89
|
+
const formattedTransparency = isNil(style?.areaTransparency)
|
|
73
90
|
? transparency || 80
|
|
74
|
-
: areaTransparency;
|
|
91
|
+
: style.areaTransparency;
|
|
75
92
|
|
|
76
93
|
return (
|
|
77
94
|
<g key={`stack-${prop('key', stack)}`}>
|
|
78
95
|
{displayAnchor && (
|
|
79
96
|
<StackedAnchorPoint
|
|
80
|
-
areaColor={areaColor}
|
|
97
|
+
areaColor={style?.areaColor}
|
|
81
98
|
lineColor={lineColor}
|
|
82
99
|
stackValues={stack as unknown as Array<StackValue>}
|
|
83
100
|
timeSeries={timeSeries}
|
|
@@ -86,13 +103,13 @@ const StackLines = ({
|
|
|
86
103
|
yScale={yScale}
|
|
87
104
|
/>
|
|
88
105
|
)}
|
|
89
|
-
{showPoints &&
|
|
106
|
+
{style?.showPoints &&
|
|
90
107
|
getDates(timeSeries).map((timeTick) => (
|
|
91
108
|
<Point
|
|
92
109
|
key={timeTick.toString()}
|
|
93
110
|
lineColor={lineColor}
|
|
94
111
|
metric_id={metric_id}
|
|
95
|
-
radius={getPointRadius(lineWidth)}
|
|
112
|
+
radius={getPointRadius(style?.lineWidth)}
|
|
96
113
|
timeSeries={timeSeries}
|
|
97
114
|
timeTick={timeTick}
|
|
98
115
|
xScale={xScale}
|
|
@@ -108,7 +125,7 @@ const StackLines = ({
|
|
|
108
125
|
d={linePath(stack) || ''}
|
|
109
126
|
data-metric={metric_id}
|
|
110
127
|
fill={
|
|
111
|
-
equals(showArea, false)
|
|
128
|
+
equals(style?.showArea, false)
|
|
112
129
|
? 'transparent'
|
|
113
130
|
: getFillColor({
|
|
114
131
|
areaColor: areaColor || lineColor,
|
|
@@ -118,10 +135,10 @@ const StackLines = ({
|
|
|
118
135
|
opacity={highlight === false ? 0.3 : 1}
|
|
119
136
|
stroke={lineColor}
|
|
120
137
|
strokeDasharray={getStrokeDashArray({
|
|
121
|
-
dashLength,
|
|
122
|
-
dashOffset,
|
|
123
|
-
dotOffset,
|
|
124
|
-
lineWidth:
|
|
138
|
+
dashLength: style?.dashLength,
|
|
139
|
+
dashOffset: style?.dashOffset,
|
|
140
|
+
dotOffset: style?.dotOffset,
|
|
141
|
+
lineWidth: style?.lineWidth ?? 2
|
|
125
142
|
})}
|
|
126
143
|
strokeWidth={
|
|
127
144
|
highlight
|
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
getYScale
|
|
10
10
|
} from '../../../common/timeSeries';
|
|
11
11
|
import type { Line, TimeValue } from '../../../common/timeSeries/models';
|
|
12
|
-
import { getPointRadius } from '../../../common/utils';
|
|
12
|
+
import { getPointRadius, getStyle } from '../../../common/utils';
|
|
13
13
|
import GuidingLines from '../../InteractiveComponents/AnchorPoint/GuidingLines';
|
|
14
14
|
import RegularAnchorPoint, {
|
|
15
15
|
getYAnchorPoint
|
|
16
16
|
} from '../../InteractiveComponents/AnchorPoint/RegularAnchorPoint';
|
|
17
17
|
import { displayArea } from '../../helpers/index';
|
|
18
|
-
import type { DisplayAnchor, GlobalAreaLines } from '../../models';
|
|
18
|
+
import type { DisplayAnchor, GlobalAreaLines, LineStyle } from '../../models';
|
|
19
19
|
|
|
20
20
|
import Point from './Point';
|
|
21
21
|
import RegularLine from './RegularLines';
|
|
@@ -29,33 +29,24 @@ import {
|
|
|
29
29
|
} from './Threshold/models';
|
|
30
30
|
|
|
31
31
|
interface Props extends GlobalAreaLines {
|
|
32
|
-
areaTransparency?: number;
|
|
33
|
-
curve: 'linear' | 'step' | 'natural';
|
|
34
|
-
dashLength?: number;
|
|
35
|
-
dashOffset?: number;
|
|
36
32
|
displayAnchor?: DisplayAnchor;
|
|
37
33
|
displayedLines: Array<Line>;
|
|
38
|
-
dotOffset?: number;
|
|
39
34
|
graphSvgRef: MutableRefObject<SVGSVGElement | null>;
|
|
40
35
|
height: number;
|
|
41
|
-
lineWidth?: number;
|
|
42
36
|
scale?: 'linear' | 'logarithmic';
|
|
43
37
|
scaleLogarithmicBase?: number;
|
|
44
|
-
showArea?: boolean;
|
|
45
|
-
showPoints?: boolean;
|
|
46
38
|
timeSeries: Array<TimeValue>;
|
|
47
39
|
width: number;
|
|
48
40
|
xScale: ScaleLinear<number, number>;
|
|
49
41
|
yScalesPerUnit: Record<string, ScaleLinear<number, number>>;
|
|
42
|
+
lineStyle: LineStyle | Array<LineStyle>;
|
|
50
43
|
}
|
|
51
44
|
|
|
52
45
|
const Lines = ({
|
|
53
|
-
areaTransparency,
|
|
54
46
|
height,
|
|
55
47
|
graphSvgRef,
|
|
56
48
|
width,
|
|
57
49
|
displayAnchor,
|
|
58
|
-
curve,
|
|
59
50
|
yScalesPerUnit,
|
|
60
51
|
xScale,
|
|
61
52
|
timeSeries,
|
|
@@ -63,14 +54,9 @@ const Lines = ({
|
|
|
63
54
|
areaThresholdLines,
|
|
64
55
|
areaStackedLines,
|
|
65
56
|
areaRegularLines,
|
|
66
|
-
showArea,
|
|
67
|
-
showPoints,
|
|
68
|
-
lineWidth,
|
|
69
|
-
dotOffset,
|
|
70
|
-
dashLength,
|
|
71
|
-
dashOffset,
|
|
72
57
|
scale,
|
|
73
|
-
scaleLogarithmicBase
|
|
58
|
+
scaleLogarithmicBase,
|
|
59
|
+
lineStyle
|
|
74
60
|
}: Props): JSX.Element => {
|
|
75
61
|
const { stackedLinesData, invertedStackedLinesData } = useStackedLines({
|
|
76
62
|
lines: displayedLines,
|
|
@@ -88,18 +74,10 @@ const Lines = ({
|
|
|
88
74
|
|
|
89
75
|
const displayGuidingLines = displayAnchor?.displayGuidingLines ?? true;
|
|
90
76
|
const commonStackedLinesProps = {
|
|
91
|
-
areaTransparency,
|
|
92
|
-
curve,
|
|
93
|
-
dashLength,
|
|
94
|
-
dashOffset,
|
|
95
77
|
displayAnchor: displayGuidingLines,
|
|
96
|
-
dotOffset,
|
|
97
78
|
graphHeight: height,
|
|
98
79
|
graphSvgRef,
|
|
99
80
|
graphWidth: width,
|
|
100
|
-
lineWidth,
|
|
101
|
-
showArea,
|
|
102
|
-
showPoints,
|
|
103
81
|
xScale
|
|
104
82
|
};
|
|
105
83
|
|
|
@@ -119,6 +97,7 @@ const Lines = ({
|
|
|
119
97
|
{Object.entries(stackedLinesData).map(
|
|
120
98
|
([unit, { lines, timeSeries: stackedTimeSeries }]) => (
|
|
121
99
|
<StackedLines
|
|
100
|
+
lineStyle={lineStyle}
|
|
122
101
|
key={`stacked-${unit}`}
|
|
123
102
|
lines={lines}
|
|
124
103
|
timeSeries={stackedTimeSeries}
|
|
@@ -130,6 +109,7 @@ const Lines = ({
|
|
|
130
109
|
{Object.entries(invertedStackedLinesData).map(
|
|
131
110
|
([unit, { lines, timeSeries: stackedTimeSeries }]) => (
|
|
132
111
|
<StackedLines
|
|
112
|
+
lineStyle={lineStyle}
|
|
133
113
|
key={`invert-stacked-${unit}`}
|
|
134
114
|
lines={lines}
|
|
135
115
|
timeSeries={stackedTimeSeries}
|
|
@@ -196,6 +176,11 @@ const Lines = ({
|
|
|
196
176
|
timeSeries
|
|
197
177
|
});
|
|
198
178
|
|
|
179
|
+
const style = getStyle({
|
|
180
|
+
style: lineStyle,
|
|
181
|
+
metricId: metric_id
|
|
182
|
+
}) as LineStyle;
|
|
183
|
+
|
|
199
184
|
return (
|
|
200
185
|
<g key={metric_id}>
|
|
201
186
|
{displayGuidingLines && (
|
|
@@ -209,13 +194,13 @@ const Lines = ({
|
|
|
209
194
|
yScale={yScale}
|
|
210
195
|
/>
|
|
211
196
|
)}
|
|
212
|
-
{showPoints &&
|
|
197
|
+
{style?.showPoints &&
|
|
213
198
|
getDates(relatedTimeSeries).map((timeTick) => (
|
|
214
199
|
<Point
|
|
215
200
|
key={timeTick.toString()}
|
|
216
201
|
lineColor={lineColor}
|
|
217
202
|
metric_id={metric_id}
|
|
218
|
-
radius={getPointRadius(lineWidth)}
|
|
203
|
+
radius={getPointRadius(style?.lineWidth)}
|
|
219
204
|
timeSeries={relatedTimeSeries}
|
|
220
205
|
timeTick={timeTick}
|
|
221
206
|
xScale={xScale}
|
|
@@ -230,21 +215,21 @@ const Lines = ({
|
|
|
230
215
|
))}
|
|
231
216
|
<RegularLine
|
|
232
217
|
areaColor={areaColor || lineColor}
|
|
233
|
-
curve={curve}
|
|
234
|
-
dashLength={dashLength}
|
|
235
|
-
dashOffset={dashOffset}
|
|
236
|
-
dotOffset={dotOffset}
|
|
237
|
-
filled={isNil(showArea) ? filled : showArea}
|
|
218
|
+
curve={style?.curve || 'linear'}
|
|
219
|
+
dashLength={style?.dashLength}
|
|
220
|
+
dashOffset={style?.dashOffset}
|
|
221
|
+
dotOffset={style?.dotOffset}
|
|
222
|
+
filled={isNil(style?.showArea) ? filled : style.showArea}
|
|
238
223
|
graphHeight={height}
|
|
239
224
|
highlight={highlight}
|
|
240
225
|
lineColor={lineColor}
|
|
241
|
-
lineWidth={lineWidth}
|
|
226
|
+
lineWidth={style?.lineWidth || 2}
|
|
242
227
|
metric_id={metric_id}
|
|
243
228
|
timeSeries={relatedTimeSeries}
|
|
244
229
|
transparency={
|
|
245
|
-
isNil(areaTransparency)
|
|
230
|
+
isNil(style?.areaTransparency)
|
|
246
231
|
? transparency || 80
|
|
247
|
-
: areaTransparency
|
|
232
|
+
: style.areaTransparency
|
|
248
233
|
}
|
|
249
234
|
unit={unit}
|
|
250
235
|
xScale={xScale}
|
|
@@ -9,6 +9,7 @@ import dataCurvesWithSameColor from '../mockedData/curvesWithSameColor.json';
|
|
|
9
9
|
import dataLastDay from '../mockedData/lastDay.json';
|
|
10
10
|
import dataLastDayWithIncompleteValues from '../mockedData/lastDayWithIncompleteValues.json';
|
|
11
11
|
import dataLastDayWithNullValues from '../mockedData/lastDayWithNullValues.json';
|
|
12
|
+
import dataPingServiceLines from '../mockedData/pingService.json';
|
|
12
13
|
import dataPingServiceLinesBars from '../mockedData/pingServiceLinesBars.json';
|
|
13
14
|
import dataPingServiceLinesBarsMixed from '../mockedData/pingServiceLinesBarsMixed.json';
|
|
14
15
|
import dataPingServiceLinesBarsStacked from '../mockedData/pingServiceLinesBarsStacked.json';
|
|
@@ -19,7 +20,10 @@ import { LineChartProps } from './models';
|
|
|
19
20
|
import WrapperChart from '.';
|
|
20
21
|
|
|
21
22
|
interface Props
|
|
22
|
-
extends Pick<
|
|
23
|
+
extends Pick<
|
|
24
|
+
LineChartProps,
|
|
25
|
+
'legend' | 'tooltip' | 'axis' | 'lineStyle' | 'barStyle' | 'additionalLines'
|
|
26
|
+
> {
|
|
23
27
|
data?: LineChartData;
|
|
24
28
|
}
|
|
25
29
|
|
|
@@ -63,7 +67,9 @@ const initialize = ({
|
|
|
63
67
|
tooltip,
|
|
64
68
|
legend,
|
|
65
69
|
axis,
|
|
66
|
-
lineStyle
|
|
70
|
+
lineStyle,
|
|
71
|
+
barStyle,
|
|
72
|
+
additionalLines
|
|
67
73
|
}: Props): void => {
|
|
68
74
|
cy.adjustViewport();
|
|
69
75
|
|
|
@@ -84,7 +90,9 @@ const initialize = ({
|
|
|
84
90
|
data={data as unknown as LineChartData}
|
|
85
91
|
legend={legend}
|
|
86
92
|
lineStyle={lineStyle}
|
|
93
|
+
barStyle={barStyle}
|
|
87
94
|
tooltip={tooltip}
|
|
95
|
+
additionalLines={additionalLines}
|
|
88
96
|
/>
|
|
89
97
|
</Provider>
|
|
90
98
|
)
|
|
@@ -131,7 +139,7 @@ const initializeCustomUnits = ({
|
|
|
131
139
|
const checkGraphWidth = (): void => {
|
|
132
140
|
cy.findByTestId('graph-interaction-zone')
|
|
133
141
|
.should('have.attr', 'height')
|
|
134
|
-
.and('equal', '
|
|
142
|
+
.and('equal', '376.203125');
|
|
135
143
|
|
|
136
144
|
cy.findByTestId('graph-interaction-zone').then((graph) => {
|
|
137
145
|
expect(Number(graph[0].attributes.width.value)).to.be.greaterThan(1170);
|
|
@@ -170,7 +178,7 @@ describe('Line chart', () => {
|
|
|
170
178
|
|
|
171
179
|
cy.contains('Min: 70.31').should('be.visible');
|
|
172
180
|
|
|
173
|
-
cy.findByTestId('graph-interaction-zone').realMouseMove(
|
|
181
|
+
cy.findByTestId('graph-interaction-zone').realMouseMove(230, 26);
|
|
174
182
|
|
|
175
183
|
cy.get('[data-metric="querytime"]').should(
|
|
176
184
|
'have.attr',
|
|
@@ -182,6 +190,11 @@ describe('Line chart', () => {
|
|
|
182
190
|
'data-highlight',
|
|
183
191
|
'false'
|
|
184
192
|
);
|
|
193
|
+
cy.get('[data-metric="hitratio"]').should(
|
|
194
|
+
'have.attr',
|
|
195
|
+
'data-highlight',
|
|
196
|
+
'true'
|
|
197
|
+
);
|
|
185
198
|
|
|
186
199
|
cy.makeSnapshot();
|
|
187
200
|
});
|
|
@@ -215,25 +228,6 @@ describe('Line chart', () => {
|
|
|
215
228
|
cy.makeSnapshot();
|
|
216
229
|
});
|
|
217
230
|
|
|
218
|
-
it('displays the tooltip a single metric when the corresponding prop is set', () => {
|
|
219
|
-
initialize({ tooltip: { mode: 'single', sortOrder: 'name' } });
|
|
220
|
-
|
|
221
|
-
checkGraphWidth();
|
|
222
|
-
|
|
223
|
-
cy.contains('Min: 70.31').should('be.visible');
|
|
224
|
-
|
|
225
|
-
cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26);
|
|
226
|
-
|
|
227
|
-
cy.get('[data-metric="hitratio"]').should(
|
|
228
|
-
'have.attr',
|
|
229
|
-
'data-highlight',
|
|
230
|
-
'true'
|
|
231
|
-
);
|
|
232
|
-
cy.get('[data-metric="querytime"]').should('not.exist');
|
|
233
|
-
|
|
234
|
-
cy.makeSnapshot();
|
|
235
|
-
});
|
|
236
|
-
|
|
237
231
|
it('does not display the tooltip when the corresponding prop is set', () => {
|
|
238
232
|
initialize({ tooltip: { mode: 'hidden', sortOrder: 'name' } });
|
|
239
233
|
|
|
@@ -443,7 +437,7 @@ describe('Line chart', () => {
|
|
|
443
437
|
|
|
444
438
|
cy.contains(':00 AM').should('be.visible');
|
|
445
439
|
|
|
446
|
-
cy.get('text[transform="rotate(-35, -2,
|
|
440
|
+
cy.get('text[transform="rotate(-35, -2, 145.04834208635688)"]').should(
|
|
447
441
|
'be.visible'
|
|
448
442
|
);
|
|
449
443
|
|
|
@@ -479,15 +473,14 @@ describe('Line chart', () => {
|
|
|
479
473
|
});
|
|
480
474
|
|
|
481
475
|
it('displays the curve in a step style when the prop is set', () => {
|
|
482
|
-
initialize({ lineStyle: { curve: 'step' } });
|
|
476
|
+
initialize({ lineStyle: { curve: 'step' }, data: dataPingServiceLines });
|
|
483
477
|
|
|
484
478
|
checkGraphWidth();
|
|
485
479
|
|
|
486
480
|
cy.contains(':00 AM').should('be.visible');
|
|
487
|
-
cy.get('[data-metric="
|
|
488
|
-
cy.get('[data-metric="
|
|
489
|
-
cy.get('[data-metric="
|
|
490
|
-
checkLegendInformation();
|
|
481
|
+
cy.get('[data-metric="1"]').should('be.visible');
|
|
482
|
+
cy.get('[data-metric="2"]').should('be.visible');
|
|
483
|
+
cy.get('[data-metric="3"]').should('be.visible');
|
|
491
484
|
|
|
492
485
|
cy.makeSnapshot();
|
|
493
486
|
});
|
|
@@ -525,7 +518,8 @@ describe('Line chart', () => {
|
|
|
525
518
|
|
|
526
519
|
checkGraphWidth();
|
|
527
520
|
cy.contains(':00 AM').should('be.visible');
|
|
528
|
-
cy.get('circle[cx="
|
|
521
|
+
cy.get('circle[cx="250.83333333333334"]').should('be.visible');
|
|
522
|
+
cy.get('circle[cy="52.93597418085514"]').should('be.visible');
|
|
529
523
|
|
|
530
524
|
cy.makeSnapshot();
|
|
531
525
|
});
|
|
@@ -552,7 +546,7 @@ describe('Line chart', () => {
|
|
|
552
546
|
.and('equals', '4 10');
|
|
553
547
|
});
|
|
554
548
|
|
|
555
|
-
it('displays lines with
|
|
549
|
+
it('displays lines with dashes width when props are set', () => {
|
|
556
550
|
initialize({ lineStyle: { dashLength: 5, dashOffset: 8 } });
|
|
557
551
|
|
|
558
552
|
checkGraphWidth();
|
|
@@ -562,6 +556,31 @@ describe('Line chart', () => {
|
|
|
562
556
|
.should('have.attr', 'stroke-dasharray')
|
|
563
557
|
.and('equals', '5 8');
|
|
564
558
|
});
|
|
559
|
+
|
|
560
|
+
it('displays only one line with custom style when props are set', () => {
|
|
561
|
+
initialize({
|
|
562
|
+
lineStyle: [
|
|
563
|
+
{
|
|
564
|
+
dashLength: 5,
|
|
565
|
+
dashOffset: 4,
|
|
566
|
+
lineWidth: 1,
|
|
567
|
+
showPoints: true,
|
|
568
|
+
showArea: true,
|
|
569
|
+
metricId: 13534
|
|
570
|
+
}
|
|
571
|
+
]
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
checkGraphWidth();
|
|
575
|
+
|
|
576
|
+
cy.contains(':00 AM').should('be.visible');
|
|
577
|
+
cy.get('path.visx-area-closed')
|
|
578
|
+
.should('have.attr', 'stroke-dasharray')
|
|
579
|
+
.and('equals', '5 4');
|
|
580
|
+
cy.get('circle[cx="33.44444444444444"]').should('be.visible');
|
|
581
|
+
|
|
582
|
+
cy.makeSnapshot();
|
|
583
|
+
});
|
|
565
584
|
});
|
|
566
585
|
});
|
|
567
586
|
|
|
@@ -690,4 +709,58 @@ describe('Lines and bars', () => {
|
|
|
690
709
|
|
|
691
710
|
cy.makeSnapshot();
|
|
692
711
|
});
|
|
712
|
+
|
|
713
|
+
it('displays stacked lines and bars when a line and a bar are customized', () => {
|
|
714
|
+
initialize({
|
|
715
|
+
data: dataPingServiceLinesBarsStacked,
|
|
716
|
+
lineStyle: [
|
|
717
|
+
{
|
|
718
|
+
metricId: 1,
|
|
719
|
+
showArea: false,
|
|
720
|
+
dotOffset: 4,
|
|
721
|
+
lineWidth: 3
|
|
722
|
+
}
|
|
723
|
+
],
|
|
724
|
+
barStyle: [
|
|
725
|
+
{
|
|
726
|
+
metricId: 10,
|
|
727
|
+
opacity: 0.5,
|
|
728
|
+
radius: 0.3
|
|
729
|
+
}
|
|
730
|
+
]
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
checkGraphWidth();
|
|
734
|
+
|
|
735
|
+
cy.get(
|
|
736
|
+
'path[d="M7.501377410468319,273.3424587717121 h56.51239669421488 h1v1 v100.86066622828793 a1,1 0 0 1 -1,1 h-56.51239669421488 a1,1 0 0 1 -1,-1 v-100.86066622828793 v-1h1z"]'
|
|
737
|
+
).should('be.visible');
|
|
738
|
+
cy.get(
|
|
739
|
+
'path[d="M24.05509641873278,218.3663782225586 h23.404958677685954 a17.553719008264462,17.553719008264462 0 0 1 17.553719008264462,17.553719008264462 v19.86864253262454 v17.553719008264462h-17.553719008264462 h-23.404958677685954 h-17.553719008264462v-17.553719008264462 v-19.86864253262454 a17.553719008264462,17.553719008264462 0 0 1 17.553719008264462,-17.553719008264462z"]'
|
|
740
|
+
).should('be.visible');
|
|
741
|
+
|
|
742
|
+
cy.makeSnapshot();
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
it('displays additional lines when props are set', () => {
|
|
746
|
+
initialize({
|
|
747
|
+
data: dataPingServiceLines,
|
|
748
|
+
additionalLines: [
|
|
749
|
+
{ color: 'pink', unit: '%', yValue: 3 },
|
|
750
|
+
{ color: 'red', unit: 'ms', yValue: 0.15, text: 'some text' }
|
|
751
|
+
]
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
checkGraphWidth();
|
|
755
|
+
|
|
756
|
+
cy.get('path[data-metric="1"]').should('be.visible');
|
|
757
|
+
cy.get('path[data-metric="3"]').should('be.visible');
|
|
758
|
+
cy.get('path[data-metric="3"]').should('be.visible');
|
|
759
|
+
|
|
760
|
+
cy.contains('some text').should('be.visible');
|
|
761
|
+
cy.findByTestId('pink-3').should('be.visible');
|
|
762
|
+
cy.findByTestId('red-0.15').should('be.visible');
|
|
763
|
+
|
|
764
|
+
cy.makeSnapshot();
|
|
765
|
+
});
|
|
693
766
|
});
|
|
@@ -22,6 +22,7 @@ import dataLastDayThreshold from '../mockedData/lastDayThreshold.json';
|
|
|
22
22
|
import dataLastDayWithLotOfUnits from '../mockedData/lastDayWithLotOfUnits.json';
|
|
23
23
|
import dataLastMonth from '../mockedData/lastMonth.json';
|
|
24
24
|
import dataLastWeek from '../mockedData/lastWeek.json';
|
|
25
|
+
import dataPingService from '../mockedData/pingService.json';
|
|
25
26
|
import dataPingServiceLinesBars from '../mockedData/pingServiceLinesBars.json';
|
|
26
27
|
import dataPingServiceLinesBarsMixed from '../mockedData/pingServiceLinesBarsMixed.json';
|
|
27
28
|
import dataPingServiceLinesBarsStacked from '../mockedData/pingServiceLinesBarsStacked.json';
|
|
@@ -536,7 +537,7 @@ export const customLinesAndBars: Story = {
|
|
|
536
537
|
render: (args) => (
|
|
537
538
|
<WrapperChart
|
|
538
539
|
{...args}
|
|
539
|
-
data={
|
|
540
|
+
data={dataPingService as unknown as LineChartData}
|
|
540
541
|
/>
|
|
541
542
|
)
|
|
542
543
|
};
|
|
@@ -565,7 +566,7 @@ export const linesAndBars: Story = {
|
|
|
565
566
|
render: (args) => (
|
|
566
567
|
<WrapperChart
|
|
567
568
|
{...args}
|
|
568
|
-
data={
|
|
569
|
+
data={dataPingServiceLinesBarsMixed as unknown as LineChartData}
|
|
569
570
|
/>
|
|
570
571
|
)
|
|
571
572
|
};
|
|
@@ -695,3 +696,24 @@ export const customYUnits: Story = {
|
|
|
695
696
|
args: argumentsData,
|
|
696
697
|
render: (args) => <CustomYUnits {...args} />
|
|
697
698
|
};
|
|
699
|
+
|
|
700
|
+
export const WithAdditionalLines: Story = {
|
|
701
|
+
argTypes,
|
|
702
|
+
args: {
|
|
703
|
+
...argumentsData,
|
|
704
|
+
additionalLines: [
|
|
705
|
+
{
|
|
706
|
+
yValue: 3,
|
|
707
|
+
text: 'my text',
|
|
708
|
+
color: 'grey',
|
|
709
|
+
unit: '%'
|
|
710
|
+
}
|
|
711
|
+
]
|
|
712
|
+
},
|
|
713
|
+
render: (args) => (
|
|
714
|
+
<WrapperChart
|
|
715
|
+
{...args}
|
|
716
|
+
data={dataPingService as unknown as LineChartData}
|
|
717
|
+
/>
|
|
718
|
+
)
|
|
719
|
+
};
|
|
@@ -13,6 +13,7 @@ import { ClickAwayListener, Skeleton } from '@mui/material';
|
|
|
13
13
|
|
|
14
14
|
import { useDeepCompare } from '../../utils';
|
|
15
15
|
import BarGroup from '../BarChart/BarGroup';
|
|
16
|
+
import AdditionalLine from '../common/BaseChart/AdditionalLine';
|
|
16
17
|
import BaseChart from '../common/BaseChart/BaseChart';
|
|
17
18
|
import ChartSvgWrapper from '../common/BaseChart/ChartSvgWrapper';
|
|
18
19
|
import { useComputeBaseChartDimensions } from '../common/BaseChart/useComputeBaseChartDimensions';
|
|
@@ -110,7 +111,8 @@ const Chart = ({
|
|
|
110
111
|
thresholdUnit,
|
|
111
112
|
limitLegend,
|
|
112
113
|
skipIntersectionObserver,
|
|
113
|
-
transformMatrix
|
|
114
|
+
transformMatrix,
|
|
115
|
+
additionalLines
|
|
114
116
|
}: Props): JSX.Element => {
|
|
115
117
|
const { classes } = useChartStyles();
|
|
116
118
|
|
|
@@ -150,15 +152,16 @@ const Chart = ({
|
|
|
150
152
|
secondUnit
|
|
151
153
|
});
|
|
152
154
|
|
|
153
|
-
const { legendRef, graphWidth, graphHeight } =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
155
|
+
const { legendRef, graphWidth, graphHeight, titleRef } =
|
|
156
|
+
useComputeBaseChartDimensions({
|
|
157
|
+
hasSecondUnit: Boolean(secondUnit),
|
|
158
|
+
height,
|
|
159
|
+
legendDisplay: legend?.display,
|
|
160
|
+
legendHeight: legend?.height,
|
|
161
|
+
legendPlacement: legend?.placement,
|
|
162
|
+
width,
|
|
163
|
+
maxAxisCharacters: maxRightAxisCharacters || maxLeftAxisCharacters
|
|
164
|
+
});
|
|
162
165
|
|
|
163
166
|
const xScale = useMemo(
|
|
164
167
|
() =>
|
|
@@ -273,6 +276,7 @@ const Chart = ({
|
|
|
273
276
|
lines={linesGraph}
|
|
274
277
|
setLines={setLinesGraph}
|
|
275
278
|
title={title}
|
|
279
|
+
titleRef={titleRef}
|
|
276
280
|
>
|
|
277
281
|
<GraphValueTooltip
|
|
278
282
|
baseAxis={baseAxis}
|
|
@@ -312,20 +316,13 @@ const Chart = ({
|
|
|
312
316
|
)}
|
|
313
317
|
{!isEmpty(linesDisplayedAsLine) && (
|
|
314
318
|
<Lines
|
|
315
|
-
|
|
316
|
-
curve={lineStyle?.curve || 'linear'}
|
|
317
|
-
dashLength={lineStyle?.dashLength}
|
|
318
|
-
dashOffset={lineStyle?.dashOffset}
|
|
319
|
+
lineStyle={lineStyle}
|
|
319
320
|
displayAnchor={displayAnchor}
|
|
320
321
|
displayedLines={linesDisplayedAsLine}
|
|
321
|
-
dotOffset={lineStyle?.dotOffset}
|
|
322
322
|
graphSvgRef={graphSvgRef}
|
|
323
323
|
height={graphHeight - margin.top}
|
|
324
|
-
lineWidth={lineStyle?.lineWidth}
|
|
325
324
|
scale={axis?.scale}
|
|
326
325
|
scaleLogarithmicBase={axis?.scaleLogarithmicBase}
|
|
327
|
-
showArea={lineStyle?.showArea}
|
|
328
|
-
showPoints={lineStyle?.showPoints}
|
|
329
326
|
timeSeries={timeSeries}
|
|
330
327
|
width={graphWidth}
|
|
331
328
|
xScale={xScale}
|
|
@@ -333,6 +330,14 @@ const Chart = ({
|
|
|
333
330
|
{...shapeLines}
|
|
334
331
|
/>
|
|
335
332
|
)}
|
|
333
|
+
{additionalLines?.map((additionalLine) => (
|
|
334
|
+
<AdditionalLine
|
|
335
|
+
key={additionalLine.yValue}
|
|
336
|
+
{...additionalLine}
|
|
337
|
+
graphWidth={graphWidth}
|
|
338
|
+
yScale={yScalesPerUnit[additionalLine.unit]}
|
|
339
|
+
/>
|
|
340
|
+
))}
|
|
336
341
|
<InteractionWithGraph
|
|
337
342
|
annotationData={{ ...annotationEvent }}
|
|
338
343
|
commonData={{
|
|
@@ -70,6 +70,7 @@ const WrapperChart = ({
|
|
|
70
70
|
limitLegend,
|
|
71
71
|
getRef,
|
|
72
72
|
transformMatrix,
|
|
73
|
+
additionalLines,
|
|
73
74
|
...rest
|
|
74
75
|
}: Props): JSX.Element | null => {
|
|
75
76
|
const { classes, cx } = useChartStyles();
|
|
@@ -126,6 +127,7 @@ const WrapperChart = ({
|
|
|
126
127
|
width={width ?? responsiveWidth}
|
|
127
128
|
zoomPreview={zoomPreview}
|
|
128
129
|
skipIntersectionObserver={rest.skipIntersectionObserver}
|
|
130
|
+
additionalLines={additionalLines}
|
|
129
131
|
transformMatrix={transformMatrix}
|
|
130
132
|
/>
|
|
131
133
|
);
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
Axis as AxisYLeft,
|
|
9
9
|
AxisYRight
|
|
10
10
|
} from '../common/Axes/models';
|
|
11
|
-
import type { LineChartData } from '../common/models';
|
|
11
|
+
import type { AdditionalLineProps, LineChartData } from '../common/models';
|
|
12
12
|
import type { Line, TimeValue } from '../common/timeSeries/models';
|
|
13
13
|
|
|
14
14
|
import type { FactorsVariation } from './BasicComponents/Lines/Threshold/models';
|
|
@@ -110,17 +110,18 @@ export interface LineStyle {
|
|
|
110
110
|
export interface LineChartProps {
|
|
111
111
|
annotationEvent?: AnnotationEvent;
|
|
112
112
|
axis?: ChartAxis;
|
|
113
|
-
barStyle?: BarStyle
|
|
113
|
+
barStyle?: BarStyle | Array<BarStyle & { metricId: number }>;
|
|
114
114
|
displayAnchor?: DisplayAnchor;
|
|
115
115
|
header?: LineChartHeader;
|
|
116
116
|
height?: number | null;
|
|
117
117
|
legend?: LegendModel;
|
|
118
|
-
lineStyle?: LineStyle
|
|
118
|
+
lineStyle?: LineStyle | Array<LineStyle & { metricId: number }>;
|
|
119
119
|
timeShiftZones?: InteractedZone;
|
|
120
120
|
tooltip?: Tooltip;
|
|
121
121
|
width: number;
|
|
122
122
|
zoomPreview?: InteractedZone;
|
|
123
123
|
skipIntersectionObserver?: boolean;
|
|
124
|
+
additionalLines?: Array<AdditionalLineProps>;
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
export interface Area {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { AdditionalLineProps } from '../models';
|
|
3
|
+
|
|
4
|
+
interface Props extends AdditionalLineProps {
|
|
5
|
+
graphWidth: number;
|
|
6
|
+
yScale;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const AdditionalLine = ({
|
|
10
|
+
yValue,
|
|
11
|
+
color,
|
|
12
|
+
text,
|
|
13
|
+
graphWidth,
|
|
14
|
+
yScale
|
|
15
|
+
}: Props): JSX.Element => {
|
|
16
|
+
const positionY = useMemo(() => yScale(yValue), [yValue, yScale]);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<g>
|
|
20
|
+
{text && (
|
|
21
|
+
<text x={8} y={positionY - 8} fill={color} style={{ fontSize: '10px' }}>
|
|
22
|
+
{text}
|
|
23
|
+
</text>
|
|
24
|
+
)}
|
|
25
|
+
<line
|
|
26
|
+
x1={0}
|
|
27
|
+
x2={graphWidth}
|
|
28
|
+
y1={positionY}
|
|
29
|
+
y2={positionY}
|
|
30
|
+
stroke={color}
|
|
31
|
+
data-testid={`${color}-${yValue}`}
|
|
32
|
+
/>
|
|
33
|
+
</g>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default AdditionalLine;
|
|
@@ -23,6 +23,7 @@ interface Props {
|
|
|
23
23
|
displayLegend: boolean;
|
|
24
24
|
legendHeight?: number;
|
|
25
25
|
};
|
|
26
|
+
titleRef: MutableRefObject<HTMLDivElement | null>;
|
|
26
27
|
legendRef: MutableRefObject<HTMLDivElement | null>;
|
|
27
28
|
limitLegend?: number | false;
|
|
28
29
|
lines: Array<Line>;
|
|
@@ -42,6 +43,7 @@ const BaseChart = ({
|
|
|
42
43
|
setLines,
|
|
43
44
|
children,
|
|
44
45
|
legendRef,
|
|
46
|
+
titleRef,
|
|
45
47
|
title,
|
|
46
48
|
header,
|
|
47
49
|
isHorizontal = true
|
|
@@ -68,7 +70,9 @@ const BaseChart = ({
|
|
|
68
70
|
|
|
69
71
|
return (
|
|
70
72
|
<>
|
|
71
|
-
<
|
|
73
|
+
<div ref={titleRef}>
|
|
74
|
+
<Header header={header} title={title} ref={titleRef} />
|
|
75
|
+
</div>
|
|
72
76
|
<div className={classes.container}>
|
|
73
77
|
<Stack
|
|
74
78
|
direction={equals(legend?.placement, 'left') ? 'row' : 'row-reverse'}
|
|
@@ -19,13 +19,11 @@ const Header = ({ title, header }: Props): JSX.Element => {
|
|
|
19
19
|
Component: (
|
|
20
20
|
<div className={classes.header}>
|
|
21
21
|
<div />
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)}
|
|
28
|
-
</div>
|
|
22
|
+
{displayTitle && (
|
|
23
|
+
<Typography align="center" variant="body1" className={classes.title}>
|
|
24
|
+
{title}
|
|
25
|
+
</Typography>
|
|
26
|
+
)}
|
|
29
27
|
{header?.extraComponent}
|
|
30
28
|
</div>
|
|
31
29
|
),
|
|
@@ -3,7 +3,11 @@ import { makeStyles } from 'tss-react/mui';
|
|
|
3
3
|
export const ussHeaderChartStyles = makeStyles()({
|
|
4
4
|
header: {
|
|
5
5
|
display: 'grid',
|
|
6
|
-
gridTemplateColumns: '
|
|
6
|
+
gridTemplateColumns: 'auto 1fr auto',
|
|
7
7
|
width: '100%'
|
|
8
|
+
},
|
|
9
|
+
title: {
|
|
10
|
+
whiteSpace: 'pre-wrap',
|
|
11
|
+
lineHeight: '1.2'
|
|
8
12
|
}
|
|
9
13
|
});
|
|
@@ -21,6 +21,7 @@ interface UseComputeBaseChartDimensionsState {
|
|
|
21
21
|
graphHeight: number;
|
|
22
22
|
graphWidth: number;
|
|
23
23
|
legendRef: MutableRefObject<HTMLDivElement | null>;
|
|
24
|
+
titleRef: MutableRefObject<HTMLDivElement | null>;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export const useComputeBaseChartDimensions = ({
|
|
@@ -33,6 +34,7 @@ export const useComputeBaseChartDimensions = ({
|
|
|
33
34
|
maxAxisCharacters
|
|
34
35
|
}: UseComputeBaseChartDimensionsProps): UseComputeBaseChartDimensionsState => {
|
|
35
36
|
const legendRef = useRef<HTMLDivElement | null>(null);
|
|
37
|
+
const titleRef = useRef<HTMLDivElement | null>(null);
|
|
36
38
|
|
|
37
39
|
const currentLegendHeight =
|
|
38
40
|
legendHeight ?? (legendRef.current?.getBoundingClientRect().height || 0);
|
|
@@ -57,12 +59,17 @@ export const useComputeBaseChartDimensions = ({
|
|
|
57
59
|
: 0;
|
|
58
60
|
const graphHeight =
|
|
59
61
|
(height || 0) > 0
|
|
60
|
-
? (height || 0) -
|
|
62
|
+
? (height || 0) -
|
|
63
|
+
margin.top -
|
|
64
|
+
legendBoundingHeight -
|
|
65
|
+
(titleRef.current?.getBoundingClientRect().height || 0) -
|
|
66
|
+
5
|
|
61
67
|
: 0;
|
|
62
68
|
|
|
63
69
|
return {
|
|
64
70
|
graphHeight,
|
|
65
71
|
graphWidth,
|
|
66
|
-
legendRef
|
|
72
|
+
legendRef,
|
|
73
|
+
titleRef
|
|
67
74
|
};
|
|
68
75
|
};
|
|
@@ -581,7 +581,7 @@ const formatMetricValue = ({
|
|
|
581
581
|
|
|
582
582
|
const formattedMetricValue = numeral(Math.abs(value))
|
|
583
583
|
.format(`0.[00]${formatSuffix}`)
|
|
584
|
-
.replace(/iB/g, unit);
|
|
584
|
+
.replace(/(iB|B)/g, unit);
|
|
585
585
|
|
|
586
586
|
if (lt(value, 0)) {
|
|
587
587
|
return `-${formattedMetricValue}`;
|
|
@@ -12,11 +12,14 @@ import {
|
|
|
12
12
|
length,
|
|
13
13
|
lt,
|
|
14
14
|
lte,
|
|
15
|
-
pluck
|
|
15
|
+
pluck,
|
|
16
|
+
type
|
|
16
17
|
} from 'ramda';
|
|
17
18
|
|
|
18
19
|
import { Theme, darken, getLuminance, lighten } from '@mui/material';
|
|
19
20
|
|
|
21
|
+
import { BarStyle } from '../BarChart/models';
|
|
22
|
+
import { LineStyle } from '../Chart/models';
|
|
20
23
|
import { Threshold, Thresholds } from './models';
|
|
21
24
|
import { formatMetricValue } from './timeSeries';
|
|
22
25
|
import { Line, TimeValue } from './timeSeries/models';
|
|
@@ -182,6 +185,24 @@ export const commonTickLabelProps = {
|
|
|
182
185
|
textAnchor: 'middle'
|
|
183
186
|
};
|
|
184
187
|
|
|
188
|
+
interface GetStyleProps {
|
|
189
|
+
metricId?: number;
|
|
190
|
+
style:
|
|
191
|
+
| LineStyle
|
|
192
|
+
| BarStyle
|
|
193
|
+
| Array<LineStyle & { metricId: number }>
|
|
194
|
+
| Array<BarStyle & { metricId: number }>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export const getStyle = ({
|
|
198
|
+
style,
|
|
199
|
+
metricId
|
|
200
|
+
}: GetStyleProps): BarStyle | LineStyle => {
|
|
201
|
+
return equals(type(style), 'Array')
|
|
202
|
+
? style.find((metricStyle) => equals(metricId, metricStyle.metricId))
|
|
203
|
+
: style;
|
|
204
|
+
};
|
|
205
|
+
|
|
185
206
|
interface GetFormattedAxisValuesProps {
|
|
186
207
|
thresholdUnit?: string;
|
|
187
208
|
axisUnit: string;
|
|
@@ -329,20 +329,7 @@
|
|
|
329
329
|
0.32339333333,
|
|
330
330
|
null
|
|
331
331
|
],
|
|
332
|
-
"prints": [
|
|
333
|
-
[
|
|
334
|
-
"Last:0.32"
|
|
335
|
-
],
|
|
336
|
-
[
|
|
337
|
-
"Min:0.03"
|
|
338
|
-
],
|
|
339
|
-
[
|
|
340
|
-
"Max:0.97"
|
|
341
|
-
],
|
|
342
|
-
[
|
|
343
|
-
"Average:0.51"
|
|
344
|
-
]
|
|
345
|
-
],
|
|
332
|
+
"prints": [["Last:0.32"], ["Min:0.03"], ["Max:0.97"], ["Average:0.51"]],
|
|
346
333
|
"last_value": 0.32,
|
|
347
334
|
"minimum_value": 0.03,
|
|
348
335
|
"maximum_value": 0.97,
|
|
@@ -667,18 +654,10 @@
|
|
|
667
654
|
null
|
|
668
655
|
],
|
|
669
656
|
"prints": [
|
|
670
|
-
[
|
|
671
|
-
|
|
672
|
-
],
|
|
673
|
-
[
|
|
674
|
-
"Min:70.31"
|
|
675
|
-
],
|
|
676
|
-
[
|
|
677
|
-
"Max:88.03"
|
|
678
|
-
],
|
|
679
|
-
[
|
|
680
|
-
"Average:78.07"
|
|
681
|
-
]
|
|
657
|
+
["Last:87.27"],
|
|
658
|
+
["Min:70.31"],
|
|
659
|
+
["Max:88.03"],
|
|
660
|
+
["Average:78.07"]
|
|
682
661
|
],
|
|
683
662
|
"last_value": 87.27,
|
|
684
663
|
"minimum_value": 70.31,
|
|
@@ -1003,20 +982,7 @@
|
|
|
1003
982
|
null,
|
|
1004
983
|
null
|
|
1005
984
|
],
|
|
1006
|
-
"prints": [
|
|
1007
|
-
[
|
|
1008
|
-
"Last:0.65"
|
|
1009
|
-
],
|
|
1010
|
-
[
|
|
1011
|
-
"Min:0.03"
|
|
1012
|
-
],
|
|
1013
|
-
[
|
|
1014
|
-
"Max:0.98"
|
|
1015
|
-
],
|
|
1016
|
-
[
|
|
1017
|
-
"Average:0.50"
|
|
1018
|
-
]
|
|
1019
|
-
],
|
|
985
|
+
"prints": [["Last:0.65"], ["Min:0.03"], ["Max:0.98"], ["Average:0.50"]],
|
|
1020
986
|
"last_value": 0.65,
|
|
1021
987
|
"minimum_value": 0.03,
|
|
1022
988
|
"maximum_value": 0.98,
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"ds_filled": true,
|
|
63
63
|
"ds_invert": false,
|
|
64
64
|
"ds_legend": null,
|
|
65
|
-
"ds_stack":
|
|
65
|
+
"ds_stack": true,
|
|
66
66
|
"ds_order": 1,
|
|
67
67
|
"ds_transparency": 80.0,
|
|
68
68
|
"ds_color_line_mode": 0
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"ds_filled": true,
|
|
100
100
|
"ds_invert": false,
|
|
101
101
|
"ds_legend": null,
|
|
102
|
-
"ds_stack":
|
|
102
|
+
"ds_stack": true,
|
|
103
103
|
"ds_order": 1,
|
|
104
104
|
"ds_transparency": 80.0,
|
|
105
105
|
"ds_color_line_mode": 0
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"ds_filled": false,
|
|
145
145
|
"ds_invert": false,
|
|
146
146
|
"ds_legend": null,
|
|
147
|
-
"ds_stack":
|
|
147
|
+
"ds_stack": true,
|
|
148
148
|
"ds_order": 2,
|
|
149
149
|
"ds_transparency": 80.0,
|
|
150
150
|
"ds_color_line_mode": 0
|
|
@@ -130,7 +130,9 @@ const useGraphQuery = ({
|
|
|
130
130
|
parameters: {
|
|
131
131
|
search: {
|
|
132
132
|
lists: resources.map((resource) => ({
|
|
133
|
-
field:
|
|
133
|
+
field: equals(resource.resourceType, 'hostgroup')
|
|
134
|
+
? resourceTypeQueryParameter[WidgetResourceType.hostGroup]
|
|
135
|
+
: resourceTypeQueryParameter[resource.resourceType],
|
|
134
136
|
values: equals(resource.resourceType, 'service')
|
|
135
137
|
? pluck('name', resource.resources)
|
|
136
138
|
: pluck('id', resource.resources)
|