Skip to content

Commit 107c129

Browse files
Graduates Launchpad out of preview (#3558)
* Adds context to upgrade url * Graduates Launchpad out of preview - Adds a promotion for Launchpad - Allows access until promo ends Removes (disables) legacy "focus" editor * Uses code when returned on redirect --------- Co-authored-by: Ramin Tadayon <[email protected]>
1 parent cf6766d commit 107c129

File tree

17 files changed

+331
-201
lines changed

17 files changed

+331
-201
lines changed

package.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@
929929
},
930930
{
931931
"id": "graph",
932-
"title": "Commit Graph",
932+
"title": "Commit Graph (ᴘʀᴏ)",
933933
"order": 50,
934934
"properties": {
935935
"gitlens.graph.layout": {
@@ -1226,7 +1226,7 @@
12261226
},
12271227
{
12281228
"id": "focus",
1229-
"title": "Launchpad (Preview)",
1229+
"title": "Launchpad (ᴘʀᴏ)",
12301230
"order": 60,
12311231
"properties": {
12321232
"gitlens.launchpad.ignoredRepositories": {
@@ -1376,7 +1376,7 @@
13761376
},
13771377
{
13781378
"id": "cloud-patches",
1379-
"title": "Cloud Patches (Preview)",
1379+
"title": "Cloud Patches (ᴘʀᴇᴠɪᴇᴡ)",
13801380
"order": 70,
13811381
"properties": {
13821382
"gitlens.cloudPatches.enabled": {
@@ -1542,7 +1542,7 @@
15421542
},
15431543
{
15441544
"id": "launchpad-view",
1545-
"title": "Launchpad View",
1545+
"title": "Launchpad View (ᴇxᴘᴇʀɪᴍᴇɴᴛᴀʟ)",
15461546
"order": 101,
15471547
"properties": {
15481548
"gitlens.views.launchpad.enabled": {
@@ -2182,7 +2182,7 @@
21822182
},
21832183
{
21842184
"id": "visual-history",
2185-
"title": "Visual File History",
2185+
"title": "Visual File History (ᴘʀᴏ)",
21862186
"order": 155,
21872187
"properties": {
21882188
"gitlens.visualHistory.allowMultiple": {
@@ -2587,7 +2587,7 @@
25872587
},
25882588
{
25892589
"id": "worktrees-view",
2590-
"title": "Worktrees View",
2590+
"title": "Worktrees View (ᴘʀᴏ)",
25912591
"order": 210,
25922592
"properties": {
25932593
"gitlens.worktrees.promptForLocation": {
@@ -2897,7 +2897,7 @@
28972897
},
28982898
{
28992899
"id": "cloud-patches-view",
2900-
"title": "Cloud Patches View",
2900+
"title": "Cloud Patches View (ᴘʀᴇᴠɪᴇᴡ)",
29012901
"order": 240,
29022902
"properties": {
29032903
"gitlens.views.drafts.files.layout": {
@@ -3017,7 +3017,7 @@
30173017
},
30183018
{
30193019
"id": "workspaces-view",
3020-
"title": "GitKraken Workspaces View",
3020+
"title": "GitKraken Workspaces View (ᴘʀᴇᴠɪᴇᴡ)",
30213021
"order": 260,
30223022
"properties": {
30233023
"gitlens.views.workspaces.showBranchComparison": {
@@ -3654,7 +3654,7 @@
36543654
},
36553655
{
36563656
"id": "ai",
3657-
"title": "AI (Experimental)",
3657+
"title": "AI (ᴇxᴘᴇʀɪᴍᴇɴᴛᴀʟ)",
36583658
"order": 1000,
36593659
"properties": {
36603660
"gitlens.ai.experimental.generateCommitMessage.enabled": {
@@ -9911,7 +9911,7 @@
99119911
},
99129912
{
99139913
"command": "gitlens.showFocusPage",
9914-
"when": "gitlens:enabled"
9914+
"when": "false && gitlens:enabled"
99159915
},
99169916
{
99179917
"command": "gitlens.launchpad.split",
@@ -17590,13 +17590,13 @@
1759017590
},
1759117591
{
1759217592
"view": "gitlens.views.worktrees",
17593-
"contents": "Special: 1st seat of Pro is now 50%+ off",
17593+
"contents": "Limited-time Sale: Save 33% or more on your 1st seat of Pro.",
1759417594
"when": "gitlens:plus:required && gitlens:plus:state == 4 && (gitlens:promo == pro50 || !gitlens:promo)"
1759517595
},
1759617596
{
1759717597
"view": "gitlens.views.worktrees",
17598-
"contents": "DevEx Days 24 Sale: Save up to 80% on GitLens Pro - lowest price of the year!",
17599-
"when": "gitlens:plus:required && gitlens:plus:state == 4 && gitlens:promo == devexdays24"
17598+
"contents": "Launchpad Sale: Save 75% or more on GitLens Pro",
17599+
"when": "gitlens:plus:required && gitlens:plus:state == 4 && gitlens:promo =~ /(launchpad|launchpad-extended)/"
1760017600
},
1760117601
{
1760217602
"view": "gitlens.views.worktrees",
@@ -17899,7 +17899,7 @@
1789917899
{
1790017900
"id": "launchpad",
1790117901
"title": "Unblock your team with Launchpad",
17902-
"description": "**Launchpad** ᴘʀᴇᴠɪᴇᴡ brings all of your GitHub pull requests into a unified, actionable list to better track work in progress, pending work, reviews, and more. Stay focused and take action on the most important items to keep your team unblocked. [Learn more](https://gitkraken.com/solutions/launchpad?utm_source=gitlens-extension&utm_medium=in-app-links)\n\n[Open Launchpad](command:gitlens.showLaunchpad?%7B%22source%22%3A%22walkthrough%22%7D)",
17902+
"description": "**Launchpad** ᴘʀᴏ brings all of your GitHub pull requests into a unified, actionable list to better track work in progress, pending work, reviews, and more. Stay focused and take action on the most important items to keep your team unblocked. [Learn more](https://gitkraken.com/solutions/launchpad?utm_source=gitlens-extension&utm_medium=in-app-links)\n\n[Open Launchpad](command:gitlens.showLaunchpad?%7B%22source%22%3A%22walkthrough%22%7D)",
1790317903
"media": {
1790417904
"altText": "Illustrations of Launchpad",
1790517905
"svg": "walkthroughs/welcome/launchpad-quick.svg"

src/commands/quickCommand.buttons.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ export const PickCommitToggleQuickInputButton = class extends ToggleQuickInputBu
122122
}
123123
};
124124

125+
export const LearnAboutProQuickInputButton: QuickInputButton = {
126+
iconPath: new ThemeIcon('info'),
127+
tooltip: 'Learn about GitLens Pro',
128+
};
129+
125130
export const MergeQuickInputButton: QuickInputButton = {
126131
iconPath: new ThemeIcon('merge'),
127132
tooltip: 'Merge...',

src/commands/quickCommand.steps.ts

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { ThemeIcon } from 'vscode';
33
import { GlyphChars, quickPickTitleMaxChars } from '../constants';
44
import { Commands } from '../constants.commands';
55
import { Container } from '../container';
6-
import type { PlusFeatures } from '../features';
6+
import type { FeatureAccess, RepoFeatureAccess } from '../features';
7+
import { PlusFeatures } from '../features';
78
import * as BranchActions from '../git/actions/branch';
89
import * as CommitActions from '../git/actions/commit';
910
import * as ContributorActions from '../git/actions/contributor';
@@ -43,6 +44,7 @@ import type { GitWorktree, WorktreeQuickPickItem } from '../git/models/worktree'
4344
import { createWorktreeQuickPickItem, getWorktreesByBranch, sortWorktrees } from '../git/models/worktree';
4445
import { remoteUrlRegex } from '../git/parsers/remoteParser';
4546
import type { FocusCommandArgs } from '../plus/focus/focus';
47+
import { getApplicablePromo } from '../plus/gk/account/promos';
4648
import { isSubscriptionPaidPlan, isSubscriptionPreviewTrialExpired } from '../plus/gk/account/subscription';
4749
import {
4850
CommitApplyFileChangesCommandQuickPickItem,
@@ -98,6 +100,7 @@ import {
98100
OpenRemoteResourceCommandQuickPickItem,
99101
} from '../quickpicks/remoteProviderPicker';
100102
import { filterMap, filterMapAsync, intersection, isStringArray } from '../system/array';
103+
import { executeCommand } from '../system/command';
101104
import { configuration } from '../system/configuration';
102105
import { formatPath } from '../system/formatPath';
103106
import { debounce } from '../system/function';
@@ -106,6 +109,7 @@ import { Logger } from '../system/logger';
106109
import { getSettledValue } from '../system/promise';
107110
import { pad, pluralize, truncate } from '../system/string';
108111
import { openWorkspace } from '../system/utils';
112+
import { getIconPathUris } from '../system/vscode';
109113
import type { ViewsWithRepositoryFolders } from '../views/viewBase';
110114
import type {
111115
AsyncStepResultGenerator,
@@ -136,6 +140,7 @@ import {
136140
ShowDetailsViewQuickInputButton,
137141
ShowTagsToggleQuickInputButton,
138142
} from './quickCommand.buttons';
143+
import type { OpenWalkthroughCommandArgs } from './walkthroughs';
139144

140145
export function appendReposToTitle<
141146
State extends { repo: Repository } | { repos: Repository[] },
@@ -2599,11 +2604,11 @@ function getShowRepositoryStatusStepItems<
25992604
}
26002605

26012606
export async function* ensureAccessStep<
2602-
State extends PartialStepState & { repo: Repository },
2603-
Context extends { repos: Repository[]; title: string },
2604-
>(state: State, context: Context, feature: PlusFeatures): AsyncStepResultGenerator<void> {
2605-
const access = await Container.instance.git.access(feature, state.repo.path);
2606-
if (access.allowed) return undefined;
2607+
State extends PartialStepState & { repo?: Repository },
2608+
Context extends { title: string },
2609+
>(state: State, context: Context, feature: PlusFeatures): AsyncStepResultGenerator<FeatureAccess | RepoFeatureAccess> {
2610+
const access = await Container.instance.git.access(feature, state.repo?.path);
2611+
if (access.allowed) return access;
26072612

26082613
const directives: DirectiveQuickPickItem[] = [];
26092614
let placeholder: string;
@@ -2615,13 +2620,28 @@ export async function* ensureAccessStep<
26152620
);
26162621
placeholder = 'You must verify your email before you can continue';
26172622
} else {
2618-
if (access.subscription.required == null) return undefined;
2623+
if (access.subscription.required == null) return access;
2624+
2625+
let detail;
2626+
const promo = getApplicablePromo(access.subscription.current.state);
2627+
if (promo != null) {
2628+
// NOTE: Don't add a default case, so that if we add a new promo the build will break without handling it
2629+
switch (promo.key) {
2630+
case 'pro50':
2631+
detail = '$(star-full) Limited-Time Sale: Save 33% or more on your 1st seat of Pro';
2632+
break;
2633+
case 'launchpad':
2634+
case 'launchpad-extended':
2635+
detail = `$(rocket) Launchpad Sale: Save 75% or more on GitLens Pro`;
2636+
break;
2637+
}
2638+
}
26192639

26202640
placeholder = 'Pro feature — requires a trial or paid plan for use on privately-hosted repos';
26212641
if (isSubscriptionPaidPlan(access.subscription.required) && access.subscription.current.account != null) {
26222642
placeholder = 'Pro feature — requires a paid plan for use on privately-hosted repos';
26232643
directives.push(
2624-
createDirectiveQuickPickItem(Directive.RequiresPaidSubscription, true),
2644+
createDirectiveQuickPickItem(Directive.RequiresPaidSubscription, true, { detail: detail }),
26252645
createQuickPickSeparator(),
26262646
createDirectiveQuickPickItem(Directive.Cancel),
26272647
);
@@ -2644,12 +2664,45 @@ export async function* ensureAccessStep<
26442664
}
26452665
}
26462666

2667+
switch (feature) {
2668+
case PlusFeatures.Focus:
2669+
directives.splice(
2670+
0,
2671+
0,
2672+
createDirectiveQuickPickItem(Directive.Cancel, undefined, {
2673+
label: 'Launchpad prioritizes your pull requests to keep you focused and your team unblocked',
2674+
detail: 'Click to learn more about Launchpad',
2675+
iconPath: new ThemeIcon('rocket'),
2676+
onDidSelect: () =>
2677+
void executeCommand<OpenWalkthroughCommandArgs>(Commands.OpenWalkthrough, {
2678+
step: 'launchpad',
2679+
source: 'launchpad',
2680+
detail: 'info',
2681+
}),
2682+
}),
2683+
createQuickPickSeparator(),
2684+
);
2685+
break;
2686+
case PlusFeatures.Worktrees:
2687+
directives.splice(
2688+
0,
2689+
0,
2690+
createDirectiveQuickPickItem(Directive.Noop, undefined, {
2691+
label: 'Worktrees minimize context switching by allowing simultaneous work on multiple branches',
2692+
iconPath: getIconPathUris(Container.instance, 'icon-repo.svg'),
2693+
}),
2694+
);
2695+
break;
2696+
}
2697+
26472698
const step = createPickStep<DirectiveQuickPickItem>({
2648-
title: appendReposToTitle(context.title, state, context),
2699+
title: context.title,
26492700
placeholder: placeholder,
26502701
items: directives,
2702+
buttons: [],
2703+
isConfirmationStep: true,
26512704
});
26522705

26532706
const selection: StepSelection<typeof step> = yield step;
2654-
return canPickStepContinue(step, state, selection) ? undefined : StepResultBreak;
2707+
return canPickStepContinue(step, state, selection) ? access : StepResultBreak;
26552708
}

src/constants.telemetry.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,3 +466,6 @@ type SubscriptionEventData = {
466466
Record<`previous.subscription.${string}`, string | number | boolean | undefined> &
467467
Record<`previous.subscription.previewTrial.${string}`, string | number | boolean | undefined>
468468
>;
469+
470+
/** Used to provide a "source context" to gk.dev for both tracking and customization purposes */
471+
export type TrackingContext = 'graph' | 'launchpad' | 'visual_file_history' | 'worktrees';

src/constants.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export const keys = Object.freeze([
124124
] as const);
125125
export type Keys = (typeof keys)[number];
126126

127-
export type PromoKeys = 'devexdays24' | 'pro50';
127+
export type PromoKeys = 'launchpad' | 'launchpad-extended' | 'pro50';
128128

129129
export const enum Schemes {
130130
File = 'file',
@@ -152,24 +152,24 @@ export const trackableSchemes = Object.freeze(
152152
]),
153153
);
154154

155+
const utm = 'utm_source=gitlens-extension&utm_medium=in-app-links';
155156
export const urls = Object.freeze({
156-
codeSuggest: 'https://gitkraken.com/solutions/code-suggest?utm_source=gitlens-extension&utm_medium=in-app-links',
157-
cloudPatches: 'https://gitkraken.com/solutions/cloud-patches?utm_source=gitlens-extension&utm_medium=in-app-links',
158-
graph: 'https://gitkraken.com/solutions/commit-graph?utm_source=gitlens-extension&utm_medium=in-app-links',
159-
launchpad: 'https://gitkraken.com/solutions/launchpad?utm_source=gitlens-extension&utm_medium=in-app-links',
160-
platform: 'https://gitkraken.com/devex?utm_source=gitlens-extension&utm_medium=in-app-links',
161-
pricing: 'https://gitkraken.com/gitlens/pricing?utm_source=gitlens-extension&utm_medium=in-app-links',
162-
proFeatures: 'https://gitkraken.com/gitlens/pro-features?utm_source=gitlens-extension&utm_medium=in-app-links',
163-
security: 'https://help.gitkraken.com/gitlens/security?utm_source=gitlens-extension&utm_medium=in-app-links',
164-
workspaces: 'https://gitkraken.com/solutions/workspaces?utm_source=gitlens-extension&utm_medium=in-app-links',
157+
codeSuggest: `https://gitkraken.com/solutions/code-suggest?${utm}`,
158+
cloudPatches: `https://gitkraken.com/solutions/cloud-patches?${utm}`,
159+
graph: `https://gitkraken.com/solutions/commit-graph?${utm}`,
160+
launchpad: `https://gitkraken.com/solutions/launchpad?${utm}`,
161+
platform: `https://gitkraken.com/devex?${utm}`,
162+
pricing: `https://gitkraken.com/gitlens/pricing?${utm}`,
163+
proFeatures: `https://gitkraken.com/gitlens/pro-features?${utm}`,
164+
security: `https://help.gitkraken.com/gitlens/security?${utm}`,
165+
workspaces: `https://gitkraken.com/solutions/workspaces?${utm}`,
165166

166-
cli: 'https://gitkraken.com/cli?utm_source=gitlens-extension&utm_medium=in-app-links',
167-
browserExtension: 'https://gitkraken.com/browser-extension?utm_source=gitlens-extension&utm_medium=in-app-links',
168-
desktop: 'https://gitkraken.com/git-client?utm_source=gitlens-extension&utm_medium=in-app-links',
167+
cli: `https://gitkraken.com/cli?${utm}`,
168+
browserExtension: `https://gitkraken.com/browser-extension?${utm}`,
169+
desktop: `https://gitkraken.com/git-client?${utm}`,
169170

170171
releaseNotes: 'https://help.gitkraken.com/gitlens/gitlens-release-notes-current/',
171-
releaseAnnouncement:
172-
'https://www.gitkraken.com/blog/gitkraken-launches-devex-platform-acquires-codesee?utm_source=gitlens-extension&utm_medium=in-app-links',
172+
releaseAnnouncement: `https://www.gitkraken.com/blog/gitkraken-launches-devex-platform-acquires-codesee?${utm}`,
173173
});
174174

175175
export type WalkthroughSteps =

src/container.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import type { GitHubApi } from './plus/integrations/providers/github/github';
3434
import type { GitLabApi } from './plus/integrations/providers/gitlab/gitlab';
3535
import { RepositoryIdentityService } from './plus/repos/repositoryIdentityService';
3636
import { registerAccountWebviewView } from './plus/webviews/account/registration';
37-
import { registerFocusWebviewCommands, registerFocusWebviewPanel } from './plus/webviews/focus/registration';
3837
import type { GraphWebviewShowingArgs } from './plus/webviews/graph/registration';
3938
import {
4039
registerGraphWebviewCommands,
@@ -251,9 +250,10 @@ export class Container {
251250
this._disposables.push((this._graphView = registerGraphWebviewView(this._webviews)));
252251
this._disposables.push(new GraphStatusBarController(this));
253252

254-
const focusPanels = registerFocusWebviewPanel(this._webviews);
255-
this._disposables.push(focusPanels);
256-
this._disposables.push(registerFocusWebviewCommands(focusPanels));
253+
// NOTE: Commenting out for now as we are deprecating this
254+
// const focusPanels = registerFocusWebviewPanel(this._webviews);
255+
// this._disposables.push(focusPanels);
256+
// this._disposables.push(registerFocusWebviewCommands(focusPanels));
257257

258258
const timelinePanels = registerTimelineWebviewPanel(this._webviews);
259259
this._disposables.push(timelinePanels);

0 commit comments

Comments
 (0)