7
7
import { CommitContext , Workspace , WorkspaceInfo , WorkspaceInstance , WorkspaceInstanceConditions , WorkspaceInstancePhase } from '@gitpod/gitpod-protocol' ;
8
8
import { GitpodHostUrl } from '@gitpod/gitpod-protocol/lib/util/gitpod-host-url' ;
9
9
import moment from 'moment' ;
10
- import React , { useState } from 'react' ;
10
+ import React , { useRef , useState } from 'react' ;
11
11
import ConfirmationModal from '../components/ConfirmationModal' ;
12
+ import Modal from '../components/Modal' ;
12
13
import { ContextMenuEntry } from '../components/ContextMenu' ;
13
14
import { Item , ItemField , ItemFieldContextMenu , ItemFieldIcon } from '../components/ItemsList' ;
14
15
import PendingChangesDropdown from '../components/PendingChangesDropdown' ;
15
16
import Tooltip from '../components/Tooltip' ;
16
17
import { WorkspaceModel } from './workspace-model' ;
18
+ import { getGitpodService } from '../service/service' ;
17
19
18
20
function getLabel ( state : WorkspaceInstancePhase , conditions ?: WorkspaceInstanceConditions ) {
19
21
if ( conditions ?. failed ) {
@@ -30,10 +32,14 @@ interface Props {
30
32
}
31
33
32
34
export function WorkspaceEntry ( { desc, model, isAdmin, stopWorkspace } : Props ) {
33
- const [ isModalVisible , setModalVisible ] = useState ( false ) ;
35
+ const [ isDeleteModalVisible , setDeleteModalVisible ] = useState ( false ) ;
36
+ const [ isRenameModalVisible , setRenameModalVisible ] = useState ( false ) ;
37
+ const renameInputRef = useRef < HTMLInputElement > ( null ) ;
34
38
const state : WorkspaceInstancePhase = desc . latestInstance ?. status ?. phase || 'stopped' ;
35
39
const currentBranch = desc . latestInstance ?. status . repo ?. branch || Workspace . getBranchName ( desc . workspace ) || '<unknown>' ;
36
40
const ws = desc . workspace ;
41
+ const [ workspaceDescription , setWsDescription ] = useState ( ws . description ) ;
42
+
37
43
const startUrl = new GitpodHostUrl ( window . location . href ) . with ( {
38
44
pathname : '/start/' ,
39
45
hash : '#' + ws . id
@@ -45,7 +51,16 @@ export function WorkspaceEntry({ desc, model, isAdmin, stopWorkspace }: Props) {
45
51
{
46
52
title : 'Open' ,
47
53
href : startUrl . toString ( )
48
- } ] ;
54
+ } ,
55
+ {
56
+ title : 'Rename' ,
57
+ href : "" ,
58
+ onClick : ( ) => {
59
+ setRenameModalVisible ( true ) ;
60
+ }
61
+ } ,
62
+
63
+ ] ;
49
64
if ( state === 'running' ) {
50
65
menuEntries . push ( {
51
66
title : 'Stop' ,
@@ -78,13 +93,30 @@ export function WorkspaceEntry({ desc, model, isAdmin, stopWorkspace }: Props) {
78
93
title : 'Delete' ,
79
94
customFontStyle : 'text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300' ,
80
95
onClick : ( ) => {
81
- setModalVisible ( true ) ;
96
+ setDeleteModalVisible ( true ) ;
82
97
}
83
98
}
84
99
) ;
85
100
}
86
101
const project = getProject ( ws ) ;
87
102
103
+ const updateWorkspaceDescription = async ( ) => {
104
+ // Need this check because ref is called twice
105
+ // https://reactjs.org/docs/refs-and-the-dom.html#caveats-with-callback-refs
106
+ if ( ! renameInputRef . current ) {
107
+ return ;
108
+ }
109
+ try {
110
+ setWsDescription ( renameInputRef . current ! . value ) ;
111
+ await getGitpodService ( ) . server . setWorkspaceDescription ( ws . id , renameInputRef . current ! . value ) ;
112
+ } catch ( error ) {
113
+ // A simple alert for now because there is an open issue to introduce Toast
114
+ console . error ( error ) ;
115
+ window . alert ( "Something went wrong. Please try renaming again." ) ;
116
+ }
117
+ setRenameModalVisible ( false ) ;
118
+ }
119
+
88
120
return < Item className = "whitespace-nowrap py-6 px-6" >
89
121
< ItemFieldIcon >
90
122
< WorkspaceStatusIndicator instance = { desc ?. latestInstance } />
@@ -96,7 +128,7 @@ export function WorkspaceEntry({ desc, model, isAdmin, stopWorkspace }: Props) {
96
128
</ Tooltip >
97
129
</ ItemField >
98
130
< ItemField className = "w-4/12 flex flex-col" >
99
- < div className = "text-gray-500 dark:text-gray-400 overflow-ellipsis truncate" > { ws . description } </ div >
131
+ < div className = "text-gray-500 dark:text-gray-400 overflow-ellipsis truncate" > { workspaceDescription } </ div >
100
132
< a href = { ws . contextURL } >
101
133
< div className = "text-sm text-gray-400 dark:text-gray-500 overflow-ellipsis truncate hover:text-blue-600 dark:hover:text-blue-400" > { ws . contextURL } </ div >
102
134
</ a >
@@ -111,18 +143,32 @@ export function WorkspaceEntry({ desc, model, isAdmin, stopWorkspace }: Props) {
111
143
</ Tooltip >
112
144
</ ItemField >
113
145
< ItemFieldContextMenu menuEntries = { menuEntries } />
114
- { isModalVisible && < ConfirmationModal
146
+ { isDeleteModalVisible && < ConfirmationModal
115
147
title = "Delete Workspace"
116
148
areYouSureText = "Are you sure you want to delete this workspace?"
117
149
children = { {
118
150
name : ws . id ,
119
151
description : ws . description ,
120
152
} }
121
153
buttonText = "Delete Workspace"
122
- visible = { isModalVisible }
123
- onClose = { ( ) => setModalVisible ( false ) }
154
+ visible = { isDeleteModalVisible }
155
+ onClose = { ( ) => setDeleteModalVisible ( false ) }
124
156
onConfirm = { ( ) => model . deleteWorkspace ( ws . id ) }
125
157
/> }
158
+ < Modal visible = { isRenameModalVisible } onClose = { ( ) => setRenameModalVisible ( false ) } onEnter = { ( ) => { updateWorkspaceDescription ( ) ; return true } } >
159
+ < h3 className = "mb-4" > Rename Workspace Description</ h3 >
160
+ < div className = "border-t border-b border-gray-200 dark:border-gray-800 -mx-6 px-6 py-4 space-y-2" >
161
+ < input className = "w-full" type = "text" defaultValue = { workspaceDescription } ref = { renameInputRef } />
162
+ < div className = "mt-1" >
163
+ < p className = "text-gray-500" > You can use a friendlier name for this workspace description.</ p >
164
+ < p className = "text-gray-500" > Workspace URLs and endpoints will remain the same.</ p >
165
+ </ div >
166
+ </ div >
167
+ < div className = "flex justify-end mt-6" >
168
+ < button className = "secondary" onClick = { ( ) => setRenameModalVisible ( false ) } > Cancel</ button >
169
+ < button className = "ml-2" type = "submit" onClick = { updateWorkspaceDescription } > Rename</ button >
170
+ </ div >
171
+ </ Modal >
126
172
</ Item > ;
127
173
}
128
174
@@ -134,7 +180,7 @@ export function getProject(ws: Workspace) {
134
180
}
135
181
}
136
182
137
- export function WorkspaceStatusIndicator ( { instance} : { instance ?: WorkspaceInstance } ) {
183
+ export function WorkspaceStatusIndicator ( { instance } : { instance ?: WorkspaceInstance } ) {
138
184
const state : WorkspaceInstancePhase = instance ?. status ?. phase || 'stopped' ;
139
185
const conditions = instance ?. status ?. conditions ;
140
186
let stateClassName = 'rounded-full w-3 h-3 text-sm align-middle' ;
0 commit comments