Skip to content

Adds help center URL fallback for disabled walkthroughs #4418

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/telemetry-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -2301,7 +2301,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
}
```

Expand Down
33 changes: 15 additions & 18 deletions src/commands/quickCommand.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,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,
Expand Down Expand Up @@ -2688,23 +2687,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<OpenWalkthroughCommandArgs>('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<OpenWalkthroughCommandArgs>('gitlens.openWalkthrough', {
step: 'accelerate-pr-reviews',
source: { source: 'launchpad', detail: 'info' },
}),
}),
createQuickPickSeparator(),
);
break;
case 'startWork':
directives.splice(
Expand Down
29 changes: 27 additions & 2 deletions src/commands/walkthroughs.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -42,9 +43,33 @@ export class OpenWalkthroughCommand extends GlCommandBase {
}
}

const helpCenterWalkthroughUrls = new Map<WalkthroughSteps | 'default', string>([
['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);
Expand Down
2 changes: 1 addition & 1 deletion src/constants.context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/constants.telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -963,6 +963,7 @@ interface UsageTrackEvent {

interface WalkthroughEvent {
step?: WalkthroughSteps;
usingFallbackUrl?: boolean;
}

type WalkthroughActionNames =
Expand Down
6 changes: 6 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
18 changes: 18 additions & 0 deletions src/constants.walkthroughs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export type WalkthroughContextKeys =
| 'gettingStarted'
| 'homeView'
| 'visualizeCodeHistory'
| 'prReviews'
| 'streamlineCollaboration'
| 'integrations'
| 'aiFeatures';

export const walkthroughProgressSteps: WalkthroughContextKeys[] = [
'gettingStarted',
'homeView',
'visualizeCodeHistory',
'prReviews',
'streamlineCollaboration',
'integrations',
'aiFeatures',
];
10 changes: 4 additions & 6 deletions src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import { log } from './system/decorators/log';
import { Logger } from './system/logger';
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';
Expand Down Expand Up @@ -205,9 +205,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)));
Expand Down Expand Up @@ -715,8 +713,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;
}

Expand Down
15 changes: 6 additions & 9 deletions src/plus/gk/subscriptionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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) {
Expand All @@ -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 ${
Expand All @@ -512,17 +511,15 @@ 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) {
void this.learnAboutPro({ source: 'prompt', detail: { action: 'trial-started' } }, source);
}
} 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}.`,
Expand All @@ -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,
);

Expand Down
34 changes: 16 additions & 18 deletions src/plus/launchpad/launchpad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -1176,22 +1175,21 @@ export class LaunchpadCommand extends QuickCommand<State> {
context: Context,
): AsyncStepResultGenerator<{ connected: boolean | IntegrationIds; resume: () => void | undefined }> {
const hasConnectedIntegration = some(context.connectedIntegrations.values(), c => c);
const confirmations: (QuickPickItemOfT<IntegrationIds> | 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<OpenWalkthroughCommandArgs>('gitlens.openWalkthrough', {
step: 'accelerate-pr-reviews',
source: { source: 'launchpad', detail: 'info' },
}),
}),
createQuickPickSeparator(),
]
: [];
const confirmations: (QuickPickItemOfT<IntegrationIds> | 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<OpenWalkthroughCommandArgs>('gitlens.openWalkthrough', {
step: 'accelerate-pr-reviews',
source: { source: 'launchpad', detail: 'info' },
}),
}),
createQuickPickSeparator(),
]
: [];

for (const integration of supportedLaunchpadIntegrations) {
if (context.connectedIntegrations.get(integration)) {
Expand Down Expand Up @@ -1251,7 +1249,7 @@ export class LaunchpadCommand extends QuickCommand<State> {
const step = this.createConfirmStep(
`${this.title} \u00a0\u2022\u00a0 Connect an ${hasConnectedIntegration ? 'Additional ' : ''}Integration`,
[
...(hasConnectedIntegration || !isWalkthroughSupported()
...(hasConnectedIntegration
? []
: [
createDirectiveQuickPickItem(Directive.Cancel, undefined, {
Expand Down
13 changes: 2 additions & 11 deletions src/plus/launchpad/launchpadIndicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -253,20 +252,12 @@ export class LaunchpadIndicator implements Disposable {
tooltip.isTrusted = true;

tooltip.appendMarkdown(`GitLens Launchpad ${proBadge}\u00a0\u00a0\u00a0\u00a0&mdash;\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' ||
Expand All @@ -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.",
Expand Down
Loading