diff --git a/docs/telemetry-events.md b/docs/telemetry-events.md index c6f11625b639d..220b68bd5423b 100644 --- a/docs/telemetry-events.md +++ b/docs/telemetry-events.md @@ -3335,7 +3335,8 @@ or ```typescript { - 'step': 'welcome-in-trial' | 'welcome-paid' | 'welcome-in-trial-expired-eligible' | 'welcome-in-trial-expired' | 'get-started-community' | 'visualize-code-history' | 'accelerate-pr-reviews' | 'streamline-collaboration' | 'improve-workflows-with-integrations' + 'step': 'welcome-in-trial' | 'welcome-paid' | 'welcome-in-trial-expired-eligible' | 'welcome-in-trial-expired' | 'get-started-community' | 'visualize-code-history' | 'accelerate-pr-reviews' | 'streamline-collaboration' | 'improve-workflows-with-integrations', + 'usingFallbackUrl': boolean } ``` diff --git a/src/commands/quickCommand.steps.ts b/src/commands/quickCommand.steps.ts index 7ce4de1942eaa..b392e457f7062 100644 --- a/src/commands/quickCommand.steps.ts +++ b/src/commands/quickCommand.steps.ts @@ -118,7 +118,6 @@ import { first, map } from '../system/iterable'; import { Logger } from '../system/logger'; import { getSettledValue } from '../system/promise'; import { pad, pluralize, truncate } from '../system/string'; -import { isWalkthroughSupported } from '../telemetry/walkthroughStateProvider'; import type { ViewsWithRepositoryFolders } from '../views/viewBase'; import type { AsyncStepResultGenerator, @@ -2712,23 +2711,21 @@ export async function* ensureAccessStep< switch (feature) { case 'launchpad': - if (isWalkthroughSupported()) { - directives.splice( - 0, - 0, - createDirectiveQuickPickItem(Directive.Cancel, undefined, { - label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked', - detail: 'Click to learn more about Launchpad', - iconPath: new ThemeIcon('rocket'), - onDidSelect: () => - void executeCommand('gitlens.openWalkthrough', { - step: 'accelerate-pr-reviews', - source: { source: 'launchpad', detail: 'info' }, - }), - }), - createQuickPickSeparator(), - ); - } + directives.splice( + 0, + 0, + createDirectiveQuickPickItem(Directive.Cancel, undefined, { + label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked', + detail: 'Click to learn more about Launchpad', + iconPath: new ThemeIcon('rocket'), + onDidSelect: () => + void executeCommand('gitlens.openWalkthrough', { + step: 'accelerate-pr-reviews', + source: { source: 'launchpad', detail: 'info' }, + }), + }), + createQuickPickSeparator(), + ); break; case 'startWork': directives.splice( diff --git a/src/commands/walkthroughs.ts b/src/commands/walkthroughs.ts index 4744d9f297847..bb852ce3faab0 100644 --- a/src/commands/walkthroughs.ts +++ b/src/commands/walkthroughs.ts @@ -1,13 +1,14 @@ import type { WalkthroughSteps } from '../constants'; import { urls } from '../constants'; import type { GlCommands } from '../constants.commands'; -import type { Source, Sources } from '../constants.telemetry'; +import type { Source, Sources, TelemetryEvents } from '../constants.telemetry'; import type { Container } from '../container'; import type { SubscriptionUpgradeCommandArgs } from '../plus/gk/models/subscription'; import type { LaunchpadCommandArgs } from '../plus/launchpad/launchpad'; import { command, executeCommand, executeCoreCommand } from '../system/-webview/command'; import { openWalkthrough as openWalkthroughCore } from '../system/-webview/vscode'; import { openUrl } from '../system/-webview/vscode/uris'; +import { isWalkthroughSupported } from '../telemetry/walkthroughStateProvider'; import type { ConnectCloudIntegrationsCommandArgs } from './cloudIntegrations'; import { GlCommandBase } from './commandBase'; import type { WorktreeGitCommandArgs } from './git/worktree'; @@ -42,9 +43,33 @@ export class OpenWalkthroughCommand extends GlCommandBase { } } +const helpCenterWalkthroughUrls = new Map([ + ['default', urls.getStarted], + ['welcome-in-trial', urls.welcomeInTrial], + ['welcome-paid', urls.welcomePaid], + ['welcome-in-trial-expired-eligible', urls.welcomeTrialReactivationEligible], + ['welcome-in-trial-expired', urls.welcomeTrialExpired], + ['get-started-community', urls.getStarted], + ['visualize-code-history', urls.interactiveCodeHistory], + ['accelerate-pr-reviews', urls.acceleratePrReviews], + ['streamline-collaboration', urls.streamlineCollaboration], + ['improve-workflows-with-integrations', urls.startIntegrations], +]); + function openWalkthrough(container: Container, args?: OpenWalkthroughCommandArgs) { + const walkthroughSupported = isWalkthroughSupported(); if (container.telemetry.enabled) { - container.telemetry.sendEvent('walkthrough', { step: args?.step }, args?.source); + const walkthroughEvent: TelemetryEvents['walkthrough'] = { step: args?.step }; + if (!walkthroughSupported) { + walkthroughEvent.usingFallbackUrl = true; + } + container.telemetry.sendEvent('walkthrough', walkthroughEvent, args?.source); + } + + if (!walkthroughSupported) { + const url = helpCenterWalkthroughUrls.get(args?.step ?? 'default')!; + void openUrl(url); + return; } void openWalkthroughCore(container.context.extension.id, 'welcome', args?.step, false); diff --git a/src/constants.context.ts b/src/constants.context.ts index 9783a7ae70114..b3ad26096b1b9 100644 --- a/src/constants.context.ts +++ b/src/constants.context.ts @@ -2,11 +2,11 @@ import type { Uri } from 'vscode'; import type { AnnotationStatus, Keys } from './constants'; import type { SubscriptionState } from './constants.subscription'; import type { CustomEditorTypes, GroupableTreeViewTypes, WebviewTypes, WebviewViewTypes } from './constants.views'; +import type { WalkthroughContextKeys } from './constants.walkthroughs'; import type { Features } from './features'; import type { OrgAIProviders } from './plus/gk/models/organization'; import type { PromoKeys } from './plus/gk/models/promo'; import type { SubscriptionPlanIds } from './plus/gk/models/subscription'; -import type { WalkthroughContextKeys } from './telemetry/walkthroughStateProvider'; export type ContextKeys = { 'gitlens:debugging': boolean; diff --git a/src/constants.telemetry.ts b/src/constants.telemetry.ts index 400e295b4f84c..437aa0ff07627 100644 --- a/src/constants.telemetry.ts +++ b/src/constants.telemetry.ts @@ -5,12 +5,12 @@ import type { GlCommands, GlCommandsDeprecated } from './constants.commands'; import type { IntegrationIds, SupportedCloudIntegrationIds } from './constants.integrations'; import type { SubscriptionState } from './constants.subscription'; import type { CustomEditorTypes, TreeViewTypes, WebviewTypes, WebviewViewTypes } from './constants.views'; +import type { WalkthroughContextKeys } from './constants.walkthroughs'; import type { FeaturePreviews, FeaturePreviewStatus } from './features'; import type { GitContributionTiers } from './git/models/contributor'; import type { AIActionType } from './plus/ai/models/model'; import type { Subscription, SubscriptionAccount, SubscriptionStateString } from './plus/gk/models/subscription'; import type { Flatten } from './system/object'; -import type { WalkthroughContextKeys } from './telemetry/walkthroughStateProvider'; import type { GraphColumnConfig } from './webviews/plus/graph/protocol'; import type { TimelinePeriod, TimelineScopeType, TimelineSliceBy } from './webviews/plus/timeline/protocol'; @@ -1079,6 +1079,7 @@ interface UsageTrackEvent { interface WalkthroughEvent { step?: WalkthroughSteps; + usingFallbackUrl?: boolean; } type WalkthroughActionNames = diff --git a/src/constants.ts b/src/constants.ts index cc44edc3cc2d1..32a21fe73663c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -188,6 +188,12 @@ export const urls = Object.freeze({ startIntegrations: `https://help.gitkraken.com/gitlens/gitlens-start-here/?${utm}#improve-workflows-with-integrations`, streamlineCollaboration: `https://help.gitkraken.com/gitlens/gitlens-start-here/?${utm}#streamline-collaboration`, aiFeatures: `https://help.gitkraken.com/gitlens/gl-gk-ai/?${utm}`, + + getStarted: `https://help.gitkraken.com/gitlens/gitlens-home/?${utm}`, + welcomeInTrial: `https://help.gitkraken.com/gitlens/gitlens-home/?${utm}`, + welcomePaid: `https://help.gitkraken.com/gitlens/gitlens-home/?${utm}`, + welcomeTrialExpired: `https://help.gitkraken.com/gitlens/gitlens-community-vs-gitlens-pro/?${utm}`, + welcomeTrialReactivationEligible: `https://help.gitkraken.com/gitlens/gitlens-community-vs-gitlens-pro/?${utm}`, }); export type WalkthroughSteps = diff --git a/src/constants.walkthroughs.ts b/src/constants.walkthroughs.ts new file mode 100644 index 0000000000000..4a7b967d79518 --- /dev/null +++ b/src/constants.walkthroughs.ts @@ -0,0 +1,18 @@ +export type WalkthroughContextKeys = + | 'gettingStarted' + | 'homeView' + | 'visualizeCodeHistory' + | 'prReviews' + | 'streamlineCollaboration' + | 'integrations' + | 'aiFeatures'; + +export const walkthroughProgressSteps: Record = { + gettingStarted: 'Getting Started', + homeView: 'Home View', + visualizeCodeHistory: 'Visualize Code History', + prReviews: 'PR Reviews', + streamlineCollaboration: 'Streamline Collaboration', + integrations: 'Integrations', + aiFeatures: 'AI Features', +}; diff --git a/src/container.ts b/src/container.ts index ea7a1cf95a80b..3b64e7905c390 100644 --- a/src/container.ts +++ b/src/container.ts @@ -60,7 +60,7 @@ import { Logger } from './system/logger'; import { AIFeedbackProvider } from './telemetry/aiFeedbackProvider'; import { TelemetryService } from './telemetry/telemetry'; import { UsageTracker } from './telemetry/usageTracker'; -import { isWalkthroughSupported, WalkthroughStateProvider } from './telemetry/walkthroughStateProvider'; +import { WalkthroughStateProvider } from './telemetry/walkthroughStateProvider'; import { GitTerminalLinkProvider } from './terminal/linkProvider'; import { GitDocumentTracker } from './trackers/documentTracker'; import { LineTracker } from './trackers/lineTracker'; @@ -207,9 +207,7 @@ export class Container { ); this._disposables.push((this._uri = new UriService(this))); this._disposables.push((this._subscription = new SubscriptionService(this, this._connection, previousVersion))); - if (isWalkthroughSupported()) { - this._disposables.push((this._walkthrough = new WalkthroughStateProvider(this))); - } + this._disposables.push((this._walkthrough = new WalkthroughStateProvider(this))); this._disposables.push((this._organizations = new OrganizationService(this, this._connection))); this._disposables.push((this._git = new GitProviderService(this))); @@ -729,8 +727,8 @@ export class Container { return this._usage; } - private readonly _walkthrough: WalkthroughStateProvider | undefined; - get walkthrough(): WalkthroughStateProvider | undefined { + private readonly _walkthrough: WalkthroughStateProvider; + get walkthrough(): WalkthroughStateProvider { return this._walkthrough; } diff --git a/src/plus/gk/subscriptionService.ts b/src/plus/gk/subscriptionService.ts index 3879798923e3f..f276d82af7769 100644 --- a/src/plus/gk/subscriptionService.ts +++ b/src/plus/gk/subscriptionService.ts @@ -62,7 +62,6 @@ import { flatten } from '../../system/object'; import { pauseOnCancelOrTimeout } from '../../system/promise'; import { pluralize } from '../../system/string'; import { createDisposable } from '../../system/unifiedDisposable'; -import { isWalkthroughSupported } from '../../telemetry/walkthroughStateProvider'; import { LoginUriPathPrefix } from './authenticationConnection'; import { authenticationProviderScopes } from './authenticationProvider'; import type { GKCheckInResponse } from './models/checkin'; @@ -486,13 +485,13 @@ export class SubscriptionService implements Disposable { void this.resendVerification(source); } } else if (isSubscriptionPaid(this._subscription)) { - const learn: MessageItem | undefined = isWalkthroughSupported() ? { title: 'Learn More' } : undefined; + const learn: MessageItem = { title: 'Learn More' }; const confirm: MessageItem = { title: 'Continue', isCloseAffordance: true }; const result = await window.showInformationMessage( `You are now on ${actual.name} and have full access to all GitLens Pro features.`, { modal: true }, confirm, - ...(learn ? [learn] : []), + learn, ); if (result === learn) { @@ -501,7 +500,7 @@ export class SubscriptionService implements Disposable { } else if (isSubscriptionTrial(this._subscription)) { const days = getSubscriptionTimeRemaining(this._subscription, 'days') ?? 0; - const learn: MessageItem | undefined = isWalkthroughSupported() ? { title: 'Learn More' } : undefined; + const learn: MessageItem = { title: 'Learn More' }; const confirm: MessageItem = { title: 'Continue', isCloseAffordance: true }; const result = await window.showInformationMessage( `Welcome to your ${effective.name} Trial.\n\nYou now have full access to all GitLens Pro features for ${ @@ -512,7 +511,7 @@ export class SubscriptionService implements Disposable { detail: 'Your trial also includes access to the GitKraken DevEx platform, unleashing powerful Git visualization & productivity capabilities everywhere you work: IDE, desktop, browser, and terminal.', }, confirm, - ...(learn ? [learn] : []), + learn, ); if (result === learn) { @@ -520,9 +519,7 @@ export class SubscriptionService implements Disposable { } } else { const upgrade: MessageItem = { title: 'Upgrade to Pro' }; - const learn: MessageItem | undefined = isWalkthroughSupported() - ? { title: 'Community vs. Pro' } - : undefined; + const learn: MessageItem = { title: 'Community vs. Pro' }; const confirm: MessageItem = { title: 'Continue', isCloseAffordance: true }; const result = await window.showInformationMessage( `You are now on ${actual.name}.`, @@ -531,7 +528,7 @@ export class SubscriptionService implements Disposable { detail: 'You only have access to Pro features on publicly-hosted repos. For full access to all Pro features, please upgrade to GitLens Pro.', }, upgrade, - ...(learn ? [learn] : []), + learn, confirm, ); diff --git a/src/plus/launchpad/launchpad.ts b/src/plus/launchpad/launchpad.ts index 47e369158b359..e623efa428164 100644 --- a/src/plus/launchpad/launchpad.ts +++ b/src/plus/launchpad/launchpad.ts @@ -53,7 +53,6 @@ import { getScopedCounter } from '../../system/counter'; import { fromNow } from '../../system/date'; import { some } from '../../system/iterable'; import { interpolate, pluralize } from '../../system/string'; -import { isWalkthroughSupported } from '../../telemetry/walkthroughStateProvider'; import { ProviderBuildStatusState, ProviderPullRequestReviewState } from '../integrations/providers/models'; import type { LaunchpadCategorizedResult, LaunchpadItem } from './launchpadProvider'; import { @@ -1178,22 +1177,21 @@ export class LaunchpadCommand extends QuickCommand { context: Context, ): AsyncStepResultGenerator<{ connected: boolean | IntegrationIds; resume: () => void | undefined }> { const hasConnectedIntegration = some(context.connectedIntegrations.values(), c => c); - const confirmations: (QuickPickItemOfT | DirectiveQuickPickItem)[] = - !hasConnectedIntegration && isWalkthroughSupported() - ? [ - createDirectiveQuickPickItem(Directive.Cancel, undefined, { - label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked', - detail: 'Click to learn more about Launchpad', - iconPath: new ThemeIcon('rocket'), - onDidSelect: () => - void executeCommand('gitlens.openWalkthrough', { - step: 'accelerate-pr-reviews', - source: { source: 'launchpad', detail: 'info' }, - }), - }), - createQuickPickSeparator(), - ] - : []; + const confirmations: (QuickPickItemOfT | DirectiveQuickPickItem)[] = !hasConnectedIntegration + ? [ + createDirectiveQuickPickItem(Directive.Cancel, undefined, { + label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked', + detail: 'Click to learn more about Launchpad', + iconPath: new ThemeIcon('rocket'), + onDidSelect: () => + void executeCommand('gitlens.openWalkthrough', { + step: 'accelerate-pr-reviews', + source: { source: 'launchpad', detail: 'info' }, + }), + }), + createQuickPickSeparator(), + ] + : []; for (const integration of supportedLaunchpadIntegrations) { if (context.connectedIntegrations.get(integration)) { @@ -1253,7 +1251,7 @@ export class LaunchpadCommand extends QuickCommand { const step = this.createConfirmStep( `${this.title} \u00a0\u2022\u00a0 Connect an ${hasConnectedIntegration ? 'Additional ' : ''}Integration`, [ - ...(hasConnectedIntegration || !isWalkthroughSupported() + ...(hasConnectedIntegration ? [] : [ createDirectiveQuickPickItem(Directive.Cancel, undefined, { diff --git a/src/plus/launchpad/launchpadIndicator.ts b/src/plus/launchpad/launchpadIndicator.ts index 5ae9b8488470e..59abfc6fdff39 100644 --- a/src/plus/launchpad/launchpadIndicator.ts +++ b/src/plus/launchpad/launchpadIndicator.ts @@ -11,7 +11,6 @@ import { once } from '../../system/event'; import { groupByMap } from '../../system/iterable'; import { wait } from '../../system/promise'; import { pluralize } from '../../system/string'; -import { isWalkthroughSupported } from '../../telemetry/walkthroughStateProvider'; import type { ConnectionStateChangeEvent } from '../integrations/integrationService'; import type { LaunchpadCommandArgs } from './launchpad'; import type { LaunchpadItem, LaunchpadProvider, LaunchpadRefreshEvent } from './launchpadProvider'; @@ -253,20 +252,12 @@ export class LaunchpadIndicator implements Disposable { tooltip.isTrusted = true; tooltip.appendMarkdown(`GitLens Launchpad ${proBadge}\u00a0\u00a0\u00a0\u00a0—\u00a0\u00a0\u00a0\u00a0`); - if (isWalkthroughSupported()) { - tooltip.appendMarkdown( - `[$(question)](command:gitlens.launchpad.indicator.action?%22info%22 "What is this?")`, - ); - } + tooltip.appendMarkdown(`[$(question)](command:gitlens.launchpad.indicator.action?%22info%22 "What is this?")`); tooltip.appendMarkdown('\u00a0'); tooltip.appendMarkdown(`[$(gear)](command:workbench.action.openSettings?%22gitlens.launchpad%22 "Settings")`); tooltip.appendMarkdown('\u00a0\u00a0|\u00a0\u00a0'); tooltip.appendMarkdown(`[$(circle-slash) Hide](command:gitlens.launchpad.indicator.action?%22hide%22 "Hide")`); - const launchpadLink = isWalkthroughSupported() - ? '[Launchpad](command:gitlens.launchpad.indicator.action?%22info%22 "Learn about Launchpad")' - : 'Launchpad'; - if ( state === 'idle' || state === 'disconnected' || @@ -275,7 +266,7 @@ export class LaunchpadIndicator implements Disposable { ) { tooltip.appendMarkdown('\n\n---\n\n'); tooltip.appendMarkdown( - `${launchpadLink} organizes your pull requests into actionable groups to help you focus and keep your team unblocked.`, + `[Launchpad](command:gitlens.launchpad.indicator.action?%22info%22 "Learn about Launchpad") organizes your pull requests into actionable groups to help you focus and keep your team unblocked.`, ); tooltip.appendMarkdown( "\n\nIt's always accessible using the `GitLens: Open Launchpad` command from the Command Palette.", diff --git a/src/telemetry/walkthroughStateProvider.ts b/src/telemetry/walkthroughStateProvider.ts index 41f7e58981122..28aac2d6fcea6 100644 --- a/src/telemetry/walkthroughStateProvider.ts +++ b/src/telemetry/walkthroughStateProvider.ts @@ -2,6 +2,7 @@ import type { Event } from 'vscode'; import { Disposable, EventEmitter } from 'vscode'; import { SubscriptionState } from '../constants.subscription'; import type { TrackedUsageKeys } from '../constants.telemetry'; +import type { WalkthroughContextKeys } from '../constants.walkthroughs'; import type { Container } from '../container'; import type { SubscriptionChangeEvent } from '../plus/gk/subscriptionService'; import { setContext } from '../system/-webview/context'; @@ -9,15 +10,6 @@ import { isCursor } from '../system/-webview/cursor'; import { wait } from '../system/promise'; import type { UsageChangeEvent } from './usageTracker'; -export type WalkthroughContextKeys = - | 'gettingStarted' - | 'homeView' - | 'visualizeCodeHistory' - | 'prReviews' - | 'streamlineCollaboration' - | 'integrations' - | 'aiFeatures'; - type WalkthroughUsage = { subscriptionStates?: SubscriptionState[] | Readonly; subscriptionCommands?: TrackedUsageKeys[] | Readonly; @@ -158,8 +150,12 @@ export class WalkthroughStateProvider implements Disposable { private readonly completed = new Set(); private subscriptionState: SubscriptionState | undefined; + readonly isWalkthroughSupported = isWalkthroughSupported(); + constructor(private readonly container: Container) { - void setContext('gitlens:walkthroughSupported', true); + if (this.isWalkthroughSupported) { + void setContext('gitlens:walkthroughSupported', true); + } this.disposables.push( this._onDidChangeProgress, @@ -269,6 +265,14 @@ export class WalkthroughStateProvider implements Disposable { return this.doneCount / this.walkthroughSize; } + getState(): Map { + const state = new Map(); + for (const key of walkthroughRequiredMapping.keys()) { + state.set(key, this.completed.has(key)); + } + return state; + } + dispose(): void { Disposable.from(...this.disposables).dispose(); } diff --git a/src/webviews/apps/home/components/onboarding.ts b/src/webviews/apps/home/components/onboarding.ts index 4ca8b4adff736..039b61ee1bcf1 100644 --- a/src/webviews/apps/home/components/onboarding.ts +++ b/src/webviews/apps/home/components/onboarding.ts @@ -1,10 +1,12 @@ import { consume } from '@lit/context'; -import { html, LitElement } from 'lit'; +import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import type { OpenWalkthroughCommandArgs } from '../../../../commands/walkthroughs'; +import { walkthroughProgressSteps } from '../../../../constants.walkthroughs'; import { createCommandLink } from '../../../../system/commands'; import type { State } from '../../../home/protocol'; import { DismissWalkthroughSection } from '../../../home/protocol'; +import { ruleStyles } from '../../plus/shared/components/vscode.css'; import { ipcContext } from '../../shared/contexts/ipc'; import type { HostIpc } from '../../shared/ipc'; import { stateContext } from '../context'; @@ -15,7 +17,33 @@ import '../../shared/components/overlays/tooltip'; @customElement('gl-onboarding') export class GlOnboarding extends LitElement { - static override styles = [homeBaseStyles, walkthroughProgressStyles]; + static override styles = [ + homeBaseStyles, + walkthroughProgressStyles, + ruleStyles, + css` + .walkthrough-progress__label { + margin-block: 0; + } + .walkthrough-progress__steps { + margin-block: 0; + padding-inline-start: 0; + } + .walkthrough-progress__step { + list-style: none; + margin-block-start: 0.3rem; + } + .walkthrough-progress__step-label { + margin-inline-start: 0.3rem; + } + code-icon[icon='circle-large'] { + color: var(--color-foreground--50); + } + code-icon[icon='pass'] { + color: #00dd00; + } + `, + ]; @consume({ context: stateContext, subscribe: true }) @state() @@ -36,7 +64,7 @@ export class GlOnboarding extends LitElement { aria-label="Dismiss" > - + ('gitlens.openWalkthrough', { @@ -55,9 +83,33 @@ export class GlOnboarding extends LitElement { value=${this._state.walkthroughProgress.progress} > +
+
Open Walkthrough
+
+ ${this.renderWalkthroughProgress()} +
`; } + private renderWalkthroughProgress(): unknown { + if (this._state.walkthroughProgress == null) return undefined; + + return html`

+ Walkthrough Progress + (${this._state.walkthroughProgress.doneCount}/${this._state.walkthroughProgress.allCount}) +

+
    + ${Object.entries(walkthroughProgressSteps).map(([key, label]) => { + const isCompleted = + this._state.walkthroughProgress!.state[key as keyof typeof walkthroughProgressSteps]; + return html`
  • + + ${label} +
  • `; + })} +
`; + } + private onDismissWalkthrough = () => { this._state.walkthroughProgress = undefined; this._ipc.sendCommand(DismissWalkthroughSection); diff --git a/src/webviews/home/homeWebview.ts b/src/webviews/home/homeWebview.ts index ea898e6c8399c..44b760b70d212 100644 --- a/src/webviews/home/homeWebview.ts +++ b/src/webviews/home/homeWebview.ts @@ -17,6 +17,7 @@ import { supportedOrderedCloudIntegrationIds, } from '../../constants.integrations'; import type { HomeTelemetryContext, Source } from '../../constants.telemetry'; +import type { WalkthroughContextKeys } from '../../constants.walkthroughs'; import type { Container } from '../../container'; import { executeGitCommand } from '../../git/actions'; import { revealBranch } from '../../git/actions/branch'; @@ -175,7 +176,7 @@ export class HomeWebviewProvider implements WebviewProvider = Object.fromEntries(walkthroughState); - void this.host.notify(DidChangeWalkthroughProgress, { + return { allCount: this.container.walkthrough.walkthroughSize, doneCount: this.container.walkthrough.doneCount, progress: this.container.walkthrough.progress, - }); + state: state as Record, + }; + } + + private notifyDidChangeProgress() { + const state = this.getWalkthroughProgress(); + if (state == null) return; + + void this.host.notify(DidChangeWalkthroughProgress, state); } private notifyDidChangeConfig() { diff --git a/src/webviews/home/protocol.ts b/src/webviews/home/protocol.ts index 1c52455add412..bd3d1e392db9a 100644 --- a/src/webviews/home/protocol.ts +++ b/src/webviews/home/protocol.ts @@ -1,5 +1,6 @@ import type { IntegrationDescriptor } from '../../constants.integrations'; import type { Source } from '../../constants.telemetry'; +import type { WalkthroughContextKeys } from '../../constants.walkthroughs'; import type { GitBranchMergedStatus } from '../../git/gitProvider'; import type { GitBranchStatus, GitTrackingState, GitTrackingUpstream } from '../../git/models/branch'; import type { GitDiffFileStats } from '../../git/models/diff'; @@ -44,6 +45,7 @@ export interface State extends WebviewState { doneCount: number; allCount: number; progress: number; + state: Record; }; previewEnabled: boolean; newInstall: boolean; @@ -302,6 +304,7 @@ export interface DidChangeProgressParams { progress: number; doneCount: number; allCount: number; + state: Record; } export const DidChangeWalkthroughProgress = new IpcNotification( scope,