7
7
import { useContext , useEffect , useState } from "react" ;
8
8
import { getGitpodService , gitpodHostUrl } from "../service/service" ;
9
9
import { iconForAuthProvider , openAuthorizeWindow , simplifyProviderName } from "../provider-utils" ;
10
- import { AuthProviderInfo , ProviderRepository , Team , User } from "@gitpod/gitpod-protocol" ;
10
+ import { AuthProviderInfo , ProviderRepository , Team , TeamMemberInfo , User } from "@gitpod/gitpod-protocol" ;
11
11
import { TeamsContext } from "../teams/teams-context" ;
12
12
import { useHistory , useLocation } from "react-router" ;
13
13
import ContextMenu , { ContextMenuEntry } from "../components/ContextMenu" ;
@@ -65,6 +65,24 @@ export default function NewProject() {
65
65
}
66
66
} , [ ] ) ;
67
67
68
+ const [ teamMembers , setTeamMembers ] = useState < Record < string , TeamMemberInfo [ ] > > ( { } ) ;
69
+ useEffect ( ( ) => {
70
+ if ( ! teams ) {
71
+ return ;
72
+ }
73
+ ( async ( ) => {
74
+ const members : Record < string , TeamMemberInfo [ ] > = { } ;
75
+ await Promise . all ( teams . map ( async ( team ) => {
76
+ try {
77
+ members [ team . id ] = await getGitpodService ( ) . server . getTeamMembers ( team . id ) ;
78
+ } catch ( error ) {
79
+ console . error ( 'Could not get members of team' , team , error ) ;
80
+ }
81
+ } ) ) ;
82
+ setTeamMembers ( members ) ;
83
+ } ) ( ) ;
84
+ } , [ teams ] ) ;
85
+
68
86
useEffect ( ( ) => {
69
87
if ( selectedTeamOrUser && selectedRepo ) {
70
88
createProject ( selectedTeamOrUser , selectedRepo ) ;
@@ -91,7 +109,7 @@ export default function NewProject() {
91
109
} , [ selectedAccount ] ) ;
92
110
93
111
useEffect ( ( ) => {
94
- if ( ! provider || isBitbucket ( ) ) {
112
+ if ( ! provider || isBitbucket ( ) ) {
95
113
return ;
96
114
}
97
115
( async ( ) => {
@@ -101,7 +119,7 @@ export default function NewProject() {
101
119
} , [ provider ] ) ;
102
120
103
121
const isGitHub = ( ) => provider === "github.com" ;
104
- const isBitbucket = ( ) => provider == "bitbucket.org" ;
122
+ const isBitbucket = ( ) => provider === "bitbucket.org" ;
105
123
106
124
const updateReposInAccounts = async ( installationId ?: string ) => {
107
125
setLoaded ( false ) ;
@@ -163,7 +181,7 @@ export default function NewProject() {
163
181
}
164
182
165
183
const createProject = async ( teamOrUser : Team | User , selectedRepo : string ) => {
166
- if ( ! provider || isBitbucket ( ) ) {
184
+ if ( ! provider || isBitbucket ( ) ) {
167
185
return ;
168
186
}
169
187
const repo = reposInAccounts . find ( r => r . account === selectedAccount && ( r . path ? r . path === selectedRepo : r . name === selectedRepo ) ) ;
@@ -243,6 +261,7 @@ export default function NewProject() {
243
261
const showSearchInput = ! ! repoSearchFilter || filteredRepos . length > 0 ;
244
262
245
263
const renderRepos = ( ) => ( < >
264
+ { ! isBitbucket ( ) && < p className = "text-gray-500 text-center text-base" > Select a Git repository on < strong > { provider } </ strong > . (< a className = "gp-link cursor-pointer" onClick = { ( ) => setShowGitProviders ( true ) } > change</ a > )</ p > }
246
265
< div className = { `mt-10 border rounded-xl border-gray-100 dark:border-gray-800 flex-col` } >
247
266
< div className = "px-8 pt-8 flex flex-col space-y-2" data-analytics = '{"label":"Identity"}' >
248
267
< ContextMenu classes = "w-full left-0 cursor-pointer" menuEntries = { getDropDownEntries ( accounts ) } >
@@ -357,39 +376,42 @@ export default function NewProject() {
357
376
const userFullName = user ?. fullName || user ?. name || '...' ;
358
377
const teamsToRender = teams || [ ] ;
359
378
return ( < >
360
- < h3 className = "pb-2 mt-8" > Select Team</ h3 >
361
- < h4 className = "pb-2" > Adding < strong > { selectedRepo } </ strong > </ h4 >
362
-
363
- < div className = "mt-8 border rounded-xl border-gray-100 dark:border-gray-800 flex-col" >
364
- < div key = { `user-${ userFullName } ` } className = { `w-96 border-b px-8 py-4 flex space-x-2 justify-between dark:hover:bg-gray-800 focus:bg-gitpod-kumquat-light transition ease-in-out group dark:border-gray-800 rounded-t-xl` } >
365
- < div className = "w-8/12 m-auto overflow-ellipsis truncate" > { userFullName } </ div >
366
- < div className = "w-4/12 flex justify-end" >
367
- < div className = "flex self-center hover:bg-gray-200 dark:hover:bg-gray-700 rounded-md cursor-pointer opacity-0 group-hover:opacity-100" >
368
- < button className = "primary py-1" onClick = { ( ) => setSelectedTeamOrUser ( user ) } > Select</ button >
369
- </ div >
379
+ < p className = "mt-2 text-gray-500 text-center text-base" > Select team or personal account</ p >
380
+ < div className = "mt-14 flex flex-col space-y-2" >
381
+ < label key = { `user-${ userFullName } ` } className = { `w-80 px-4 py-3 flex space-x-3 items-center cursor-pointer rounded-xl hover:bg-gray-100 dark:hover:bg-gray-800` } onClick = { ( ) => setSelectedTeamOrUser ( user ) } >
382
+ < input type = "radio" />
383
+ < div className = "flex-grow overflow-ellipsis truncate flex flex-col" >
384
+ < span className = "font-semibold" > { userFullName } </ span >
385
+ < span className = "text-sm text-gray-400" > Personal account</ span >
370
386
</ div >
371
- </ div >
387
+ </ label >
372
388
{ teamsToRender . map ( ( t ) => (
373
- < div key = { `team-${ t . name } ` } className = { `w-96 border-b px-8 py-4 flex space-x-2 justify-between dark:hover:bg-gray-800 focus:bg-gitpod-kumquat-light transition ease-in-out group dark:border-gray-800` } >
374
- < div className = "w-8/12 m-auto overflow-ellipsis truncate" > { t . name } </ div >
375
- < div className = "w-4/12 flex justify-end" >
376
- < div className = "flex self-center hover:bg-gray-200 dark:hover:bg-gray-700 rounded-md cursor-pointer opacity-0 group-hover:opacity-100" >
377
- < button className = "primary py-1" onClick = { ( ) => setSelectedTeamOrUser ( t ) } > Select</ button >
378
- </ div >
389
+ < label key = { `team-${ t . name } ` } className = { `w-80 px-4 py-3 flex space-x-3 items-center cursor-pointer rounded-xl hover:bg-gray-100 dark:hover:bg-gray-800` } onClick = { ( ) => setSelectedTeamOrUser ( t ) } >
390
+ < input type = "radio" />
391
+ < div className = "flex-grow overflow-ellipsis truncate flex flex-col" >
392
+ < span className = "font-semibold" > { t . name } </ span >
393
+ < span className = "text-sm text-gray-400" > { ! ! teamMembers [ t . id ]
394
+ ? `${ teamMembers [ t . id ] . length } member${ teamMembers [ t . id ] . length === 1 ? '' : 's' } `
395
+ : 'Team'
396
+ } </ span >
379
397
</ div >
380
- </ div >
398
+ </ label >
381
399
) ) }
382
- < div className = "w-96 py-4 px-8 flex text-gray-500" >
383
- < div className = "w-full relative" onClick = { ( ) => setShowNewTeam ( ! showNewTeam ) } >
384
- < div className = "space-x-2" > New Team</ div >
400
+ < label className = "w-80 px-4 py-3 flex flex-col cursor-pointer rounded-xl hover:bg-gray-100 dark:hover:bg-gray-800" >
401
+ < div className = "flex space-x-3 items-center relative" >
402
+ < input type = "radio" onChange = { ( ) => setShowNewTeam ( ! showNewTeam ) } />
403
+ < div className = "flex-grow overflow-ellipsis truncate flex flex-col" >
404
+ < span className = "font-semibold" > Create new team</ span >
405
+ < span className = "text-sm text-gray-400" > Collaborate with others</ span >
406
+ </ div >
385
407
{ teamsToRender . length > 0 && (
386
- < img src = { CaretDown } title = "Select Account" className = { `${ showNewTeam ? "transform rotate-180" : "" } filter-grayscale absolute top-1/2 right-3 cursor-pointer` } />
408
+ < img alt = "" src = { CaretDown } title = "Select Account" className = { `${ showNewTeam ? "transform rotate-180" : "" } filter-grayscale absolute top-1/2 right-3 cursor-pointer` } />
387
409
) }
388
410
</ div >
389
- </ div >
390
- { ( showNewTeam || teamsToRender . length === 0 ) && (
391
- < NewTeam className = "w-96 px-8 pb-8" onSuccess = { ( t ) => setSelectedTeamOrUser ( t ) } />
392
- ) }
411
+ { ( showNewTeam || teamsToRender . length === 0 ) && (
412
+ < NewTeam onSuccess = { ( t ) => setSelectedTeamOrUser ( t ) } />
413
+ ) }
414
+ </ label >
393
415
</ div >
394
416
</ > )
395
417
} ;
@@ -406,15 +428,9 @@ export default function NewProject() {
406
428
</ div > ) ;
407
429
}
408
430
409
- const renderSelectRepoHeading = ( ) => {
410
- return < p className = "text-gray-500 text-center text-base" > Select a Git repository on < strong > { provider } </ strong > . (< a className = "gp-link cursor-pointer" onClick = { ( ) => setShowGitProviders ( true ) } > change</ a > )</ p >
411
- }
412
-
413
431
return ( < div className = "flex flex-col w-96 mt-24 mx-auto items-center" >
414
432
< h1 > New Project</ h1 >
415
433
416
- { isBitbucket ( ) || renderSelectRepoHeading ( ) }
417
-
418
434
{ ! selectedRepo && renderSelectRepository ( ) }
419
435
420
436
{ selectedRepo && ! selectedTeamOrUser && renderSelectTeam ( ) }
@@ -504,7 +520,6 @@ function GitProviders(props: {
504
520
505
521
function NewTeam ( props : {
506
522
onSuccess : ( team : Team ) => void ,
507
- className ?: string ,
508
523
} ) {
509
524
const { setTeams } = useContext ( TeamsContext ) ;
510
525
@@ -530,15 +545,13 @@ function NewTeam(props: {
530
545
setError ( undefined ) ;
531
546
}
532
547
533
- return (
534
- < div className = { props . className } >
535
- < div className = "flex flex-row space-x-2" >
536
- < input type = "text" className = "py-1 flex-grow w-36" name = "new-team-inline" value = { teamName } placeholder = "team-name" onChange = { ( e ) => onTeamNameChanged ( e . target . value ) } />
537
- < button key = { `new-team-inline-create` } disabled = { ! teamName } onClick = { ( ) => onNewTeam ( ) } > Create Team</ button >
538
- </ div >
539
- { error && < p className = "text-gitpod-red" > { error } </ p > }
548
+ return < >
549
+ < div className = "mt-6 mb-1 flex flex-row space-x-2" >
550
+ < input type = "text" className = "py-1 min-w-0" name = "new-team-inline" value = { teamName } onChange = { ( e ) => onTeamNameChanged ( e . target . value ) } />
551
+ < button key = { `new-team-inline-create` } disabled = { ! teamName } onClick = { ( ) => onNewTeam ( ) } > Continue</ button >
540
552
</ div >
541
- )
553
+ { error && < p className = "text-gitpod-red" > { error } </ p > }
554
+ </ > ;
542
555
}
543
556
544
557
async function openReconfigureWindow ( params : { account ?: string , onSuccess : ( p : any ) => void } ) {
0 commit comments