diff --git a/LICENSE.plus b/LICENSE.plus index f604ec14a3c11..3d91132688de5 100644 --- a/LICENSE.plus +++ b/LICENSE.plus @@ -1,4 +1,4 @@ -GitLens+ License +GitLens Pro License Copyright (c) 2021-2025 Axosoft, LLC dba GitKraken ("GitKraken") @@ -13,8 +13,8 @@ with, the GitKraken End User License Agreement, available at https://gitkraken.com/eula (the "EULA"), or other agreement governing the use of the Software, as agreed by you and GitKraken, and otherwise have a valid subscription for the correct number of user seats for the applicable version of -the Software (e.g., GitLens+, GitLens+ Pro, GitLens+ Advanced, GitLens+ Teams, -and GitLens+ Enterprise). Subject to the foregoing sentence, you are free to modify +the Software (e.g., GitLens Pro, GitLens Advanced, GitLens Business, +and GitLens Enterprise). Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that GitKraken and/or its licensors (as applicable) retain all right, title and interest in and to all such modifications and/or patches, and all such modifications and/or patches may @@ -25,7 +25,7 @@ modifications and/or patches. You are not granted any other rights beyond what is expressly stated herein. Except as set forth above, it is forbidden to copy, merge, publish, distribute, sublicense, and/or sell the Software. -The full text of this GitLens+ License shall be included in all copies or +The full text of this GitLens Pro License shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR diff --git a/docs/telemetry-events.md b/docs/telemetry-events.md index 62b06e010023c..8ef93f8f9ff59 100644 --- a/docs/telemetry-events.md +++ b/docs/telemetry-events.md @@ -1484,7 +1484,7 @@ void 'repoPrivacy': 'private' | 'public' | 'local', 'repository.visibility': 'private' | 'public' | 'local', // Provided for compatibility with other GK surfaces - 'source': 'account' | 'subscription' | 'graph' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'view' | 'code-suggest' | 'ai' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'commandPalette' | 'deeplink' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'startWork' | 'trial-indicator' | 'scm-input' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'view' | 'code-suggest' | 'ai' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'commandPalette' | 'deeplink' | 'feature-badge' | 'feature-gate' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'startWork' | 'trial-indicator' | 'scm-input' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` diff --git a/src/commands/quickWizard.base.ts b/src/commands/quickWizard.base.ts index 6f927121969a5..c5dc0c337289e 100644 --- a/src/commands/quickWizard.base.ts +++ b/src/commands/quickWizard.base.ts @@ -1,6 +1,7 @@ import type { Disposable, InputBox, QuickInputButton, QuickPick, QuickPickItem } from 'vscode'; import { InputBoxValidationSeverity, QuickInputButtons, window } from 'vscode'; import type { GlCommands } from '../constants.commands'; +import { SubscriptionPlanId } from '../constants.subscription'; import { Container } from '../container'; import { Directive, isDirective, isDirectiveQuickPickItem } from '../quickpicks/items/directive'; import { configuration } from '../system/-webview/configuration'; @@ -746,7 +747,7 @@ export abstract class QuickWizardCommandBase extends GlCommandBase { } case Directive.RequiresPaidSubscription: - void Container.instance.subscription.upgrade({ + void Container.instance.subscription.upgrade(SubscriptionPlanId.Pro, { source: 'quick-wizard', detail: { action: rootStep.command?.key, diff --git a/src/commands/walkthroughs.ts b/src/commands/walkthroughs.ts index 1198c89271aff..8d49b45da697e 100644 --- a/src/commands/walkthroughs.ts +++ b/src/commands/walkthroughs.ts @@ -3,6 +3,7 @@ import { urls } from '../constants'; import type { GlCommands } from '../constants.commands'; import type { Source, Sources } from '../constants.telemetry'; import type { Container } from '../container'; +import type { SubscriptionUpgradeCommandArgs } from '../plus/gk/models/subscription'; import type { LaunchpadCommandArgs } from '../plus/launchpad/launchpad'; import { command, executeCommand } from '../system/-webview/command'; import { openUrl, openWalkthrough as openWalkthroughCore } from '../system/-webview/vscode'; @@ -80,7 +81,7 @@ export class WalkthroughPlusUpgradeCommand extends GlCommandBase { name: 'plus/upgrade', command: command, }); - executeCommand(command, { source: 'walkthrough' }); + executeCommand(command, { source: 'walkthrough' }); } } diff --git a/src/constants.telemetry.ts b/src/constants.telemetry.ts index 12033c43693a4..d05d794db9c5d 100644 --- a/src/constants.telemetry.ts +++ b/src/constants.telemetry.ts @@ -934,6 +934,8 @@ export type Sources = | 'cloud-patches' | 'commandPalette' | 'deeplink' + | 'feature-badge' + | 'feature-gate' | 'graph' | 'home' | 'inspect' diff --git a/src/plus/LICENSE.plus b/src/plus/LICENSE.plus index f604ec14a3c11..3d91132688de5 100644 --- a/src/plus/LICENSE.plus +++ b/src/plus/LICENSE.plus @@ -1,4 +1,4 @@ -GitLens+ License +GitLens Pro License Copyright (c) 2021-2025 Axosoft, LLC dba GitKraken ("GitKraken") @@ -13,8 +13,8 @@ with, the GitKraken End User License Agreement, available at https://gitkraken.com/eula (the "EULA"), or other agreement governing the use of the Software, as agreed by you and GitKraken, and otherwise have a valid subscription for the correct number of user seats for the applicable version of -the Software (e.g., GitLens+, GitLens+ Pro, GitLens+ Advanced, GitLens+ Teams, -and GitLens+ Enterprise). Subject to the foregoing sentence, you are free to modify +the Software (e.g., GitLens Pro, GitLens Advanced, GitLens Business, +and GitLens Enterprise). Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that GitKraken and/or its licensors (as applicable) retain all right, title and interest in and to all such modifications and/or patches, and all such modifications and/or patches may @@ -25,7 +25,7 @@ modifications and/or patches. You are not granted any other rights beyond what is expressly stated herein. Except as set forth above, it is forbidden to copy, merge, publish, distribute, sublicense, and/or sell the Software. -The full text of this GitLens+ License shall be included in all copies or +The full text of this GitLens Pro License shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR diff --git a/src/plus/gk/__debug__accountDebug.ts b/src/plus/gk/__debug__accountDebug.ts index fff9d05198b62..fe256984d2b31 100644 --- a/src/plus/gk/__debug__accountDebug.ts +++ b/src/plus/gk/__debug__accountDebug.ts @@ -140,13 +140,13 @@ class AccountDebug { createQuickPickSeparator('Trial'), { label: 'Pro Trial', - description: 'Pro, account', + description: 'Pro trial (pro plan), account', iconPath: new ThemeIcon('blank'), item: { state: SubscriptionState.ProTrial }, }, { label: 'Pro Trial (Reactivated)', - description: 'Pro, account', + description: 'Pro trial (pro plan), account', iconPath: new ThemeIcon('blank'), item: { state: SubscriptionState.ProTrial, @@ -155,13 +155,13 @@ class AccountDebug { }, { label: 'Pro Trial (Advanced)', - description: 'Advanced, account', + description: 'Pro trial (advanced plan), account', iconPath: new ThemeIcon('blank'), item: { state: SubscriptionState.ProTrial, planId: SubscriptionPlanId.Advanced }, }, { - label: 'Pro Trial (Advanced Reactivated)', - description: 'Advanced, account', + label: 'Pro Trial (Advanced, Reactivated)', + description: 'Pro trial (advanced plan), account', iconPath: new ThemeIcon('blank'), item: { state: SubscriptionState.ProTrial, @@ -190,19 +190,19 @@ class AccountDebug { }, { label: 'Advanced', - description: 'Advanced, account', + description: 'Advanced plan, account', iconPath: new ThemeIcon('blank'), item: { state: SubscriptionState.Paid, planId: SubscriptionPlanId.Advanced }, }, { label: 'Teams', - description: 'Teams, account', + description: 'Teams plan, account', iconPath: new ThemeIcon('blank'), item: { state: SubscriptionState.Paid, planId: SubscriptionPlanId.Teams }, }, { label: 'Enterprise', - description: 'Enterprise, no account', + description: 'Enterprise plan, account', iconPath: new ThemeIcon('blank'), item: { state: SubscriptionState.Paid, planId: SubscriptionPlanId.Enterprise }, }, diff --git a/src/plus/gk/models/subscription.ts b/src/plus/gk/models/subscription.ts index bb158785d0f04..f3e326520f741 100644 --- a/src/plus/gk/models/subscription.ts +++ b/src/plus/gk/models/subscription.ts @@ -1,4 +1,5 @@ import type { SubscriptionPlanId, SubscriptionState } from '../../../constants.subscription'; +import type { Source } from '../../../constants.telemetry'; import type { Organization } from './organization'; export type FreeSubscriptionPlans = Extract< @@ -50,3 +51,7 @@ export interface SubscriptionPreviewTrial { readonly startedOn: string; readonly expiresOn: string; } + +export interface SubscriptionUpgradeCommandArgs extends Source { + plan?: SubscriptionPlanId; +} diff --git a/src/plus/gk/subscriptionService.ts b/src/plus/gk/subscriptionService.ts index b3ef385887795..8b6f7575f5ca0 100644 --- a/src/plus/gk/subscriptionService.ts +++ b/src/plus/gk/subscriptionService.ts @@ -71,19 +71,20 @@ import { authenticationProviderScopes } from './authenticationProvider'; import type { GKCheckInResponse } from './models/checkin'; import type { Organization } from './models/organization'; import type { Promo } from './models/promo'; -import type { Subscription } from './models/subscription'; +import type { Subscription, SubscriptionUpgradeCommandArgs } from './models/subscription'; import type { ServerConnection } from './serverConnection'; import { ensurePlusFeaturesEnabled } from './utils/-webview/plus.utils'; import { getConfiguredActiveOrganizationId, updateActiveOrganizationId } from './utils/-webview/subscription.utils'; import { getSubscriptionFromCheckIn } from './utils/checkin.utils'; import { assertSubscriptionState, + compareSubscriptionPlans, computeSubscriptionState, getCommunitySubscription, getPreviewSubscription, getSubscriptionPlan, getSubscriptionPlanName, - getSubscriptionPlanPriority, + getSubscriptionPlanTierType, getSubscriptionStateString, getSubscriptionTimeRemaining, getTimeRemaining, @@ -357,11 +358,8 @@ export class SubscriptionService implements Disposable { registerCommand('gitlens.plus.startPreviewTrial', (src?: Source) => this.startPreviewTrial(src)), registerCommand('gitlens.plus.reactivateProTrial', (src?: Source) => this.reactivateProTrial(src)), registerCommand('gitlens.plus.resendVerification', (src?: Source) => this.resendVerification(src)), - registerCommand('gitlens.plus.upgrade', (srcAndPlan?: Source & { plan?: SubscriptionPlanId }) => - this.upgrade( - srcAndPlan ? { source: srcAndPlan.source, detail: srcAndPlan.detail } : undefined, - srcAndPlan?.plan, - ), + registerCommand('gitlens.plus.upgrade', (args?: SubscriptionUpgradeCommandArgs) => + this.upgrade(args?.plan, args ? { source: args.source, detail: args.detail } : undefined), ), registerCommand('gitlens.plus.hide', (src?: Source) => this.setProFeaturesVisibility(false, src)), @@ -548,7 +546,7 @@ export class SubscriptionService implements Disposable { ); if (result === upgrade) { - void this.upgrade(source); + void this.upgrade(SubscriptionPlanId.Pro, source); } else if (result === learn) { void this.learnAboutPro({ source: 'prompt', detail: { action: 'trial-ended' } }, source); } @@ -657,9 +655,10 @@ export class SubscriptionService implements Disposable { @gate(() => '') @log() async reactivateProTrial(source: Source | undefined): Promise { - if (!(await ensurePlusFeaturesEnabled())) return; const scope = getLogScope(); + if (!(await ensurePlusFeaturesEnabled())) return; + if (this.container.telemetry.enabled) { this.container.telemetry.sendEvent('subscription/action', { action: 'reactivate' }, source); } @@ -892,11 +891,13 @@ export class SubscriptionService implements Disposable { } @log() - async upgrade(source: Source | undefined, plan?: SubscriptionPlanId): Promise { + async upgrade(plan: SubscriptionPlanId | undefined, source: Source | undefined): Promise { const scope = getLogScope(); if (!(await ensurePlusFeaturesEnabled())) return false; + plan ??= SubscriptionPlanId.Pro; + let aborted = false; const promo = await this.container.productConfig.getApplicablePromo(this._subscription.state); @@ -920,14 +921,13 @@ export class SubscriptionService implements Disposable { const hasAccount = this._subscription.account != null; if (hasAccount) { - // Do a pre-check-in to see if we've already upgraded to a paid plan. + // Do a pre-check-in to see if we've already upgraded to a paid plan try { const session = await this.ensureSession(false, source); if (session != null) { if ( (await this.checkUpdatedSubscription(source)) === SubscriptionState.Paid && - getSubscriptionPlanPriority(this._subscription.plan.effective.id) >= - getSubscriptionPlanPriority(plan ?? SubscriptionPlanId.Pro) + compareSubscriptionPlans(this._subscription.plan.effective.id, plan) >= 0 ) { return true; } @@ -938,20 +938,7 @@ export class SubscriptionService implements Disposable { const query = new URLSearchParams(); query.set('source', 'gitlens'); query.set('product', 'gitlens'); - - let planType = 'PRO'; - switch (plan) { - case SubscriptionPlanId.Advanced: - planType = 'ADVANCED'; - break; - case SubscriptionPlanId.Teams: - planType = 'TEAMS'; - break; - case SubscriptionPlanId.Enterprise: - planType = 'ENTERPRISE'; - break; - } - query.set('planType', planType); + query.set('planType', getSubscriptionPlanTierType(plan)); if (promo?.code != null) { query.set('promoCode', promo.code); diff --git a/src/plus/gk/utils/-webview/acount.utils.ts b/src/plus/gk/utils/-webview/acount.utils.ts index c986186c776a3..1b7e21d72c558 100644 --- a/src/plus/gk/utils/-webview/acount.utils.ts +++ b/src/plus/gk/utils/-webview/acount.utils.ts @@ -1,5 +1,6 @@ import type { Uri } from 'vscode'; import { window } from 'vscode'; +import { SubscriptionPlanId } from '../../../../constants.subscription'; import type { Source } from '../../../../constants.telemetry'; import type { Container } from '../../../../container'; import type { PlusFeatures } from '../../../../features'; @@ -142,7 +143,7 @@ export async function ensureFeatureAccess( ); if (result === upgrade) { - if (await container.subscription.upgrade(source)) { + if (await container.subscription.upgrade(SubscriptionPlanId.Pro, source)) { continue; } } diff --git a/src/plus/gk/utils/-webview/plus.utils.ts b/src/plus/gk/utils/-webview/plus.utils.ts index dc017bae216ea..0e96fc6b69cb7 100644 --- a/src/plus/gk/utils/-webview/plus.utils.ts +++ b/src/plus/gk/utils/-webview/plus.utils.ts @@ -1,6 +1,6 @@ import type { MessageItem } from 'vscode'; import { window } from 'vscode'; -import { proTrialLengthInDays } from '../../../../constants.subscription'; +import { proTrialLengthInDays, SubscriptionPlanId } from '../../../../constants.subscription'; import type { Source } from '../../../../constants.telemetry'; import type { Container } from '../../../../container'; import { configuration } from '../../../../system/-webview/configuration'; @@ -28,6 +28,7 @@ export async function ensurePlusFeaturesEnabled(): Promise { await configuration.updateEffective('plusFeatures.enabled', true); return true; } + export async function ensurePaidPlan( container: Container, title: string, @@ -100,7 +101,7 @@ export async function ensurePaidPlan( ); if (result === upgrade) { - void container.subscription.upgrade(source); + void container.subscription.upgrade(SubscriptionPlanId.Pro, source); } } diff --git a/src/plus/gk/utils/checkin.utils.ts b/src/plus/gk/utils/checkin.utils.ts index 5598e15aa4788..66c03d9b8b995 100644 --- a/src/plus/gk/utils/checkin.utils.ts +++ b/src/plus/gk/utils/checkin.utils.ts @@ -2,7 +2,7 @@ import { SubscriptionPlanId } from '../../../constants.subscription'; import type { GKCheckInResponse, GKLicense, GKLicenseType } from '../models/checkin'; import type { Organization } from '../models/organization'; import type { Subscription } from '../models/subscription'; -import { getSubscriptionPlan, getSubscriptionPlanPriority } from './subscription.utils'; +import { compareSubscriptionPlans, getSubscriptionPlan, getSubscriptionPlanPriority } from './subscription.utils'; export function getSubscriptionFromCheckIn( data: GKCheckInResponse, @@ -129,7 +129,7 @@ export function getSubscriptionFromCheckIn( ); } - if (effective == null || getSubscriptionPlanPriority(actual.id) >= getSubscriptionPlanPriority(effective.id)) { + if (effective == null || compareSubscriptionPlans(actual.id, effective.id) >= 0) { effective = { ...actual }; } diff --git a/src/plus/gk/utils/subscription.utils.ts b/src/plus/gk/utils/subscription.utils.ts index d6ab49529398c..7a4b719a8a662 100644 --- a/src/plus/gk/utils/subscription.utils.ts +++ b/src/plus/gk/utils/subscription.utils.ts @@ -5,24 +5,32 @@ import type { PaidSubscriptionPlans, Subscription, SubscriptionPlan } from '../m export const SubscriptionUpdatedUriPathPrefix = 'did-update-subscription'; +export function compareSubscriptionPlans( + planA: SubscriptionPlanId | undefined, + planB: SubscriptionPlanId | undefined, +): number { + return getSubscriptionPlanPriority(planA) - getSubscriptionPlanPriority(planB); +} + export function getSubscriptionStateName( state: SubscriptionState, planId?: SubscriptionPlanId, - effectivePlanId?: SubscriptionPlanId, + _effectivePlanId?: SubscriptionPlanId, ): string { switch (state) { case SubscriptionState.Community: case SubscriptionState.ProPreviewExpired: return getSubscriptionPlanName(SubscriptionPlanId.Community); case SubscriptionState.ProPreview: - return `${getSubscriptionPlanName(SubscriptionPlanId.Pro)} (Preview)`; + return `${getSubscriptionPlanName(SubscriptionPlanId.Pro)} Preview`; case SubscriptionState.ProTrial: - return `${getSubscriptionPlanName(SubscriptionPlanId.Pro)} (${ - effectivePlanId != null && - getSubscriptionPlanPriority(effectivePlanId) > getSubscriptionPlanPriority(SubscriptionPlanId.Pro) - ? `${getSubscriptionPlanTier(effectivePlanId)} ` - : '' - }Trial)`; + return `${getSubscriptionPlanName(SubscriptionPlanId.Pro)} Trial`; + // return `${getSubscriptionPlanName( + // _effectivePlanId != null && + // compareSubscriptionPlans(_effectivePlanId, planId ?? SubscriptionPlanId.Pro) > 0 + // ? _effectivePlanId + // : planId ?? SubscriptionPlanId.Pro, + // )} Trial`; case SubscriptionState.ProTrialExpired: return getSubscriptionPlanName(SubscriptionPlanId.CommunityWithAccount); case SubscriptionState.ProTrialReactivationEligible: @@ -66,10 +74,7 @@ export function computeSubscriptionState(subscription: Optional getSubscriptionPlanPriority(effective.id) - ) { + if (actual.id === effective.id || compareSubscriptionPlans(actual.id, effective.id) > 0) { switch (actual.id === effective.id ? effective.id : actual.id) { case SubscriptionPlanId.Community: return preview == null ? SubscriptionState.Community : SubscriptionState.ProPreviewExpired; @@ -91,7 +96,7 @@ export function computeSubscriptionState(subscription: Optional getSubscriptionPlanPriority(SubscriptionPlanId.CommunityWithAccount)) { + if (compareSubscriptionPlans(actual.id, SubscriptionPlanId.CommunityWithAccount) > 0) { return SubscriptionState.Paid; } switch (effective.id) { @@ -147,8 +152,6 @@ export function getSubscriptionPlanTier( id: SubscriptionPlanId, ): 'Community' | 'Pro' | 'Advanced' | 'Teams' | 'Enterprise' { switch (id) { - case SubscriptionPlanId.CommunityWithAccount: - return 'Community'; case SubscriptionPlanId.Pro: return 'Pro'; case SubscriptionPlanId.Advanced: @@ -157,11 +160,24 @@ export function getSubscriptionPlanTier( return 'Teams'; case SubscriptionPlanId.Enterprise: return 'Enterprise'; - case SubscriptionPlanId.Community: default: return 'Community'; } } + +export function getSubscriptionPlanTierType(id: SubscriptionPlanId): 'PRO' | 'ADVANCED' | 'TEAMS' | 'ENTERPRISE' { + switch (id) { + case SubscriptionPlanId.Advanced: + return 'ADVANCED'; + case SubscriptionPlanId.Teams: + return 'TEAMS'; + case SubscriptionPlanId.Enterprise: + return 'ENTERPRISE'; + default: + return 'PRO'; + } +} + const plansPriority = new Map([ [undefined, -1], [SubscriptionPlanId.Community, 0], diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index b0d715963b4ba..57157ac25b020 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -12,7 +12,7 @@ import { InactiveOverviewState, inactiveOverviewStateContext, } from '../plus/home/components/overviewState'; -import type { GLHomeHeader } from '../plus/shared/components/home-header'; +import type { GlHomeHeader } from '../plus/shared/components/home-header'; import { GlApp } from '../shared/app'; import { scrollableBase } from '../shared/components/styles/lit/base.css'; import type { HostIpc } from '../shared/ipc'; @@ -40,7 +40,7 @@ export class GlHomeApp extends GlApp { private _inactiveOverviewState!: InactiveOverviewState; @query('gl-home-header') - private _header!: GLHomeHeader; + private _header!: GlHomeHeader; private badgeSource = { source: 'home', detail: 'badge' }; diff --git a/src/webviews/apps/plus/LICENSE.plus b/src/webviews/apps/plus/LICENSE.plus index f604ec14a3c11..3d91132688de5 100644 --- a/src/webviews/apps/plus/LICENSE.plus +++ b/src/webviews/apps/plus/LICENSE.plus @@ -1,4 +1,4 @@ -GitLens+ License +GitLens Pro License Copyright (c) 2021-2025 Axosoft, LLC dba GitKraken ("GitKraken") @@ -13,8 +13,8 @@ with, the GitKraken End User License Agreement, available at https://gitkraken.com/eula (the "EULA"), or other agreement governing the use of the Software, as agreed by you and GitKraken, and otherwise have a valid subscription for the correct number of user seats for the applicable version of -the Software (e.g., GitLens+, GitLens+ Pro, GitLens+ Advanced, GitLens+ Teams, -and GitLens+ Enterprise). Subject to the foregoing sentence, you are free to modify +the Software (e.g., GitLens Pro, GitLens Advanced, GitLens Business, +and GitLens Enterprise). Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that GitKraken and/or its licensors (as applicable) retain all right, title and interest in and to all such modifications and/or patches, and all such modifications and/or patches may @@ -25,7 +25,7 @@ modifications and/or patches. You are not granted any other rights beyond what is expressly stated herein. Except as set forth above, it is forbidden to copy, merge, publish, distribute, sublicense, and/or sell the Software. -The full text of this GitLens+ License shall be included in all copies or +The full text of this GitLens Pro License shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR diff --git a/src/webviews/apps/plus/graph-next/graph-app.ts b/src/webviews/apps/plus/graph-next/graph-app.ts index 96d3c52c57497..321669af8c681 100644 --- a/src/webviews/apps/plus/graph-next/graph-app.ts +++ b/src/webviews/apps/plus/graph-next/graph-app.ts @@ -8,7 +8,7 @@ import { emitTelemetrySentEvent } from '../../shared/telemetry'; import type { GraphMinimapDaySelectedEventDetail } from '../graph/minimap/minimap'; import type { GlGraphMinimapContainer } from '../graph/minimap/minimap-container'; import { stateContext } from './context'; -import type { GLGraphWrapper } from './graph-wrapper/graph-wrapper'; +import type { GlGraphWrapper } from './graph-wrapper/graph-wrapper'; import { graphStateContext } from './stateProvider'; import '../graph/minimap/minimap-container'; import './graph-wrapper/graph-wrapper'; @@ -32,7 +32,7 @@ export class GraphAppWC extends SignalWatcher(LitElement) { minimapEl!: GlGraphMinimapContainer; @query('gl-graph-wrapper') - graphWrapper!: GLGraphWrapper; + graphWrapper!: GlGraphWrapper; private handleHeaderSearchNavigation(e: CustomEventType<'gl-select-commits'>) { this.graphWrapper.selectCommits([e.detail], false, true); diff --git a/src/webviews/apps/plus/graph-next/graph-wrapper/graph-wrapper.ts b/src/webviews/apps/plus/graph-next/graph-wrapper/graph-wrapper.ts index c9cfe1664fbbf..53233bfd37862 100644 --- a/src/webviews/apps/plus/graph-next/graph-wrapper/graph-wrapper.ts +++ b/src/webviews/apps/plus/graph-next/graph-wrapper/graph-wrapper.ts @@ -84,7 +84,7 @@ customElements.define('web-graph', WebGraph); declare global { interface HTMLElementTagNameMap { - 'gl-graph-wrapper': GLGraphWrapper; + 'gl-graph-wrapper': GlGraphWrapper; } interface GlobalEventHandlersEventMap { @@ -121,7 +121,7 @@ declare global { } @customElement('gl-graph-wrapper') -export class GLGraphWrapper extends SignalWatcher(LitElement) { +export class GlGraphWrapper extends SignalWatcher(LitElement) { // use Light DOM protected override createRenderRoot(): HTMLElement | DocumentFragment { return this; diff --git a/src/webviews/apps/plus/home/components/merge-target-status.ts b/src/webviews/apps/plus/home/components/merge-target-status.ts index 40f8d19e13b0b..a38731cb08a14 100644 --- a/src/webviews/apps/plus/home/components/merge-target-status.ts +++ b/src/webviews/apps/plus/home/components/merge-target-status.ts @@ -1,6 +1,7 @@ import { css, html, LitElement, nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import type { Source } from '../../../../../constants.telemetry'; +import { SubscriptionPlanId } from '../../../../../constants.subscription'; +import type { SubscriptionUpgradeCommandArgs } from '../../../../../plus/gk/models/subscription'; import { createCommandLink } from '../../../../../system/commands'; import { pluralize } from '../../../../../system/string'; import type { BranchAndTargetRefs, BranchRef, GetOverviewBranch } from '../../../../home/protocol'; @@ -560,7 +561,8 @@ export class GlMergeTargetUpgrade extends LitElement {
('gitlens.plus.upgrade', { + plan: SubscriptionPlanId.Pro, source: 'merge-target', })}" >Upgrade to Pro * { + margin-block: 0.8rem 0; + } + + .upgrade ul { + padding-inline-start: 2rem; + } + + .upgrade li { + text-wrap: pretty; + } + + .upgrade gl-promo::part(text) { + margin-block-start: 0; + /* border-radius: 0.3rem; + padding: 0.2rem 0.4rem; + background-color: var(--gl-account-chip-color); */ + } + + .upgrade gl-promo:not([has-promo]) { + display: none; + } + + .upgrade-button { + text-transform: uppercase; + font-size: 1rem; + } `, ]; + private _showUpgrade = false; + @property({ type: Boolean, reflect: true, attribute: 'show-upgrade' }) + get showUpgrade() { + return this._showUpgrade; + } + private set showUpgrade(value: boolean) { + this._showUpgrade = value; + } + @query('#chip') private _chip!: HTMLElement; @@ -269,6 +289,10 @@ export class GLAccountChip extends LitElement { } private get planTier() { + if (isSubscriptionTrial(this.subscription)) { + return 'Pro Trial'; + } + return getSubscriptionPlanTier(this.planId); } @@ -295,58 +319,33 @@ export class GLAccountChip extends LitElement { override render(): unknown { return html` - - ${this.accountAvatar - ? html`` - : html``} - ${this.planTier} - -
-
- ${this.planName} - - ${this.hasAccount - ? html` - + ${this.accountAvatar + ? html`` + : html``} + ${this.planTier} + +
+
+ ${this.planName} + + ${this.hasAccount + ? html`('gitlens.plus.login', { source: 'account', })}" - tooltip="Manage Account" - aria-label="Manage Account" - > - ` - : html``} - + tooltip="Sign In" + aria-label="Sign In" + >` + : nothing} + +
+ ${this.renderAccountInfo()} ${this.renderAccountState()}
- ${this.renderOrganization()} ${this.renderAccountState()} -
- `; + + ${this.renderUpgradeContent()}`; } show(): void { @@ -354,29 +353,29 @@ export class GLAccountChip extends LitElement { this.focus(); } - private renderOrganization() { + private renderAccountInfo() { const organization = this._state.subscription?.activeOrganization?.name ?? ''; if (!this.hasAccount || !organization) return nothing; - return html`