11import type { Event } from 'vscode' ;
22import { Disposable , EventEmitter } from 'vscode' ;
33import { Commands } from '../constants.commands' ;
4+ import { SubscriptionState } from '../constants.subscription' ;
45import type { TrackedUsageKeys } from '../constants.telemetry' ;
56import type { Container } from '../container' ;
7+ import type { SubscriptionChangeEvent } from '../plus/gk/account/subscriptionService' ;
68import { wait } from '../system/promise' ;
79import { setContext } from '../system/vscode/context' ;
810import type { UsageChangeEvent } from './usageTracker' ;
@@ -15,7 +17,23 @@ export enum WalkthroughContextKeys {
1517 Integrations = 'integrations' ,
1618}
1719
18- type WalkthroughUsage = { states : TrackedUsageKeys [ ] ; usage : TrackedUsageKeys [ ] } ;
20+ type WalkthroughUsage = {
21+ subscriptionStates ?: SubscriptionState [ ] | Readonly < SubscriptionState [ ] > ;
22+ subscriptionCommands ?: TrackedUsageKeys [ ] | Readonly < TrackedUsageKeys [ ] > ;
23+ usage : TrackedUsageKeys [ ] ;
24+ } ;
25+
26+ const triedProStates : Readonly < SubscriptionState [ ] > = [
27+ SubscriptionState . ProTrial ,
28+ SubscriptionState . ProTrialExpired ,
29+ SubscriptionState . ProTrialReactivationEligible ,
30+ SubscriptionState . Paid ,
31+ ] ;
32+
33+ const tryProCommands : Readonly < TrackedUsageKeys [ ] > = [
34+ `command:${ Commands . PlusStartPreviewTrial } :executed` ,
35+ `command:${ Commands . PlusReactivateProTrial } :executed` ,
36+ ] ;
1937
2038const walkthroughRequiredMapping : Readonly < Map < WalkthroughContextKeys , WalkthroughUsage > > = new Map <
2139 WalkthroughContextKeys ,
@@ -24,22 +42,16 @@ const walkthroughRequiredMapping: Readonly<Map<WalkthroughContextKeys, Walkthrou
2442 [
2543 WalkthroughContextKeys . GettingStarted ,
2644 {
27- states : [
28- `command:${ Commands . PlusStartPreviewTrial } :executed` ,
29- `command:${ Commands . PlusReactivateProTrial } :executed` ,
30- `command:${ Commands . OpenWalkthrough } :executed` ,
31- `command:${ Commands . GetStarted } :executed` ,
32- ] ,
45+ subscriptionStates : triedProStates ,
46+ subscriptionCommands : tryProCommands ,
3347 usage : [ ] ,
3448 } ,
3549 ] ,
3650 [
3751 WalkthroughContextKeys . VisualizeCodeHistory ,
3852 {
39- states : [
40- `command:${ Commands . PlusStartPreviewTrial } :executed` ,
41- `command:${ Commands . PlusReactivateProTrial } :executed` ,
42- ] ,
53+ subscriptionStates : triedProStates ,
54+ subscriptionCommands : tryProCommands ,
4355 usage : [
4456 'graphDetailsView:shown' ,
4557 'graphView:shown' ,
@@ -56,10 +68,8 @@ const walkthroughRequiredMapping: Readonly<Map<WalkthroughContextKeys, Walkthrou
5668 [
5769 WalkthroughContextKeys . PrReviews ,
5870 {
59- states : [
60- `command:${ Commands . PlusStartPreviewTrial } :executed` ,
61- `command:${ Commands . PlusReactivateProTrial } :executed` ,
62- ] ,
71+ subscriptionStates : triedProStates ,
72+ subscriptionCommands : tryProCommands ,
6373 usage : [
6474 'launchpadView:shown' ,
6575 'worktreesView:shown' ,
@@ -75,17 +85,14 @@ const walkthroughRequiredMapping: Readonly<Map<WalkthroughContextKeys, Walkthrou
7585 [
7686 WalkthroughContextKeys . StreamlineCollaboration ,
7787 {
78- states : [
79- `command:${ Commands . PlusStartPreviewTrial } :executed` ,
80- `command:${ Commands . PlusReactivateProTrial } :executed` ,
81- ] ,
88+ subscriptionStates : triedProStates ,
89+ subscriptionCommands : tryProCommands ,
8290 usage : [ `command:${ Commands . CreateCloudPatch } :executed` , `command:${ Commands . CreatePatch } :executed` ] ,
8391 } ,
8492 ] ,
8593 [
8694 WalkthroughContextKeys . Integrations ,
8795 {
88- states : [ ] ,
8996 usage : [
9097 `command:${ Commands . PlusConnectCloudIntegrations } :executed` ,
9198 `command:${ Commands . PlusManageCloudIntegrations } :executed` ,
@@ -95,23 +102,28 @@ const walkthroughRequiredMapping: Readonly<Map<WalkthroughContextKeys, Walkthrou
95102] ) ;
96103
97104export class WalkthroughStateProvider implements Disposable {
105+ readonly walkthroughSize = walkthroughRequiredMapping . size ;
98106 protected disposables : Disposable [ ] = [ ] ;
99107 private readonly completed = new Set < WalkthroughContextKeys > ( ) ;
100- readonly walkthroughSize : number ;
108+ private subscriptionState : SubscriptionState | undefined ;
101109
102110 private readonly _onProgressChanged = new EventEmitter < void > ( ) ;
103111 get onProgressChanged ( ) : Event < void > {
104112 return this . _onProgressChanged . event ;
105113 }
106114
107115 constructor ( private readonly container : Container ) {
108- this . disposables . push ( this . container . usage . onDidChange ( this . onUsageChanged , this ) ) ;
109- this . walkthroughSize = walkthroughRequiredMapping . size ;
116+ this . disposables . push (
117+ this . container . usage . onDidChange ( this . onUsageChanged , this ) ,
118+ this . container . subscription . onDidChange ( this . onSubscriptionChanged , this ) ,
119+ ) ;
110120
111- this . initializeState ( ) ;
121+ void this . initializeState ( ) ;
112122 }
113123
114- private initializeState ( ) {
124+ private async initializeState ( ) {
125+ this . subscriptionState = ( await this . container . subscription . getSubscription ( true ) ) . state ;
126+
115127 for ( const key of walkthroughRequiredMapping . keys ( ) ) {
116128 if ( this . validateStep ( key ) ) {
117129 void this . completeStep ( key ) ;
@@ -147,6 +159,29 @@ export class WalkthroughStateProvider implements Disposable {
147159 }
148160 }
149161
162+ private onSubscriptionChanged ( e : SubscriptionChangeEvent ) {
163+ this . subscriptionState = e . current . state ;
164+ const stepsToValidate = this . getStepsFromSubscriptionState ( e . current . state ) ;
165+ let shouldFire = false ;
166+ for ( const step of stepsToValidate ) {
167+ // no need to check if the step is already completed
168+ if ( this . completed . has ( step ) ) {
169+ continue ;
170+ }
171+
172+ if ( this . validateStep ( step ) ) {
173+ void this . completeStep ( step ) ;
174+ this . container . telemetry . sendEvent ( 'walkthrough/completion' , {
175+ 'context.key' : step ,
176+ } ) ;
177+ shouldFire = true ;
178+ }
179+ }
180+ if ( shouldFire ) {
181+ this . _onProgressChanged . fire ( undefined ) ;
182+ }
183+ }
184+
150185 private _isInitialized : boolean = false ;
151186 private _initPromise : Promise < void > | undefined ;
152187 /**
@@ -191,8 +226,19 @@ export class WalkthroughStateProvider implements Disposable {
191226
192227 private getStepsFromUsage ( usageKey : TrackedUsageKeys ) : WalkthroughContextKeys [ ] {
193228 const keys : WalkthroughContextKeys [ ] = [ ] ;
194- for ( const [ key , { states, usage : events } ] of walkthroughRequiredMapping ) {
195- if ( states . includes ( usageKey ) || events . includes ( usageKey ) ) {
229+ for ( const [ key , { subscriptionCommands, usage } ] of walkthroughRequiredMapping ) {
230+ if ( subscriptionCommands ?. includes ( usageKey ) || usage . includes ( usageKey ) ) {
231+ keys . push ( key ) ;
232+ }
233+ }
234+
235+ return keys ;
236+ }
237+
238+ private getStepsFromSubscriptionState ( _state : SubscriptionState ) : WalkthroughContextKeys [ ] {
239+ const keys : WalkthroughContextKeys [ ] = [ ] ;
240+ for ( const [ key , { subscriptionStates } ] of walkthroughRequiredMapping ) {
241+ if ( subscriptionStates != null ) {
196242 keys . push ( key ) ;
197243 }
198244 }
@@ -201,11 +247,24 @@ export class WalkthroughStateProvider implements Disposable {
201247 }
202248
203249 private validateStep ( key : WalkthroughContextKeys ) : boolean {
204- const { states, usage : events } = walkthroughRequiredMapping . get ( key ) ! ;
205- if ( states . length && ! states . some ( state => this . container . usage . isUsed ( state ) ) ) {
250+ const { subscriptionStates, subscriptionCommands, usage } = walkthroughRequiredMapping . get ( key ) ! ;
251+
252+ let subscriptionState : boolean | undefined ;
253+ if ( subscriptionStates != null && subscriptionStates . length > 0 ) {
254+ subscriptionState = this . subscriptionState != null && subscriptionStates . includes ( this . subscriptionState ) ;
255+ }
256+ let subscriptionCommandState : boolean | undefined ;
257+ if ( subscriptionCommands != null && subscriptionCommands . length > 0 ) {
258+ subscriptionCommandState = subscriptionCommands . some ( event => this . container . usage . isUsed ( event ) ) ;
259+ }
260+ if (
261+ ( subscriptionState === undefined && subscriptionCommandState === false ) ||
262+ ( subscriptionState === false && subscriptionCommandState !== true )
263+ ) {
206264 return false ;
207265 }
208- if ( events . length && ! events . some ( event => this . container . usage . isUsed ( event ) ) ) {
266+
267+ if ( usage . length > 0 && ! usage . some ( event => this . container . usage . isUsed ( event ) ) ) {
209268 return false ;
210269 }
211270 return true ;
0 commit comments