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,16 +12,20 @@ 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' ;
2124import type { QuickPickItemOfT } from '../../quickpicks/items/common' ;
25+ import { createQuickPickItemOfT } from '../../quickpicks/items/common' ;
2226import { createDirectiveQuickPickItem , Directive } from '../../quickpicks/items/directive' ;
2327import { fromNow } from '../../system/date' ;
28+ import { some } from '../../system/iterable' ;
2429
2530export type StartWorkItem = {
2631 item : SearchedIssue ;
@@ -36,6 +41,7 @@ export type StartWorkResult = { items: StartWorkItem[] };
3641interface Context {
3742 result : StartWorkResult ;
3843 title : string ;
44+ connectedIntegrations : Map < IntegrationId , boolean > ;
3945}
4046
4147interface State {
@@ -58,6 +64,8 @@ function assertsStartWorkStepState(state: StepState<State>): asserts state is St
5864 throw new Error ( 'Missing item' ) ;
5965}
6066
67+ export const supportedStartWorkIntegrations = [ HostingIntegrationId . GitHub ] ;
68+
6169export class StartWorkCommand extends QuickCommand < State > {
6270 constructor ( container : Container ) {
6371 super ( container , 'startWork' , 'startWork' , `Start Work\u00a0\u00a0${ proBadge } ` , {
@@ -77,11 +85,20 @@ export class StartWorkCommand extends QuickCommand<State> {
7785 const context : Context = {
7886 result : { items : [ ] } ,
7987 title : this . title ,
88+ connectedIntegrations : await this . getConnectedIntegrations ( ) ,
8089 } ;
8190
8291 while ( this . canStepsContinue ( state ) ) {
8392 context . title = this . title ;
8493
94+ const hasConnectedIntegrations = [ ...context . connectedIntegrations . values ( ) ] . some ( c => c ) ;
95+ if ( ! hasConnectedIntegrations ) {
96+ const result = yield * this . confirmCloudIntegrationsConnectStep ( state , context ) ;
97+ if ( result === StepResultBreak ) {
98+ return result ;
99+ }
100+ }
101+
85102 await updateContextItems ( this . container , context ) ;
86103
87104 if ( state . counter < 1 || state . item == null ) {
@@ -107,6 +124,65 @@ export class StartWorkCommand extends QuickCommand<State> {
107124 return state . counter < 0 ? StepResultBreak : undefined ;
108125 }
109126
127+ private async * confirmCloudIntegrationsConnectStep (
128+ state : StepState < State > ,
129+ context : Context ,
130+ ) : AsyncStepResultGenerator < { connected : boolean | IntegrationId ; resume : ( ) => void } > {
131+ // 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?
132+ const hasConnectedIntegration = some ( context . connectedIntegrations . values ( ) , c => c ) ;
133+ const step = this . createConfirmStep (
134+ `${ this . title } \u00a0\u2022\u00a0 Connect an ${ hasConnectedIntegration ? 'Additional ' : '' } Integration` ,
135+ [
136+ createQuickPickItemOfT (
137+ {
138+ label : `Connect an ${ hasConnectedIntegration ? 'Additional ' : '' } Integration...` ,
139+ detail : hasConnectedIntegration
140+ ? 'Connect additional integrations to view their issues in Start Work'
141+ : 'Connect an integration to accelerate your work' ,
142+ picked : true ,
143+ } ,
144+ true ,
145+ ) ,
146+ ] ,
147+ createDirectiveQuickPickItem ( Directive . Cancel , false , { label : 'Cancel' } ) ,
148+ {
149+ placeholder : hasConnectedIntegration
150+ ? 'Connect additional integrations to Start Work'
151+ : 'Connect an integration to get started with Start Work' ,
152+ buttons : [ ] ,
153+ ignoreFocusOut : true ,
154+ } ,
155+ ) ;
156+
157+ // Note: This is a hack to allow the quickpick to stay alive after the user finishes connecting the integration.
158+ // Otherwise it disappears.
159+ let freeze ! : ( ) => Disposable ;
160+ let quickpick ! : QuickPick < any > ;
161+ step . onDidActivate = qp => {
162+ quickpick = qp ;
163+ freeze = ( ) => freezeStep ( step , qp ) ;
164+ } ;
165+
166+ const selection : StepSelection < typeof step > = yield step ;
167+
168+ if ( canPickStepContinue ( step , state , selection ) ) {
169+ const previousPlaceholder = quickpick . placeholder ;
170+ quickpick . placeholder = 'Connecting integrations...' ;
171+ quickpick . ignoreFocusOut = true ;
172+ const resume = freeze ( ) ;
173+ const connected = await this . container . integrations . connectCloudIntegrations (
174+ { integrationIds : supportedStartWorkIntegrations } ,
175+ {
176+ source : 'startWork' ,
177+ } ,
178+ ) ;
179+ quickpick . placeholder = previousPlaceholder ;
180+ return { connected : connected , resume : ( ) => resume [ Symbol . dispose ] ( ) } ;
181+ }
182+
183+ return StepResultBreak ;
184+ }
185+
110186 private * pickIssueStep ( state : StepState < State > , context : Context ) : StepResultGenerator < StartWorkItem > {
111187 const buildIssueItem = ( i : StartWorkItem ) => {
112188 const buttons = [ StartWorkQuickInputButton ] ;
@@ -171,6 +247,18 @@ export class StartWorkCommand extends QuickCommand<State> {
171247 const element = selection [ 0 ] ;
172248 return { ...element . item } ;
173249 }
250+
251+ private async getConnectedIntegrations ( ) : Promise < Map < IntegrationId , boolean > > {
252+ const connected = new Map < IntegrationId , boolean > ( ) ;
253+ await Promise . allSettled (
254+ supportedStartWorkIntegrations . map ( async integrationId => {
255+ const integration = await this . container . integrations . get ( integrationId ) ;
256+ connected . set ( integrationId , integration . maybeConnected ?? ( await integration . isConnected ( ) ) ) ;
257+ } ) ,
258+ ) ;
259+
260+ return connected ;
261+ }
174262}
175263
176264async function updateContextItems ( container : Container , context : Context ) {
0 commit comments