1
1
import { PanelOptionsEditorBuilder , SelectableValue } from '@grafana/data' ;
2
2
import { getBackendSrv } from '@grafana/runtime' ;
3
- import { Button , Collapse , Field , Input , Select } from '@grafana/ui' ;
3
+ import {
4
+ Button ,
5
+ Collapse ,
6
+ Field ,
7
+ Input ,
8
+ RadioButtonGroup ,
9
+ Select ,
10
+ } from '@grafana/ui' ;
4
11
import React from 'react' ;
5
12
import { ButtonOptions , Options } from 'types' ;
6
13
@@ -11,83 +18,101 @@ interface EditorProps {
11
18
12
19
const Editor : React . FC < EditorProps > = ( { buttons, onChange } ) => {
13
20
const [ elems , setElems ] = React . useState < SelectableValue < string > [ ] > ( ) ;
14
- const [ isOpen , setOpen ] = React . useState < boolean > ( true ) ;
21
+ const [ isOpen , setOpen ] = React . useState < boolean [ ] > ( [ true ] ) ;
15
22
React . useEffect ( ( ) => {
16
- let isSubscribed = true ;
23
+ let cancel = false ;
17
24
const fetchData = async ( ) => {
18
25
const ds = await getBackendSrv ( ) . get ( '/api/datasources' ) ;
19
- if ( isSubscribed )
26
+ if ( ! cancel )
20
27
setElems (
21
- ds . map ( ( i : any ) => ( {
22
- label : i . name ,
23
- value : i . name ,
24
- name : i . name ,
25
- } ) )
28
+ ds . map ( ( i : any ) => ( { label : i . name , value : i . name , name : i . name } ) )
26
29
) ;
27
30
} ;
28
31
fetchData ( ) ;
29
32
return ( ) : void => {
30
- isSubscribed = false ;
33
+ cancel = true ;
31
34
} ;
32
35
} , [ ] ) ;
36
+
37
+ const updateButtons = ( index : number , newButton : ButtonOptions ) => {
38
+ let currentButton = { ...buttons [ index ] } ;
39
+ onChange ( [
40
+ ...buttons . slice ( 0 , index ) ,
41
+ {
42
+ text : newButton . text || currentButton . text ,
43
+ datasource : newButton . datasource || currentButton . datasource ,
44
+ query : newButton . query || currentButton . query ,
45
+ variant : newButton . variant || currentButton . variant ,
46
+ } ,
47
+ ...buttons . slice ( index + 1 ) ,
48
+ ] ) ;
49
+ } ;
50
+
33
51
return (
34
52
< React . Fragment >
35
- { buttons . map ( ( b : ButtonOptions , index : number ) => (
53
+ { buttons . map ( ( b : ButtonOptions , i : number ) => (
36
54
< Collapse
37
- label = { 'Button ' + ( index + 1 ) . toString ( ) }
38
- isOpen = { isOpen }
55
+ label = { 'Button ' + ( i + 1 ) . toString ( ) }
56
+ isOpen = { isOpen [ i ] }
39
57
collapsible
40
- onToggle = { ( ) => setOpen ( ! isOpen ) }
58
+ onToggle = { ( ) =>
59
+ setOpen ( [ ...isOpen . slice ( 0 , i ) , ! isOpen [ i ] , ...isOpen . slice ( i + 1 ) ] )
60
+ }
41
61
>
42
62
< Field label = "Text" description = "Text to be displayed on the button" >
43
63
< Input
44
- id = { 't-' + index . toString ( ) }
64
+ id = { 't-' + i . toString ( ) }
45
65
value = { b . text }
46
66
placeholder = "Button"
47
- onChange = { ( e : React . ChangeEvent < HTMLInputElement > ) => {
48
- let button = { ...buttons [ index ] } ;
49
- onChange ( [
50
- ...buttons . slice ( 0 , index ) ,
51
- { text : e . target . value , datasource : button . datasource , query : button . query } ,
52
- ...buttons . slice ( index + 1 ) ,
53
- ] ) ;
54
- } }
67
+ onChange = { ( e : React . ChangeEvent < HTMLInputElement > ) =>
68
+ updateButtons ( i , { text : e . target . value } )
69
+ }
55
70
/>
56
71
</ Field >
57
- < Field label = "Datasource" description = "Select Datasource for the query" >
72
+ < Field
73
+ label = "Datasource"
74
+ description = "Choose the Datasource for the query"
75
+ >
58
76
< Select
59
- onChange = { ( e : SelectableValue < string > ) => {
60
- let button = { ...buttons [ index ] } ;
61
- onChange ( [
62
- ...buttons . slice ( 0 , index ) ,
63
- { text : button . text , datasource : e . value || '' , query : button . query } ,
64
- ...buttons . slice ( index + 1 ) ,
65
- ] ) ;
66
- } }
77
+ onChange = { ( e : SelectableValue < string > ) =>
78
+ updateButtons ( i , { datasource : e . value } )
79
+ }
67
80
options = { elems }
68
81
/>
69
82
</ Field >
70
- < Field label = "Query" description = "Query to be triggered on Button Click" >
83
+ < Field
84
+ label = "Query"
85
+ description = "Query to be triggered on Button Click"
86
+ >
71
87
< Input
72
- id = { 'q-' + index . toString ( ) }
88
+ id = { 'q-' + i . toString ( ) }
73
89
value = { b . query }
74
- onChange = { ( e : React . ChangeEvent < HTMLInputElement > ) => {
75
- let button = { ...buttons [ index ] } ;
76
- onChange ( [
77
- ...buttons . slice ( 0 , index ) ,
78
- { text : button . text , datasource : button . datasource , query : e . target . value } ,
79
- ...buttons . slice ( index + 1 ) ,
80
- ] ) ;
81
- } }
90
+ placeholder = "Query"
91
+ onChange = { ( e : React . ChangeEvent < HTMLInputElement > ) =>
92
+ updateButtons ( i , { query : e . target . value } )
93
+ }
82
94
/>
83
95
</ Field >
96
+ < Field label = "Color" description = "Color of the button" >
97
+ < RadioButtonGroup
98
+ options = { [
99
+ { label : 'Primary' , value : 'primary' } ,
100
+ { label : 'Secondary' , value : 'secondary' } ,
101
+ { label : 'Destructive' , value : 'destructive' } ,
102
+ { label : 'Link' , value : 'link' } ,
103
+ ] }
104
+ value = { b . variant || 'primary' }
105
+ fullWidth
106
+ onChange = { ( e : any ) => updateButtons ( i , { variant : e } ) }
107
+ > </ RadioButtonGroup >
108
+ </ Field >
84
109
< Field >
85
110
< Button
86
111
icon = "trash-alt"
87
112
variant = "destructive"
88
- onClick = { ( ) => {
89
- console . log ( 'trash' ) ;
90
- } }
113
+ onClick = { ( ) =>
114
+ onChange ( [ ... buttons . slice ( 0 , i ) , ... buttons . slice ( i + 1 ) ] )
115
+ }
91
116
>
92
117
Delete
93
118
</ Button >
@@ -111,11 +136,26 @@ const Editor: React.FC<EditorProps> = ({ buttons, onChange }) => {
111
136
} ;
112
137
113
138
export function addEditor ( builder : PanelOptionsEditorBuilder < Options > ) {
114
- builder . addCustomEditor ( {
115
- id : 'buttons' ,
116
- path : 'buttons' ,
117
- name : '' ,
118
- defaultValue : [ { text : '' , datasource : '' , query : '' } ] ,
119
- editor : props => < Editor buttons = { props . value } onChange = { props . onChange } /> ,
120
- } ) ;
139
+ builder
140
+ . addRadio ( {
141
+ path : 'orientation' ,
142
+ name : 'Orientation' ,
143
+ description : 'Stacking direction in case of multiple buttons' ,
144
+ defaultValue : 'horizontal' ,
145
+ settings : {
146
+ options : [
147
+ { value : 'horizontal' , label : 'Horizontal' } ,
148
+ { value : 'vertical' , label : 'Vertical' } ,
149
+ ] ,
150
+ } ,
151
+ } )
152
+ . addCustomEditor ( {
153
+ id : 'buttons' ,
154
+ path : 'buttons' ,
155
+ name : 'Button Configuration' ,
156
+ defaultValue : [ { text : '' , datasource : '' , query : '' } ] ,
157
+ editor : props => (
158
+ < Editor buttons = { props . value } onChange = { props . onChange } />
159
+ ) ,
160
+ } ) ;
121
161
}
0 commit comments