@@ -25,7 +25,7 @@ export default function NewProject() {
25
25
const { teams } = useContext ( TeamsContext ) ;
26
26
const { user, setUser } = useContext ( UserContext ) ;
27
27
28
- const [ provider , setProvider ] = useState < string > ( "github.com" ) ;
28
+ const [ provider , setProvider ] = useState < string | undefined > ( ) ;
29
29
const [ reposInAccounts , setReposInAccounts ] = useState < ProviderRepository [ ] > ( [ ] ) ;
30
30
const [ repoSearchFilter , setRepoSearchFilter ] = useState < string > ( "" ) ;
31
31
const [ selectedAccount , setSelectedAccount ] = useState < string | undefined > ( undefined ) ;
@@ -37,6 +37,16 @@ export default function NewProject() {
37
37
const [ showNewTeam , setShowNewTeam ] = useState < boolean > ( false ) ;
38
38
const [ loaded , setLoaded ] = useState < boolean > ( false ) ;
39
39
40
+ useEffect ( ( ) => {
41
+ if ( user && provider === undefined ) {
42
+ if ( user . identities . find ( i => i . authProviderId === "Public-GitLab" ) ) {
43
+ setProvider ( "gitlab.com" ) ;
44
+ } else if ( user . identities . find ( i => i . authProviderId === "Public-GitHub" ) ) {
45
+ setProvider ( "github.com" ) ;
46
+ }
47
+ }
48
+ } , [ user ] ) ;
49
+
40
50
useEffect ( ( ) => {
41
51
const params = new URLSearchParams ( location . search ) ;
42
52
const teamParam = params . get ( "team" ) ;
@@ -53,7 +63,6 @@ export default function NewProject() {
53
63
if ( first ) {
54
64
setSelectedAccount ( first . account ) ;
55
65
}
56
- setLoaded ( true ) ;
57
66
} ) ( ) ;
58
67
} , [ ] ) ;
59
68
@@ -69,6 +78,7 @@ export default function NewProject() {
69
78
} else {
70
79
const mostRecent = reposInAccounts . reduce ( ( prev , current ) => ( prev . installationUpdatedAt || 0 ) > ( current . installationUpdatedAt || 0 ) ? prev : current ) ;
71
80
setSelectedAccount ( mostRecent . account ) ;
81
+ setLoaded ( true ) ;
72
82
}
73
83
74
84
} , [ reposInAccounts ] ) ;
@@ -90,6 +100,9 @@ export default function NewProject() {
90
100
const isGitHub = ( ) => provider === "github.com" ;
91
101
92
102
const updateReposInAccounts = async ( installationId ?: string ) => {
103
+ if ( ! provider ) {
104
+ return [ ] ;
105
+ }
93
106
try {
94
107
const repos = await getGitpodService ( ) . server . getProviderRepositoriesForUser ( { provider, hints : { installationId } } ) ;
95
108
setReposInAccounts ( repos ) ;
@@ -106,7 +119,7 @@ export default function NewProject() {
106
119
}
107
120
108
121
const updateOrgsState = async ( ) => {
109
- if ( isGitHub ( ) ) {
122
+ if ( provider && isGitHub ( ) ) {
110
123
try {
111
124
const ghToken = await getToken ( provider ) ;
112
125
setNoOrgs ( ghToken ?. scopes . includes ( "read:org" ) !== true ) ;
@@ -140,6 +153,9 @@ export default function NewProject() {
140
153
}
141
154
142
155
const createProject = async ( teamOrUser : Team | User , selectedRepo : string ) => {
156
+ if ( ! provider ) {
157
+ return ;
158
+ }
143
159
const repo = reposInAccounts . find ( r => r . account === selectedAccount && r . name === selectedRepo ) ;
144
160
if ( ! repo ) {
145
161
console . error ( "No repo selected!" )
@@ -166,7 +182,6 @@ export default function NewProject() {
166
182
return splitted . shift ( ) && splitted . join ( "/" ) ;
167
183
}
168
184
169
- const reposToRender = Array . from ( reposInAccounts ) . filter ( r => r . account === selectedAccount && r . name . includes ( repoSearchFilter ) ) ;
170
185
const accounts = new Map < string , { avatarUrl : string } > ( ) ;
171
186
reposInAccounts . forEach ( r => { if ( ! accounts . has ( r . account ) ) accounts . set ( r . account , { avatarUrl : r . accountAvatarUrl } ) } ) ;
172
187
@@ -203,33 +218,38 @@ export default function NewProject() {
203
218
204
219
const renderSelectRepository = ( ) => {
205
220
221
+ const noReposAvailable = reposInAccounts . length === 0 ;
222
+ const filteredRepos = Array . from ( reposInAccounts ) . filter ( r => r . account === selectedAccount && r . name . includes ( repoSearchFilter ) ) ;
206
223
const icon = selectedAccount && accounts . get ( selectedAccount ) ?. avatarUrl ;
207
224
208
- const renderRepos = ( ) => ( < div className = "mt-10 border rounded-t-xl border-gray-100 flex-col" >
209
- < div className = "px-8 pt-8 flex flex-col space-y-2" >
210
- < ContextMenu classes = "w-full left-0 cursor-pointer" menuEntries = { getDropDownEntries ( accounts ) } >
211
- < div className = "w-full" >
212
- < img src = { icon } className = "rounded-full w-6 h-6 absolute top-1/4 left-4" />
213
- < input className = "w-full px-12 cursor-pointer font-semibold" readOnly type = "text" value = { selectedAccount || "" } > </ input >
214
- < img src = { CaretDown } title = "Select Account" className = "filter-grayscale absolute top-1/2 right-3" />
225
+ const renderRepos = ( ) => ( < >
226
+ < div className = { `mt-10 border ${ isGitHub ( ) ? "rounded-t-xl border-b-0" : "rounded-xl" } border-gray-100 flex-col` } >
227
+ < div className = "px-8 pt-8 flex flex-col space-y-2" >
228
+ < ContextMenu classes = "w-full left-0 cursor-pointer" menuEntries = { getDropDownEntries ( accounts ) } >
229
+ < div className = "w-full" >
230
+ { icon && (
231
+ < img src = { icon } className = "rounded-full w-6 h-6 absolute top-1/4 left-4" />
232
+ ) }
233
+ < input className = "w-full px-12 cursor-pointer font-semibold" readOnly type = "text" value = { selectedAccount || "" } > </ input >
234
+ < img src = { CaretDown } title = "Select Account" className = "filter-grayscale absolute top-1/2 right-3" />
235
+ </ div >
236
+ </ ContextMenu >
237
+ < div className = "w-full relative " >
238
+ < img src = { search } title = "Search" className = "filter-grayscale absolute top-1/3 left-3" />
239
+ < input className = "w-96 pl-10 border-0" type = "text" placeholder = "Search Repositories" value = { repoSearchFilter }
240
+ onChange = { ( e ) => setRepoSearchFilter ( e . target . value ) } > </ input >
215
241
</ div >
216
- </ ContextMenu >
217
- < div className = "w-full relative " >
218
- < img src = { search } title = "Search" className = "filter-grayscale absolute top-1/3 left-3" />
219
- < input className = "w-96 pl-10 border-0" type = "text" placeholder = "Search Repositories" value = { repoSearchFilter }
220
- onChange = { ( e ) => setRepoSearchFilter ( e . target . value ) } > </ input >
221
242
</ div >
222
- </ div >
223
- < div className = "p-6 flex-col" >
224
- { reposToRender . length > 0 && (
225
- < div className = "overscroll-contain max-h-80 overflow-y-auto pr-2" >
226
- { reposToRender . map ( r => (
227
- < div key = { `repo-${ r . name } ` } className = "flex p-3 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gitpod-kumquat-light transition ease-in-out group" >
228
-
229
- < div className = "flex-grow" >
230
- < div className = "text-base text-gray-900 dark:text-gray-50 font-medium rounded-xl whitespace-nowrap" > { toSimpleName ( r . name ) } </ div >
231
- < p > Updated { moment ( r . updatedAt ) . fromNow ( ) } </ p >
232
- </ div >
243
+ < div className = "p-6 flex-col" >
244
+ { filteredRepos . length > 0 && (
245
+ < div className = "overscroll-contain max-h-80 overflow-y-auto pr-2" >
246
+ { filteredRepos . map ( r => (
247
+ < div key = { `repo-${ r . name } ` } className = "flex p-3 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gitpod-kumquat-light transition ease-in-out group" >
248
+
249
+ < div className = "flex-grow" >
250
+ < div className = "text-base text-gray-900 dark:text-gray-50 font-medium rounded-xl whitespace-nowrap" > { toSimpleName ( r . name ) } </ div >
251
+ < p > Updated { moment ( r . updatedAt ) . fromNow ( ) } </ p >
252
+ </ div >
233
253
< div className = "flex justify-end" >
234
254
< div className = "h-full my-auto flex self-center opacity-0 group-hover:opacity-100" >
235
255
{ ! r . inUse ? (
@@ -239,48 +259,56 @@ export default function NewProject() {
239
259
) }
240
260
</ div >
241
261
</ div >
262
+ </ div >
263
+ ) ) }
264
+ </ div >
265
+ ) }
266
+ { ! noReposAvailable && filteredRepos . length === 0 && (
267
+ < p className = "text-center" > No Results</ p >
268
+ ) }
269
+ { loaded && noReposAvailable && ( < div >
270
+ < div className = "px-12 py-16 text-center text-gray-500 bg-gray-50 dark:bg-gray-800 rounded-xl" >
271
+ < img src = { NoAccess } title = "No Access" className = "m-auto mb-4" />
272
+ < h3 className = "mb-2 text-gray-600 dark:text-gray-400" >
273
+ No Access
274
+ </ h3 >
275
+ < span className = "dark:text-gray-500" >
276
+ Authorize GitHub (github.com) or select a different account.
277
+ </ span >
278
+ < br />
279
+ < button className = "mt-6" onClick = { ( ) => reconfigure ( ) } > Authorize</ button >
280
+ </ div >
281
+ </ div > ) }
282
+ </ div >
283
+
284
+ </ div >
285
+ { isGitHub ( ) && (
286
+ < div className = "pt-3 bg-gray-100 rounded-b-xl border-gray-100 border" >
287
+ < div className = "text-gray-500 text-center w-96 mx-8" >
288
+ Repository not found? < a href = "javascript:void(0)" onClick = { e => reconfigure ( ) } className = "text-gray-400 underline underline-thickness-thin underline-offset-small hover:text-gray-600" > Reconfigure</ a >
289
+ </ div >
290
+ { isGitHub ( ) && noOrgs && (
291
+ < div className = "text-gray-500 mx-auto text-center" >
292
+ Missing organizations? < a href = "javascript:void(0)" onClick = { e => grantReadOrgPermissions ( ) } className = "text-gray-400 underline underline-thickness-thin underline-offset-small hover:text-gray-600" > Grant permissions</ a >
242
293
</ div >
243
- ) ) }
294
+ ) }
244
295
</ div >
245
- ) }
246
- { reposToRender . length === 0 && (
247
- < p className = "text-center " > not found</ p >
248
- ) }
249
- </ div >
250
-
251
- < div className = "px-3 pt-3 bg-gray-100" >
252
- < div className = "text-gray-500 text-center" >
253
- Repository not found? < a href = "javascript:void(0)" onClick = { e => reconfigure ( ) } className = "text-gray-400 underline underline-thickness-thin underline-offset-small hover:text-gray-600" > Reconfigure</ a >
254
- </ div >
255
- { isGitHub ( ) && noOrgs && (
256
- < div className = "text-gray-500 mx-auto text-center" >
257
- Missing organizations? < a href = "javascript:void(0)" onClick = { e => grantReadOrgPermissions ( ) } className = "text-gray-400 underline underline-thickness-thin underline-offset-small hover:text-gray-600" > Grant permissions</ a >
296
+ ) }
297
+ </ >
298
+ ) ;
299
+
300
+ const renderEmptyState = ( ) => ( < div >
301
+ < div className = "mt-8 border rounded-xl border-gray-100 dark:border-gray-700 flex-col" >
302
+ < div >
303
+ < div className = "px-12 py-16 text-center text-gray-500 bg-gray-50 dark:bg-gray-800 rounded-xl" >
304
+ < h3 className = "mb-2 text-gray-600 dark:text-gray-400" >
305
+ Loading ...
306
+ </ h3 >
258
307
</ div >
259
- ) }
260
- </ div >
261
- < div className = "h-3 border rounded-b-xl border-gray-100 bg-gray-100" > </ div >
262
- </ div > ) ;
263
-
264
- const renderEmptyState = ( ) => ( < div className = "mt-8 border rounded-xl border-gray-100 dark:border-gray-700 flex-col" >
265
- < div >
266
- < div className = "px-12 py-16 text-center text-gray-500 bg-gray-50 dark:bg-gray-800 rounded-xl" >
267
- < img src = { NoAccess } title = "No Access" className = "m-auto mb-4" />
268
- < h3 className = "mb-2 text-gray-600 dark:text-gray-400" >
269
- No Access
270
- </ h3 >
271
- < span className = "dark:text-gray-500" >
272
- Authorize GitHub (github.com) or select a different account.
273
- </ span >
274
- < br />
275
- < button className = "mt-6" onClick = { ( ) => reconfigure ( ) } > Authorize Provider</ button >
276
- < br />
277
- < button className = "mt-6" onClick = { ( ) => setShowGitProviders ( true ) } > Select Git Provider</ button >
278
308
</ div >
279
309
</ div >
280
310
</ div > )
281
311
282
- const empty = reposInAccounts . length === 0 ;
283
-
284
312
const onGitProviderSeleted = async ( host : string , updateUser ?: boolean ) => {
285
313
if ( updateUser ) {
286
314
setUser ( await getGitpodService ( ) . server . getLoggedInUser ( ) ) ;
@@ -289,9 +317,15 @@ export default function NewProject() {
289
317
setProvider ( host ) ;
290
318
}
291
319
292
- return ( < >
293
- { ( loaded && empty && ! showGitProviders ) ? renderEmptyState ( ) : ( showGitProviders ? ( < GitProviders onHostSelected = { onGitProviderSeleted } /> ) : renderRepos ( ) ) }
294
- </ > )
320
+ if ( ! loaded ) {
321
+ return renderEmptyState ( ) ;
322
+ }
323
+
324
+ if ( showGitProviders ) {
325
+ return ( < GitProviders onHostSelected = { onGitProviderSeleted } /> ) ;
326
+ }
327
+
328
+ return renderRepos ( ) ;
295
329
} ;
296
330
297
331
const renderSelectTeam = ( ) => {
@@ -337,7 +371,7 @@ export default function NewProject() {
337
371
338
372
return ( < div className = "flex flex-col w-96 mt-24 mx-auto items-center" >
339
373
< h1 > New Project</ h1 >
340
- < p className = "text-gray-500 text-center text-base" > Select a git repository.</ p >
374
+ < p className = "text-gray-500 text-center text-base" > Select a git repository on < strong > { provider } </ strong > .</ p >
341
375
342
376
{ ! selectedRepo && renderSelectRepository ( ) }
343
377
0 commit comments