11import { consume } from '@lit/context' ;
2- import type { TemplateResult } from 'lit' ;
32import { html , LitElement , nothing } from 'lit' ;
43import { customElement , property } from 'lit/decorators.js' ;
54import { ifDefined } from 'lit/directives/if-defined.js' ;
65import { pluralize } from '@gitlens/utils/string.js' ;
7- import type { ConnectCloudIntegrationsCommandArgs } from '../../../../../commands/cloudIntegrations.js' ;
8- import type { LaunchpadCommandArgs } from '../../../../../plus/launchpad/launchpad.js' ;
96import type { LaunchpadSummaryResult } from '../../../../../plus/launchpad/launchpadIndicator.js' ;
10- import { createCommandLink } from '../../../../../system/commands.js' ;
117import type { GitBranchShape , Wip } from '../../../../plus/graph/detailsProtocol.js' ;
128import type { BranchMergeTargetStatus } from '../../../../rpc/services/branches.js' ;
139import type { BranchRef } from '../../../../shared/branchRefs.js' ;
@@ -18,7 +14,7 @@ import { detailsWipEmptyPaneStyles } from './gl-details-wip-empty-pane.css.js';
1814import '../../../shared/components/button.js' ;
1915import '../../../shared/components/button-container.js' ;
2016import '../../../shared/components/code-icon.js' ;
21- import '../../../shared/components/skeleton-loader .js' ;
17+ import './gl-launchpad-summary .js' ;
2218
2319type NextStepAction = {
2420 actionLabel : string ;
@@ -100,7 +96,7 @@ export class GlDetailsWipEmptyPane extends LitElement {
10096
10197 // Launchpad renders from initial mount (when `showLaunchpad`) — the summary content is
10298 // branch-agnostic (PRs across the user's connected integrations) and the inner
103- // `renderLaunchpadSummary ` handles its own loading/empty/unconnected states with a
99+ // `gl-launchpad-summary ` handles its own loading/empty/unconnected states with a
104100 // stable footprint. Gating on `branch != null` here would cause the section to pop into
105101 // existence the moment WIP arrived, shifting `Start New` down — the very layout flip
106102 // this scaffold was reshaped to avoid.
@@ -131,7 +127,11 @@ export class GlDetailsWipEmptyPane extends LitElement {
131127 < code-icon icon ="refresh "> </ code-icon >
132128 </ gl-button >
133129 </ header >
134- ${ this . renderLaunchpadSummary ( ) }
130+ < gl-launchpad-summary
131+ .summary =${ this . launchpadSummary }
132+ ?has-integrations-connected =${ this . hasIntegrationsConnected }
133+ source="graph-details"
134+ > </ gl-launchpad-summary >
135135 </ section > ` ;
136136 }
137137
@@ -267,195 +267,6 @@ export class GlDetailsWipEmptyPane extends LitElement {
267267 </ section > ` ;
268268 }
269269
270- private renderLaunchpadSummary ( ) : TemplateResult {
271- if ( ! this . hasIntegrationsConnected ) {
272- return html `< ul class ="launchpad-items ">
273- < li >
274- < a
275- class ="launchpad-item launchpad-item--link "
276- href =${ createCommandLink < ConnectCloudIntegrationsCommandArgs > (
277- 'gitlens.plus.cloudIntegrations.connect' ,
278- { source : { source : 'graph' } } ,
279- ) }
280- >
281- < code-icon class ="launchpad-item__icon " icon ="plug "> </ code-icon >
282- < span > Connect to see PRs here</ span >
283- </ a >
284- </ li >
285- </ ul > ` ;
286- }
287-
288- const summary = this . launchpadSummary ;
289- if ( summary == null ) {
290- // Single skeleton line matches the most common landed content — "You are all caught
291- // up!" or a single group summary. Two lines was nearly always over-tall, causing a
292- // downward shift when content landed.
293- return html `< div class ="launchpad-items launchpad-items--loading ">
294- < skeleton-loader lines ="1 "> </ skeleton-loader >
295- </ div > ` ;
296- }
297-
298- if ( ! ( 'total' in summary ) ) {
299- return html `< ul class ="launchpad-items ">
300- < li class ="launchpad-item launchpad-item--muted "> Unable to load items</ li >
301- </ ul > ` ;
302- }
303-
304- const items : TemplateResult [ ] = [ ] ;
305-
306- if ( summary . error != null ) {
307- items . push (
308- html `< li >
309- < span class ="launchpad-item launchpad-item--muted ">
310- < code-icon class ="launchpad-item__icon " icon ="warning "> </ code-icon >
311- < span > Some integrations failed to load</ span >
312- </ span >
313- </ li > ` ,
314- ) ;
315- }
316-
317- if ( summary . total === 0 ) {
318- items . push ( html `< li class ="launchpad-item launchpad-item--muted "> You are all caught up!</ li > ` ) ;
319- return html `< ul class ="launchpad-items ">
320- ${ items }
321- </ ul > ` ;
322- }
323-
324- if ( ! summary . hasGroupedItems ) {
325- items . push (
326- html `< li class ="launchpad-item launchpad-item--muted "> No pull requests need your attention</ li >
327- < li class ="launchpad-item launchpad-item--muted "> (${ summary . total } other pull requests)</ li > ` ,
328- ) ;
329- return html `< ul class ="launchpad-items ">
330- ${ items }
331- </ ul > ` ;
332- }
333-
334- for ( const group of summary . groups ) {
335- switch ( group ) {
336- case 'mergeable' : {
337- const total = summary . mergeable ?. total ?? 0 ;
338- if ( total === 0 ) continue ;
339-
340- items . push (
341- html `< li >
342- < a
343- class ="launchpad-item launchpad-item--link launchpad-item--mergeable "
344- href =${ this . createShowLaunchpadLink ( 'mergeable' ) }
345- >
346- < code-icon class ="launchpad-item__icon " icon ="rocket "> </ code-icon >
347- < span > ${ pluralize ( 'pull request' , total ) } can be merged</ span >
348- </ a >
349- </ li > ` ,
350- ) ;
351- break ;
352- }
353- case 'blocked' : {
354- const total = summary . blocked ?. total ?? 0 ;
355- if ( total === 0 ) continue ;
356-
357- const messages : { count : number ; message : string } [ ] = [ ] ;
358- if ( summary . blocked ! . unassignedReviewers ) {
359- messages . push ( {
360- count : summary . blocked ! . unassignedReviewers ,
361- message : `${ summary . blocked ! . unassignedReviewers > 1 ? 'need' : 'needs' } reviewers` ,
362- } ) ;
363- }
364- if ( summary . blocked ! . failedChecks ) {
365- messages . push ( {
366- count : summary . blocked ! . failedChecks ,
367- message : `${ summary . blocked ! . failedChecks > 1 ? 'have' : 'has' } failed CI checks` ,
368- } ) ;
369- }
370- if ( summary . blocked ! . conflicts ) {
371- messages . push ( {
372- count : summary . blocked ! . conflicts ,
373- message : `${ summary . blocked ! . conflicts > 1 ? 'have' : 'has' } conflicts` ,
374- } ) ;
375- }
376-
377- const href = this . createShowLaunchpadLink ( 'blocked' ) ;
378- if ( messages . length === 1 ) {
379- items . push (
380- html `< li >
381- < a class ="launchpad-item launchpad-item--link launchpad-item--blocked " href =${ href } >
382- < code-icon class ="launchpad-item__icon " icon ="error "> </ code-icon >
383- < span > ${ pluralize ( 'pull request' , total ) } ${ messages [ 0 ] . message } </ span >
384- </ a >
385- </ li > ` ,
386- ) ;
387- } else {
388- items . push (
389- html `< li >
390- < a class ="launchpad-item launchpad-item--link launchpad-item--blocked " href =${ href } >
391- < code-icon class ="launchpad-item__icon " icon ="error "> </ code-icon >
392- < span
393- > ${ pluralize ( 'pull request' , total ) } ${ total > 1 ? 'are' : 'is' } blocked
394- (${ messages . map ( m => `${ m . count } ${ m . message } ` ) . join ( ', ' ) } )</ span
395- >
396- </ a >
397- </ li > ` ,
398- ) ;
399- }
400- break ;
401- }
402- case 'follow-up' : {
403- const total = summary . followUp ?. total ?? 0 ;
404- if ( total === 0 ) continue ;
405-
406- items . push (
407- html `< li >
408- < a
409- class ="launchpad-item launchpad-item--link launchpad-item--attention "
410- href =${ this . createShowLaunchpadLink ( 'follow-up' ) }
411- >
412- < code-icon class ="launchpad-item__icon " icon ="report "> </ code-icon >
413- < span
414- > ${ pluralize ( 'pull request' , total ) } ${ total > 1 ? 'require' : 'requires' }
415- follow-up</ span
416- >
417- </ a >
418- </ li > ` ,
419- ) ;
420- break ;
421- }
422- case 'needs-review' : {
423- const total = summary . needsReview ?. total ?? 0 ;
424- if ( total === 0 ) continue ;
425-
426- items . push (
427- html `< li >
428- < a
429- class ="launchpad-item launchpad-item--link launchpad-item--attention "
430- href =${ this . createShowLaunchpadLink ( 'needs-review' ) }
431- >
432- < code-icon class ="launchpad-item__icon " icon ="comment-unresolved "> </ code-icon >
433- < span
434- > ${ pluralize ( 'pull request' , total ) } ${ total > 1 ? 'need' : 'needs' } your
435- review</ span
436- >
437- </ a >
438- </ li > ` ,
439- ) ;
440- break ;
441- }
442- }
443- }
444-
445- return html `< ul class ="launchpad-items ">
446- ${ items }
447- </ ul > ` ;
448- }
449-
450- private createShowLaunchpadLink ( group : NonNullable < LaunchpadCommandArgs [ 'state' ] > [ 'initialGroup' ] ) : string {
451- return `command:gitlens.showLaunchpad?${ encodeURIComponent (
452- JSON . stringify ( {
453- source : 'graph-details' ,
454- state : { initialGroup : group } ,
455- } satisfies Omit < LaunchpadCommandArgs , 'command' > ) ,
456- ) } `;
457- }
458-
459270 private computeNextSteps ( branch : GitBranchShape ) : NextStep [ ] {
460271 const ahead = branch . tracking ?. ahead ?? 0 ;
461272 const behind = branch . tracking ?. behind ?? 0 ;
0 commit comments