Browse Source

Reframes premium to GitLens+

Trying to improve clarity that there are only a small subset of features that require an account
main
Eric Amodio 2 years ago
parent
commit
ffb876aa7c
37 changed files with 247 additions and 296 deletions
  1. +39
    -39
      package.json
  2. +2
    -2
      src/commands/git/worktree.ts
  3. +4
    -4
      src/commands/quickCommand.steps.ts
  4. +1
    -1
      src/config.ts
  5. +15
    -15
      src/constants.ts
  6. +4
    -4
      src/env/node/git/localGitProvider.ts
  7. +1
    -1
      src/features.ts
  8. +2
    -2
      src/git/gitProvider.ts
  9. +5
    -5
      src/git/gitProviderService.ts
  10. +2
    -2
      src/git/models/repository.ts
  11. +4
    -4
      src/premium/github/githubGitProvider.ts
  12. +4
    -4
      src/premium/subscription/authenticationProvider.ts
  13. +35
    -36
      src/premium/subscription/subscriptionService.ts
  14. +4
    -4
      src/premium/subscription/utils.ts
  15. +4
    -4
      src/premium/webviews/timeline/timelineWebview.ts
  16. +4
    -4
      src/premium/webviews/timeline/timelineWebviewView.ts
  17. +5
    -5
      src/quickpicks/items/directive.ts
  18. +1
    -2
      src/storage.ts
  19. +5
    -5
      src/subscription.ts
  20. +4
    -4
      src/views/nodes/worktreesNode.ts
  21. +5
    -5
      src/views/worktreesView.ts
  22. +1
    -1
      src/webviews/apps/home/partials/links.html
  23. +12
    -39
      src/webviews/apps/home/partials/state.free-preview-expired.html
  24. +11
    -10
      src/webviews/apps/home/partials/state.free-preview.html
  25. +10
    -10
      src/webviews/apps/home/partials/state.free.html
  26. +5
    -5
      src/webviews/apps/home/partials/state.paid.html
  27. +6
    -6
      src/webviews/apps/home/partials/state.plus-trial-expired.html
  28. +10
    -36
      src/webviews/apps/home/partials/state.plus-trial.html
  29. +1
    -1
      src/webviews/apps/home/partials/state.verify-email.html
  30. +6
    -6
      src/webviews/apps/premium/timeline/partials/state.free-preview-expired.html
  31. +4
    -4
      src/webviews/apps/premium/timeline/partials/state.free.html
  32. +1
    -1
      src/webviews/apps/welcome/welcome.html
  33. +2
    -2
      src/webviews/home/homeWebviewView.ts
  34. +8
    -2
      walkthroughs/getting-started/12-plus.md
  35. +13
    -14
      walkthroughs/plus/1-intro.md
  36. +2
    -2
      walkthroughs/plus/4-coming-soon.md

+ 39
- 39
package.json View File

@ -3264,7 +3264,7 @@
"gitlens.plusFeatures.enabled": { "gitlens.plusFeatures.enabled": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"markdownDescription": "Specifies whether to enable premium features",
"markdownDescription": "Specifies whether to enable GitLens+ features",
"scope": "window", "scope": "window",
"order": 60 "order": 60
}, },
@ -3615,48 +3615,48 @@
"commands": [ "commands": [
{ {
"command": "gitlens.plus.learn", "command": "gitlens.plus.learn",
"title": "Learn about Premium Features",
"category": "GitLens"
"title": "Learn about GitLens+ Features",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.loginOrSignUp", "command": "gitlens.plus.loginOrSignUp",
"title": "Sign In (for premium features)...",
"category": "GitLens Premium"
"title": "Sign In to GitLens+...",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.logout", "command": "gitlens.plus.logout",
"title": "Disconnect Account",
"category": "GitLens Premium"
"title": "Disconnect from GitLens+",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.startPreviewTrial", "command": "gitlens.plus.startPreviewTrial",
"title": "Try Premium Features Now",
"category": "GitLens Premium"
"title": "Try GitLens+ Features Now",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.manage", "command": "gitlens.plus.manage",
"title": "Manage Your Account...",
"category": "GitLens Premium"
"title": "Manage Your GitLens+ Account...",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.purchase", "command": "gitlens.plus.purchase",
"title": "Upgrade Your Account...",
"category": "GitLens Premium"
"title": "Upgrade Your GitLens+ Account...",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.hide", "command": "gitlens.plus.hide",
"title": "Hide Premium Features...",
"category": "GitLens Premium"
"title": "Hide GitLens+ Features...",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.restore", "command": "gitlens.plus.restore",
"title": "Restore Premium Features...",
"category": "GitLens Premium"
"title": "Restore GitLens+ Features...",
"category": "GitLens+"
}, },
{ {
"command": "gitlens.plus.reset", "command": "gitlens.plus.reset",
"title": "Reset...", "title": "Reset...",
"category": "GitLens Premium"
"category": "GitLens+"
}, },
{ {
"command": "gitlens.getStarted", "command": "gitlens.getStarted",
@ -5959,19 +5959,19 @@
"commandPalette": [ "commandPalette": [
{ {
"command": "gitlens.plus.loginOrSignUp", "command": "gitlens.plus.loginOrSignUp",
"when": "!gitlens:premium"
"when": "!gitlens:plus"
}, },
{ {
"command": "gitlens.plus.logout", "command": "gitlens.plus.logout",
"when": "gitlens:premium"
"when": "gitlens:plus"
}, },
{ {
"command": "gitlens.plus.startPreviewTrial", "command": "gitlens.plus.startPreviewTrial",
"when": "!gitlens:premium"
"when": "!gitlens:plus"
}, },
{ {
"command": "gitlens.plus.manage", "command": "gitlens.plus.manage",
"when": "gitlens:premium"
"when": "gitlens:plus"
}, },
{ {
"command": "gitlens.plus.hide", "command": "gitlens.plus.hide",
@ -10679,12 +10679,12 @@
}, },
{ {
"view": "gitlens.views.worktrees", "view": "gitlens.views.worktrees",
"contents": "Try worktrees now, without an account, for 3 days on public and private repos, or [sign in](command:gitlens.plus.loginOrSignUp \"Sign in now\") for unlimited use on public repos.\n\n[Try worktrees now](command:gitlens.plus.startPreviewTrial)",
"contents": "Try worktrees now, without an account, for 3 days on public and private repos, or [sign in](command:gitlens.plus.loginOrSignUp \"Sign in to GitLens+\") for use on public repos.\n\n[Try worktrees now](command:gitlens.plus.startPreviewTrial)",
"when": "gitlens:plus:state == 0" "when": "gitlens:plus:state == 0"
}, },
{ {
"view": "gitlens.views.worktrees", "view": "gitlens.views.worktrees",
"contents": "Sign in to use worktrees and other premium features on public repos and get a free 7-day trial for both public and private repos.\n\n[Sign in](command:gitlens.plus.loginOrSignUp)",
"contents": "Sign in to use worktrees and other GitLens+ features on public repos and get a free 7-day trial for both public and private repos.\n\n[Sign in to GitLens+](command:gitlens.plus.loginOrSignUp)",
"when": "gitlens:plus:state == 2" "when": "gitlens:plus:state == 2"
}, },
{ {
@ -10694,7 +10694,7 @@
}, },
{ {
"view": "gitlens.views.worktrees", "view": "gitlens.views.worktrees",
"contents": "✨ Worktrees are a [premium feature](command:gitlens.plus.learn) which can be used on public repos with a [free account](command:gitlens.plus.loginOrSignUp) and private repos with a [paid account](command:gitlens.plus.purchase).\n\n🛈 Non-premium features can always be used on any repo.",
"contents": "✨ Worktrees are a [GitLens+ feature](command:gitlens.plus.learn) which can be used on public repos with a [free account](command:gitlens.plus.loginOrSignUp) and private repos with a [paid account](command:gitlens.plus.purchase).\n\n🛈 All other GitLens features can always be used on any repo.",
"when": "gitlens:plus:state > -1" "when": "gitlens:plus:state > -1"
} }
], ],
@ -10907,24 +10907,24 @@
} }
}, },
{ {
"id": "gitlens.welcome.premium",
"title": "✨ Premium features",
"description": "New premium features like Visual File History and Worktrees are now available in GitLens.\n\n[Learn about Premium Features](command:gitlens.plus.learn?false \"Opens the GitLens Premium Features walkthrough\")",
"id": "gitlens.welcome.plus",
"title": "Introducing GitLens+",
"description": "Check out the all-new, completely optional, GitLens+ features.\n\n[Learn about GitLens+ features](command:gitlens.plus.learn?false \"Open the GitLens+ features walkthrough\")",
"media": { "media": {
"markdown": "walkthroughs/getting-started/12-premium-features.md"
"markdown": "walkthroughs/getting-started/12-plus.md"
} }
} }
] ]
}, },
{ {
"id": "gitlens.plus", "id": "gitlens.plus",
"title": "GitLens Premium Features",
"title": "Introducing GitLens+",
"description": "Get even more out of GitLens in VS Code!", "description": "Get even more out of GitLens in VS Code!",
"steps": [ "steps": [
{ {
"id": "gitlens.plus.intro.tryNow", "id": "gitlens.plus.intro.tryNow",
"title": "Introducing premium features",
"description": "Try premium features now, without an account, for 3 days.\n\n[Try premium features now](command:gitlens.plus.startPreviewTrial)",
"title": "Introducing GitLens+",
"description": "Try GitLens+ features now, without an account, for 3 days.\n\n[Try GitLens+ features now](command:gitlens.plus.startPreviewTrial)",
"media": { "media": {
"markdown": "walkthroughs/plus/1-intro.md" "markdown": "walkthroughs/plus/1-intro.md"
}, },
@ -10932,8 +10932,8 @@
}, },
{ {
"id": "gitlens.plus.intro.signIn", "id": "gitlens.plus.intro.signIn",
"title": "Introducing premium features",
"description": "Sign in for an additional 7 day trial of premium features.\n\n[Sign in](command:gitlens.plus.loginOrSignUp)",
"title": "Introducing GitLens+",
"description": "Sign in for use on public repos and get an additional 7 day trial for private repos.\n\n[Sign in to GitLens+](command:gitlens.plus.loginOrSignUp)",
"media": { "media": {
"markdown": "walkthroughs/plus/1-intro.md" "markdown": "walkthroughs/plus/1-intro.md"
}, },
@ -10941,7 +10941,7 @@
}, },
{ {
"id": "gitlens.plus.intro", "id": "gitlens.plus.intro",
"title": "Introducing premium features",
"title": "Introducing GitLens+",
"media": { "media": {
"markdown": "walkthroughs/plus/1-intro.md" "markdown": "walkthroughs/plus/1-intro.md"
}, },
@ -10973,8 +10973,8 @@
}, },
{ {
"id": "gitlens.plus.tryNow", "id": "gitlens.plus.tryNow",
"title": "Try premium features now",
"description": "Try premium features now, without an account, for 3 days.\n\n[Try premium features now](command:gitlens.plus.startPreviewTrial)",
"title": "Try GitLens+ now",
"description": "Try GitLens+ features now, without an account, for 3 days.\n\n[Try GitLens+ features now](command:gitlens.plus.startPreviewTrial)",
"media": { "media": {
"markdown": "walkthroughs/plus/5-try-now.md" "markdown": "walkthroughs/plus/5-try-now.md"
}, },
@ -10982,8 +10982,8 @@
}, },
{ {
"id": "gitlens.plus.signIn", "id": "gitlens.plus.signIn",
"title": "Extend your premium features trial",
"description": "Sign in for an additional 7 day trial of premium features.\n\n[Sign in](command:gitlens.plus.loginOrSignUp)",
"title": "Get access to GitLens+ features on public repos",
"description": "Sign in for use on public repos and get an additional 7 day trial for private repos.\n\n[Sign in to GitLens+](command:gitlens.plus.loginOrSignUp)",
"media": { "media": {
"markdown": "walkthroughs/plus/5-try-now.md" "markdown": "walkthroughs/plus/5-try-now.md"
}, },

+ 2
- 2
src/commands/git/worktree.ts View File

@ -1,7 +1,7 @@
import { MessageItem, QuickInputButtons, Uri, window } from 'vscode'; import { MessageItem, QuickInputButtons, Uri, window } from 'vscode';
import { configuration } from '../../configuration'; import { configuration } from '../../configuration';
import { Container } from '../../container'; import { Container } from '../../container';
import { PremiumFeatures } from '../../features';
import { PlusFeatures } from '../../features';
import { import {
WorktreeCreateError, WorktreeCreateError,
WorktreeCreateErrorReason, WorktreeCreateErrorReason,
@ -200,7 +200,7 @@ export class WorktreeGitCommand extends QuickCommand {
} }
} }
const result = yield* ensureAccessStep(state as any, context, PremiumFeatures.Worktrees);
const result = yield* ensureAccessStep(state as any, context, PlusFeatures.Worktrees);
if (result === StepResult.Break) break; if (result === StepResult.Break) break;
context.title = getTitle(state.subcommand === 'delete' ? 'Worktrees' : this.title, state.subcommand); context.title = getTitle(state.subcommand === 'delete' ? 'Worktrees' : this.title, state.subcommand);

+ 4
- 4
src/commands/quickCommand.steps.ts View File

@ -2,7 +2,7 @@ import { QuickInputButton, QuickPick } from 'vscode';
import { BranchSorting, configuration, TagSorting } from '../configuration'; import { BranchSorting, configuration, TagSorting } from '../configuration';
import { Commands, GlyphChars, quickPickTitleMaxChars } from '../constants'; import { Commands, GlyphChars, quickPickTitleMaxChars } from '../constants';
import { Container } from '../container'; import { Container } from '../container';
import type { PremiumFeatures } from '../features';
import type { PlusFeatures } from '../features';
import type { PagedResult } from '../git/gitProvider'; import type { PagedResult } from '../git/gitProvider';
import { import {
BranchSortOptions, BranchSortOptions,
@ -2233,7 +2233,7 @@ function getShowRepositoryStatusStepItems<
export async function* ensureAccessStep< export async function* ensureAccessStep<
State extends PartialStepState & { repo: Repository }, State extends PartialStepState & { repo: Repository },
Context extends { repos: Repository[]; title: string }, Context extends { repos: Repository[]; title: string },
>(state: State, context: Context, feature: PremiumFeatures): AsyncStepResultGenerator<void> {
>(state: State, context: Context, feature: PlusFeatures): AsyncStepResultGenerator<void> {
const access = await Container.instance.git.access(feature, state.repo.path); const access = await Container.instance.git.access(feature, state.repo.path);
if (access.allowed) return undefined; if (access.allowed) return undefined;
@ -2247,7 +2247,7 @@ export async function* ensureAccessStep<
if (isSubscriptionPaidPlan(access.subscription.required) && access.subscription.current.account != null) { if (isSubscriptionPaidPlan(access.subscription.required) && access.subscription.current.account != null) {
directives.push(DirectiveQuickPickItem.create(Directive.RequiresPaidSubscription, true)); directives.push(DirectiveQuickPickItem.create(Directive.RequiresPaidSubscription, true));
placeholder = 'Premium features require an upgraded account';
placeholder = 'GitLens+ features require an upgraded account';
} else { } else {
if ( if (
access.subscription.current.account == null && access.subscription.current.account == null &&
@ -2260,7 +2260,7 @@ export async function* ensureAccessStep<
} else { } else {
directives.push(DirectiveQuickPickItem.create(Directive.RequiresFreeSubscription)); directives.push(DirectiveQuickPickItem.create(Directive.RequiresFreeSubscription));
} }
placeholder = 'Premium features require an account';
placeholder = 'GitLens+ features require a free account';
} }
} }

+ 1
- 1
src/config.ts View File

@ -113,7 +113,7 @@ export interface Config {
[key: string]: any; [key: string]: any;
} }
> | null; > | null;
premiumFeatures: {
plusFeatures: {
enabled: boolean; enabled: boolean;
}; };
remotes: RemotesConfig[] | null; remotes: RemotesConfig[] | null;

+ 15
- 15
src/constants.ts View File

@ -137,17 +137,17 @@ export const enum Commands {
GitCommandsSwitch = 'gitlens.gitCommands.switch', GitCommandsSwitch = 'gitlens.gitCommands.switch',
GitCommandsTag = 'gitlens.gitCommands.tag', GitCommandsTag = 'gitlens.gitCommands.tag',
GitCommandsWorktree = 'gitlens.gitCommands.worktree', GitCommandsWorktree = 'gitlens.gitCommands.worktree',
PremiumHide = 'gitlens.plus.hide',
PremiumLearn = 'gitlens.plus.learn',
PremiumLoginOrSignUp = 'gitlens.plus.loginOrSignUp',
PremiumLogout = 'gitlens.plus.logout',
PremiumManage = 'gitlens.plus.manage',
PremiumPurchase = 'gitlens.plus.purchase',
PremiumResendVerification = 'gitlens.plus.resendVerification',
PremiumRestore = 'gitlens.plus.restore',
PremiumShowPlans = 'gitlens.plus.showPlans',
PremiumStartPreviewTrial = 'gitlens.plus.startPreviewTrial',
PremiumValidate = 'gitlens.plus.validate',
PlusHide = 'gitlens.plus.hide',
PlusLearn = 'gitlens.plus.learn',
PlusLoginOrSignUp = 'gitlens.plus.loginOrSignUp',
PlusLogout = 'gitlens.plus.logout',
PlusManage = 'gitlens.plus.manage',
PlusPurchase = 'gitlens.plus.purchase',
PlusResendVerification = 'gitlens.plus.resendVerification',
PlusRestore = 'gitlens.plus.restore',
PlusShowPlans = 'gitlens.plus.showPlans',
PlusStartPreviewTrial = 'gitlens.plus.startPreviewTrial',
PlusValidate = 'gitlens.plus.validate',
QuickOpenFileHistory = 'gitlens.quickOpenFileHistory', QuickOpenFileHistory = 'gitlens.quickOpenFileHistory',
RefreshHover = 'gitlens.refreshHover', RefreshHover = 'gitlens.refreshHover',
ResetAvatarCache = 'gitlens.resetAvatarCache', ResetAvatarCache = 'gitlens.resetAvatarCache',
@ -257,10 +257,10 @@ export const enum ContextKeys {
ViewsSearchAndCompareKeepResults = 'gitlens:views:searchAndCompare:keepResults', ViewsSearchAndCompareKeepResults = 'gitlens:views:searchAndCompare:keepResults',
Vsls = 'gitlens:vsls', Vsls = 'gitlens:vsls',
Premium = 'gitlens:premium',
PremiumAllowed = 'gitlens:plus:allowed',
PremiumRequired = 'gitlens:plus:required',
PremiumState = 'gitlens:plus:state',
Plus = 'gitlens:plus',
PlusAllowed = 'gitlens:plus:allowed',
PlusRequired = 'gitlens:plus:required',
PlusState = 'gitlens:plus:state',
} }
export const enum CoreCommands { export const enum CoreCommands {

+ 4
- 4
src/env/node/git/localGitProvider.ts View File

@ -26,7 +26,7 @@ import type {
import { configuration } from '../../../configuration'; import { configuration } from '../../../configuration';
import { CoreGitConfiguration, GlyphChars, Schemes } from '../../../constants'; import { CoreGitConfiguration, GlyphChars, Schemes } from '../../../constants';
import type { Container } from '../../../container'; import type { Container } from '../../../container';
import { Features, PremiumFeatures } from '../../../features';
import { Features, PlusFeatures } from '../../../features';
import { import {
StashApplyError, StashApplyError,
StashApplyErrorReason, StashApplyErrorReason,
@ -397,8 +397,8 @@ export class LocalGitProvider implements GitProvider, Disposable {
}; };
} }
private _allowedFeatures = new Map<string, Map<PremiumFeatures, boolean>>();
async allows(feature: PremiumFeatures, plan: SubscriptionPlanId, repoPath?: string): Promise<boolean> {
private _allowedFeatures = new Map<string, Map<PlusFeatures, boolean>>();
async allows(feature: PlusFeatures, plan: SubscriptionPlanId, repoPath?: string): Promise<boolean> {
if (plan === SubscriptionPlanId.Free) return false; if (plan === SubscriptionPlanId.Free) return false;
if (plan === SubscriptionPlanId.Pro) return true; if (plan === SubscriptionPlanId.Pro) return true;
@ -416,7 +416,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
? true ? true
: (await this.visibility(repoPath)) === RepositoryVisibility.Public; : (await this.visibility(repoPath)) === RepositoryVisibility.Public;
if (allowedByRepo == null) { if (allowedByRepo == null) {
allowedByRepo = new Map<PremiumFeatures, boolean>();
allowedByRepo = new Map<PlusFeatures, boolean>();
this._allowedFeatures.set(repoPath, allowedByRepo); this._allowedFeatures.set(repoPath, allowedByRepo);
} }

+ 1
- 1
src/features.ts View File

@ -10,7 +10,7 @@ export type FeatureAccess =
| { allowed: true; subscription: { current: Subscription; required?: undefined } } | { allowed: true; subscription: { current: Subscription; required?: undefined } }
| { allowed: false; subscription: { current: Subscription; required?: RequiredSubscriptionPlans } }; | { allowed: false; subscription: { current: Subscription; required?: RequiredSubscriptionPlans } };
export const enum PremiumFeatures {
export const enum PlusFeatures {
Timeline = 'timeline', Timeline = 'timeline',
Worktrees = 'worktrees', Worktrees = 'worktrees',
} }

+ 2
- 2
src/git/gitProvider.ts View File

@ -1,6 +1,6 @@
import { Disposable, Event, Range, TextDocument, Uri, WorkspaceFolder } from 'vscode'; import { Disposable, Event, Range, TextDocument, Uri, WorkspaceFolder } from 'vscode';
import type { Commit, InputBox } from '../@types/vscode.git'; import type { Commit, InputBox } from '../@types/vscode.git';
import { Features, PremiumFeatures } from '../features';
import { Features, PlusFeatures } from '../features';
import type { SubscriptionPlanId } from '../subscription'; import type { SubscriptionPlanId } from '../subscription';
import type { GitUri } from './gitUri'; import type { GitUri } from './gitUri';
import type { import type {
@ -115,7 +115,7 @@ export interface GitProvider extends Disposable {
): Repository; ): Repository;
openRepositoryInitWatcher?(): RepositoryInitWatcher; openRepositoryInitWatcher?(): RepositoryInitWatcher;
allows(feature: PremiumFeatures, plan: SubscriptionPlanId, repoPath?: string): Promise<boolean>;
allows(feature: PlusFeatures, plan: SubscriptionPlanId, repoPath?: string): Promise<boolean>;
supports(feature: Features): Promise<boolean>; supports(feature: Features): Promise<boolean>;
visibility(repoPath: string): Promise<RepositoryVisibility>; visibility(repoPath: string): Promise<RepositoryVisibility>;

+ 5
- 5
src/git/gitProviderService.ts View File

@ -21,7 +21,7 @@ import { ContextKeys, CoreGitConfiguration, GlyphChars, Schemes } from '../const
import type { Container } from '../container'; import type { Container } from '../container';
import { setContext } from '../context'; import { setContext } from '../context';
import { AccessDeniedError, ProviderNotFoundError } from '../errors'; import { AccessDeniedError, ProviderNotFoundError } from '../errors';
import type { FeatureAccess, Features, PremiumFeatures } from '../features';
import type { FeatureAccess, Features, PlusFeatures } from '../features';
import { Logger } from '../logger'; import { Logger } from '../logger';
import type { SubscriptionChangeEvent } from '../premium/subscription/subscriptionService'; import type { SubscriptionChangeEvent } from '../premium/subscription/subscriptionService';
import { asRepoComparisonKey, RepoComparisionKey, Repositories } from '../repositories'; import { asRepoComparisonKey, RepoComparisionKey, Repositories } from '../repositories';
@ -126,7 +126,7 @@ export const enum RepositoriesVisibility {
} }
export class GitProviderService implements Disposable { export class GitProviderService implements Disposable {
static readonly previewFeatures: Map<PremiumFeatures | undefined, boolean> | undefined; // = new Map();
static readonly previewFeatures: Map<PlusFeatures | undefined, boolean> | undefined; // = new Map();
private readonly _onDidChangeProviders = new EventEmitter<GitProvidersChangeEvent>(); private readonly _onDidChangeProviders = new EventEmitter<GitProvidersChangeEvent>();
get onDidChangeProviders(): Event<GitProvidersChangeEvent> { get onDidChangeProviders(): Event<GitProvidersChangeEvent> {
@ -533,7 +533,7 @@ export class GitProviderService implements Disposable {
} }
private _accessCache = new Map<string | undefined, Promise<FeatureAccess>>(); private _accessCache = new Map<string | undefined, Promise<FeatureAccess>>();
async access(feature?: PremiumFeatures, repoPath?: string | Uri): Promise<FeatureAccess> {
async access(feature?: PlusFeatures, repoPath?: string | Uri): Promise<FeatureAccess> {
let cacheKey; let cacheKey;
if (repoPath != null) { if (repoPath != null) {
const { path } = this.getProvider(repoPath); const { path } = this.getProvider(repoPath);
@ -549,7 +549,7 @@ export class GitProviderService implements Disposable {
} }
@debug() @debug()
private async accessCore(feature?: PremiumFeatures, repoPath?: string | Uri): Promise<FeatureAccess> {
private async accessCore(feature?: PlusFeatures, repoPath?: string | Uri): Promise<FeatureAccess> {
const subscription = await this.getSubscription(); const subscription = await this.getSubscription();
if (subscription.account?.verified === false) { if (subscription.account?.verified === false) {
return { allowed: false, subscription: { current: subscription } }; return { allowed: false, subscription: { current: subscription } };
@ -630,7 +630,7 @@ export class GitProviderService implements Disposable {
return getRepoAccess.call(this, repoPath, plan); return getRepoAccess.call(this, repoPath, plan);
} }
async ensureAccess(feature: PremiumFeatures, repoPath?: string): Promise<void> {
async ensureAccess(feature: PlusFeatures, repoPath?: string): Promise<void> {
const { allowed, subscription } = await this.access(feature, repoPath); const { allowed, subscription } = await this.access(feature, repoPath);
if (!allowed) throw new AccessDeniedError(subscription.current, subscription.required); if (!allowed) throw new AccessDeniedError(subscription.current, subscription.required);
} }

+ 2
- 2
src/git/models/repository.ts View File

@ -14,7 +14,7 @@ import type { CreatePullRequestActionContext } from '../../api/gitlens';
import { configuration } from '../../configuration'; import { configuration } from '../../configuration';
import { CoreGitCommands, CoreGitConfiguration, Schemes } from '../../constants'; import { CoreGitCommands, CoreGitConfiguration, Schemes } from '../../constants';
import { Container } from '../../container'; import { Container } from '../../container';
import type { FeatureAccess, Features, PremiumFeatures } from '../../features';
import type { FeatureAccess, Features, PlusFeatures } from '../../features';
import { Logger } from '../../logger'; import { Logger } from '../../logger';
import { Messages } from '../../messages'; import { Messages } from '../../messages';
import { asRepoComparisonKey } from '../../repositories'; import { asRepoComparisonKey } from '../../repositories';
@ -400,7 +400,7 @@ export class Repository implements Disposable {
} }
@log() @log()
access(feature?: PremiumFeatures): Promise<FeatureAccess> {
access(feature?: PlusFeatures): Promise<FeatureAccess> {
return this.container.git.access(feature, this.uri); return this.container.git.access(feature, this.uri);
} }

+ 4
- 4
src/premium/github/githubGitProvider.ts View File

@ -25,7 +25,7 @@ import {
OpenVirtualRepositoryError, OpenVirtualRepositoryError,
OpenVirtualRepositoryErrorReason, OpenVirtualRepositoryErrorReason,
} from '../../errors'; } from '../../errors';
import { Features, PremiumFeatures } from '../../features';
import { Features, PlusFeatures } from '../../features';
import { import {
GitProvider, GitProvider,
GitProviderId, GitProviderId,
@ -188,8 +188,8 @@ export class GitHubGitProvider implements GitProvider, Disposable {
); );
} }
private _allowedFeatures = new Map<string, Map<PremiumFeatures, boolean>>();
async allows(feature: PremiumFeatures, plan: SubscriptionPlanId, repoPath?: string): Promise<boolean> {
private _allowedFeatures = new Map<string, Map<PlusFeatures, boolean>>();
async allows(feature: PlusFeatures, plan: SubscriptionPlanId, repoPath?: string): Promise<boolean> {
if (plan === SubscriptionPlanId.Free) return false; if (plan === SubscriptionPlanId.Free) return false;
if (plan === SubscriptionPlanId.Pro) return true; if (plan === SubscriptionPlanId.Pro) return true;
@ -207,7 +207,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
? true ? true
: (await this.visibility(repoPath)) === RepositoryVisibility.Public; : (await this.visibility(repoPath)) === RepositoryVisibility.Public;
if (allowedByRepo == null) { if (allowedByRepo == null) {
allowedByRepo = new Map<PremiumFeatures, boolean>();
allowedByRepo = new Map<PlusFeatures, boolean>();
this._allowedFeatures.set(repoPath, allowedByRepo); this._allowedFeatures.set(repoPath, allowedByRepo);
} }

+ 4
- 4
src/premium/subscription/authenticationProvider.ts View File

@ -24,9 +24,9 @@ interface StoredSession {
scopes: string[]; scopes: string[];
} }
const authenticationId = 'gitlens-gitkraken';
const authenticationLabel = 'GitKraken';
const authenticationSecretKey = `gitkraken.auth`;
const authenticationId = 'gitlens+';
const authenticationLabel = 'GitLens+';
const authenticationSecretKey = `gitlens.plus.auth`;
export class SubscriptionAuthenticationProvider implements AuthenticationProvider, Disposable { export class SubscriptionAuthenticationProvider implements AuthenticationProvider, Disposable {
private _onDidChangeSessions = new EventEmitter<AuthenticationProviderAuthenticationSessionsChangeEvent>(); private _onDidChangeSessions = new EventEmitter<AuthenticationProviderAuthenticationSessionsChangeEvent>();
@ -82,7 +82,7 @@ export class SubscriptionAuthenticationProvider implements AuthenticationProvide
if (ex === 'Cancelled') throw ex; if (ex === 'Cancelled') throw ex;
Logger.error(ex, cc); Logger.error(ex, cc);
void window.showErrorMessage(`Unable to sign in: ${ex}`);
void window.showErrorMessage(`Unable to sign in to GitLens+: ${ex}`);
throw ex; throw ex;
} }
} }

+ 35
- 36
src/premium/subscription/subscriptionService.ts View File

@ -47,7 +47,7 @@ import { memoize } from '../../system/decorators/memoize';
import { once } from '../../system/function'; import { once } from '../../system/function';
import { pluralize } from '../../system/string'; import { pluralize } from '../../system/string';
import { openWalkthrough } from '../../system/utils'; import { openWalkthrough } from '../../system/utils';
import { ensurePremiumFeaturesEnabled } from './utils';
import { ensurePlusFeaturesEnabled } from './utils';
// TODO: What user-agent should we use? // TODO: What user-agent should we use?
const userAgent = 'Visual-Studio-Code-GitLens'; const userAgent = 'Visual-Studio-Code-GitLens';
@ -59,7 +59,7 @@ export interface SubscriptionChangeEvent {
} }
export class SubscriptionService implements Disposable { export class SubscriptionService implements Disposable {
private static authenticationProviderId = 'gitlens-gitkraken';
private static authenticationProviderId = 'gitlens+';
private static authenticationScopes = ['gitlens']; private static authenticationScopes = ['gitlens'];
private _onDidChange = new EventEmitter<SubscriptionChangeEvent>(); private _onDidChange = new EventEmitter<SubscriptionChangeEvent>();
@ -161,24 +161,24 @@ export class SubscriptionService implements Disposable {
void this.container.viewCommands; void this.container.viewCommands;
return [ return [
commands.registerCommand(Commands.PremiumLearn, openToSide => this.learn(openToSide)),
commands.registerCommand(Commands.PremiumLoginOrSignUp, () => this.loginOrSignUp()),
commands.registerCommand(Commands.PremiumLogout, () => this.logout()),
commands.registerCommand(Commands.PlusLearn, openToSide => this.learn(openToSide)),
commands.registerCommand(Commands.PlusLoginOrSignUp, () => this.loginOrSignUp()),
commands.registerCommand(Commands.PlusLogout, () => this.logout()),
commands.registerCommand(Commands.PremiumStartPreviewTrial, () => this.startPreviewTrial()),
commands.registerCommand(Commands.PremiumManage, () => this.manage()),
commands.registerCommand(Commands.PremiumPurchase, () => this.purchase()),
commands.registerCommand(Commands.PlusStartPreviewTrial, () => this.startPreviewTrial()),
commands.registerCommand(Commands.PlusManage, () => this.manage()),
commands.registerCommand(Commands.PlusPurchase, () => this.purchase()),
commands.registerCommand(Commands.PremiumResendVerification, () => this.resendVerification()),
commands.registerCommand(Commands.PremiumValidate, () => this.validate()),
commands.registerCommand(Commands.PlusResendVerification, () => this.resendVerification()),
commands.registerCommand(Commands.PlusValidate, () => this.validate()),
commands.registerCommand(Commands.PremiumShowPlans, () => this.showPlans()),
commands.registerCommand(Commands.PlusShowPlans, () => this.showPlans()),
commands.registerCommand(Commands.PremiumHide, () =>
configuration.updateEffective('premiumFeatures.enabled', false),
commands.registerCommand(Commands.PlusHide, () =>
configuration.updateEffective('plusFeatures.enabled', false),
), ),
commands.registerCommand(Commands.PremiumRestore, () =>
configuration.updateEffective('premiumFeatures.enabled', true),
commands.registerCommand(Commands.PlusRestore, () =>
configuration.updateEffective('plusFeatures.enabled', true),
), ),
commands.registerCommand('gitlens.plus.reset', () => this.logout(true)), commands.registerCommand('gitlens.plus.reset', () => this.logout(true)),
@ -198,7 +198,7 @@ export class SubscriptionService implements Disposable {
@gate() @gate()
@log() @log()
async loginOrSignUp(): Promise<boolean> { async loginOrSignUp(): Promise<boolean> {
if (!(await ensurePremiumFeaturesEnabled())) return false;
if (!(await ensurePlusFeaturesEnabled())) return false;
void this.showHomeView(); void this.showHomeView();
@ -209,7 +209,7 @@ export class SubscriptionService implements Disposable {
if (loggedIn) { if (loggedIn) {
const { const {
account, account,
plan: { actual },
plan: { actual, effective },
} = this._subscription; } = this._subscription;
if (account?.verified === false) { if (account?.verified === false) {
@ -232,10 +232,9 @@ export class SubscriptionService implements Disposable {
const result = await window.showInformationMessage( const result = await window.showInformationMessage(
`You are now signed in to your ${ `You are now signed in to your ${
actual.name actual.name
} account which gives you access to premium features for public repos.\n\nYou were also granted a trial of premium features for both public and private repos for ${pluralize(
'more day',
remaining ?? 0,
)}.`,
} account which gives you access to GitLens+ features on public repos.\n\nYou were also granted a trial of ${
effective.name
} for both public and private repos for ${pluralize('more day', remaining ?? 0)}.`,
{ modal: true }, { modal: true },
confirm, confirm,
learn, learn,
@ -281,7 +280,7 @@ export class SubscriptionService implements Disposable {
@log() @log()
async purchase(): Promise<void> { async purchase(): Promise<void> {
if (!(await ensurePremiumFeaturesEnabled())) return;
if (!(await ensurePlusFeaturesEnabled())) return;
if (this._subscription.account == null) { if (this._subscription.account == null) {
void this.showPlans(); void this.showPlans();
@ -345,7 +344,7 @@ export class SubscriptionService implements Disposable {
@log() @log()
async showHomeView(silent: boolean = false): Promise<void> { async showHomeView(silent: boolean = false): Promise<void> {
if (silent && !configuration.get('premiumFeatures.enabled', undefined, true)) return;
if (silent && !configuration.get('plusFeatures.enabled', undefined, true)) return;
if (!this.container.homeView.visible) { if (!this.container.homeView.visible) {
await executeCommand(Commands.ShowHomeView); await executeCommand(Commands.ShowHomeView);
@ -359,17 +358,17 @@ export class SubscriptionService implements Disposable {
@gate() @gate()
@log() @log()
async startPreviewTrial(): Promise<void> { async startPreviewTrial(): Promise<void> {
if (!(await ensurePremiumFeaturesEnabled())) return;
if (!(await ensurePlusFeaturesEnabled())) return;
let { plan, previewTrial } = this._subscription; let { plan, previewTrial } = this._subscription;
if (previewTrial != null || plan.effective.id !== SubscriptionPlanId.Free) { if (previewTrial != null || plan.effective.id !== SubscriptionPlanId.Free) {
void this.showHomeView(); void this.showHomeView();
if (plan.effective.id === SubscriptionPlanId.Free) { if (plan.effective.id === SubscriptionPlanId.Free) {
const confirm: MessageItem = { title: 'Sign In', isCloseAffordance: true };
const confirm: MessageItem = { title: 'Sign in to GitLens+', isCloseAffordance: true };
const cancel: MessageItem = { title: 'Cancel' }; const cancel: MessageItem = { title: 'Cancel' };
const result = await window.showInformationMessage( const result = await window.showInformationMessage(
'Your GitLens premium features trial has ended.\nPlease sign in to use premium features on public repos and get a free 7-day trial for both public and private repos.',
'Your GitLens+ features trial has ended.\nPlease sign in to use GitLens+ features on public repos and get a free 7-day trial for both public and private repos.',
{ modal: true }, { modal: true },
confirm, confirm,
cancel, cancel,
@ -413,7 +412,7 @@ export class SubscriptionService implements Disposable {
const confirm: MessageItem = { title: 'OK', isCloseAffordance: true }; const confirm: MessageItem = { title: 'OK', isCloseAffordance: true };
const learn: MessageItem = { title: 'Learn More' }; const learn: MessageItem = { title: 'Learn More' };
const result = await window.showInformationMessage( const result = await window.showInformationMessage(
`You have started a ${days} day trial of GitLens premium features for both public and private repos.`,
`You have started a ${days} day trial of GitLens+ features for both public and private repos.`,
{ modal: true }, { modal: true },
confirm, confirm,
learn, learn,
@ -642,7 +641,7 @@ export class SubscriptionService implements Disposable {
if (createIfNeeded) { if (createIfNeeded) {
void window.showErrorMessage( void window.showErrorMessage(
`Unable to sign in to your account. Please try again. If this issue persists, please contact support. Account=${name} Error=${ex.message}`,
`Unable to sign in to your GitLens+ account. Please try again. If this issue persists, please contact support. Account=${name} Error=${ex.message}`,
'OK', 'OK',
); );
} }
@ -702,12 +701,12 @@ export class SubscriptionService implements Disposable {
} }
private getStoredSubscription(): Subscription | undefined { private getStoredSubscription(): Subscription | undefined {
const storedSubscription = this.container.storage.get<Stored<Subscription>>(StorageKeys.PremiumSubscription);
const storedSubscription = this.container.storage.get<Stored<Subscription>>(StorageKeys.Subscription);
return storedSubscription?.data; return storedSubscription?.data;
} }
private async storeSubscription(subscription: Subscription): Promise<void> { private async storeSubscription(subscription: Subscription): Promise<void> {
return this.container.storage.store<Stored<Subscription>>(StorageKeys.PremiumSubscription, {
return this.container.storage.store<Stored<Subscription>>(StorageKeys.Subscription, {
v: 1, v: 1,
data: subscription, data: subscription,
}); });
@ -723,8 +722,8 @@ export class SubscriptionService implements Disposable {
: subscription.required != null && isSubscriptionPaidPlan(subscription.required) : subscription.required != null && isSubscriptionPaidPlan(subscription.required)
? 'paid' ? 'paid'
: 'free+'; : 'free+';
void setContext(ContextKeys.PremiumAllowed, allowed);
void setContext(ContextKeys.PremiumRequired, required);
void setContext(ContextKeys.PlusAllowed, allowed);
void setContext(ContextKeys.PlusRequired, required);
}); });
const { const {
@ -732,8 +731,8 @@ export class SubscriptionService implements Disposable {
state, state,
} = this._subscription; } = this._subscription;
void setContext(ContextKeys.Premium, actual.id != SubscriptionPlanId.Free ? actual.id : undefined);
void setContext(ContextKeys.PremiumState, state);
void setContext(ContextKeys.Plus, actual.id != SubscriptionPlanId.Free ? actual.id : undefined);
void setContext(ContextKeys.PlusState, state);
} }
private updateStatusBar(): void { private updateStatusBar(): void {
@ -772,7 +771,7 @@ export class SubscriptionService implements Disposable {
this._statusBarSubscription.tooltip = new MarkdownString( this._statusBarSubscription.tooltip = new MarkdownString(
trial trial
? `**Please verify your email**\n\nBefore you can start your **${effective.name}** trial, please verify the email for the account you created.\n\nClick for details` ? `**Please verify your email**\n\nBefore you can start your **${effective.name}** trial, please verify the email for the account you created.\n\nClick for details`
: `**Please verify your email**\n\nBefore you use premium GitLens features, please verify the email for the account you created.\n\nClick for details`,
: `**Please verify your email**\n\nBefore you can use GitLens+ features, please verify the email for the account you created.\n\nClick for details`,
true, true,
); );
} else { } else {
@ -782,7 +781,7 @@ export class SubscriptionService implements Disposable {
this._statusBarSubscription.tooltip = new MarkdownString( this._statusBarSubscription.tooltip = new MarkdownString(
`You are currently trialing **${ `You are currently trialing **${
effective.name effective.name
}**, which gives you access to premium GitLens features. You have ${pluralize(
}**, which gives you access to GitLens+ features on both public and private repos. You have ${pluralize(
'day', 'day',
remaining ?? 0, remaining ?? 0,
)} remaining in your trial.\n\nClick for details`, )} remaining in your trial.\n\nClick for details`,

+ 4
- 4
src/premium/subscription/utils.ts View File

@ -1,13 +1,13 @@
import { MessageItem, window } from 'vscode'; import { MessageItem, window } from 'vscode';
import { configuration } from '../../configuration'; import { configuration } from '../../configuration';
export async function ensurePremiumFeaturesEnabled(): Promise<boolean> {
if (configuration.get('premiumFeatures.enabled', undefined, true)) return true;
export async function ensurePlusFeaturesEnabled(): Promise<boolean> {
if (configuration.get('plusFeatures.enabled', undefined, true)) return true;
const confirm: MessageItem = { title: 'Enable' }; const confirm: MessageItem = { title: 'Enable' };
const cancel: MessageItem = { title: 'Cancel', isCloseAffordance: true }; const cancel: MessageItem = { title: 'Cancel', isCloseAffordance: true };
const result = await window.showInformationMessage( const result = await window.showInformationMessage(
'Premium features are currently disabled. Would you like to enable them?',
'GitLens+ features are currently disabled. Would you like to enable them?',
{ modal: true }, { modal: true },
confirm, confirm,
cancel, cancel,
@ -15,6 +15,6 @@ export async function ensurePremiumFeaturesEnabled(): Promise {
if (result !== confirm) return false; if (result !== confirm) return false;
void (await configuration.updateEffective('premiumFeatures.enabled', true));
void (await configuration.updateEffective('plusFeatures.enabled', true));
return true; return true;
} }

+ 4
- 4
src/premium/webviews/timeline/timelineWebview.ts View File

@ -5,7 +5,7 @@ import { configuration } from '../../../configuration';
import { Commands, ContextKeys } from '../../../constants'; import { Commands, ContextKeys } from '../../../constants';
import type { Container } from '../../../container'; import type { Container } from '../../../container';
import { setContext } from '../../../context'; import { setContext } from '../../../context';
import { PremiumFeatures } from '../../../features';
import { PlusFeatures } from '../../../features';
import { GitUri } from '../../../git/gitUri'; import { GitUri } from '../../../git/gitUri';
import { RepositoryChange, RepositoryChangeComparisonMode, RepositoryChangeEvent } from '../../../git/models'; import { RepositoryChange, RepositoryChangeComparisonMode, RepositoryChangeEvent } from '../../../git/models';
import { createFromDateDelta } from '../../../system/date'; import { createFromDateDelta } from '../../../system/date';
@ -16,7 +16,7 @@ import { hasVisibleTextEditor, isTextEditor } from '../../../system/utils';
import { IpcMessage, onIpc } from '../../../webviews/protocol'; import { IpcMessage, onIpc } from '../../../webviews/protocol';
import { WebviewBase } from '../../../webviews/webviewBase'; import { WebviewBase } from '../../../webviews/webviewBase';
import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService'; import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService';
import { ensurePremiumFeaturesEnabled } from '../../subscription/utils';
import { ensurePlusFeaturesEnabled } from '../../subscription/utils';
import { import {
Commit, Commit,
DidChangeStateNotificationType, DidChangeStateNotificationType,
@ -63,7 +63,7 @@ export class TimelineWebview extends WebviewBase {
} }
override async show(column: ViewColumn = ViewColumn.Beside): Promise<void> { override async show(column: ViewColumn = ViewColumn.Beside): Promise<void> {
if (!(await ensurePremiumFeaturesEnabled())) return;
if (!(await ensurePlusFeaturesEnabled())) return;
return super.show(column); return super.show(column);
} }
@ -202,7 +202,7 @@ export class TimelineWebview extends WebviewBase {
@debug({ args: false }) @debug({ args: false })
private async getState(current: Context): Promise<State> { private async getState(current: Context): Promise<State> {
const access = await this.container.git.access(PremiumFeatures.Timeline);
const access = await this.container.git.access(PlusFeatures.Timeline);
const dateFormat = this.container.config.defaultDateFormat ?? 'MMMM Do, YYYY h:mma'; const dateFormat = this.container.config.defaultDateFormat ?? 'MMMM Do, YYYY h:mma';
const period = current.period ?? defaultPeriod; const period = current.period ?? defaultPeriod;

+ 4
- 4
src/premium/webviews/timeline/timelineWebviewView.ts View File

@ -4,7 +4,7 @@ import type { ShowQuickCommitCommandArgs } from '../../../commands';
import { configuration } from '../../../configuration'; import { configuration } from '../../../configuration';
import { Commands } from '../../../constants'; import { Commands } from '../../../constants';
import { Container } from '../../../container'; import { Container } from '../../../container';
import { PremiumFeatures } from '../../../features';
import { PlusFeatures } from '../../../features';
import type { RepositoriesChangeEvent } from '../../../git/gitProviderService'; import type { RepositoriesChangeEvent } from '../../../git/gitProviderService';
import { GitUri } from '../../../git/gitUri'; import { GitUri } from '../../../git/gitUri';
import { RepositoryChange, RepositoryChangeComparisonMode, RepositoryChangeEvent } from '../../../git/models'; import { RepositoryChange, RepositoryChangeComparisonMode, RepositoryChangeEvent } from '../../../git/models';
@ -16,7 +16,7 @@ import { hasVisibleTextEditor, isTextEditor } from '../../../system/utils';
import { IpcMessage, onIpc } from '../../../webviews/protocol'; import { IpcMessage, onIpc } from '../../../webviews/protocol';
import { WebviewViewBase } from '../../../webviews/webviewViewBase'; import { WebviewViewBase } from '../../../webviews/webviewViewBase';
import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService'; import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService';
import { ensurePremiumFeaturesEnabled } from '../../subscription/utils';
import { ensurePlusFeaturesEnabled } from '../../subscription/utils';
import { import {
Commit, Commit,
DidChangeStateNotificationType, DidChangeStateNotificationType,
@ -56,7 +56,7 @@ export class TimelineWebviewView extends WebviewViewBase {
} }
override async show(options?: { preserveFocus?: boolean | undefined }): Promise<void> { override async show(options?: { preserveFocus?: boolean | undefined }): Promise<void> {
if (!(await ensurePremiumFeaturesEnabled())) return;
if (!(await ensurePlusFeaturesEnabled())) return;
return super.show(options); return super.show(options);
} }
@ -195,7 +195,7 @@ export class TimelineWebviewView extends WebviewViewBase {
@debug({ args: false }) @debug({ args: false })
private async getState(current: Context): Promise<State> { private async getState(current: Context): Promise<State> {
const access = await this.container.git.access(PremiumFeatures.Timeline);
const access = await this.container.git.access(PlusFeatures.Timeline);
const dateFormat = this.container.config.defaultDateFormat ?? 'MMMM Do, YYYY h:mma'; const dateFormat = this.container.config.defaultDateFormat ?? 'MMMM Do, YYYY h:mma';
const period = current.period ?? defaultPeriod; const period = current.period ?? defaultPeriod;

+ 5
- 5
src/quickpicks/items/directive.ts View File

@ -46,21 +46,21 @@ export namespace DirectiveQuickPickItem {
label = 'Try again'; label = 'Try again';
break; break;
case Directive.StartPreviewTrial: case Directive.StartPreviewTrial:
label = 'Try Premium Features Now';
detail = 'Try premium features now, without an account, for 3 days';
label = 'Try GitLens+ Features Now';
detail = 'Try GitLens+ features now, without an account, for 3 days';
break; break;
case Directive.RequiresVerification: case Directive.RequiresVerification:
label = 'Resend Verification Email'; label = 'Resend Verification Email';
detail = 'You must verify your account email address before you can continue'; detail = 'You must verify your account email address before you can continue';
break; break;
case Directive.RequiresFreeSubscription: case Directive.RequiresFreeSubscription:
label = 'Sign In';
label = 'Sign in to GitLens+';
detail = detail =
'To use premium features on public repos and get a free 7-day trial for both public and private repos';
'To use GitLens+ features on public repos and get a free 7-day trial for both public and private repos';
break; break;
case Directive.RequiresPaidSubscription: case Directive.RequiresPaidSubscription:
label = 'Upgrade your account'; label = 'Upgrade your account';
detail = 'To use premium features on both public and private repos';
detail = 'To use GitLens+ features on both public and private repos';
break; break;
} }
} }

+ 1
- 2
src/storage.ts View File

@ -74,8 +74,7 @@ export const enum StorageKeys {
PendingWhatsNewOnFocus = 'gitlens:pendingWhatsNewOnFocus', PendingWhatsNewOnFocus = 'gitlens:pendingWhatsNewOnFocus',
Version = 'gitlens:version', Version = 'gitlens:version',
PremiumSubscription = 'gitlens:plus:subscription',
PremiumPreview = 'gitlens:plus:preview',
Subscription = 'gitlens:premium:subscription', // Don't change this key name as its the stored subscription
Deprecated_Version = 'gitlensVersion', Deprecated_Version = 'gitlensVersion',
} }

+ 5
- 5
src/subscription.ts View File

@ -114,16 +114,16 @@ export function getSubscriptionPlan(id: SubscriptionPlanId, startedOn?: Date, ex
export function getSubscriptionPlanName(id: SubscriptionPlanId) { export function getSubscriptionPlanName(id: SubscriptionPlanId) {
switch (id) { switch (id) {
case SubscriptionPlanId.FreePlus: case SubscriptionPlanId.FreePlus:
return 'GitLens Free+';
return 'GitLens+';
case SubscriptionPlanId.Pro: case SubscriptionPlanId.Pro:
return 'GitLens Pro';
return 'GitLens+ Pro';
case SubscriptionPlanId.Teams: case SubscriptionPlanId.Teams:
return 'GitLens Teams';
return 'GitLens+ Teams';
case SubscriptionPlanId.Enterprise: case SubscriptionPlanId.Enterprise:
return 'GitLens Enterprise';
return 'GitLens+ Enterprise';
case SubscriptionPlanId.Free: case SubscriptionPlanId.Free:
default: default:
return 'GitLens Free';
return 'GitLens';
} }
} }

+ 4
- 4
src/views/nodes/worktreesNode.ts View File

@ -1,6 +1,6 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GlyphChars } from '../../constants'; import { GlyphChars } from '../../constants';
import { PremiumFeatures } from '../../features';
import { PlusFeatures } from '../../features';
import { GitUri } from '../../git/gitUri'; import { GitUri } from '../../git/gitUri';
import { Repository } from '../../git/models'; import { Repository } from '../../git/models';
import { gate } from '../../system/decorators/gate'; import { gate } from '../../system/decorators/gate';
@ -39,7 +39,7 @@ export class WorktreesNode extends ViewNode {
async getChildren(): Promise<ViewNode[]> { async getChildren(): Promise<ViewNode[]> {
if (this._children == null) { if (this._children == null) {
const access = await this.repo.access(PremiumFeatures.Worktrees);
const access = await this.repo.access(PlusFeatures.Worktrees);
if (!access.allowed) return []; if (!access.allowed) return [];
const worktrees = await this.repo.getWorktrees(); const worktrees = await this.repo.getWorktrees();
@ -52,7 +52,7 @@ export class WorktreesNode extends ViewNode {
} }
async getTreeItem(): Promise<TreeItem> { async getTreeItem(): Promise<TreeItem> {
const access = await this.repo.access(PremiumFeatures.Worktrees);
const access = await this.repo.access(PlusFeatures.Worktrees);
const item = new TreeItem( const item = new TreeItem(
'Worktrees', 'Worktrees',
@ -62,7 +62,7 @@ export class WorktreesNode extends ViewNode {
item.contextValue = ContextValues.Worktrees; item.contextValue = ContextValues.Worktrees;
item.description = access.allowed item.description = access.allowed
? undefined ? undefined
: ` ${GlyphChars.Warning} Premium feature which requires an account`;
: ` ${GlyphChars.Warning} GitLens+ feature which requires an account`;
// TODO@eamodio `folder` icon won't work here for some reason // TODO@eamodio `folder` icon won't work here for some reason
item.iconPath = new ThemeIcon('folder-opened'); item.iconPath = new ThemeIcon('folder-opened');
return item; return item;

+ 5
- 5
src/views/worktreesView.ts View File

@ -12,10 +12,10 @@ import {
} from 'vscode'; } from 'vscode';
import { configuration, ViewFilesLayout, ViewShowBranchComparison, WorktreesViewConfig } from '../configuration'; import { configuration, ViewFilesLayout, ViewShowBranchComparison, WorktreesViewConfig } from '../configuration';
import { Container } from '../container'; import { Container } from '../container';
import { PremiumFeatures } from '../features';
import { PlusFeatures } from '../features';
import { GitUri } from '../git/gitUri'; import { GitUri } from '../git/gitUri';
import { GitWorktree, RepositoryChange, RepositoryChangeComparisonMode, RepositoryChangeEvent } from '../git/models'; import { GitWorktree, RepositoryChange, RepositoryChangeComparisonMode, RepositoryChangeEvent } from '../git/models';
import { ensurePremiumFeaturesEnabled } from '../premium/subscription/utils';
import { ensurePlusFeaturesEnabled } from '../premium/subscription/utils';
import { getSubscriptionTimeRemaining, SubscriptionState } from '../subscription'; import { getSubscriptionTimeRemaining, SubscriptionState } from '../subscription';
import { gate } from '../system/decorators/gate'; import { gate } from '../system/decorators/gate';
import { pluralize } from '../system/string'; import { pluralize } from '../system/string';
@ -50,7 +50,7 @@ export class WorktreesRepositoryNode extends RepositoryFolderNode
export class WorktreesViewNode extends RepositoriesSubscribeableNode<WorktreesView, WorktreesRepositoryNode> { export class WorktreesViewNode extends RepositoriesSubscribeableNode<WorktreesView, WorktreesRepositoryNode> {
async getChildren(): Promise<ViewNode[]> { async getChildren(): Promise<ViewNode[]> {
const access = await this.view.container.git.access(PremiumFeatures.Worktrees);
const access = await this.view.container.git.access(PlusFeatures.Worktrees);
if (!access.allowed) return []; if (!access.allowed) return [];
if (this.children == null) { if (this.children == null) {
@ -129,7 +129,7 @@ export class WorktreesView extends ViewBase
} }
override async show(options?: { preserveFocus?: boolean | undefined }): Promise<void> { override async show(options?: { preserveFocus?: boolean | undefined }): Promise<void> {
if (!(await ensurePremiumFeaturesEnabled())) return;
if (!(await ensurePlusFeaturesEnabled())) return;
return super.show(options); return super.show(options);
} }
@ -154,7 +154,7 @@ export class WorktreesView extends ViewBase
case SubscriptionState.Free: case SubscriptionState.Free:
case SubscriptionState.FreePreviewExpired: case SubscriptionState.FreePreviewExpired:
case SubscriptionState.VerificationRequired: case SubscriptionState.VerificationRequired:
this.description = '✨ premium feature';
this.description = '✨ GitLens+ feature';
break; break;
case SubscriptionState.FreeInPreview: { case SubscriptionState.FreeInPreview: {
const days = getSubscriptionTimeRemaining(subscription, 'days')!; const days = getSubscriptionTimeRemaining(subscription, 'days')!;

+ 1
- 1
src/webviews/apps/home/partials/links.html View File

@ -8,7 +8,7 @@
<a href="command:gitlens.getStarted" appearance="secondary">Walkthrough</a> <a href="command:gitlens.getStarted" appearance="secondary">Walkthrough</a>
</li> </li>
<li> <li>
<a href="command:gitlens.plus.learn" appearance="secondary">Premium features walkthrough</a>
<a href="command:gitlens.plus.learn" appearance="secondary">GitLens+ features walkthrough</a>
</li> </li>
<li> <li>
<a href="command:gitlens.showWelcomePage?%22quick-setup%22" appearance="secondary" <a href="command:gitlens.showWelcomePage?%22quick-setup%22" appearance="secondary"

+ 12
- 39
src/webviews/apps/home/partials/state.free-preview-expired.html View File

@ -1,55 +1,28 @@
<template id="state:free-preview-expired"> <template id="state:free-preview-expired">
<section> <section>
<h3>Continue using Premium Features</h3>
<h3>Continue using GitLens+ Features</h3>
<p> <p>
Your Your
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium features</a> trial
has ended. Don't worry, non-premium features are always accessible.
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ features</a> trial
has ended. Don't worry, all other GitLens features are always accessible.
</p> </p>
<p> <p>
Sign in to use premium features on public repos and get an <b>additional 7-day free trial</b> for both
public and private repos.
Sign in to use GitLens+ features on public repos and get an additional 7-day free trial for both public and
private repos.
</p> </p>
<vscode-button data-action="command:gitlens.plus.loginOrSignUp">Sign in</vscode-button>
<vscode-button data-action="command:gitlens.plus.loginOrSignUp">Sign in to GitLens+</vscode-button>
<p> <p>
Or, <a title="Upgrade your account" href="command:gitlens.plus.purchase">upgrade your account</a> to use Or, <a title="Upgrade your account" href="command:gitlens.plus.purchase">upgrade your account</a> to use
premium features on both public and private repos.
GitLens+ features on both public and private repos.
</p> </p>
<h3>Premium Features (Optional)</h3>
<p> <p>
<a title="Learn more about premium features" href="command:gitlens.plus.learn">Premium features</a> are
all-new, completely optional, features that enhance your current GitLens experience when you sign with an
account.
</p>
<p>
<i class="codicon codicon-info"></i>&nbsp;Non-premium features are always accessible, without an account,
and will continue to evolve and be invested in.
</p>
<h4>Visual File History</h4>
<img
class="image--preview"
src="#{root}/images/docs/visual-file-history-hover.png"
alt="Visual File History screenshot"
/>
<p class="feature-desc">
The
<a
title="Learn more about the Visual File History"
href="command:gitlens.openWalkthrough?%22gitlens.plus%7Cgitlens.plus.visualFileHistory%22"
>Visual File History</a
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn"
>Learn more about GitLens+ features</a
> >
allows you to quickly see the evolution of a file, including when changes were made, how large they were,
and who made them.
</p> </p>
<h4>Worktrees</h4>
<img class="image--preview" src="#{root}/images/docs/worktrees-view.png" alt="Worktrees screenshot" />
<p class="feature-desc">
<a
title="Learn more about worktrees"
href="command:gitlens.openWalkthrough?%22gitlens.plus%7Cgitlens.plus.worktrees%22"
>Worktrees</a
>
allow you to easily work on different branches of a repository simultaneously.
<p>
<i class="codicon codicon-info"></i>&nbsp;All other GitLens features are always accessible, without an
account, and will continue to evolve and be invested in.
</p> </p>
</section> </section>
</template> </template>

+ 11
- 10
src/webviews/apps/home/partials/state.free-preview.html View File

@ -1,26 +1,27 @@
<template id="state:free-preview"> <template id="state:free-preview">
<section> <section>
<h3>Trying GitLens Premium Features</h3>
<h3>Trying GitLens+ Features</h3>
<p> <p>
You have <span data-bind="previewDays">3 days</span> left in your You have <span data-bind="previewDays">3 days</span> left in your
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium features</a>
trial. Once your trial ends, you'll need a free account to continue using premium features on public repos.
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ features</a>
trial. Once your trial ends, you'll need a free account to continue using GitLens+ features on public repos.
</p> </p>
<vscode-button data-action="command:gitlens.plus.loginOrSignUp">Sign in</vscode-button>
<vscode-button data-action="command:gitlens.plus.loginOrSignUp">Sign in to GitLens+</vscode-button>
<p> <p>
Or, <a title="Upgrade your account" href="command:gitlens.plus.purchase">upgrade your account</a> to use Or, <a title="Upgrade your account" href="command:gitlens.plus.purchase">upgrade your account</a> to use
premium features on both public and private repos.
GitLens+ features on both public and private repos.
</p> </p>
<h3>Premium Features (Optional)</h3>
<h3>GitLens+</h3>
<p> <p>
<a title="Learn more about premium features" href="command:gitlens.plus.learn">Premium features</a> are
all-new, completely optional, features that enhance your current GitLens experience when you sign with an
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+</a> adds all-new,
completely optional, features that enhance your current GitLens experience when you sign in with a free
account. account.
</p> </p>
<p> <p>
<i class="codicon codicon-info"></i>&nbsp;Non-premium features are always accessible, without an account,
and will continue to evolve and be invested in.
<i class="codicon codicon-info"></i>&nbsp;All other GitLens features are always accessible, without an
account, and will continue to evolve and be invested in.
</p> </p>
<p style="margin-bottom: 1rem">The first new GitLens+ features are the Visual File History and Worktrees.</p>
<h4>Visual File History</h4> <h4>Visual File History</h4>
<img <img
class="image--preview" class="image--preview"

+ 10
- 10
src/webviews/apps/home/partials/state.free.html View File

@ -1,23 +1,23 @@
<template id="state:free"> <template id="state:free">
<section> <section>
<h3>Introducing Premium Features (Optional)</h3>
<h3>Introducing GitLens+</h3>
<p> <p>
<a title="Learn more about premium features" href="command:gitlens.plus.learn">Premium features</a> are
all-new, completely optional, features that enhance your current GitLens experience when you sign with an
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+</a> adds all-new,
completely optional, features that enhance your current GitLens experience when you sign in with a free
account. account.
</p> </p>
<p> <p>
<i class="codicon codicon-info"></i>&nbsp;Non-premium features are always accessible, without an account,
and will continue to evolve and be invested in.
<i class="codicon codicon-info"></i>&nbsp;All other GitLens features are always accessible, without an
account, and will continue to evolve and be invested in.
</p> </p>
<vscode-button data-action="command:gitlens.plus.startPreviewTrial">Try premium features now</vscode-button>
<p style="margin-bottom: 1rem">
<vscode-button data-action="command:gitlens.plus.startPreviewTrial">Try GitLens+ features now</vscode-button>
<p>
Try Try
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium features</a> now,
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ features</a> now,
without an account, for 3 days on public and private repos, or without an account, for 3 days on public and private repos, or
<a title="Sign in now" href="command:gitlens.plus.loginOrSignUp">sign in</a> for unlimited use on public
repos.
<a title="Sign in to GitLens+" href="command:gitlens.plus.loginOrSignUp">sign in</a> for use on public repos.
</p> </p>
<p style="margin-bottom: 1rem">The first new GitLens+ features are the Visual File History and Worktrees.</p>
<h4>Visual File History</h4> <h4>Visual File History</h4>
<img <img
class="image--preview" class="image--preview"

+ 5
- 5
src/webviews/apps/home/partials/state.paid.html View File

@ -1,11 +1,11 @@
<template id="state:paid"> <template id="state:paid">
<section> <section>
<h3 data-bind="plan">GitLens Pro</h3>
<p>Thank you for purchasing <span data-bind="plan">GitLens Pro</span>!</p>
<h3 data-bind="plan">GitLens+ Pro</h3>
<p>Thank you for purchasing <span data-bind="plan">GitLens+ Pro</span>!</p>
<p> <p>
Your <span data-bind="plan">GitLens Pro</span> account gives you access to use
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium features</a> for both
public and private repos.
Your <span data-bind="plan">GitLens+ Pro</span> account gives you access to use
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ features</a> on
both public and private repos.
</p> </p>
<p> <p>
<a title="Manage your account" href="command:gitlens.plus.manage">Manage your account</a> <a title="Manage your account" href="command:gitlens.plus.manage">Manage your account</a>

+ 6
- 6
src/webviews/apps/home/partials/state.plus-trial-expired.html View File

@ -1,19 +1,19 @@
<template id="state:plus-trial-expired"> <template id="state:plus-trial-expired">
<section> <section>
<h3>GitLens Free+</h3>
<h3>GitLens+</h3>
<p> <p>
Your Free+ account gives you access to use
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium features</a> on
Your GitLens+ account gives you access to use
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ features</a> on
public repos. public repos.
</p> </p>
<p> <p>
<a title="Manage your account" href="command:gitlens.plus.manage">Manage your account</a> <a title="Manage your account" href="command:gitlens.plus.manage">Manage your account</a>
</p> </p>
<p>Upgrade your account for access to both public and private repos.</p>
<p>Upgrade your account for access to GitLens+ features on both public and private repos.</p>
<vscode-button data-action="command:gitlens.plus.purchase">Upgrade your account</vscode-button> <vscode-button data-action="command:gitlens.plus.purchase">Upgrade your account</vscode-button>
<p> <p>
<i class="codicon codicon-info"></i>&nbsp;Non-premium features are always accessible, without an account,
and will continue to evolve and be invested in.
<i class="codicon codicon-info"></i>&nbsp;All other GitLens features are always accessible, without an
account, and will continue to evolve and be invested in.
</p> </p>
</section> </section>
</template> </template>

+ 10
- 36
src/webviews/apps/home/partials/state.plus-trial.html View File

@ -1,48 +1,22 @@
<template id="state:plus-trial"> <template id="state:plus-trial">
<section> <section>
<h3>Premium Feature Trial</h3>
<h3>GitLens+ Pro Trial</h3>
<p> <p>
You have <span data-bind="trialDays">7 days</span> left in your You have <span data-bind="trialDays">7 days</span> left in your
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium features</a>
trial. Once your trial ends, you can continue using premium features on public repos.
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ features</a>
trial on both public and private repos. Once your trial ends, you can continue using GitLens+ features on
public repos.
</p> </p>
<p>Upgrade your account for access to both public and private repos.</p>
<p>Upgrade your account for access to GitLens+ features on both public and private repos.</p>
<vscode-button data-action="command:gitlens.plus.purchase">Upgrade your account</vscode-button> <vscode-button data-action="command:gitlens.plus.purchase">Upgrade your account</vscode-button>
<h3>Premium Features</h3>
<p> <p>
<a title="Learn more about premium features" href="command:gitlens.plus.learn">Premium features</a> are
all-new, completely optional, features that enhance your current GitLens experience when you sign with an
account.
</p>
<p>
<i class="codicon codicon-info"></i>&nbsp;Non-premium features are always accessible, without an account,
and will continue to evolve and be invested in.
</p>
<h4>Visual File History</h4>
<img
class="image--preview"
src="#{root}/images/docs/visual-file-history-hover.png"
alt="Visual File History screenshot"
/>
<p class="feature-desc">
The
<a
title="Learn more about the Visual File History"
href="command:gitlens.openWalkthrough?%22gitlens.plus%7Cgitlens.plus.visualFileHistory%22"
>Visual File History</a
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn"
>Learn more about GitLens+ features</a
> >
allows you to quickly see the evolution of a file, including when changes were made, how large they were,
and who made them.
</p> </p>
<h4>Worktrees</h4>
<img class="image--preview" src="#{root}/images/docs/worktrees-view.png" alt="Worktrees screenshot" />
<p class="feature-desc">
<a
title="Learn more about worktrees"
href="command:gitlens.openWalkthrough?%22gitlens.plus%7Cgitlens.plus.worktrees%22"
>Worktrees</a
>
allow you to easily work on different branches of a repository simultaneously.
<p>
<i class="codicon codicon-info"></i>&nbsp;All other GitLens features are always accessible, without an
account, and will continue to evolve and be invested in.
</p> </p>
</section> </section>
</template> </template>

+ 1
- 1
src/webviews/apps/home/partials/state.verify-email.html View File

@ -1,7 +1,7 @@
<template id="state:verify-email"> <template id="state:verify-email">
<section> <section>
<h3>Please verify your email</h3> <h3>Please verify your email</h3>
<p>To continue using premium GitLens features, please verify the email for the account you created.</p>
<p>To use GitLens+ features, please verify the email for the account you created.</p>
<vscode-button data-action="command:gitlens.plus.resendVerification">Resend verification email</vscode-button> <vscode-button data-action="command:gitlens.plus.resendVerification">Resend verification email</vscode-button>
<vscode-button data-action="command:gitlens.plus.validate">Refresh verification status</vscode-button> <vscode-button data-action="command:gitlens.plus.validate">Refresh verification status</vscode-button>
</section> </section>

+ 6
- 6
src/webviews/apps/premium/timeline/partials/state.free-preview-expired.html View File

@ -1,17 +1,17 @@
<template id="state:free-preview-expired"> <template id="state:free-preview-expired">
<section> <section>
<p> <p>
Sign in to use the Visual File History and other premium features on public repos and get an
<b>additional 7-day free trial</b> for both public and private repos.
Sign in to use the Visual File History and other GitLens+ features on public repos and get an additional
7-day free trial for both public and private repos.
</p> </p>
<vscode-button data-action="command:gitlens.plus.loginOrSignUp">Sign in</vscode-button>
<vscode-button data-action="command:gitlens.plus.loginOrSignUp">Sign in to GitLens+</vscode-button>
<p> <p>
✨ The Visual File History is ✨ The Visual File History is
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium feature</a> which can
be used on public repos with a
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ feature</a> which
can be used on public repos with a
<a title="Sign in" href="command:gitlens.plus.loginOrSignUp">free account</a> and private repos with a <a title="Sign in" href="command:gitlens.plus.loginOrSignUp">free account</a> and private repos with a
<a title="View plans" href="command:gitlens.plus.purchase">paid account</a>. <a title="View plans" href="command:gitlens.plus.purchase">paid account</a>.
</p> </p>
<p><i class="codicon codicon-info"></i>&nbsp;Non-premium features can always be used on any repo.</p>
<p><i class="codicon codicon-info"></i>&nbsp;All other GitLens features can always be used on any repo.</p>
</section> </section>
</template> </template>

+ 4
- 4
src/webviews/apps/premium/timeline/partials/state.free.html View File

@ -2,7 +2,7 @@
<section> <section>
<p> <p>
Try it now, without an account, for 3 days on public and private repos, or Try it now, without an account, for 3 days on public and private repos, or
<a title="Sign in now" href="command:gitlens.plus.loginOrSignUp">sign in</a> for unlimited use on public
<a title="Sign in to GitLens+" href="command:gitlens.plus.loginOrSignUp">sign in</a> for use on public
repos. repos.
</p> </p>
<vscode-button data-action="command:gitlens.plus.startPreviewTrial" <vscode-button data-action="command:gitlens.plus.startPreviewTrial"
@ -10,11 +10,11 @@
> >
<p> <p>
✨ The Visual File History is ✨ The Visual File History is
<a title="Learn more about premium features" href="command:gitlens.plus.learn">premium feature</a> which can
be used on public repos with a
<a title="Learn more about GitLens+ features" href="command:gitlens.plus.learn">GitLens+ feature</a> which
can be used on public repos with a
<a title="Sign in" href="command:gitlens.plus.loginOrSignUp">free account</a> and private repos with a <a title="Sign in" href="command:gitlens.plus.loginOrSignUp">free account</a> and private repos with a
<a title="View plans" href="command:gitlens.plus.purchase">paid account</a>. <a title="View plans" href="command:gitlens.plus.purchase">paid account</a>.
</p> </p>
<p><i class="codicon codicon-info"></i>&nbsp;Non-premium features can always be used on any repo.</p>
<p><i class="codicon codicon-info"></i>&nbsp;All other GitLens features can always be used on any repo.</p>
</section> </section>
</template> </template>

+ 1
- 1
src/webviews/apps/welcome/welcome.html View File

@ -58,7 +58,7 @@
>Get Started Walkthrough</a >Get Started Walkthrough</a
> >
<span class="button__subaction" <span class="button__subaction"
>or <a href="command:gitlens.plus.learn">learn about premium features</a></span
>or <a href="command:gitlens.plus.learn">learn about GitLens+ features</a></span
> >
</div> </div>

+ 2
- 2
src/webviews/home/homeWebviewView.ts View File

@ -1,7 +1,7 @@
import { commands, Disposable, window } from 'vscode'; import { commands, Disposable, window } from 'vscode';
import type { Container } from '../../container'; import type { Container } from '../../container';
import type { SubscriptionChangeEvent } from '../../premium/subscription/subscriptionService'; import type { SubscriptionChangeEvent } from '../../premium/subscription/subscriptionService';
import { ensurePremiumFeaturesEnabled } from '../../premium/subscription/utils';
import { ensurePlusFeaturesEnabled } from '../../premium/subscription/utils';
import { SyncedStorageKeys } from '../../storage'; import { SyncedStorageKeys } from '../../storage';
import type { Subscription } from '../../subscription'; import type { Subscription } from '../../subscription';
import { WebviewViewBase } from '../webviewViewBase'; import { WebviewViewBase } from '../webviewViewBase';
@ -15,7 +15,7 @@ export class HomeWebviewView extends WebviewViewBase {
} }
override async show(options?: { preserveFocus?: boolean | undefined }): Promise<void> { override async show(options?: { preserveFocus?: boolean | undefined }): Promise<void> {
if (!(await ensurePremiumFeaturesEnabled())) return;
if (!(await ensurePlusFeaturesEnabled())) return;
return super.show(options); return super.show(options);
} }

walkthroughs/getting-started/12-premium-features.md → walkthroughs/getting-started/12-plus.md View File

@ -1,7 +1,13 @@
## Premium GitLens Features
## GitLens+ Features
<p align="center"> <p align="center">
<img src="../../images/docs/visual-file-history-hover.png" alt="Visual File History View"/>
<img src="../../images/docs/visual-file-history-hover.png" alt="Visual File History view"/>
<br/>New Visual File History
</p>
<p align="center">
<img src="../../images/docs/worktrees-view.png" alt="Worktrees view"/>
<br/>New Worktrees
</p> </p>
Even more features are coming soon, like a visual commit graph and integrations for GitHub Enterprise and GitLab repositories. Even more features are coming soon, like a visual commit graph and integrations for GitHub Enterprise and GitLab repositories.

+ 13
- 14
walkthroughs/plus/1-intro.md View File

@ -1,25 +1,24 @@
## Introducing Premium Features
## Introducing GitLens+
Premium features are all-new, completely optional, features that enhance your current GitLens experience when you sign with an account. Anyone can try premium features for public and private repos for 3 days, without an account.
GitLens+ adds all-new, completely optional, features that enhance your current GitLens experience when you sign in with a free account. A free GitLens+ account gives you access to these new GitLens+ features on public repos, while a paid account allows you to use them on private repos.
🛈 Non-premium features are always accessible, without an account, and will continue to evolve and be invested in.
🛈 All other GitLens features are always accessible, without an account, and will continue to evolve and be invested in.
[Learn more about GitLens+](https://gitkraken.com/gitlens/premium-features 'Learn more')
The first new GitLens+ features are the Visual File History and Worktrees.
<p align="center"> <p align="center">
<img src="../../images/docs/visual-file-history-hover.png" alt="Visual File History View"/> <img src="../../images/docs/visual-file-history-hover.png" alt="Visual File History View"/>
<br/>New Visual File History GitLens+ Feature
</p> </p>
The new Visual File History and Worktrees premium features can be used with a free, GitLens Free+ account. Free+ accounts can use premium features on public repos, while paid accounts can also use them on private repos.
[**Try premium features now**](command:gitlens.plus.startPreviewTrial 'Try premium features now')
[Learn more about premium features](https://gitkraken.com/gitlens/premium-features 'Learn more')
## More premium features coming soon
## Does this affect existing features?
Additional premium features like a visual commit graph, and integrations for GitHub Enterprise and GitLab are coming soon.
No, the introduction of GitLens+ has no impact on existing GitLens features, so you won't lose access to any of the GitLens features you know and love. In fact, we are heavily investing in enhancing and expanding the GitLens feature set. Creating an account simply gives you access to a subset of new features that will enable you to get even more out of Git in VS Code!
## Does this affect existing features?
All other features will continue to be free without an account.
No, the introduction of premium features has no impact on existing GitLens features, so you won't lose access to any of the GitLens features you know and love. Creating an account simply gives you access to new premium features that will enable you to get even more out of Git in VS Code!
## More GitLens+ features coming soon
All non-premium features will continue to be free without an account.
Additional features like a visual commit graph, and integrations for GitHub Enterprise and GitLab are coming soon.

+ 2
- 2
walkthroughs/plus/4-coming-soon.md View File

@ -1,7 +1,7 @@
## More Premium Features Coming Soon
## More GitLens+ Features Coming Soon
<p align="center"> <p align="center">
<img src="../../images/docs/coming-soon-commit-graph.png" alt="Worktrees View in Side Bar"/> <img src="../../images/docs/coming-soon-commit-graph.png" alt="Worktrees View in Side Bar"/>
</p> </p>
You can expect more premium features like a visual commit graph for better repo visualization, and additional integrations with hosting services like GitHub Enterprise and GitLab.
You can expect more GitLens+ features like a visual commit graph for better repo visualization, and additional integrations with hosting services like GitHub Enterprise and GitLab.

Loading…
Cancel
Save