1+ import  {  md5  }  from  '@env/crypto' ; 
12import  slug  from  'slug' ; 
23import  type  {  QuickPick  }  from  'vscode' ; 
34import  {  Uri  }  from  'vscode' ; 
@@ -52,11 +53,12 @@ interface Context {
5253
5354interface  State  { 
5455	item ?: StartWorkItem ; 
55- 	action ?: StartWorkAction ; 
56+ 	type ?: StartWorkType ; 
5657	inWorktree ?: boolean ; 
5758} 
5859
59- export  type  StartWorkAction  =  'start' ; 
60+ export  type  StartWorkType  =  'branch'  |  'branch-worktree'  |  'issue'  |  'issue-worktree' ; 
61+ type  StartWorkTypeItem  =  {  type : StartWorkType ;  inWorktree ?: boolean  } ; 
6062
6163export  interface  StartWorkCommandArgs  { 
6264	readonly  command : 'startWork' ; 
@@ -99,30 +101,57 @@ export class StartWorkCommand extends QuickCommand<State> {
99101			connectedIntegrations : await  this . getConnectedIntegrations ( ) , 
100102		} ; 
101103
102- 		const  opened  =  false ; 
104+ 		let  opened  =  false ; 
103105		while  ( this . canStepsContinue ( state ) )  { 
106+ 			const  hasConnectedIntegrations  =  [ ...context . connectedIntegrations . values ( ) ] . some ( c  =>  c ) ; 
104107			context . title  =  this . title ; 
105108
106109			if  ( state . counter  <  1 )  { 
107- 				const  result  =  yield *  this . selectCommandStep ( state ) ; 
110+ 				if  ( this . container . telemetry . enabled )  { 
111+ 					this . container . telemetry . sendEvent ( 
112+ 						opened  ? 'startWork/steps/type'  : 'startWork/opened' , 
113+ 						{ 
114+ 							...context . telemetryContext ! , 
115+ 							connected : hasConnectedIntegrations , 
116+ 						} , 
117+ 						this . source , 
118+ 					) ; 
119+ 				} 
120+ 
121+ 				opened  =  true ; 
122+ 				const  result  =  yield *  this . selectTypeStep ( state ) ; 
108123				if  ( result  ===  StepResultBreak )  continue ; 
109- 				state . action  =  result . action ; 
124+ 				state . type  =  result . type ; 
110125				state . inWorktree  =  result . inWorktree ; 
126+ 				if  ( this . container . telemetry . enabled )  { 
127+ 					this . container . telemetry . sendEvent ( 
128+ 						'startWork/type/chosen' , 
129+ 						{ 
130+ 							...context . telemetryContext ! , 
131+ 							connected : hasConnectedIntegrations , 
132+ 							type : state . type , 
133+ 						} , 
134+ 						this . source , 
135+ 					) ; 
136+ 				} 
111137			} 
112138
113- 			if  ( state . counter  <  2  &&  ! state . action )  { 
114- 				const  hasConnectedIntegrations  =  [ ...context . connectedIntegrations . values ( ) ] . some ( c  =>  c ) ; 
139+ 			if  ( ( state . counter  <  2  &&  state . type  ===  'issue' )  ||  state . type  ===  'issue-worktree' )  { 
115140				if  ( ! hasConnectedIntegrations )  { 
116141					if  ( this . container . telemetry . enabled )  { 
117142						this . container . telemetry . sendEvent ( 
118143							opened  ? 'startWork/steps/connect'  : 'startWork/opened' , 
119144							{ 
120145								...context . telemetryContext ! , 
121146								connected : false , 
147+ 								type : state . type , 
122148							} , 
123149							this . source , 
124150						) ; 
125151					} 
152+ 
153+ 					opened  =  true ; 
154+ 
126155					const  isUsingCloudIntegrations  =  configuration . get ( 'cloudIntegrations.enabled' ,  undefined ,  false ) ; 
127156					const  result  =  isUsingCloudIntegrations 
128157						? yield *  this . confirmCloudIntegrationsConnectStep ( state ,  context ) 
@@ -133,67 +162,99 @@ export class StartWorkCommand extends QuickCommand<State> {
133162				} 
134163
135164				await  updateContextItems ( this . container ,  context ) ; 
165+ 				if  ( this . container . telemetry . enabled )  { 
166+ 					this . container . telemetry . sendEvent ( 
167+ 						opened  ? 'startWork/steps/issue'  : 'startWork/opened' , 
168+ 						{ 
169+ 							...context . telemetryContext ! , 
170+ 							connected : true , 
171+ 							type : state . type , 
172+ 						} , 
173+ 						this . source , 
174+ 					) ; 
175+ 				} 
176+ 
177+ 				opened  =  true ; 
178+ 
136179				const  result  =  yield *  this . pickIssueStep ( state ,  context ) ; 
137180				if  ( result  ===  StepResultBreak )  continue ; 
138- 				if  ( typeof   result   !==   'string' )  { 
181+ 				if  ( ! isStartWorkTypeItem ( result ) )  { 
139182					state . item  =  result ; 
140- 					state . action  =  'start' ; 
183+ 					if  ( this . container . telemetry . enabled )  { 
184+ 						this . container . telemetry . sendEvent ( 
185+ 							'startWork/issue/chosen' , 
186+ 							{ 
187+ 								...context . telemetryContext ! , 
188+ 								connected : true , 
189+ 								type : state . type , 
190+ 								'item.id' : getStartWorkItemIdHash ( result ) , 
191+ 								'item.type' : result . item . issue . type , 
192+ 								'item.provider' : result . item . issue . provider . id , 
193+ 								'item.assignees.count' : result . item . issue . assignees ?. length  ??  undefined , 
194+ 								'item.createdDate' : result . item . issue . createdDate . getTime ( ) , 
195+ 								'item.updatedDate' : result . item . issue . updatedDate . getTime ( ) , 
196+ 
197+ 								'item.comments.count' : result . item . issue . commentsCount  ??  undefined , 
198+ 								'item.upvotes.count' : result . item . issue . thumbsUpCount  ??  undefined , 
199+ 
200+ 								'item.issue.state' : result . item . issue . state , 
201+ 							} , 
202+ 							this . source , 
203+ 						) ; 
204+ 					} 
141205				}  else  { 
142- 					state . action  =  result ; 
206+ 					state . type  =  result . type ; 
207+ 					state . inWorktree  =  result . inWorktree ; 
143208				} 
144209			} 
145210
146211			const  issue  =  state . item ?. item ?. issue ; 
147212			const  repo  =  issue  &&  ( await  this . getIssueRepositoryIfExists ( issue ) ) ; 
148213
149- 			if  ( typeof  state . action  ===  'string' )  { 
150- 				switch  ( state . action )  { 
151- 					case  'start' : { 
152- 						const  result  =  yield *  getSteps ( 
153- 							this . container , 
154- 							{ 
155- 								command : 'branch' , 
156- 								state : { 
157- 									subcommand : 'create' , 
158- 									repo : repo , 
159- 									name : issue 
160- 										? `${ slug ( issue . id ,  {  lower : false  } ) } ${ slug ( issue . title ) }  
161- 										: undefined , 
162- 									suggestNameOnly : true , 
163- 									suggestRepoOnly : true , 
164- 									flags : state . inWorktree  ? [ '--worktree' ]  : [ '--switch' ] , 
165- 								} , 
166- 								confirm : false , 
167- 							} , 
168- 							this . pickedVia , 
169- 						) ; 
170- 						if  ( result  ===  StepResultBreak )  { 
171- 							endSteps ( state ) ; 
172- 						}  else  { 
173- 							state . counter -- ; 
174- 							state . action  =  undefined ; 
175- 						} 
176- 						break ; 
177- 					} 
178- 				} 
214+ 			const  result  =  yield *  getSteps ( 
215+ 				this . container , 
216+ 				{ 
217+ 					command : 'branch' , 
218+ 					state : { 
219+ 						subcommand : 'create' , 
220+ 						repo : repo , 
221+ 						name : issue  ? `${ slug ( issue . id ,  {  lower : false  } ) } ${ slug ( issue . title ) }   : undefined , 
222+ 						suggestNameOnly : true , 
223+ 						suggestRepoOnly : true , 
224+ 						flags : state . inWorktree  ? [ '--worktree' ]  : [ '--switch' ] , 
225+ 					} , 
226+ 					confirm : false , 
227+ 				} , 
228+ 				this . pickedVia , 
229+ 			) ; 
230+ 			if  ( result  ===  StepResultBreak )  { 
231+ 				endSteps ( state ) ; 
232+ 			}  else  { 
233+ 				state . counter -- ; 
179234			} 
180235		} 
181236
182237		return  state . counter  <  0  ? StepResultBreak  : undefined ; 
183238	} 
184239
185- 	private  * selectCommandStep ( 
240+ 	private  * selectTypeStep ( 
186241		state : StepState < State > , 
187- 	) : StepResultGenerator < {  action ?:  StartWorkAction ;  inWorktree ?: boolean  } >  { 
242+ 	) : StepResultGenerator < {  type :  StartWorkType ;  inWorktree ?: boolean  } >  { 
188243		const  step  =  createPickStep ( { 
189244			placeholder : 'Start work by creating a new branch' , 
190245			items : [ 
191- 				createQuickPickItemOfT ( 'Create a Branch' ,  { 
192- 					action : 'start' , 
246+ 				createQuickPickItemOfT < StartWorkTypeItem > ( 'Create a Branch' ,  { 
247+ 					type : 'branch' , 
248+ 				} ) , 
249+ 				createQuickPickItemOfT < StartWorkTypeItem > ( 'Create a Branch in a Worktree' ,  { 
250+ 					type : 'branch-worktree' , 
251+ 					inWorktree : true , 
252+ 				} ) , 
253+ 				createQuickPickItemOfT < StartWorkTypeItem > ( 'Create a Branch from an Issue' ,  {  type : 'issue'  } ) , 
254+ 				createQuickPickItemOfT < StartWorkTypeItem > ( 'Create a Branch from an Issue in a Worktree' ,  { 
255+ 					type : 'issue-worktree' , 
256+ 					inWorktree : true , 
193257				} ) , 
194- 				createQuickPickItemOfT ( 'Create a Branch in a Worktree' ,  {  action : 'start' ,  inWorktree : true  } ) , 
195- 				createQuickPickItemOfT ( 'Create a Branch from an Issue' ,  { } ) , 
196- 				createQuickPickItemOfT ( 'Create a Branch from an Issue in a Worktree' ,  {  inWorktree : true  } ) , 
197258			] , 
198259		} ) ; 
199260		const  selection : StepSelection < typeof  step >  =  yield  step ; 
@@ -336,7 +397,7 @@ export class StartWorkCommand extends QuickCommand<State> {
336397	private  * pickIssueStep ( 
337398		state : StepState < State > , 
338399		context : Context , 
339- 	) : StepResultGenerator < StartWorkItem  |  StartWorkAction >  { 
400+ 	) : StepResultGenerator < StartWorkItem  |  StartWorkTypeItem >  { 
340401		const  buildIssueItem  =  ( i : StartWorkItem )  =>  { 
341402			const  buttons  =  i . item . issue . url  ? [ OpenOnGitHubQuickInputButton ]  : [ ] ; 
342403			return  { 
@@ -366,15 +427,15 @@ export class StartWorkCommand extends QuickCommand<State> {
366427
367428		function  getItemsAndPlaceholder ( ) : { 
368429			placeholder : string ; 
369- 			items : QuickPickItemOfT < StartWorkItem  |  StartWorkAction > [ ] ; 
430+ 			items : QuickPickItemOfT < StartWorkItem  |  StartWorkTypeItem > [ ] ; 
370431		}  { 
371432			if  ( ! context . result . items . length )  { 
372433				return  { 
373434					placeholder : 'No issues found. Start work anyway.' , 
374435					items : [ 
375- 						createQuickPickItemOfT ( 
436+ 						createQuickPickItemOfT < StartWorkTypeItem > ( 
376437							state . inWorktree  ? 'Create a branch on a worktree'  : 'Create a branch' , 
377- 							'start' , 
438+ 							{   type :  state . inWorktree  ?  'branch-worktree'  :  'branch' ,   inWorktree :  state . inWorktree   } , 
378439						) , 
379440					] , 
380441				} ; 
@@ -395,7 +456,7 @@ export class StartWorkCommand extends QuickCommand<State> {
395456			matchOnDetail : true , 
396457			items : items , 
397458			onDidClickItemButton : ( _quickpick ,  button ,  {  item } )  =>  { 
398- 				if  ( button  ===  OpenOnGitHubQuickInputButton  &&  typeof   item   !==   'string' )  { 
459+ 				if  ( button  ===  OpenOnGitHubQuickInputButton  &&  ! isStartWorkTypeItem ( item ) )  { 
399460					this . open ( item ) ; 
400461					return  true ; 
401462				} 
@@ -411,13 +472,6 @@ export class StartWorkCommand extends QuickCommand<State> {
411472		return  typeof  element . item  ===  'string'  ? element . item  : {  ...element . item  } ; 
412473	} 
413474
414- 	private  startWork ( state : PartialStepState < State > ,  item ?: StartWorkItem )  { 
415- 		state . action  =  'start' ; 
416- 		if  ( item  !=  null )  { 
417- 			state . item  =  item ; 
418- 		} 
419- 	} 
420- 
421475	private  open ( item : StartWorkItem ) : void { 
422476		if  ( item . item . issue . url  ==  null )  return ; 
423477		void  openUrl ( item . item . issue . url ) ; 
@@ -451,4 +505,22 @@ async function updateContextItems(container: Container, context: Context) {
451505				} ) , 
452506			)  ??  [ ] , 
453507	} ; 
508+ 	if  ( container . telemetry . enabled )  { 
509+ 		updateTelemetryContext ( context ) ; 
510+ 	} 
511+ } 
512+ 
513+ function  updateTelemetryContext ( context : Context )  { 
514+ 	context . telemetryContext  =  { 
515+ 		...context . telemetryContext ! , 
516+ 		'items.count' : context . result . items . length , 
517+ 	} ; 
518+ } 
519+ 
520+ function  isStartWorkTypeItem ( item : unknown ) : item  is StartWorkTypeItem  { 
521+ 	return  item  !=  null  &&  typeof  item  ===  'object'  &&  'type'  in  item ; 
522+ } 
523+ 
524+ export  function  getStartWorkItemIdHash ( item : StartWorkItem )  { 
525+ 	return  md5 ( item . item . issue . id ) ; 
454526} 
0 commit comments