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