1
- import classNames from 'classnames ' ;
1
+ import { css , cx } from '@emotion/css ' ;
2
2
import { indexOf } from 'lodash' ;
3
3
import React from 'react' ;
4
4
import { Unsubscribable } from 'rxjs' ;
5
5
6
+ import { GrafanaTheme2 } from '@grafana/data' ;
6
7
import { selectors } from '@grafana/e2e-selectors' ;
7
8
import { getTemplateSrv , RefreshEvent } from '@grafana/runtime' ;
8
- import { Icon , TextLink } from '@grafana/ui' ;
9
+ import { Icon , TextLink , Themeable2 , withTheme2 } from '@grafana/ui' ;
9
10
import appEvents from 'app/core/app_events' ;
10
11
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/types' ;
11
12
@@ -14,12 +15,12 @@ import { DashboardModel } from '../../state/DashboardModel';
14
15
import { PanelModel } from '../../state/PanelModel' ;
15
16
import { RowOptionsButton } from '../RowOptions/RowOptionsButton' ;
16
17
17
- export interface DashboardRowProps {
18
+ export interface DashboardRowProps extends Themeable2 {
18
19
panel : PanelModel ;
19
20
dashboard : DashboardModel ;
20
21
}
21
22
22
- export class DashboardRow extends React . Component < DashboardRowProps > {
23
+ export class UnthemedDashboardRow extends React . Component < DashboardRowProps > {
23
24
sub ?: Unsubscribable ;
24
25
25
26
componentDidMount ( ) {
@@ -93,32 +94,39 @@ export class DashboardRow extends React.Component<DashboardRowProps> {
93
94
} ;
94
95
95
96
render ( ) {
96
- const classes = classNames ( {
97
- 'dashboard-row' : true ,
98
- 'dashboard-row--collapsed' : this . props . panel . collapsed ,
99
- } ) ;
100
-
101
97
const title = getTemplateSrv ( ) . replace ( this . props . panel . title , this . props . panel . scopedVars , 'text' ) ;
102
98
const count = this . props . panel . panels ? this . props . panel . panels . length : 0 ;
103
99
const panels = count === 1 ? 'panel' : 'panels' ;
104
100
const canEdit = this . props . dashboard . meta . canEdit === true ;
101
+ const collapsed = this . props . panel . collapsed ;
102
+ const styles = getStyles ( this . props . theme ) ;
105
103
106
104
return (
107
- < div className = { classes } data-testid = "dashboard-row-container" >
105
+ < div
106
+ className = { cx ( styles . dashboardRow , {
107
+ [ styles . dashboardRowCollapsed ] : collapsed ,
108
+ } ) }
109
+ data-testid = "dashboard-row-container"
110
+ >
108
111
< button
109
- className = "dashboard-row__title pointer"
112
+ aria-expanded = { ! collapsed }
113
+ className = { cx ( styles . title , 'pointer' ) }
110
114
type = "button"
111
115
data-testid = { selectors . components . DashboardRow . title ( title ) }
112
116
onClick = { this . onToggle }
113
117
>
114
- < Icon name = { this . props . panel . collapsed ? 'angle-right' : 'angle-down' } />
118
+ < Icon name = { collapsed ? 'angle-right' : 'angle-down' } />
115
119
{ title }
116
- < span className = "dashboard-row__panel_count" >
120
+ < span
121
+ className = { cx ( styles . count , {
122
+ [ styles . countCollapsed ] : collapsed ,
123
+ } ) }
124
+ >
117
125
({ count } { panels } )
118
126
</ span >
119
127
</ button >
120
128
{ canEdit && (
121
- < div className = "dashboard-row__actions" >
129
+ < div className = { styles . actions } >
122
130
< RowOptionsButton
123
131
title = { this . props . panel . title }
124
132
repeat = { this . props . panel . repeat }
@@ -130,16 +138,114 @@ export class DashboardRow extends React.Component<DashboardRowProps> {
130
138
</ button >
131
139
</ div >
132
140
) }
133
- { this . props . panel . collapsed === true && (
141
+ { collapsed === true && (
134
142
/* disabling the a11y rules here as the button handles keyboard interactions */
135
143
/* this is just to provide a better experience for mouse users */
136
144
/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
137
- < div className = "dashboard-row__toggle-target" onClick = { this . onToggle } >
145
+ < div
146
+ className = { cx ( {
147
+ [ styles . toggleTargetCollapsed ] : collapsed ,
148
+ } ) }
149
+ onClick = { this . onToggle }
150
+ >
138
151
139
152
</ div >
140
153
) }
141
- { canEdit && < div data-testid = "dashboard-row-drag" className = "dashboard-row__drag grid-drag-handle" /> }
154
+ { canEdit && (
155
+ < div
156
+ data-testid = "dashboard-row-drag"
157
+ className = { cx ( styles . dragHandle , 'grid-drag-handle' , {
158
+ [ styles . dragHandleCollapsed ] : collapsed ,
159
+ } ) }
160
+ />
161
+ ) }
142
162
</ div >
143
163
) ;
144
164
}
145
165
}
166
+
167
+ export const DashboardRow = withTheme2 ( UnthemedDashboardRow ) ;
168
+
169
+ const getStyles = ( theme : GrafanaTheme2 ) => {
170
+ const actions = css ( {
171
+ color : theme . colors . text . secondary ,
172
+ opacity : 0 ,
173
+ [ theme . transitions . handleMotion ( 'no-preference' , 'reduce' ) ] : {
174
+ transition : '200ms opacity ease-in 200ms' ,
175
+ } ,
176
+
177
+ button : {
178
+ color : theme . colors . text . secondary ,
179
+ paddingLeft : theme . spacing ( 2 ) ,
180
+ background : 'transparent' ,
181
+ border : 'none' ,
182
+
183
+ '&:hover' : {
184
+ color : theme . colors . text . maxContrast ,
185
+ } ,
186
+ } ,
187
+ } ) ;
188
+
189
+ return {
190
+ dashboardRow : css ( {
191
+ display : 'flex' ,
192
+ alignItems : 'center' ,
193
+ height : '100%' ,
194
+
195
+ '&:hover, &:focus-within' : {
196
+ [ `.${ actions } ` ] : {
197
+ opacity : 1 ,
198
+ } ,
199
+ } ,
200
+ } ) ,
201
+ dashboardRowCollapsed : css ( {
202
+ background : theme . components . panel . background ,
203
+ } ) ,
204
+ toggleTargetCollapsed : css ( {
205
+ flex : 1 ,
206
+ cursor : 'pointer' ,
207
+ marginRight : '15px' ,
208
+ } ) ,
209
+ title : css ( {
210
+ flexGrow : 0 ,
211
+ fontSize : theme . typography . h5 . fontSize ,
212
+ fontWeight : theme . typography . fontWeightMedium ,
213
+ color : theme . colors . text . primary ,
214
+ background : 'transparent' ,
215
+ border : 'none' ,
216
+
217
+ '.fa' : {
218
+ color : theme . colors . text . secondary ,
219
+ fontSize : theme . typography . size . xs ,
220
+ padding : theme . spacing ( 0 , 1 ) ,
221
+ } ,
222
+ } ) ,
223
+ actions,
224
+ count : css ( {
225
+ paddingLeft : theme . spacing ( 2 ) ,
226
+ color : theme . colors . text . secondary ,
227
+ fontStyle : 'italic' ,
228
+ fontSize : theme . typography . size . sm ,
229
+ fontWeight : 'normal' ,
230
+ display : 'none' ,
231
+ } ) ,
232
+ countCollapsed : css ( {
233
+ display : 'inline-block' ,
234
+ } ) ,
235
+ dragHandle : css ( {
236
+ cursor : 'move' ,
237
+ width : '16px' ,
238
+ height : '100%' ,
239
+ background : 'url("public/img/grab_dark.svg") no-repeat 50% 50%' ,
240
+ backgroundSize : '8px' ,
241
+ visibility : 'hidden' ,
242
+ position : 'absolute' ,
243
+ top : 0 ,
244
+ right : 0 ,
245
+ } ) ,
246
+ dragHandleCollapsed : css ( {
247
+ visibility : 'visible' ,
248
+ opacity : 1 ,
249
+ } ) ,
250
+ } ;
251
+ } ;
0 commit comments