1- import type { QuickInputButton } from 'vscode' ;
1+ import type { QuickInputButton , QuickPick } from 'vscode' ;
22import { ThemeIcon , Uri } from 'vscode' ;
33import type {
4+ AsyncStepResultGenerator ,
45 PartialStepState ,
56 StepGenerator ,
67 StepResultGenerator ,
@@ -11,10 +12,12 @@ import {
1112 canPickStepContinue ,
1213 createPickStep ,
1314 endSteps ,
15+ freezeStep ,
1416 QuickCommand ,
1517 StepResultBreak ,
1618} from '../../commands/quickCommand' ;
1719import { proBadge } from '../../constants' ;
20+ import type { IntegrationId } from '../../constants.integrations' ;
1821import { HostingIntegrationId } from '../../constants.integrations' ;
1922import type { Container } from '../../container' ;
2023import type { SearchedIssue } from '../../git/models/issue' ;
@@ -23,6 +26,7 @@ import { createQuickPickItemOfT, createQuickPickSeparator } from '../../quickpic
2326import type { DirectiveQuickPickItem } from '../../quickpicks/items/directive' ;
2427import { createDirectiveQuickPickItem , Directive } from '../../quickpicks/items/directive' ;
2528import { fromNow } from '../../system/date' ;
29+ import { some } from '../../system/iterable' ;
2630
2731export type StartWorkItem = {
2832 item : SearchedIssue ;
@@ -38,6 +42,7 @@ export type StartWorkResult = { items: StartWorkItem[] };
3842interface Context {
3943 result : StartWorkResult ;
4044 title : string ;
45+ connectedIntegrations : Map < IntegrationId , boolean > ;
4146}
4247
4348interface State {
@@ -60,6 +65,8 @@ function assertsStartWorkStepState(state: StepState<State>): asserts state is St
6065 throw new Error ( 'Missing item' ) ;
6166}
6267
68+ export const supportedStartWorkIntegrations = [ HostingIntegrationId . GitHub ] ;
69+
6370export class StartWorkCommand extends QuickCommand < State > {
6471 constructor ( container : Container ) {
6572 super ( container , 'startWork' , 'startWork' , `Start Work\u00a0\u00a0${ proBadge } ` , {
@@ -79,11 +86,20 @@ export class StartWorkCommand extends QuickCommand<State> {
7986 const context : Context = {
8087 result : { items : [ ] } ,
8188 title : this . title ,
89+ connectedIntegrations : await this . getConnectedIntegrations ( ) ,
8290 } ;
8391
8492 while ( this . canStepsContinue ( state ) ) {
8593 context . title = this . title ;
8694
95+ const hasConnectedIntegrations = [ ...context . connectedIntegrations . values ( ) ] . some ( c => c ) ;
96+ if ( ! hasConnectedIntegrations ) {
97+ const result = yield * this . confirmCloudIntegrationsConnectStep ( state , context ) ;
98+ if ( result === StepResultBreak ) {
99+ return result ;
100+ }
101+ }
102+
87103 await updateContextItems ( this . container , context ) ;
88104
89105 if ( state . counter < 1 || state . item == null ) {
@@ -115,6 +131,65 @@ export class StartWorkCommand extends QuickCommand<State> {
115131 return state . counter < 0 ? StepResultBreak : undefined ;
116132 }
117133
134+ private async * confirmCloudIntegrationsConnectStep (
135+ state : StepState < State > ,
136+ context : Context ,
137+ ) : AsyncStepResultGenerator < { connected : boolean | IntegrationId ; resume : ( ) => void } > {
138+ // TODO: This step is almost an exact copy of the similar one from launchpad.ts. Do we want to do anything about it? Maybe to move it to an util function with ability to parameterize labels?
139+ const hasConnectedIntegration = some ( context . connectedIntegrations . values ( ) , c => c ) ;
140+ const step = this . createConfirmStep (
141+ `${ this . title } \u00a0\u2022\u00a0 Connect an ${ hasConnectedIntegration ? 'Additional ' : '' } Integration` ,
142+ [
143+ createQuickPickItemOfT (
144+ {
145+ label : `Connect an ${ hasConnectedIntegration ? 'Additional ' : '' } Integration...` ,
146+ detail : hasConnectedIntegration
147+ ? 'Connect additional integrations to view their issues in Start Work'
148+ : 'Connect an integration to accelerate your work' ,
149+ picked : true ,
150+ } ,
151+ true ,
152+ ) ,
153+ ] ,
154+ createDirectiveQuickPickItem ( Directive . Cancel , false , { label : 'Cancel' } ) ,
155+ {
156+ placeholder : hasConnectedIntegration
157+ ? 'Connect additional integrations to Start Work'
158+ : 'Connect an integration to get started with Start Work' ,
159+ buttons : [ ] ,
160+ ignoreFocusOut : true ,
161+ } ,
162+ ) ;
163+
164+ // Note: This is a hack to allow the quickpick to stay alive after the user finishes connecting the integration.
165+ // Otherwise it disappears.
166+ let freeze ! : ( ) => Disposable ;
167+ let quickpick ! : QuickPick < any > ;
168+ step . onDidActivate = qp => {
169+ quickpick = qp ;
170+ freeze = ( ) => freezeStep ( step , qp ) ;
171+ } ;
172+
173+ const selection : StepSelection < typeof step > = yield step ;
174+
175+ if ( canPickStepContinue ( step , state , selection ) ) {
176+ const previousPlaceholder = quickpick . placeholder ;
177+ quickpick . placeholder = 'Connecting integrations...' ;
178+ quickpick . ignoreFocusOut = true ;
179+ const resume = freeze ( ) ;
180+ const connected = await this . container . integrations . connectCloudIntegrations (
181+ { integrationIds : supportedStartWorkIntegrations } ,
182+ {
183+ source : 'startWork' ,
184+ } ,
185+ ) ;
186+ quickpick . placeholder = previousPlaceholder ;
187+ return { connected : connected , resume : ( ) => resume [ Symbol . dispose ] ( ) } ;
188+ }
189+
190+ return StepResultBreak ;
191+ }
192+
118193 private * pickIssueStep ( state : StepState < State > , context : Context ) : StepResultGenerator < StartWorkItem > {
119194 const buildIssueItem = ( i : StartWorkItem ) => {
120195 const buttons = [ StartWorkQuickInputButton ] ;
@@ -229,6 +304,18 @@ export class StartWorkCommand extends QuickCommand<State> {
229304 const selection : StepSelection < typeof step > = yield step ;
230305 return canPickStepContinue ( step , state , selection ) ? selection [ 0 ] . item : StepResultBreak ;
231306 }
307+
308+ private async getConnectedIntegrations ( ) : Promise < Map < IntegrationId , boolean > > {
309+ const connected = new Map < IntegrationId , boolean > ( ) ;
310+ await Promise . allSettled (
311+ supportedStartWorkIntegrations . map ( async integrationId => {
312+ const integration = await this . container . integrations . get ( integrationId ) ;
313+ connected . set ( integrationId , integration . maybeConnected ?? ( await integration . isConnected ( ) ) ) ;
314+ } ) ,
315+ ) ;
316+
317+ return connected ;
318+ }
232319}
233320
234321async function updateContextItems ( container : Container , context : Context ) {
0 commit comments