@@ -10,100 +10,51 @@ import {
10
10
AreaSeries ,
11
11
Axis ,
12
12
Chart ,
13
- ElementClickListener ,
14
13
niceTimeFormatByDay ,
15
- Partition ,
16
- PartitionElementEvent ,
17
- PartitionLayout ,
18
14
Settings ,
19
15
timeFormatter ,
20
16
} from '@elastic/charts' ;
21
- import { EuiFlexGroup , EuiText , EuiHorizontalRule , EuiFlexItem } from '@elastic/eui' ;
17
+ import {
18
+ useEuiTheme ,
19
+ EuiFlexGroup ,
20
+ EuiFlexItem ,
21
+ EuiLink ,
22
+ EuiText ,
23
+ EuiTitle ,
24
+ type EuiLinkButtonProps ,
25
+ type EuiTextProps ,
26
+ EuiToolTip ,
27
+ EuiToolTipProps ,
28
+ } from '@elastic/eui' ;
22
29
import { FormattedDate , FormattedTime } from '@kbn/i18n-react' ;
23
30
import moment from 'moment' ;
24
- import { statusColors } from '../../../common/constants' ;
25
- import type { PostureTrend , Stats } from '../../../../common/types' ;
26
- import { CompactFormattedNumber } from '../../../components/compact_formatted_number' ;
31
+ import { i18n } from '@kbn/i18n' ;
27
32
import { RULE_FAILED , RULE_PASSED } from '../../../../common/constants' ;
33
+ import { CompactFormattedNumber } from '../../../components/compact_formatted_number' ;
34
+ import type { Evaluation , PostureTrend , Stats } from '../../../../common/types' ;
28
35
import { useKibana } from '../../../common/hooks/use_kibana' ;
29
36
30
37
interface CloudPostureScoreChartProps {
38
+ compact ?: boolean ;
31
39
trend : PostureTrend [ ] ;
32
40
data : Stats ;
33
41
id : string ;
34
- partitionOnElementClick : ( elements : PartitionElementEvent [ ] ) => void ;
42
+ onEvalCounterClick : ( evaluation : Evaluation ) => void ;
35
43
}
36
44
37
45
const getPostureScorePercentage = ( postureScore : number ) : string => `${ Math . round ( postureScore ) } %` ;
38
46
39
- const ScoreChart = ( {
40
- data : { totalPassed, totalFailed } ,
41
- id,
42
- partitionOnElementClick,
43
- } : Omit < CloudPostureScoreChartProps , 'trend' > ) => {
44
- const data = [
45
- { label : RULE_PASSED , value : totalPassed } ,
46
- { label : RULE_FAILED , value : totalFailed } ,
47
- ] ;
48
- const {
49
- services : { charts } ,
50
- } = useKibana ( ) ;
51
-
52
- return (
53
- < Chart size = { { height : 90 , width : 90 } } >
54
- < Settings
55
- theme = { [
56
- // theme overrides
57
- {
58
- partition : {
59
- linkLabel : { maximumSection : Infinity , maxCount : 0 } ,
60
- outerSizeRatio : 0.75 ,
61
- emptySizeRatio : 0.7 ,
62
- } ,
63
- } ,
64
- // theme
65
- charts . theme . useChartsTheme ( ) ,
66
- ] }
67
- baseTheme = { charts . theme . useChartsBaseTheme ( ) }
68
- onElementClick = { partitionOnElementClick as ElementClickListener }
69
- />
70
- < Partition
71
- id = { id }
72
- data = { data }
73
- valueGetter = "percent"
74
- valueAccessor = { ( d ) => d . value }
75
- layout = { PartitionLayout . sunburst }
76
- layers = { [
77
- {
78
- groupByRollup : ( d : { label : string } ) => d . label ,
79
- shape : {
80
- fillColor : ( d , index ) =>
81
- d . dataName === RULE_PASSED ? statusColors . success : statusColors . danger ,
82
- } ,
83
- } ,
84
- ] }
85
- />
86
- </ Chart >
87
- ) ;
88
- } ;
89
-
90
47
const PercentageInfo = ( {
48
+ compact,
91
49
postureScore,
92
- totalPassed,
93
- totalFindings,
94
- } : CloudPostureScoreChartProps [ 'data' ] ) => {
50
+ } : CloudPostureScoreChartProps [ 'data' ] & { compact ?: CloudPostureScoreChartProps [ 'compact' ] } ) => {
51
+ const { euiTheme } = useEuiTheme ( ) ;
95
52
const percentage = getPostureScorePercentage ( postureScore ) ;
96
53
97
54
return (
98
- < EuiFlexGroup direction = "column" justifyContent = "center" >
99
- < EuiText style = { { fontSize : 40 , fontWeight : 'bold' , lineHeight : 1 } } > { percentage } </ EuiText >
100
- < EuiText size = "xs" >
101
- < CompactFormattedNumber number = { totalPassed } />
102
- { '/' }
103
- < CompactFormattedNumber number = { totalFindings } />
104
- { ' Findings passed' }
105
- </ EuiText >
106
- </ EuiFlexGroup >
55
+ < EuiTitle css = { { fontSize : compact ? euiTheme . size . l : euiTheme . size . xxl } } >
56
+ < h3 > { percentage } </ h3 >
57
+ </ EuiTitle >
107
58
) ;
108
59
} ;
109
60
@@ -149,38 +100,94 @@ const ComplianceTrendChart = ({ trend }: { trend: PostureTrend[] }) => {
149
100
tickFormat = { timeFormatter ( niceTimeFormatByDay ( 2 ) ) }
150
101
ticks = { 4 }
151
102
/>
152
- < Axis
153
- ticks = { 3 }
154
- id = "left-axis"
155
- position = "left"
156
- showGridLines
157
- domain = { { min : 0 , max : 100 } }
158
- tickFormat = { ( rawScore ) => getPostureScorePercentage ( rawScore ) }
159
- />
103
+ < Axis ticks = { 3 } id = "left-axis" position = "left" showGridLines domain = { { min : 0 , max : 100 } } />
160
104
</ Chart >
161
105
) ;
162
106
} ;
163
107
108
+ const CounterLink = ( {
109
+ text,
110
+ count,
111
+ color,
112
+ onClick,
113
+ tooltipContent,
114
+ } : {
115
+ count : number ;
116
+ text : string ;
117
+ color : EuiTextProps [ 'color' ] ;
118
+ onClick : EuiLinkButtonProps [ 'onClick' ] ;
119
+ tooltipContent : EuiToolTipProps [ 'content' ] ;
120
+ } ) => {
121
+ const { euiTheme } = useEuiTheme ( ) ;
122
+
123
+ return (
124
+ < EuiToolTip content = { tooltipContent } >
125
+ < EuiLink color = "text" onClick = { onClick } css = { { display : 'flex' } } >
126
+ < EuiText color = { color } style = { { fontWeight : euiTheme . font . weight . medium } } size = "s" >
127
+ < CompactFormattedNumber number = { count } abbreviateAbove = { 999 } />
128
+
129
+ </ EuiText >
130
+ < EuiText size = "s" > { text } </ EuiText >
131
+ </ EuiLink >
132
+ </ EuiToolTip >
133
+ ) ;
134
+ } ;
135
+
164
136
export const CloudPostureScoreChart = ( {
165
137
data,
166
138
trend,
167
- id,
168
- partitionOnElementClick,
169
- } : CloudPostureScoreChartProps ) => (
170
- < EuiFlexGroup direction = "column" gutterSize = "none" >
171
- < EuiFlexItem grow = { 4 } >
172
- < EuiFlexGroup direction = "row" >
173
- < EuiFlexItem grow = { false } style = { { justifyContent : 'center' } } >
174
- < ScoreChart { ...{ id, data, partitionOnElementClick } } />
175
- </ EuiFlexItem >
176
- < EuiFlexItem >
177
- < PercentageInfo { ...data } />
178
- </ EuiFlexItem >
179
- </ EuiFlexGroup >
180
- </ EuiFlexItem >
181
- < EuiHorizontalRule margin = "xs" />
182
- < EuiFlexItem grow = { 6 } >
183
- < ComplianceTrendChart trend = { trend } />
184
- </ EuiFlexItem >
185
- </ EuiFlexGroup >
186
- ) ;
139
+ onEvalCounterClick,
140
+ compact,
141
+ } : CloudPostureScoreChartProps ) => {
142
+ const { euiTheme } = useEuiTheme ( ) ;
143
+
144
+ return (
145
+ < EuiFlexGroup
146
+ direction = "column"
147
+ justifyContent = "spaceBetween"
148
+ style = { { height : '100%' } }
149
+ gutterSize = "none"
150
+ >
151
+ < EuiFlexItem grow = { 2 } >
152
+ < EuiFlexGroup direction = "row" justifyContent = "spaceBetween" gutterSize = "none" >
153
+ < EuiFlexItem grow = { false } >
154
+ < PercentageInfo { ...data } compact = { compact } />
155
+ </ EuiFlexItem >
156
+ < EuiFlexItem grow = { false } >
157
+ < EuiFlexGroup
158
+ justifyContent = "flexEnd"
159
+ gutterSize = "none"
160
+ alignItems = { compact ? 'center' : 'flexStart' }
161
+ style = { { paddingRight : euiTheme . size . xl } }
162
+ >
163
+ < CounterLink
164
+ text = "passed"
165
+ count = { data . totalPassed }
166
+ color = "success"
167
+ onClick = { ( ) => onEvalCounterClick ( RULE_PASSED ) }
168
+ tooltipContent = { i18n . translate (
169
+ 'xpack.csp.cloudPostureScoreChart.counterLink.passedFindingsTooltip' ,
170
+ { defaultMessage : 'Passed findings' }
171
+ ) }
172
+ />
173
+ { `-` }
174
+ < CounterLink
175
+ text = "failed"
176
+ count = { data . totalFailed }
177
+ color = "danger"
178
+ onClick = { ( ) => onEvalCounterClick ( RULE_FAILED ) }
179
+ tooltipContent = { i18n . translate (
180
+ 'xpack.csp.cloudPostureScoreChart.counterLink.failedFindingsTooltip' ,
181
+ { defaultMessage : 'Failed findings' }
182
+ ) }
183
+ />
184
+ </ EuiFlexGroup >
185
+ </ EuiFlexItem >
186
+ </ EuiFlexGroup >
187
+ </ EuiFlexItem >
188
+ < EuiFlexItem grow = { compact ? 8 : 6 } >
189
+ < ComplianceTrendChart trend = { trend } />
190
+ </ EuiFlexItem >
191
+ </ EuiFlexGroup >
192
+ ) ;
193
+ } ;
0 commit comments