Selaa lähdekoodia

Reworks plus feature enablement for less gates

Optimizes startup flow and churn during discovery
main
Eric Amodio 2 vuotta sitten
vanhempi
commit
77aea414ec
12 muutettua tiedostoa jossa 198 lisäystä ja 132 poistoa
  1. +11
    -11
      package.json
  2. +1
    -1
      src/constants.ts
  3. +7
    -1
      src/context.ts
  4. +12
    -0
      src/features.ts
  5. +75
    -51
      src/git/gitProviderService.ts
  6. +39
    -23
      src/plus/subscription/subscriptionService.ts
  7. +7
    -1
      src/plus/subscription/utils.ts
  8. +41
    -39
      src/plus/webviews/graph/graphWebview.ts
  9. +1
    -1
      src/plus/webviews/timeline/timelineWebview.ts
  10. +1
    -1
      src/plus/webviews/timeline/timelineWebviewView.ts
  11. +1
    -1
      src/views/worktreesView.ts
  12. +2
    -2
      src/webviews/apps/plus/timeline/timeline.ts

+ 11
- 11
package.json Näytä tiedosto

@ -8725,14 +8725,14 @@
"scm/sourceControl": [
{
"command": "gitlens.showGraphPage",
"when": "gitlens:enabled && config.gitlens.menus.scm.graph && config.gitlens.plusFeatures.enabled && scmProvider == git",
"when": "gitlens:enabled && config.gitlens.menus.scm.graph && gitlens:plus:enabled && scmProvider == git",
"group": "6_gitlens@1"
}
],
"scm/title": [
{
"command": "gitlens.showGraphPage",
"when": "gitlens:enabled && config.gitlens.menus.scmRepositoryInline.graph && config.gitlens.plusFeatures.enabled && scmProvider == git",
"when": "gitlens:enabled && config.gitlens.menus.scmRepositoryInline.graph && gitlens:plus:enabled && scmProvider == git",
"group": "navigation@-1000"
},
{
@ -8742,7 +8742,7 @@
},
{
"command": "gitlens.showGraphPage",
"when": "gitlens:enabled && config.gitlens.menus.scmRepository.graph && config.gitlens.plusFeatures.enabled && scmProvider == git",
"when": "gitlens:enabled && config.gitlens.menus.scmRepository.graph && gitlens:plus:enabled && scmProvider == git",
"group": "2_z_gitlens@2"
}
],
@ -8918,7 +8918,7 @@
},
{
"command": "gitlens.showGraphPage",
"when": "view =~ /^gitlens\\.views\\.commits/ && config.gitlens.plusFeatures.enabled",
"when": "view =~ /^gitlens\\.views\\.commits/ && gitlens:plus:enabled",
"group": "navigation@11"
},
{
@ -8988,7 +8988,7 @@
},
{
"command": "gitlens.showGraphPage",
"when": "view =~ /^gitlens\\.views\\.commits/ && config.gitlens.plusFeatures.enabled",
"when": "view =~ /^gitlens\\.views\\.commits/ && gitlens:plus:enabled",
"group": "8_gitlens_toggles@0"
},
{
@ -10353,7 +10353,7 @@
},
{
"command": "gitlens.showGraphPage",
"when": "viewItem =~ /gitlens:repo-folder\\b/ && config.gitlens.plusFeatures.enabled",
"when": "viewItem =~ /gitlens:repo-folder\\b/ && gitlens:plus:enabled",
"group": "inline@100"
},
{
@ -10389,7 +10389,7 @@
},
{
"command": "gitlens.showGraphPage",
"when": "viewItem =~ /gitlens:repo-folder\\b/ && config.gitlens.plusFeatures.enabled",
"when": "viewItem =~ /gitlens:repo-folder\\b/ && gitlens:plus:enabled",
"group": "3_gitlens_explore@1"
},
{
@ -11900,7 +11900,7 @@
{
"view": "gitlens.views.worktrees",
"contents": "[Create Worktree...](command:gitlens.views.createWorktree)",
"when": "gitlens:plus:allowed"
"when": "!gitlens:plus:required"
},
{
"view": "gitlens.views.worktrees",
@ -11934,7 +11934,7 @@
"type": "webview",
"id": "gitlens.views.home",
"name": "Home",
"when": "!gitlens:disabled && config.gitlens.plusFeatures.enabled",
"when": "!gitlens:disabled && gitlens:plus:enabled",
"contextualTitle": "GitLens",
"icon": "$(gitlens-gitlens)",
"visibility": "visible"
@ -11945,7 +11945,7 @@
"type": "webview",
"id": "gitlens.views.timeline",
"name": "Visual File History",
"when": "!gitlens:disabled && config.gitlens.plusFeatures.enabled",
"when": "!gitlens:disabled && gitlens:plus:enabled",
"contextualTitle": "GitLens",
"icon": "$(gitlens-history-view)",
"visibility": "visible"
@ -12028,7 +12028,7 @@
{
"id": "gitlens.views.worktrees",
"name": "Worktrees",
"when": "!gitlens:disabled && !gitlens:hasVirtualFolders && config.gitlens.plusFeatures.enabled",
"when": "!gitlens:disabled && !gitlens:hasVirtualFolders && gitlens:plus:enabled",
"contextualTitle": "GitLens",
"icon": "$(gitlens-worktrees-view)",
"visibility": "collapsed"

+ 1
- 1
src/constants.ts Näytä tiedosto

@ -269,7 +269,7 @@ export const enum ContextKeys {
Vsls = 'gitlens:vsls',
Plus = 'gitlens:plus',
PlusAllowed = 'gitlens:plus:allowed',
PlusEnabled = 'gitlens:plus:enabled',
PlusRequired = 'gitlens:plus:required',
PlusState = 'gitlens:plus:state',
}

+ 7
- 1
src/context.ts Näytä tiedosto

@ -1,9 +1,14 @@
import { commands } from 'vscode';
import { commands, EventEmitter } from 'vscode';
import type { ContextKeys } from './constants';
import { CoreCommands } from './constants';
const contextStorage = new Map<string, unknown>();
const _onDidChangeContext = new EventEmitter<
ContextKeys | `${ContextKeys.ActionPrefix}${string}` | `${ContextKeys.KeyPrefix}${string}`
>();
export const onDidChangeContext = _onDidChangeContext.event;
export function getContext<T>(key: ContextKeys): T | undefined;
export function getContext<T>(key: ContextKeys, defaultValue: T): T;
export function getContext<T>(key: ContextKeys, defaultValue?: T): T | undefined {
@ -16,4 +21,5 @@ export async function setContext(
): Promise<void> {
contextStorage.set(key, value);
void (await commands.executeCommand(CoreCommands.SetContext, key, value));
_onDidChangeContext.fire(key);
}

+ 12
- 0
src/features.ts Näytä tiedosto

@ -14,6 +14,18 @@ export type FeatureAccess =
visibility?: RepositoryVisibility;
}
| {
allowed: false | 'mixed';
subscription: { current: Subscription; required?: RequiredSubscriptionPlans };
visibility?: RepositoryVisibility;
};
export type RepoFeatureAccess =
| {
allowed: true;
subscription: { current: Subscription; required?: undefined };
visibility?: RepositoryVisibility;
}
| {
allowed: false;
subscription: { current: Subscription; required?: RequiredSubscriptionPlans };
visibility?: RepositoryVisibility;

+ 75
- 51
src/git/gitProviderService.ts Näytä tiedosto

@ -17,14 +17,14 @@ import { ContextKeys, CoreGitConfiguration, GlyphChars, Schemes } from '../const
import type { Container } from '../container';
import { setContext } from '../context';
import { AccessDeniedError, ProviderNotFoundError } from '../errors';
import type { FeatureAccess, Features, PlusFeatures } from '../features';
import type { FeatureAccess, Features, PlusFeatures, RepoFeatureAccess } from '../features';
import type { RemoteProvider } from '../git/remotes/remoteProvider';
import { Logger } from '../logger';
import type { SubscriptionChangeEvent } from '../plus/subscription/subscriptionService';
import type { RepoComparisonKey } from '../repositories';
import { asRepoComparisonKey, Repositories } from '../repositories';
import type { RequiredSubscriptionPlans, Subscription } from '../subscription';
import { getSubscriptionPlanPriority, isSubscriptionPaidPlan, SubscriptionPlanId } from '../subscription';
import type { Subscription } from '../subscription';
import { isSubscriptionPaidPlan, SubscriptionPlanId } from '../subscription';
import { groupByFilterMap, groupByMap } from '../system/array';
import { gate } from '../system/decorators/gate';
import { debug, getLogScope, log } from '../system/decorators/log';
@ -72,6 +72,7 @@ import type { RemoteProviders } from './remotes/remoteProviders';
import type { RichRemoteProvider } from './remotes/richRemoteProvider';
import type { GitSearch, SearchQuery } from './search';
const emptyArray = Object.freeze([]) as unknown as any[];
const maxDefaultBranchWeight = 100;
const weightedDefaultBranches = new Map<string, number>([
['master', maxDefaultBranchWeight],
@ -264,6 +265,8 @@ export class GitProviderService implements Disposable {
}
get openRepositories(): Repository[] {
if (this.repositoryCount === 0) return emptyArray as Repository[];
const repositories = [...filter(this.repositories, r => !r.closed)];
if (repositories.length === 0) return repositories;
@ -271,7 +274,7 @@ export class GitProviderService implements Disposable {
}
get openRepositoryCount(): number {
return count(this.repositories, r => !r.closed);
return this.repositoryCount === 0 ? 0 : count(this.repositories, r => !r.closed);
}
get repositories(): IterableIterator<Repository> {
@ -515,14 +518,23 @@ export class GitProviderService implements Disposable {
return this._subscription ?? (this._subscription = await this.container.subscription.getSubscription());
}
private _accessCache = new Map<string | undefined, Promise<FeatureAccess>>();
async access(feature?: PlusFeatures, repoPath?: string | Uri): Promise<FeatureAccess> {
let cacheKey;
if (repoPath != null) {
const { path } = this.getProvider(repoPath);
cacheKey = path;
private _accessCache: Map<string, Promise<RepoFeatureAccess>> &
Map<undefined, Promise<FeatureAccess | RepoFeatureAccess>> = new Map();
async access(feature: PlusFeatures | undefined, repoPath: string | Uri): Promise<RepoFeatureAccess>;
async access(feature?: PlusFeatures, repoPath?: string | Uri): Promise<FeatureAccess | RepoFeatureAccess>;
async access(feature?: PlusFeatures, repoPath?: string | Uri): Promise<FeatureAccess | RepoFeatureAccess> {
if (repoPath == null) {
let access = this._accessCache.get(undefined);
if (access == null) {
access = this.accessCore(feature, repoPath);
this._accessCache.set(undefined, access);
}
return access;
}
const { path } = this.getProvider(repoPath);
const cacheKey = path;
let access = this._accessCache.get(cacheKey);
if (access == null) {
access = this.accessCore(feature, repoPath);
@ -532,42 +544,51 @@ export class GitProviderService implements Disposable {
return access;
}
private async accessCore(feature: PlusFeatures | undefined, repoPath: string | Uri): Promise<RepoFeatureAccess>;
private async accessCore(
feature?: PlusFeatures,
repoPath?: string | Uri,
): Promise<FeatureAccess | RepoFeatureAccess>;
@debug()
private async accessCore(feature?: PlusFeatures, repoPath?: string | Uri): Promise<FeatureAccess> {
private async accessCore(
_feature?: PlusFeatures,
repoPath?: string | Uri,
): Promise<FeatureAccess | RepoFeatureAccess> {
const subscription = await this.getSubscription();
if (subscription.account?.verified === false) {
return { allowed: false, subscription: { current: subscription } };
}
const plan = subscription.plan.effective.id;
if (isSubscriptionPaidPlan(plan)) {
return { allowed: true, subscription: { current: subscription } };
return { allowed: subscription.account?.verified !== false, subscription: { current: subscription } };
}
function getRepoAccess(
this: GitProviderService,
repoPath: string | Uri,
force: boolean = false,
): Promise<FeatureAccess> {
): Promise<RepoFeatureAccess> {
const { path: cacheKey } = this.getProvider(repoPath);
let access = force ? undefined : this._accessCache.get(cacheKey);
if (access == null) {
access = this.visibility(repoPath).then(visibility => {
if (visibility === RepositoryVisibility.Private) {
access = this.visibility(repoPath).then(
visibility => {
if (visibility === RepositoryVisibility.Private) {
return {
allowed: false,
subscription: { current: subscription, required: SubscriptionPlanId.Pro },
visibility: visibility,
};
}
return {
allowed: false,
subscription: { current: subscription, required: SubscriptionPlanId.Pro },
allowed: true,
subscription: { current: subscription },
visibility: visibility,
};
}
return {
allowed: true,
subscription: { current: subscription },
visibility: visibility,
};
});
},
// If there is a failure assume access is allowed
() => ({ allowed: true, subscription: { current: subscription } }),
);
this._accessCache.set(cacheKey, access);
}
@ -585,28 +606,26 @@ export class GitProviderService implements Disposable {
return getRepoAccess.call(this, repositories[0].path);
}
let allowed = true;
let requiredPlan: RequiredSubscriptionPlans | undefined;
let requiredPriority = -1;
const maxPriority = getSubscriptionPlanPriority(SubscriptionPlanId.Pro);
for await (const result of fastestSettled(repositories.map(r => getRepoAccess.call(this, r.path)))) {
if (result.status !== 'fulfilled' || result.value.allowed) continue;
allowed = false;
const priority = getSubscriptionPlanPriority(result.value.subscription.required);
if (requiredPriority < priority) {
requiredPriority = priority;
requiredPlan = result.value.subscription.required;
}
if (requiredPriority >= maxPriority) break;
const visibility = await this.visibility();
switch (visibility) {
case RepositoriesVisibility.Private:
return {
allowed: false,
subscription: { current: subscription, required: SubscriptionPlanId.Pro },
visibility: RepositoryVisibility.Private,
};
case RepositoriesVisibility.Mixed:
return {
allowed: 'mixed',
subscription: { current: subscription, required: SubscriptionPlanId.Pro },
};
default:
return {
allowed: true,
subscription: { current: subscription },
visibility: RepositoryVisibility.Public,
};
}
return allowed
? { allowed: true, subscription: { current: subscription } }
: { allowed: false, subscription: { current: subscription, required: requiredPlan } };
}
// Pass force = true to bypass the cache and avoid a promise loop (where we used the cached promise we just created to try to resolve itself 🤦)
@ -615,7 +634,7 @@ export class GitProviderService implements Disposable {
async ensureAccess(feature: PlusFeatures, repoPath?: string): Promise<void> {
const { allowed, subscription } = await this.access(feature, repoPath);
if (!allowed) throw new AccessDeniedError(subscription.current, subscription.required);
if (allowed === false) throw new AccessDeniedError(subscription.current, subscription.required);
}
supports(repoPath: string | Uri, feature: Features): Promise<boolean> {
@ -2203,7 +2222,12 @@ export class GitProviderService implements Disposable {
path?: string,
options?: { force?: boolean; timeout?: number },
): Promise<string>;
async resolveReference(repoPath: string, ref: string, uri?: Uri, options?: { force?: boolean; timeout?: number }): Promise<string>;
async resolveReference(
repoPath: string,
ref: string,
uri?: Uri,
options?: { force?: boolean; timeout?: number },
): Promise<string>;
@gate()
@log()
async resolveReference(

+ 39
- 23
src/plus/subscription/subscriptionService.ts Näytä tiedosto

@ -36,7 +36,6 @@ import {
getSubscriptionTimeRemaining,
getTimeRemaining,
isSubscriptionExpired,
isSubscriptionPaidPlan,
isSubscriptionTrial,
SubscriptionPlanId,
SubscriptionState,
@ -82,6 +81,11 @@ export class SubscriptionService implements Disposable {
e => setTimeout(() => this.onAuthenticationChanged(e), 0),
this,
),
configuration.onDidChange(e => {
if (configuration.changed(e, 'plusFeatures')) {
this.updateContext();
}
}),
);
const subscription = this.getStoredSubscription();
@ -274,6 +278,10 @@ export class SubscriptionService implements Disposable {
@log()
async logout(reset: boolean = false): Promise<void> {
return this.logoutCore(reset);
}
private async logoutCore(reset: boolean = false): Promise<void> {
if (this._validationTimer != null) {
clearInterval(this._validationTimer);
this._validationTimer = undefined;
@ -301,8 +309,18 @@ export class SubscriptionService implements Disposable {
this.changeSubscription({
...this._subscription,
plan: {
actual: getSubscriptionPlan(SubscriptionPlanId.Free),
effective: getSubscriptionPlan(SubscriptionPlanId.Free),
actual: getSubscriptionPlan(
SubscriptionPlanId.Free,
this._subscription.plan?.actual?.startedOn != null
? new Date(this._subscription.plan.actual.startedOn)
: undefined,
),
effective: getSubscriptionPlan(
SubscriptionPlanId.Free,
this._subscription.plan?.effective?.startedOn != null
? new Date(this._subscription.plan.actual.startedOn)
: undefined,
),
},
account: undefined,
});
@ -686,8 +704,8 @@ export class SubscriptionService implements Disposable {
session = null;
if (ex instanceof Error && ex.message.includes('User did not consent')) {
Logger.debug(scope, 'User declined authentication; logging out...');
await this.logout();
Logger.debug(scope, 'User declined authentication');
await this.logoutCore();
return null;
}
@ -700,8 +718,8 @@ export class SubscriptionService implements Disposable {
}
if (session == null) {
Logger.debug(scope, 'No valid session was found; logging out...');
await this.logout();
Logger.debug(scope, 'No valid session was found');
await this.logoutCore();
return session ?? null;
}
@ -720,11 +738,8 @@ export class SubscriptionService implements Disposable {
) {
session = null;
Logger.debug(
scope,
`Account validation failed (${ex.statusCode ?? (ex.original as any)?.code}); logging out...`,
);
await this.logout();
Logger.debug(scope, `Account validation failed (${ex.statusCode ?? (ex.original as any)?.code})`);
await this.logoutCore();
if (createIfNeeded) {
const unauthorized = ex.statusCode === 401;
@ -815,10 +830,12 @@ export class SubscriptionService implements Disposable {
this._subscription = subscription;
this._etag = Date.now();
this.updateContext();
if (!silent) {
this.updateContext();
if (!silent && previous != null) {
this._onDidChange.fire({ current: subscription, previous: previous, etag: this._etag });
if (previous != null) {
this._onDidChange.fire({ current: subscription, previous: previous, etag: this._etag });
}
}
}
@ -850,14 +867,13 @@ export class SubscriptionService implements Disposable {
this.updateStatusBar();
queueMicrotask(async () => {
const { allowed, subscription } = await this.container.git.access();
const required = allowed
? false
: subscription.required != null && isSubscriptionPaidPlan(subscription.required)
? 'paid'
: 'free+';
void setContext(ContextKeys.PlusAllowed, allowed);
void setContext(ContextKeys.PlusRequired, required);
let allowed: boolean | 'mixed' = false;
// For performance reasons, only check if we have any repositories
if (this.container.git.repositoryCount !== 0) {
({ allowed } = await this.container.git.access());
}
void setContext(ContextKeys.PlusEnabled, Boolean(allowed) || configuration.get('plusFeatures.enabled'));
void setContext(ContextKeys.PlusRequired, allowed === false);
});
const {

+ 7
- 1
src/plus/subscription/utils.ts Näytä tiedosto

@ -1,9 +1,15 @@
import type { MessageItem } from 'vscode';
import { window } from 'vscode';
import { configuration } from '../../configuration';
import { ContextKeys } from '../../constants';
import { getContext } from '../../context';
export function arePlusFeaturesEnabled(): boolean {
return getContext(ContextKeys.PlusEnabled, configuration.get('plusFeatures.enabled', undefined, true));
}
export async function ensurePlusFeaturesEnabled(): Promise<boolean> {
if (configuration.get('plusFeatures.enabled', undefined, true)) return true;
if (arePlusFeaturesEnabled()) return true;
const confirm: MessageItem = { title: 'Enable' };
const cancel: MessageItem = { title: 'Cancel', isCloseAffordance: true };

+ 41
- 39
src/plus/webviews/graph/graphWebview.ts Näytä tiedosto

@ -21,7 +21,7 @@ import { GitActions } from '../../../commands/gitCommands.actions';
import { configuration } from '../../../configuration';
import { Commands, ContextKeys, CoreGitCommands } from '../../../constants';
import type { Container } from '../../../container';
import { setContext } from '../../../context';
import { onDidChangeContext, setContext } from '../../../context';
import { PlusFeatures } from '../../../features';
import type { GitCommit } from '../../../git/models/commit';
import { GitGraphRowType } from '../../../git/models/graph';
@ -41,7 +41,7 @@ import { executeActionCommand, executeCommand, executeCoreGitCommand, registerCo
import { gate } from '../../../system/decorators/gate';
import { debug } from '../../../system/decorators/log';
import type { Deferrable } from '../../../system/function';
import { debounce } from '../../../system/function';
import { debounce, once } from '../../../system/function';
import { first, last } from '../../../system/iterable';
import { updateRecordValue } from '../../../system/object';
import { isDarkTheme, isLightTheme } from '../../../system/utils';
@ -57,7 +57,7 @@ import { onIpc } from '../../../webviews/protocol';
import type { IpcMessage, IpcMessageParams, IpcNotificationType } from '../../../webviews/protocol';
import { WebviewBase } from '../../../webviews/webviewBase';
import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService';
import { ensurePlusFeaturesEnabled } from '../../subscription/utils';
import { arePlusFeaturesEnabled, ensurePlusFeaturesEnabled } from '../../subscription/utils';
import type {
DismissBannerParams,
EnsureCommitParams,
@ -172,6 +172,11 @@ export class GraphWebview extends WebviewBase {
);
this.disposables.push(
configuration.onDidChange(this.onConfigurationChanged, this),
once(container.onReady)(() => queueMicrotask(() => this.updateStatusBar())),
onDidChangeContext(key => {
if (key !== ContextKeys.PlusEnabled) return;
this.updateStatusBar();
}),
{ dispose: () => this._statusBarItem?.dispose() },
registerCommand(
Commands.ShowInCommitGraph,
@ -203,8 +208,6 @@ export class GraphWebview extends WebviewBase {
},
),
);
this.onConfigurationChanged();
}
protected override get options(): WebviewPanelOptions & WebviewOptions {
@ -366,44 +369,22 @@ export class GraphWebview extends WebviewBase {
this.sendPendingIpcNotifications();
}
private onConfigurationChanged(e?: ConfigurationChangeEvent) {
private onConfigurationChanged(e: ConfigurationChangeEvent) {
if (configuration.changed(e, 'graph.statusBar.enabled') || configuration.changed(e, 'plusFeatures.enabled')) {
const enabled = configuration.get('graph.statusBar.enabled') && configuration.get('plusFeatures.enabled');
if (enabled) {
if (this._statusBarItem == null) {
this._statusBarItem = window.createStatusBarItem(
'gitlens.graph',
StatusBarAlignment.Left,
10000 - 3,
);
this._statusBarItem.name = 'GitLens Commit Graph';
this._statusBarItem.command = Commands.ShowGraphPage;
this._statusBarItem.text = '$(gitlens-graph)';
this._statusBarItem.tooltip = new MarkdownString(
'Visualize commits on the all-new Commit Graph ✨',
);
this._statusBarItem.accessibilityInformation = {
label: `Show the GitLens Commit Graph`,
};
}
this._statusBarItem.show();
} else {
this._statusBarItem?.dispose();
this._statusBarItem = undefined;
}
this.updateStatusBar();
}
// If we don't have an open webview ignore the rest
if (this._panel == null) return;
if (e != null && configuration.changed(e, 'graph.commitOrdering')) {
if (configuration.changed(e, 'graph.commitOrdering')) {
this.updateState();
return;
}
if (
(e != null && configuration.changed(e, 'defaultDateFormat')) ||
configuration.changed(e, 'defaultDateFormat') ||
configuration.changed(e, 'defaultDateStyle') ||
configuration.changed(e, 'advanced.abbreviatedShaLength') ||
configuration.changed(e, 'graph.avatars') ||
@ -443,6 +424,7 @@ export class GraphWebview extends WebviewBase {
this._etagSubscription = e.etag;
void this.notifyDidChangeSubscription();
this.updateStatusBar();
}
private onThemeChanged(theme: ColorTheme) {
@ -779,7 +761,7 @@ export class GraphWebview extends WebviewBase {
const access = await this.getGraphAccess();
return this.notify(DidChangeSubscriptionNotificationType, {
subscription: access.subscription.current,
allowed: access.allowed,
allowed: access.allowed !== false,
});
}
@ -913,7 +895,7 @@ export class GraphWebview extends WebviewBase {
this._etagSubscription = this.container.subscription.etag;
// If we don't have access to GitLens+, but the preview trial hasn't been started, auto-start it
if (!access.allowed && access.subscription.current.previewTrial == null) {
if (access.allowed === false && access.subscription.current.previewTrial == null) {
await this.container.subscription.startPreviewTrial(true);
access = await this.container.git.access(PlusFeatures.Graph, this.repository?.path);
}
@ -982,7 +964,7 @@ export class GraphWebview extends WebviewBase {
selectedRepositoryVisibility: visibility,
selectedRows: this._selectedRows,
subscription: access.subscription.current,
allowed: access.allowed,
allowed: access.allowed !== false,
avatars: data != null ? Object.fromEntries(data.avatars) : undefined,
loading: deferRows,
rows: data?.rows,
@ -1020,6 +1002,13 @@ export class GraphWebview extends WebviewBase {
this._searchCancellation = undefined;
}
private setSelectedRows(sha: string | undefined) {
if (this._selectedSha === sha) return;
this._selectedSha = sha;
this._selectedRows = sha != null ? { [sha]: true } : {};
}
private setGraph(graph: GitGraph | undefined) {
this._graph = graph;
if (graph == null) {
@ -1045,11 +1034,24 @@ export class GraphWebview extends WebviewBase {
}
}
private setSelectedRows(sha: string | undefined) {
if (this._selectedSha === sha) return;
this._selectedSha = sha;
this._selectedRows = sha != null ? { [sha]: true } : {};
private updateStatusBar() {
const enabled = configuration.get('graph.statusBar.enabled') && arePlusFeaturesEnabled();
if (enabled) {
if (this._statusBarItem == null) {
this._statusBarItem = window.createStatusBarItem('gitlens.graph', StatusBarAlignment.Left, 10000 - 3);
this._statusBarItem.name = 'GitLens Commit Graph';
this._statusBarItem.command = Commands.ShowGraphPage;
this._statusBarItem.text = '$(gitlens-graph)';
this._statusBarItem.tooltip = new MarkdownString('Visualize commits on the all-new Commit Graph ✨');
this._statusBarItem.accessibilityInformation = {
label: `Show the GitLens Commit Graph`,
};
}
this._statusBarItem.show();
} else {
this._statusBarItem?.dispose();
this._statusBarItem = undefined;
}
}
@debug()

+ 1
- 1
src/plus/webviews/timeline/timelineWebview.ts Näytä tiedosto

@ -189,7 +189,7 @@ export class TimelineWebview extends WebviewBase {
const shortDateFormat = configuration.get('defaultDateShortFormat') ?? 'short';
const period = current.period ?? defaultPeriod;
if (!access.allowed) {
if (access.allowed === false) {
const dataset = generateRandomTimelineDataset();
return {
dataset: dataset.sort((a, b) => b.sort - a.sort),

+ 1
- 1
src/plus/webviews/timeline/timelineWebviewView.ts Näytä tiedosto

@ -184,7 +184,7 @@ export class TimelineWebviewView extends WebviewViewBase {
const shortDateFormat = configuration.get('defaultDateShortFormat') ?? 'short';
const period = current.period ?? defaultPeriod;
if (!access.allowed) {
if (access.allowed === false) {
const dataset = generateRandomTimelineDataset();
return {
dataset: dataset.sort((a, b) => b.sort - a.sort),

+ 1
- 1
src/views/worktreesView.ts Näytä tiedosto

@ -44,7 +44,7 @@ export class WorktreesRepositoryNode extends RepositoryFolderNode
export class WorktreesViewNode extends RepositoriesSubscribeableNode<WorktreesView, WorktreesRepositoryNode> {
async getChildren(): Promise<ViewNode[]> {
const access = await this.view.container.git.access(PlusFeatures.Worktrees);
if (!access.allowed) return [];
if (access.allowed === false) return [];
if (this.children == null) {
const repositories = this.view.container.git.openRepositories;

+ 2
- 2
src/webviews/apps/plus/timeline/timeline.ts Näytä tiedosto

@ -89,11 +89,11 @@ export class TimelineApp extends App {
private updateState(): void {
const $overlay = document.getElementById('overlay') as HTMLDivElement;
$overlay.classList.toggle('hidden', this.state.access.allowed);
$overlay.classList.toggle('hidden', this.state.access.allowed === true);
const $slot = document.getElementById('overlay-slot') as HTMLDivElement;
if (!this.state.access.allowed) {
if (this.state.access.allowed !== true) {
const { current: subscription, required } = this.state.access.subscription;
const requiresPublic = required === SubscriptionPlanId.FreePlus;

Ladataan…
Peruuta
Tallenna