@@ -14,6 +14,9 @@ import type {
14
14
GraphRepository ,
15
15
State ,
16
16
} from '../../../../plus/webviews/graph/protocol' ;
17
+ import type { Subscription } from '../../../../subscription' ;
18
+ import { SubscriptionState } from '../../../../subscription' ;
19
+ import { fromNow } from '../../shared/date' ;
17
20
18
21
export interface GraphWrapperProps extends State {
19
22
nonce ?: string ;
@@ -114,6 +117,8 @@ export function GraphWrapper({
114
117
repositories = [ ] ,
115
118
rows = [ ] ,
116
119
selectedRepository,
120
+ subscription,
121
+ allowed,
117
122
config,
118
123
paging,
119
124
onSelectRepository,
@@ -139,7 +144,12 @@ export function GraphWrapper({
139
144
const [ mainWidth , setMainWidth ] = useState < number > ( ) ;
140
145
const [ mainHeight , setMainHeight ] = useState < number > ( ) ;
141
146
const mainRef = useRef < HTMLElement > ( null ) ;
142
- const [ showBanner , setShowBanner ] = useState ( previewBanner ) ;
147
+ // banner
148
+ const [ showPreview , setShowPreview ] = useState ( previewBanner ) ;
149
+ // account
150
+ const [ showAccount , setShowAccount ] = useState ( true ) ;
151
+ const [ isAllowed , setIsAllowed ] = useState ( allowed ?? false ) ;
152
+ const [ subscriptionSnapshot , setSubscriptionSnapshot ] = useState < Subscription | undefined > ( subscription ) ;
143
153
// repo selection UI
144
154
const [ repoExpanded , setRepoExpanded ] = useState ( false ) ;
145
155
@@ -173,6 +183,8 @@ export function GraphWrapper({
173
183
setPagingState ( state . paging ) ;
174
184
setIsLoading ( false ) ;
175
185
setStyleProps ( getStyleProps ( state . mixedColumnColors ) ) ;
186
+ setIsAllowed ( state . allowed ?? false ) ;
187
+ setSubscriptionSnapshot ( state . subscription ) ;
176
188
}
177
189
178
190
useEffect ( ( ) => {
@@ -207,15 +219,135 @@ export function GraphWrapper({
207
219
onSelectionChange ?.( graphRows . map ( r => r . sha ) ) ;
208
220
} ;
209
221
210
- const handleDismissBanner = ( ) => {
211
- setShowBanner ( false ) ;
222
+ const handleDismissPreview = ( ) => {
223
+ setShowPreview ( false ) ;
212
224
onDismissPreview ?.( ) ;
213
225
} ;
214
226
227
+ const handleDismissAccount = ( ) => {
228
+ setShowAccount ( false ) ;
229
+ } ;
230
+
231
+ const renderAlertContent = ( ) => {
232
+ if ( subscriptionSnapshot == null ) return ;
233
+
234
+ let icon = 'account' ;
235
+ let modifier = '' ;
236
+ let content ;
237
+ let actions ;
238
+ switch ( subscriptionSnapshot . state ) {
239
+ case SubscriptionState . Free :
240
+ case SubscriptionState . Paid :
241
+ return ;
242
+ case SubscriptionState . FreeInPreview :
243
+ icon = 'calendar' ;
244
+ modifier = 'neutral' ;
245
+ content = (
246
+ < >
247
+ < p className = "alert__title" > Trial Preview</ p >
248
+ < p className = "alert__message" >
249
+ You're able to view the Commit Graph with any repository until your preview expires
250
+ { subscriptionSnapshot . previewTrial
251
+ ? ` ${ fromNow ( new Date ( subscriptionSnapshot . previewTrial . expiresOn ) ) } `
252
+ : '' }
253
+ .
254
+ </ p >
255
+ </ >
256
+ ) ;
257
+ break ;
258
+ case SubscriptionState . FreePreviewExpired :
259
+ icon = 'warning' ;
260
+ modifier = 'warning' ;
261
+ content = (
262
+ < >
263
+ < p className = "alert__title" > Extend Your Trial</ p >
264
+ < p className = "alert__message" > Sign in to extend your free trial an additional 7-days.</ p >
265
+ </ >
266
+ ) ;
267
+ actions = (
268
+ < >
269
+ < a className = "alert-action" href = "command:gitlens.plus.loginOrSignUp" >
270
+ Try for 7-days
271
+ </ a > { ' ' }
272
+ < a className = "alert-action" href = "command:gitlens.plus.purchase" >
273
+ View Plans
274
+ </ a >
275
+ </ >
276
+ ) ;
277
+ break ;
278
+ case SubscriptionState . FreePlusInTrial :
279
+ icon = 'calendar' ;
280
+ modifier = 'neutral' ;
281
+ content = (
282
+ < >
283
+ < p className = "alert__title" > Extended Trial</ p >
284
+ < p className = "alert__message" >
285
+ You're able to view the Commit Graph with any repository until your trial expires
286
+ { subscriptionSnapshot . previewTrial
287
+ ? ` ${ fromNow ( new Date ( subscriptionSnapshot . previewTrial . expiresOn ) ) } `
288
+ : '' }
289
+ .
290
+ </ p >
291
+ </ >
292
+ ) ;
293
+ break ;
294
+ case SubscriptionState . FreePlusTrialExpired :
295
+ icon = 'warning' ;
296
+ modifier = 'warning' ;
297
+ content = (
298
+ < >
299
+ < p className = "alert__title" > Trial Expired</ p >
300
+ < p className = "alert__message" >
301
+ Upgrade your account to use the Commit Graph and other GitLens+ features on private repos.
302
+ </ p >
303
+ < p >
304
+ < a className = "alert-action" href = "command:gitlens.plus.purchase" >
305
+ Upgrade Your Account
306
+ </ a >
307
+ </ p >
308
+ </ >
309
+ ) ;
310
+ break ;
311
+ case SubscriptionState . VerificationRequired :
312
+ icon = 'unverified' ;
313
+ modifier = 'warning' ;
314
+ content = (
315
+ < >
316
+ < p className = "alert__title" > Please verify your email</ p >
317
+ < p className = "alert__message" > Please verify the email for the account you created.</ p >
318
+ </ >
319
+ ) ;
320
+ actions = (
321
+ < >
322
+ < a className = "alert-action" href = "command:gitlens.plus.resendVerification" >
323
+ Resend Verification Email
324
+ </ a >
325
+ < a className = "alert-action" href = "command:gitlens.plus.validate" >
326
+ Refresh Verification Status
327
+ </ a >
328
+ </ >
329
+ ) ;
330
+ break ;
331
+ }
332
+
333
+ return (
334
+ < div className = { `alert${ modifier !== '' ? ` alert--${ modifier } ` : '' } ` } >
335
+ < span className = { `alert__icon codicon codicon-${ icon } ` } > </ span >
336
+ < div className = "alert__content" > { content } </ div >
337
+ { actions && < div className = "alert__actions" > { actions } </ div > }
338
+ { isAllowed && (
339
+ < button className = "alert__dismiss" type = "button" onClick = { ( ) => handleDismissAccount ( ) } >
340
+ < span className = "codicon codicon-chrome-close" > </ span >
341
+ </ button >
342
+ ) }
343
+ </ div >
344
+ ) ;
345
+ } ;
346
+
215
347
return (
216
348
< >
217
- { showBanner && (
218
- < section className = "graph-app__banner" >
349
+ < section className = "graph-app__banners" >
350
+ { showPreview && (
219
351
< div className = "alert" >
220
352
< span className = "alert__icon codicon codicon-search" > </ span >
221
353
< div className = "alert__content" >
@@ -230,13 +362,20 @@ export function GraphWrapper({
230
362
.
231
363
</ p >
232
364
</ div >
233
- < button className = "alert__action " type = "button" onClick = { ( ) => handleDismissBanner ( ) } >
365
+ < button className = "alert__dismiss " type = "button" onClick = { ( ) => handleDismissPreview ( ) } >
234
366
< span className = "codicon codicon-chrome-close" > </ span >
235
367
</ button >
236
368
</ div >
237
- </ section >
238
- ) }
239
- < main ref = { mainRef } id = "main" className = "graph-app__main" >
369
+ ) }
370
+ { showAccount && renderAlertContent ( ) }
371
+ </ section >
372
+ < main
373
+ ref = { mainRef }
374
+ id = "main"
375
+ className = { `graph-app__main${ ! isAllowed ? ' is-gated' : '' } ` }
376
+ aria-hidden = { ! isAllowed }
377
+ >
378
+ { ! isAllowed && < div className = "graph-app__cover" > </ div > }
240
379
{ currentRepository !== undefined ? (
241
380
< >
242
381
{ mainWidth !== undefined && mainHeight !== undefined && (
@@ -263,7 +402,7 @@ export function GraphWrapper({
263
402
< p > No repository is selected</ p >
264
403
) }
265
404
</ main >
266
- < footer className = " actionbar graph-app__footer" >
405
+ < footer className = { ` actionbar graph-app__footer${ ! isAllowed ? ' is-gated' : '' } ` } aria-hidden = { ! isAllowed } >
267
406
< div className = "actionbar__group" >
268
407
< div className = "actioncombo" >
269
408
< button
@@ -321,7 +460,7 @@ export function GraphWrapper({
321
460
) }
322
461
</ div >
323
462
</ div >
324
- { graphList . length > 0 && (
463
+ { isAllowed && graphList . length > 0 && (
325
464
< span className = "actionbar__details" >
326
465
showing { graphList . length } item{ graphList . length ? 's' : '' }
327
466
</ span >
0 commit comments