1+ import type { QuickPick } from 'vscode' ;
12import { Uri } from 'vscode' ;
23import type {
4+ AsyncStepResultGenerator ,
35 PartialStepState ,
46 StepGenerator ,
57 StepResultGenerator ,
@@ -10,16 +12,20 @@ import {
1012 canPickStepContinue ,
1113 createPickStep ,
1214 endSteps ,
15+ freezeStep ,
1316 QuickCommand ,
1417 StepResultBreak ,
1518} from '../../commands/quickCommand' ;
1619import { proBadge } from '../../constants' ;
20+ import type { IntegrationId } from '../../constants.integrations' ;
1721import { HostingIntegrationId } from '../../constants.integrations' ;
1822import type { Container } from '../../container' ;
1923import type { SearchedIssue } from '../../git/models/issue' ;
2024import type { QuickPickItemOfT } from '../../quickpicks/items/common' ;
25+ import { createQuickPickItemOfT } from '../../quickpicks/items/common' ;
2126import { createDirectiveQuickPickItem , Directive } from '../../quickpicks/items/directive' ;
2227import { fromNow } from '../../system/date' ;
28+ import { some } from '../../system/iterable' ;
2329
2430export type StartWorkItem = {
2531 item : SearchedIssue ;
@@ -30,6 +36,7 @@ export type StartWorkResult = { items: StartWorkItem[] };
3036interface Context {
3137 result : StartWorkResult ;
3238 title : string ;
39+ connectedIntegrations : Map < IntegrationId , boolean > ;
3340}
3441
3542interface State {
@@ -52,6 +59,8 @@ function assertsStartWorkStepState(state: StepState<State>): asserts state is St
5259 throw new Error ( 'Missing item' ) ;
5360}
5461
62+ export const supportedStartWorkIntegrations = [ HostingIntegrationId . GitHub ] ;
63+
5564export class StartWorkCommand extends QuickCommand < State > {
5665 constructor ( container : Container ) {
5766 super ( container , 'startWork' , 'startWork' , `Start Work\u00a0\u00a0${ proBadge } ` , {
@@ -71,11 +80,20 @@ export class StartWorkCommand extends QuickCommand<State> {
7180 const context : Context = {
7281 result : { items : [ ] } ,
7382 title : this . title ,
83+ connectedIntegrations : await this . getConnectedIntegrations ( ) ,
7484 } ;
7585
7686 while ( this . canStepsContinue ( state ) ) {
7787 context . title = this . title ;
7888
89+ const hasConnectedIntegrations = [ ...context . connectedIntegrations . values ( ) ] . some ( c => c ) ;
90+ if ( ! hasConnectedIntegrations ) {
91+ const result = yield * this . confirmCloudIntegrationsConnectStep ( state , context ) ;
92+ if ( result === StepResultBreak ) {
93+ return result ;
94+ }
95+ }
96+
7997 await updateContextItems ( this . container , context ) ;
8098
8199 if ( state . counter < 1 || state . item == null ) {
@@ -101,6 +119,65 @@ export class StartWorkCommand extends QuickCommand<State> {
101119 return state . counter < 0 ? StepResultBreak : undefined ;
102120 }
103121
122+ private async * confirmCloudIntegrationsConnectStep (
123+ state : StepState < State > ,
124+ context : Context ,
125+ ) : AsyncStepResultGenerator < { connected : boolean | IntegrationId ; resume : ( ) => void } > {
126+ // 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?
127+ const hasConnectedIntegration = some ( context . connectedIntegrations . values ( ) , c => c ) ;
128+ const step = this . createConfirmStep (
129+ `${ this . title } \u00a0\u2022\u00a0 Connect an ${ hasConnectedIntegration ? 'Additional ' : '' } Integration` ,
130+ [
131+ createQuickPickItemOfT (
132+ {
133+ label : `Connect an ${ hasConnectedIntegration ? 'Additional ' : '' } Integration...` ,
134+ detail : hasConnectedIntegration
135+ ? 'Connect additional integrations to view their issues in Start Work'
136+ : 'Connect an integration to accelerate your work' ,
137+ picked : true ,
138+ } ,
139+ true ,
140+ ) ,
141+ ] ,
142+ createDirectiveQuickPickItem ( Directive . Cancel , false , { label : 'Cancel' } ) ,
143+ {
144+ placeholder : hasConnectedIntegration
145+ ? 'Connect additional integrations to Start Work'
146+ : 'Connect an integration to get started with Start Work' ,
147+ buttons : [ ] ,
148+ ignoreFocusOut : true ,
149+ } ,
150+ ) ;
151+
152+ // Note: This is a hack to allow the quickpick to stay alive after the user finishes connecting the integration.
153+ // Otherwise it disappears.
154+ let freeze ! : ( ) => Disposable ;
155+ let quickpick ! : QuickPick < any > ;
156+ step . onDidActivate = qp => {
157+ quickpick = qp ;
158+ freeze = ( ) => freezeStep ( step , qp ) ;
159+ } ;
160+
161+ const selection : StepSelection < typeof step > = yield step ;
162+
163+ if ( canPickStepContinue ( step , state , selection ) ) {
164+ const previousPlaceholder = quickpick . placeholder ;
165+ quickpick . placeholder = 'Connecting integrations...' ;
166+ quickpick . ignoreFocusOut = true ;
167+ const resume = freeze ( ) ;
168+ const connected = await this . container . integrations . connectCloudIntegrations (
169+ { integrationIds : supportedStartWorkIntegrations } ,
170+ {
171+ source : 'startWork' ,
172+ } ,
173+ ) ;
174+ quickpick . placeholder = previousPlaceholder ;
175+ return { connected : connected , resume : ( ) => resume [ Symbol . dispose ] ( ) } ;
176+ }
177+
178+ return StepResultBreak ;
179+ }
180+
104181 private * pickIssueStep ( state : StepState < State > , context : Context ) : StepResultGenerator < StartWorkItem > {
105182 const buildIssueItem = ( i : StartWorkItem ) => {
106183 return {
@@ -158,6 +235,18 @@ export class StartWorkCommand extends QuickCommand<State> {
158235 const element = selection [ 0 ] ;
159236 return { ...element . item } ;
160237 }
238+
239+ private async getConnectedIntegrations ( ) : Promise < Map < IntegrationId , boolean > > {
240+ const connected = new Map < IntegrationId , boolean > ( ) ;
241+ await Promise . allSettled (
242+ supportedStartWorkIntegrations . map ( async integrationId => {
243+ const integration = await this . container . integrations . get ( integrationId ) ;
244+ connected . set ( integrationId , integration . maybeConnected ?? ( await integration . isConnected ( ) ) ) ;
245+ } ) ,
246+ ) ;
247+
248+ return connected ;
249+ }
161250}
162251
163252async function updateContextItems ( container : Container , context : Context ) {
0 commit comments