@@ -79,6 +79,28 @@ function AddEnvVarModal(p: EnvVarModalProps) {
79
79
</ Modal >
80
80
}
81
81
82
+ function DeleteEnvVarModal ( p : { variable : UserEnvVarValue , deleteVariable : ( ) => void , onClose : ( ) => void } ) {
83
+ return < Modal visible = { true } onClose = { p . onClose } >
84
+ < h3 className = "mb-4" > Delete Variable?</ h3 >
85
+ < div className = "border-t border-b border-gray-200 dark:border-gray-800 -mx-6 px-6 py-4 flex flex-col" >
86
+ < div className = "grid grid-cols-3 gap-4 px-3" >
87
+ < h4 className = "truncate" > Name</ h4 >
88
+ < h4 className = "truncate" > Value</ h4 >
89
+ < h4 className = "truncate" > Scope</ h4 >
90
+ </ div >
91
+ < div className = "grid grid-cols-3 gap-4 text-gray-400 bg-gray-100 dark:bg-gray-800 rounded-xl p-3" >
92
+ < span className = "truncate text-gray-900 dark:text-gray-50" > { p . variable . name } </ span >
93
+ < span className = "truncate" > { p . variable . value } </ span >
94
+ < span className = "truncate" > { p . variable . repositoryPattern } </ span >
95
+ </ div >
96
+ </ div >
97
+ < div className = "flex justify-end mt-6" >
98
+ < button className = "secondary" onClick = { p . onClose } > Cancel</ button >
99
+ < button className = "ml-2 danger" onClick = { ( ) => { p . deleteVariable ( ) ; p . onClose ( ) ; } } > Delete Variable</ button >
100
+ </ div >
101
+ </ Modal > ;
102
+ }
103
+
82
104
function sortEnvVars ( a : UserEnvVarValue , b : UserEnvVarValue ) {
83
105
if ( a . name === b . name ) {
84
106
return a . repositoryPattern > b . repositoryPattern ? 1 : - 1 ;
@@ -90,6 +112,7 @@ export default function EnvVars() {
90
112
const [ envVars , setEnvVars ] = useState ( [ ] as UserEnvVarValue [ ] ) ;
91
113
const [ currentEnvVar , setCurrentEnvVar ] = useState ( { name : '' , value : '' , repositoryPattern : '' } as UserEnvVarValue ) ;
92
114
const [ isAddEnvVarModalVisible , setAddEnvVarModalVisible ] = useState ( false ) ;
115
+ const [ isDeleteEnvVarModalVisible , setDeleteEnvVarModalVisible ] = useState ( false ) ;
93
116
const update = async ( ) => {
94
117
await getGitpodService ( ) . server . getAllEnvVars ( ) . then ( r => setEnvVars ( r . sort ( sortEnvVars ) ) ) ;
95
118
}
@@ -102,19 +125,27 @@ export default function EnvVars() {
102
125
const add = ( ) => {
103
126
setCurrentEnvVar ( { name : '' , value : '' , repositoryPattern : '' } ) ;
104
127
setAddEnvVarModalVisible ( true ) ;
128
+ setDeleteEnvVarModalVisible ( false ) ;
105
129
}
106
130
107
- const edit = ( ev : UserEnvVarValue ) => {
108
- setCurrentEnvVar ( ev ) ;
131
+ const edit = ( variable : UserEnvVarValue ) => {
132
+ setCurrentEnvVar ( variable ) ;
109
133
setAddEnvVarModalVisible ( true ) ;
134
+ setDeleteEnvVarModalVisible ( false ) ;
135
+ }
136
+
137
+ const confirmDeleteVariable = ( variable : UserEnvVarValue ) => {
138
+ setCurrentEnvVar ( variable ) ;
139
+ setAddEnvVarModalVisible ( false ) ;
140
+ setDeleteEnvVarModalVisible ( true ) ;
110
141
}
111
142
112
143
const save = async ( variable : UserEnvVarValue ) => {
113
144
await getGitpodService ( ) . server . setEnvVar ( variable ) ;
114
145
await update ( ) ;
115
146
} ;
116
147
117
- const deleteV = async ( variable : UserEnvVarValue ) => {
148
+ const deleteVariable = async ( variable : UserEnvVarValue ) => {
118
149
await getGitpodService ( ) . server . deleteEnvVar ( variable ) ;
119
150
await update ( ) ;
120
151
} ;
@@ -145,26 +176,32 @@ export default function EnvVars() {
145
176
}
146
177
}
147
178
}
179
+ if ( ! variable . id && envVars . some ( v => v . name === name && v . repositoryPattern === pattern ) ) {
180
+ return 'A variable with this name and scope already exists' ;
181
+ }
148
182
return '' ;
149
183
} ;
150
184
151
- return < PageWithSubMenu subMenu = { settingsMenu } title = 'Variables' subtitle = 'Configure environment variables for all workspaces.' >
152
- { isAddEnvVarModalVisible ? < AddEnvVarModal
185
+ return < PageWithSubMenu subMenu = { settingsMenu } title = 'Variables' subtitle = 'Configure environment variables for all workspaces.' >
186
+ { isAddEnvVarModalVisible && < AddEnvVarModal
153
187
save = { save }
154
188
envVar = { currentEnvVar }
155
189
validate = { validate }
156
- onClose = { ( ) => setAddEnvVarModalVisible ( false ) } /> : null }
190
+ onClose = { ( ) => setAddEnvVarModalVisible ( false ) } /> }
191
+ { isDeleteEnvVarModalVisible && < DeleteEnvVarModal
192
+ variable = { currentEnvVar }
193
+ deleteVariable = { ( ) => deleteVariable ( currentEnvVar ) }
194
+ onClose = { ( ) => setDeleteEnvVarModalVisible ( false ) } /> }
157
195
< div className = "flex items-start sm:justify-between mb-2" >
158
196
< div >
159
197
< h3 > Environment Variables</ h3 >
160
198
< h2 className = "text-gray-500" > Variables are used to store information like passwords.</ h2 >
161
199
</ div >
162
200
{ envVars . length !== 0
163
- ?
164
- < div className = "mt-3 flex mt-0" >
165
- < button onClick = { add } className = "ml-2" > New Variable</ button >
166
- </ div >
167
- : null }
201
+ ? < div className = "mt-3 flex mt-0" >
202
+ < button onClick = { add } className = "ml-2" > New Variable</ button >
203
+ </ div >
204
+ : null }
168
205
</ div >
169
206
{ envVars . length === 0
170
207
? < div className = "bg-gray-100 dark:bg-gray-800 rounded-xl w-full h-96" >
@@ -183,22 +220,22 @@ export default function EnvVars() {
183
220
</ div >
184
221
</ div >
185
222
< div className = "flex flex-col" >
186
- { envVars . map ( ev => {
223
+ { envVars . map ( variable => {
187
224
return < div className = "rounded-xl whitespace-nowrap flex space-x-2 py-3 px-3 w-full justify-between hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gitpod-kumquat-light transition ease-in-out group" >
188
- < div className = "w-5/12 m-auto" > { ev . name } </ div >
189
- < div className = "w-5/12 m-auto text-sm text-gray-400" > { ev . repositoryPattern } </ div >
225
+ < div className = "w-5/12 m-auto" > { variable . name } </ div >
226
+ < div className = "w-5/12 m-auto text-sm text-gray-400" > { variable . repositoryPattern } </ div >
190
227
< div className = "w-2/12 flex justify-end" >
191
228
< div className = "flex w-8 self-center hover:bg-gray-200 dark:hover:bg-gray-700 rounded-md cursor-pointer opacity-0 group-hover:opacity-100" >
192
229
< ContextMenu menuEntries = { [
193
230
{
194
231
title : 'Edit' ,
195
- onClick : ( ) => edit ( ev ) ,
232
+ onClick : ( ) => edit ( variable ) ,
196
233
separator : true
197
234
} ,
198
235
{
199
236
title : 'Delete' ,
200
237
customFontStyle : 'text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300' ,
201
- onClick : ( ) => deleteV ( ev )
238
+ onClick : ( ) => confirmDeleteVariable ( variable )
202
239
} ,
203
240
] } >
204
241
< svg className = "w-8 h-8 p-1 text-gray-600 dark:text-gray-300" xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" > < title > Actions</ title > < g fill = "currentColor" transform = "rotate(90 12 12)" > < circle cx = "1" cy = "1" r = "2" transform = "translate(5 11)" /> < circle cx = "1" cy = "1" r = "2" transform = "translate(11 11)" /> < circle cx = "1" cy = "1" r = "2" transform = "translate(17 11)" /> </ g > </ svg >
0 commit comments