1
+ /**
2
+ * Copyright (c) 2022 Gitpod GmbH. All rights reserved.
3
+ * Licensed under the GNU Affero General Public License (AGPL).
4
+ * See License-AGPL.txt in the project root for license information.
5
+ */
6
+
7
+ import { Project , ProjectEnvVar } from "@gitpod/gitpod-protocol" ;
8
+ import { useContext , useEffect , useState } from "react" ;
9
+ import AlertBox from "../components/AlertBox" ;
10
+ import { Item , ItemField , ItemFieldContextMenu , ItemsList } from "../components/ItemsList" ;
11
+ import Modal from "../components/Modal" ;
12
+ import { getGitpodService } from "../service/service" ;
13
+ import { ProjectContext } from "./project-context" ;
14
+ import { ProjectSettingsPage } from "./ProjectSettings" ;
15
+
16
+ export default function ( ) {
17
+ const { project } = useContext ( ProjectContext ) ;
18
+ const [ envVars , setEnvVars ] = useState < ProjectEnvVar [ ] > ( [ ] ) ;
19
+ const [ showAddVariableModal , setShowAddVariableModal ] = useState < boolean > ( false ) ;
20
+
21
+ const updateEnvVars = async ( ) => {
22
+ if ( ! project ) {
23
+ return ;
24
+ }
25
+ const vars = await getGitpodService ( ) . server . getProjectEnvironmentVariables ( project . id ) ;
26
+ const sortedVars = vars . sort ( ( a , b ) => a . name . toLowerCase ( ) > b . name . toLowerCase ( ) ? 1 : - 1 ) ;
27
+ setEnvVars ( sortedVars ) ;
28
+ }
29
+
30
+ useEffect ( ( ) => {
31
+ updateEnvVars ( ) ;
32
+ // eslint-disable-next-line react-hooks/exhaustive-deps
33
+ } , [ project ] ) ;
34
+
35
+ const deleteEnvVar = async ( variableId : string ) => {
36
+ await getGitpodService ( ) . server . deleteProjectEnvironmentVariable ( variableId ) ;
37
+ updateEnvVars ( ) ;
38
+ }
39
+
40
+ return < ProjectSettingsPage project = { project } >
41
+ { showAddVariableModal && < AddVariableModal project = { project } onClose = { ( ) => { updateEnvVars ( ) ; setShowAddVariableModal ( false ) ; } } /> }
42
+ < div className = "mb-2 flex" >
43
+ < div className = "flex-grow" >
44
+ < h3 > Environment Variables</ h3 >
45
+ < h2 className = "text-gray-500" > Manage environment variables for your project.</ h2 >
46
+ </ div >
47
+ { envVars . length > 0 && < button onClick = { ( ) => setShowAddVariableModal ( true ) } > Add Variable</ button > }
48
+ </ div >
49
+ { envVars . length === 0
50
+ ? < div className = "bg-gray-100 dark:bg-gray-800 rounded-xl w-full py-28 flex flex-col items-center" >
51
+ < h3 className = "text-center pb-3 text-gray-500 dark:text-gray-400" > No Environment Variables</ h3 >
52
+ < p className = "text-center pb-6 text-gray-500 text-base w-96" > Here you can set < strong > project-specific environment variables</ strong > that will be visible during prebuilds and (optionally) in workspaces for this project.</ p >
53
+ < button onClick = { ( ) => setShowAddVariableModal ( true ) } > New Variable</ button >
54
+ </ div >
55
+ : < >
56
+ < ItemsList >
57
+ < Item header = { true } className = "grid grid-cols-3 items-center" >
58
+ < ItemField > Name</ ItemField >
59
+ < ItemField > Value</ ItemField >
60
+ < ItemField > </ ItemField >
61
+ </ Item >
62
+ { envVars . map ( variable => {
63
+ return < Item className = "grid grid-cols-3 items-center" >
64
+ < ItemField > { variable . name } </ ItemField >
65
+ < ItemField > ****</ ItemField >
66
+ < ItemField className = "flex justify-end" >
67
+ < ItemFieldContextMenu menuEntries = { [
68
+ {
69
+ title : 'Delete' ,
70
+ customFontStyle : 'text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300' ,
71
+ onClick : ( ) => deleteEnvVar ( variable . id ) ,
72
+ } ,
73
+ ] } />
74
+ </ ItemField >
75
+ </ Item >
76
+ } ) }
77
+ </ ItemsList >
78
+ </ >
79
+ }
80
+ </ ProjectSettingsPage > ;
81
+ }
82
+
83
+ function AddVariableModal ( props : { project ?: Project , onClose : ( ) => void } ) {
84
+ const [ name , setName ] = useState < string > ( "" ) ;
85
+ const [ value , setValue ] = useState < string > ( "" ) ;
86
+ const [ error , setError ] = useState < Error | undefined > ( ) ;
87
+
88
+ const addVariable = async ( ) => {
89
+ if ( ! props . project ) {
90
+ return ;
91
+ }
92
+ try {
93
+ await getGitpodService ( ) . server . setProjectEnvironmentVariable ( props . project . id , name , value ) ;
94
+ props . onClose ( ) ;
95
+ } catch ( err ) {
96
+ setError ( err ) ;
97
+ }
98
+ }
99
+
100
+ return < Modal visible = { true } onClose = { props . onClose } onEnter = { ( ) => { addVariable ( ) ; return false ; } } >
101
+ < h3 className = "mb-4" > Add Variable</ h3 >
102
+ < div className = "border-t border-b border-gray-200 dark:border-gray-800 -mx-6 px-6 py-4 flex flex-col" >
103
+ < AlertBox > < strong > Project variables might be accessible by anyone with read access to your repository.</ strong > < br /> Secret values can be exposed if they are printed in the logs, persisted to the file system, or made visible in workspaces.</ AlertBox >
104
+ { error && < div className = "bg-gitpod-kumquat-light rounded-md p-3 text-gitpod-red text-sm mb-2" >
105
+ { error }
106
+ </ div > }
107
+ < div className = "mt-4" >
108
+ < h4 > Name</ h4 >
109
+ < input autoFocus className = "w-full" type = "text" name = "name" value = { name } onChange = { e => setName ( e . target . value ) } />
110
+ </ div >
111
+ < div className = "mt-4" >
112
+ < h4 > Value</ h4 >
113
+ < input className = "w-full" type = "text" name = "value" value = { value } onChange = { e => setValue ( e . target . value ) } />
114
+ </ div >
115
+ </ div >
116
+ < div className = "flex justify-end mt-6" >
117
+ < button className = "secondary" onClick = { props . onClose } > Cancel</ button >
118
+ < button className = "ml-2" onClick = { addVariable } > Add Variable</ button >
119
+ </ div >
120
+ </ Modal > ;
121
+ }
0 commit comments