diff --git a/package.json b/package.json index d4ce4114c9c47..dd7d6036cf087 100644 --- a/package.json +++ b/package.json @@ -3583,7 +3583,7 @@ }, { "command": "gitlens.premium.purchase", - "title": "Unlock Premium Features for Private Code...", + "title": "Unlock Premium Features for Private Repos...", "category": "GitLens Premium" }, { @@ -10464,18 +10464,28 @@ }, { "view": "gitlens.views.worktrees", - "contents": "Worktrees are a premium feature, which require a free account for public code. [Learn more](https://dev.gitkraken.com/gitlens/premium-features).", - "when": "gitlens:premium:upgradeRequired == free+" + "contents": "To use premium GitLens features, please verify the email for the account you created.\n\n[Resend verification email](command:gitlens.premium.resendVerification)", + "when": "gitlens:premium:requiresVerification" }, { "view": "gitlens.views.worktrees", - "contents": "Worktrees are a premium feature, which require at least a Pro subscription for private code. [Learn more](https://dev.gitkraken.com/gitlens/premium-features).", + "contents": "Worktrees are a premium feature, which require a free account for public repos. [Learn more](https://dev.gitkraken.com/gitlens/premium-features).\n\nYou can try these premium features for free, without an account, for 3 days. All non-premium features will continue to be free without an account.", + "when": "gitlens:premium:upgradeRequired == free+ && !gitlens:premium:requiresVerification" + }, + { + "view": "gitlens.views.worktrees", + "contents": "[Try premium features now](command:gitlens.premium.startPreview)\n\n[Create a free account](command:gitlens.premium.loginOrSignUp)", + "when": "gitlens:premium:upgradeRequired == free+ && !gitlens:premium:requiresVerification" + }, + { + "view": "gitlens.views.worktrees", + "contents": "Worktrees are a premium feature, which require at least a Pro subscription for private repos. [Learn more](https://dev.gitkraken.com/gitlens/premium-features).", "when": "gitlens:premium:upgradeRequired == paid" }, { "view": "gitlens.views.worktrees", - "contents": "[Unlock Premium Features](command:gitlens.showHomeView)", - "when": "gitlens:premium:upgradeRequired" + "contents": "[Upgrade your account](command:gitlens.premium.purchase)", + "when": "gitlens:premium:upgradeRequired == paid" } ], "views": { diff --git a/src/commands/gitCommands.ts b/src/commands/gitCommands.ts index 496bfed3f503c..f17221d6691c8 100644 --- a/src/commands/gitCommands.ts +++ b/src/commands/gitCommands.ts @@ -709,10 +709,23 @@ export class GitCommandsCommand extends Command { void loadMore(); return; + case Directive.StartPreview: + void Container.instance.subscription.startPreview(); + resolve(undefined); + return; + case Directive.RequiresVerification: + void Container.instance.subscription.resendVerification(); + resolve(undefined); + return; + case Directive.RequiresFreeSubscription: + void Container.instance.subscription.loginOrSignUp(); + resolve(undefined); + return; + case Directive.RequiresPaidSubscription: - void Container.instance.subscription.showHomeView(); + void Container.instance.subscription.purchase(); resolve(undefined); return; } diff --git a/src/commands/quickCommand.steps.ts b/src/commands/quickCommand.steps.ts index 19712daac6076..500b82caf9c77 100644 --- a/src/commands/quickCommand.steps.ts +++ b/src/commands/quickCommand.steps.ts @@ -2236,27 +2236,30 @@ export async function* ensureAccessStep< const access = await Container.instance.git.access(feature, state.repo.path); if (access.allowed) return undefined; - let directive: Directive; + const directives: DirectiveQuickPickItem[] = []; let placeholder: string; if (access.subscription.current.account?.verified === false) { - directive = Directive.RequiresVerification; + directives.push(DirectiveQuickPickItem.create(Directive.RequiresVerification, true)); placeholder = 'You must verify your account email address before you can continue'; } else { if (access.subscription.required == null) return undefined; if (isPaidSubscriptionPlan(access.subscription.required)) { - directive = Directive.RequiresPaidSubscription; - placeholder = 'Requires a paid subscription'; + directives.push(DirectiveQuickPickItem.create(Directive.RequiresPaidSubscription, true)); + placeholder = 'Premium features require an upgraded account'; } else { - directive = Directive.RequiresFreeSubscription; - placeholder = 'Requires a Free+ account'; + directives.push( + DirectiveQuickPickItem.create(Directive.StartPreview, true), + DirectiveQuickPickItem.create(Directive.RequiresFreeSubscription), + ); + placeholder = 'Premium features require an account'; } } const step = QuickCommand.createPickStep({ title: appendReposToTitle(context.title, state, context), placeholder: placeholder, - items: [DirectiveQuickPickItem.create(directive, true), DirectiveQuickPickItem.create(Directive.Cancel)], + items: [...directives, DirectiveQuickPickItem.create(Directive.Cancel)], }); const selection: StepSelection = yield step; diff --git a/src/constants.ts b/src/constants.ts index 08c0496709c1e..eab88e128c3a7 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -243,6 +243,7 @@ export const enum ContextKeys { Premium = 'gitlens:premium', PremiumPaid = 'gitlens:premium:paid', + PremiumRequiresVerification = 'gitlens:premium:requiresVerification', PremiumUpgradeRequired = 'gitlens:premium:upgradeRequired', } diff --git a/src/env/browser/platform.ts b/src/env/browser/platform.ts index 3b446fceadb13..26eebd814808d 100644 --- a/src/env/browser/platform.ts +++ b/src/env/browser/platform.ts @@ -6,3 +6,16 @@ const _userAgent = navigator.userAgent; export const isLinux = _platform === 'Linux' || _userAgent.indexOf('Linux') >= 0; export const isMac = _platform === 'macOS' || _userAgent.indexOf('Macintosh') >= 0; export const isWindows = _platform === 'Windows' || _userAgent.indexOf('Windows') >= 0; + +export function getPlatform(): string { + if (isWindows) { + return 'web-windows'; + } + if (isMac) { + return 'web-macOS'; + } + if (isLinux) { + return 'web-linux'; + } + return 'web'; +} diff --git a/src/env/node/platform.ts b/src/env/node/platform.ts index 7ed8119798b9a..1a0875e3c5e36 100644 --- a/src/env/node/platform.ts +++ b/src/env/node/platform.ts @@ -5,3 +5,16 @@ export const isWeb = env.uiKind === UIKind.Web; export const isLinux = process.platform === 'linux'; export const isMac = process.platform === 'darwin'; export const isWindows = process.platform === 'win32'; + +export function getPlatform(): string { + if (isWindows) { + return 'windows'; + } + if (isMac) { + return 'macOS'; + } + if (isLinux) { + return 'linux'; + } + return isWeb ? 'web' : 'unknown'; +} diff --git a/src/premium/subscription/subscriptionService.ts b/src/premium/subscription/subscriptionService.ts index 8018cc070eaf4..d5987562742e3 100644 --- a/src/premium/subscription/subscriptionService.ts +++ b/src/premium/subscription/subscriptionService.ts @@ -1,6 +1,7 @@ import { authentication, AuthenticationSession, + version as codeVersion, commands, Disposable, env, @@ -13,6 +14,7 @@ import { window, } from 'vscode'; import { fetch } from '@env/fetch'; +import { getPlatform } from '@env/platform'; import { Commands, ContextKeys } from '../../constants'; import type { Container } from '../../container'; import { setContext } from '../../context'; @@ -157,6 +159,8 @@ export class SubscriptionService implements Disposable { } async loginOrSignUp(): Promise { + void this.showHomeView(); + const session = await this.ensureSession(true); return Boolean(session); } @@ -232,10 +236,10 @@ export class SubscriptionService implements Disposable { let { plan, preview } = this._subscription; if (preview != null || plan.effective.id !== SubscriptionPlanId.Free) { if (plan.effective.id === SubscriptionPlanId.Free) { - const ok = { title: 'Create Free+ Account' }; + const ok = { title: 'Extend Trial' }; const cancel = { title: 'Cancel' }; const result = await window.showInformationMessage( - 'Your premium feature preview has expired. Please create a Free+ account to extend your trial.', + 'Your premium feature trial has expired. Please create a free account to extend your trial.', ok, cancel, ); @@ -249,13 +253,16 @@ export class SubscriptionService implements Disposable { const startedOn = new Date(); + let days; let expiresOn = new Date(startedOn); if (!this.container.debugging && this.container.env !== 'dev') { // Normalize the date to just before midnight on the same day expiresOn.setHours(23, 59, 59, 999); expiresOn = createFromDateDelta(expiresOn, { days: 3 }); + days = 3; } else { expiresOn = createFromDateDelta(expiresOn, { minutes: 1 }); + days = 0; } preview = { @@ -271,6 +278,8 @@ export class SubscriptionService implements Disposable { }, preview: preview, }); + + void window.showInformationMessage(`You can now try premium GitLens features for ${days} days.`); } async validate(): Promise { @@ -282,12 +291,24 @@ export class SubscriptionService implements Disposable { private async checkInAndValidate(session: AuthenticationSession): Promise { try { + const checkInData = { + id: session.account.id, + platform: getPlatform(), + gitlensVersion: this.container.version, + vscodeEdition: env.appName, + vscodeHost: env.appHost, + vscodeVersion: codeVersion, + previewStartedOn: this._subscription.preview?.startedOn, + previewExpiresOn: this._subscription.preview?.expiresOn, + }; + const rsp = await fetch(Uri.joinPath(this.baseApiUri, 'gitlens/checkin').toString(), { method: 'POST', headers: { Authorization: `Bearer ${session.accessToken}`, 'User-Agent': userAgent, }, + body: JSON.stringify(checkInData), }); if (!rsp.ok) { @@ -506,6 +527,7 @@ export class SubscriptionService implements Disposable { void setContext(ContextKeys.Premium, actual.id); void setContext(ContextKeys.PremiumPaid, isPaidSubscriptionPlan(actual.id)); + void setContext(ContextKeys.PremiumRequiresVerification, this._subscription.account?.verified === false); } private updateStatusBar(pending: boolean = false): void { @@ -530,7 +552,7 @@ export class SubscriptionService implements Disposable { this._statusBarSubscription.text = effective.name; this._statusBarSubscription.command = Commands.ShowHomeView; this._statusBarSubscription.tooltip = new MarkdownString( - `You are on **${effective.name}**\n\nClick to upgrade to Free+ for access to premium features for public code`, + `You are on **${effective.name}**\n\nClick to upgrade to Free+ for access to premium features for public repos`, true, ); break; diff --git a/src/quickpicks/items/directive.ts b/src/quickpicks/items/directive.ts index 044d7fafe393c..ef88a5f048dbc 100644 --- a/src/quickpicks/items/directive.ts +++ b/src/quickpicks/items/directive.ts @@ -7,8 +7,10 @@ export enum Directive { LoadMore, Noop, RequiresVerification, + RequiresFreeSubscription, RequiresPaidSubscription, + StartPreview, } export namespace Directive { @@ -43,17 +45,21 @@ export namespace DirectiveQuickPickItem { case Directive.Noop: label = 'Try again'; break; + case Directive.StartPreview: + label = 'Try Premium Features Now'; + detail = 'Try premium features for free, without an account, for 3 days'; + break; case Directive.RequiresVerification: label = 'Resend Verification Email'; detail = 'You must verify your account email address before you can continue'; break; case Directive.RequiresFreeSubscription: - label = 'Create a Free+ Account'; - detail = 'To unlock all premium features for public code'; + label = 'Create a Free Account'; + detail = 'To unlock premium features'; break; case Directive.RequiresPaidSubscription: - label = 'Upgrade to a paid subscription'; - detail = 'To unlock all premium features for private code'; + label = 'Upgrade Your Account'; + detail = 'To unlock premium features for private repos'; break; } } diff --git a/src/webviews/apps/premium/home/home.html b/src/webviews/apps/premium/home/home.html index 5a1199eaa8662..5888f7ec52a23 100644 --- a/src/webviews/apps/premium/home/home.html +++ b/src/webviews/apps/premium/home/home.html @@ -52,7 +52,9 @@

Welcome to GitLens 12!

individually. - Hide + Dismiss welcome @@ -62,8 +64,11 @@

Try GitLens Premium Features

Premium features like Git Worktrees and Visual File History are available with a free account, with many more features coming soon, including a commit graph and GitHub Enterprise - integration. Access to premium features for private code is available with a paid account. - Learn more about GitLens premium features. + integration. Access to premium features for private repos is available with a paid account. +

+

+ Learn more about GitLens premium + features.

You can try these premium features for free, without an account, for 3 days. All non-premium features @@ -83,11 +88,14 @@

Trying Premium Features

You are currently trying premium GitLens features, like Git Worktrees and Visual File History, for 3 more days. - Learn more about GitLens premium features. +

+

+ Learn more about GitLens premium + features.

After that time, a free account will be required to continue using these premium features for public - code, or you can puchase a paid plan to access premium features for private code. + code, or you can puchase a paid plan to access premium features for private repos.

Create a free account Purchase a plan @@ -101,15 +109,16 @@

Continue using Premium Features

Premium GitLens features like Git Worktrees and Visual File History, a commit graph (coming soon), and GitHub Enterprise integration (coming soon) are only available with an - account. Learn more about GitLens premium features. + account. +

+

+ Learn more about GitLens premium + features.

Create a free account to continue trialing premium features for all code for an additional 7 days.

Create a free account Purchase a plan

All non-premium features will continue to be free without an account.

- Close @@ -118,14 +127,14 @@

Continue using Premium Features

Premium Feature Trial

You are currently trialing premium GitLens features like Git Worktrees and - Visual File History for both public and private code. In - 7 days, accessing these premium features for private code will + Visual File History for both public and private repos. In + 7 days, accessing these premium features for private repos will require a paid account.

Purchase a plan

- With your free account, you will continue to have access to premium features for public code, as well as - all non-premium features. + With your free account, you will continue to have access to premium features for public repos, as well + as all non-premium features.

@@ -133,12 +142,12 @@

Premium Feature Trial

@@ -148,15 +157,15 @@

Please validate your email

GitLens Free+

With your free account, you have access to GitLens Free+, which unlocks premium features like - Git Worktrees and Visual File History for public code. More premium + Git Worktrees and Visual File History for public repos. More premium features like a commit graph and GitHub Enterprise integration are coming soon. - Learn more about GitLens premium features.

-

Access to premium features for private code requires a paid plan.

+

+ Learn more about GitLens premium + features. +

+

Access to premium features for private repos requires a paid plan.

Purchase a plan - Close @@ -172,9 +181,6 @@

GitLens Pro

Additional premium featues like a commit graph and GitHub Enterprise integration are coming soon. Learn more about GitLens premium features.

- Close