@@ -79,10 +79,38 @@ 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-2 gap-4 px-3 text-sm text-gray-400" >
87
+ < span className = "truncate" > Name</ span >
88
+ < span className = "truncate" > Scope</ span >
89
+ </ div >
90
+ < div className = "grid grid-cols-2 gap-4 p-3 mt-3 text-gray-400 bg-gray-100 dark:bg-gray-800 rounded-xl" >
91
+ < span className = "truncate text-gray-900 dark:text-gray-50" > { p . variable . name } </ span >
92
+ < span className = "truncate text-sm" > { p . variable . repositoryPattern } </ span >
93
+ </ div >
94
+ </ div >
95
+ < div className = "flex justify-end mt-6" >
96
+ < button className = "secondary" onClick = { p . onClose } > Cancel</ button >
97
+ < button className = "ml-2 danger" onClick = { ( ) => { p . deleteVariable ( ) ; p . onClose ( ) ; } } > Delete Variable</ button >
98
+ </ div >
99
+ </ Modal > ;
100
+ }
101
+
102
+ function sortEnvVars ( a : UserEnvVarValue , b : UserEnvVarValue ) {
103
+ if ( a . name === b . name ) {
104
+ return a . repositoryPattern > b . repositoryPattern ? 1 : - 1 ;
105
+ }
106
+ return a . name > b . name ? 1 : - 1 ;
107
+ }
108
+
82
109
export default function EnvVars ( ) {
83
110
const [ envVars , setEnvVars ] = useState ( [ ] as UserEnvVarValue [ ] ) ;
84
111
const [ currentEnvVar , setCurrentEnvVar ] = useState ( { name : '' , value : '' , repositoryPattern : '' } as UserEnvVarValue ) ;
85
112
const [ isAddEnvVarModalVisible , setAddEnvVarModalVisible ] = useState ( false ) ;
113
+ const [ isDeleteEnvVarModalVisible , setDeleteEnvVarModalVisible ] = useState ( false ) ;
86
114
const update = async ( ) => {
87
115
await getGitpodService ( ) . server . getEnvVars ( ) . then ( r => setEnvVars ( r ) ) ;
88
116
}
@@ -95,19 +123,27 @@ export default function EnvVars() {
95
123
const add = ( ) => {
96
124
setCurrentEnvVar ( { name : '' , value : '' , repositoryPattern : '' } ) ;
97
125
setAddEnvVarModalVisible ( true ) ;
126
+ setDeleteEnvVarModalVisible ( false ) ;
98
127
}
99
128
100
- const edit = ( ev : UserEnvVarValue ) => {
101
- setCurrentEnvVar ( ev ) ;
129
+ const edit = ( variable : UserEnvVarValue ) => {
130
+ setCurrentEnvVar ( variable ) ;
102
131
setAddEnvVarModalVisible ( true ) ;
132
+ setDeleteEnvVarModalVisible ( false ) ;
133
+ }
134
+
135
+ const confirmDeleteVariable = ( variable : UserEnvVarValue ) => {
136
+ setCurrentEnvVar ( variable ) ;
137
+ setAddEnvVarModalVisible ( false ) ;
138
+ setDeleteEnvVarModalVisible ( true ) ;
103
139
}
104
140
105
141
const save = async ( variable : UserEnvVarValue ) => {
106
142
await getGitpodService ( ) . server . setEnvVar ( variable ) ;
107
143
await update ( ) ;
108
144
} ;
109
145
110
- const deleteV = async ( variable : UserEnvVarValue ) => {
146
+ const deleteVariable = async ( variable : UserEnvVarValue ) => {
111
147
await getGitpodService ( ) . server . deleteEnvVar ( variable ) ;
112
148
await update ( ) ;
113
149
} ;
@@ -138,26 +174,32 @@ export default function EnvVars() {
138
174
}
139
175
}
140
176
}
177
+ if ( ! variable . id && envVars . some ( v => v . name === name && v . repositoryPattern === pattern ) ) {
178
+ return 'A variable with this name and scope already exists' ;
179
+ }
141
180
return '' ;
142
181
} ;
143
182
144
- return < PageWithSubMenu subMenu = { settingsMenu } title = 'Variables' subtitle = 'Configure environment variables for all workspaces.' >
145
- { isAddEnvVarModalVisible ? < AddEnvVarModal
183
+ return < PageWithSubMenu subMenu = { settingsMenu } title = 'Variables' subtitle = 'Configure environment variables for all workspaces.' >
184
+ { isAddEnvVarModalVisible && < AddEnvVarModal
146
185
save = { save }
147
186
envVar = { currentEnvVar }
148
187
validate = { validate }
149
- onClose = { ( ) => setAddEnvVarModalVisible ( false ) } /> : null }
188
+ onClose = { ( ) => setAddEnvVarModalVisible ( false ) } /> }
189
+ { isDeleteEnvVarModalVisible && < DeleteEnvVarModal
190
+ variable = { currentEnvVar }
191
+ deleteVariable = { ( ) => deleteVariable ( currentEnvVar ) }
192
+ onClose = { ( ) => setDeleteEnvVarModalVisible ( false ) } /> }
150
193
< div className = "flex items-start sm:justify-between mb-2" >
151
194
< div >
152
195
< h3 > Environment Variables</ h3 >
153
196
< h2 className = "text-gray-500" > Variables are used to store information like passwords.</ h2 >
154
197
</ div >
155
198
{ envVars . length !== 0
156
- ?
157
- < div className = "mt-3 flex mt-0" >
158
- < button onClick = { add } className = "ml-2" > New Variable</ button >
159
- </ div >
160
- : null }
199
+ ? < div className = "mt-3 flex mt-0" >
200
+ < button onClick = { add } className = "ml-2" > New Variable</ button >
201
+ </ div >
202
+ : null }
161
203
</ div >
162
204
{ envVars . length === 0
163
205
? < div className = "bg-gray-100 dark:bg-gray-800 rounded-xl w-full h-96" >
@@ -176,22 +218,22 @@ export default function EnvVars() {
176
218
</ div >
177
219
</ div >
178
220
< div className = "flex flex-col" >
179
- { envVars . map ( ev => {
221
+ { envVars . map ( variable => {
180
222
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" >
181
- < div className = "w-5/12 m-auto" > { ev . name } </ div >
182
- < div className = "w-5/12 m-auto text-sm text-gray-400" > { ev . repositoryPattern } </ div >
223
+ < div className = "w-5/12 m-auto" > { variable . name } </ div >
224
+ < div className = "w-5/12 m-auto text-sm text-gray-400" > { variable . repositoryPattern } </ div >
183
225
< div className = "w-2/12 flex justify-end" >
184
226
< 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" >
185
227
< ContextMenu menuEntries = { [
186
228
{
187
229
title : 'Edit' ,
188
- onClick : ( ) => edit ( ev ) ,
230
+ onClick : ( ) => edit ( variable ) ,
189
231
separator : true
190
232
} ,
191
233
{
192
234
title : 'Delete' ,
193
235
customFontStyle : 'text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300' ,
194
- onClick : ( ) => deleteV ( ev )
236
+ onClick : ( ) => confirmDeleteVariable ( variable )
195
237
} ,
196
238
] } >
197
239
< 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