Просмотр исходного кода

Reworks storage to be type-safe

main
Eric Amodio 2 лет назад
Родитель
Сommit
9b6cc5c626
25 измененных файлов: 306 добавлений и 306 удалений
  1. +6
    -11
      src/avatars.ts
  2. +3
    -4
      src/commands/gitCommands.utils.ts
  3. +5
    -5
      src/container.ts
  4. +2
    -4
      src/env/node/git/localGitProvider.ts
  5. +18
    -19
      src/extension.ts
  6. +2
    -5
      src/git/gitProviderService.ts
  7. +1
    -3
      src/git/models/branch.ts
  8. +6
    -9
      src/git/models/reference.ts
  9. +1
    -2
      src/git/models/remote.ts
  10. +10
    -10
      src/git/models/repository.ts
  11. +3
    -4
      src/git/remotes/provider.ts
  12. +2
    -3
      src/plus/subscription/authenticationProvider.ts
  13. +2
    -8
      src/plus/subscription/subscriptionService.ts
  14. +9
    -22
      src/plus/webviews/graph/graphWebview.ts
  15. +7
    -15
      src/plus/webviews/graph/protocol.ts
  16. +177
    -75
      src/storage.ts
  17. +7
    -12
      src/views/nodes/compareBranchNode.ts
  18. +2
    -2
      src/views/nodes/comparePickerNode.ts
  19. +4
    -4
      src/views/nodes/compareResultsNode.ts
  20. +3
    -13
      src/views/repositoriesView.ts
  21. +20
    -47
      src/views/searchAndCompareView.ts
  22. +6
    -4
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  23. +2
    -8
      src/webviews/apps/plus/graph/graph.tsx
  24. +2
    -5
      src/webviews/commitDetails/commitDetailsWebviewView.ts
  25. +6
    -12
      src/webviews/home/homeWebviewView.ts

+ 6
- 11
src/avatars.ts Просмотреть файл

@ -4,7 +4,7 @@ import { configuration } from './configuration';
import { Container } from './container';
import type { GitRevisionReference } from './git/models/reference';
import { getGitHubNoReplyAddressParts } from './git/remotes/github';
import { StorageKeys } from './storage';
import type { StoredAvatar } from './storage';
import { debounce } from './system/function';
import { filterMap } from './system/iterable';
import { base64, equalsIgnoreCase, md5 } from './system/string';
@ -20,18 +20,18 @@ _onDidFetchAvatar.event(
? [
...filterMap(avatarCache, ([key, avatar]) =>
avatar.uri != null
? [
? ([
key,
{
uri: avatar.uri.toString(),
timestamp: avatar.timestamp,
},
]
] as [string, StoredAvatar])
: undefined,
),
]
: undefined;
void Container.instance.storage.store(StorageKeys.Avatars, avatars);
void Container.instance.storage.store('avatars', avatars);
}, 1000),
);
@ -46,11 +46,6 @@ interface Avatar {
retries: number;
}
interface SerializedAvatar {
uri: string;
timestamp: number;
}
let avatarCache: Map<string, Avatar> | undefined;
const avatarQueue = new Map<string, Promise<Uri>>();
@ -140,7 +135,7 @@ function createOrUpdateAvatar(
function ensureAvatarCache(cache: Map<string, Avatar> | undefined): asserts cache is Map<string, Avatar> {
if (cache == null) {
const avatars: [string, Avatar][] | undefined = Container.instance.storage
.get<[string, SerializedAvatar][]>(StorageKeys.Avatars)
.get('avatars')
?.map<[string, Avatar]>(([key, avatar]) => [
key,
{
@ -249,7 +244,7 @@ export function getPresenceDataUri(status: ContactPresenceStatus) {
export function resetAvatarCache(reset: 'all' | 'failed' | 'fallback') {
switch (reset) {
case 'all':
void Container.instance.storage.delete(StorageKeys.Avatars);
void Container.instance.storage.delete('avatars');
avatarCache?.clear();
avatarQueue.clear();
break;

+ 3
- 4
src/commands/gitCommands.utils.ts Просмотреть файл

@ -4,7 +4,6 @@ import { ContextKeys } from '../constants';
import type { Container } from '../container';
import { getContext } from '../context';
import type { Usage } from '../storage';
import { WorkspaceStorageKeys } from '../storage';
import { BranchGitCommand } from './git/branch';
import { CherryPickGitCommand } from './git/cherry-pick';
import { CoAuthorsGitCommand } from './git/coauthors';
@ -99,7 +98,7 @@ export class PickCommandStep implements QuickPickStep {
].filter(<T>(i: T | undefined): i is T => i != null);
if (configuration.get('gitCommands.sortBy') === GitCommandSorting.Usage) {
const usage = this.container.storage.getWorkspace<Usage>(WorkspaceStorageKeys.GitCommandPaletteUsage);
const usage = this.container.storage.getWorkspace('gitComandPalette:usage');
if (usage != null) {
this.items.sort((a, b) => (usage[b.key] ?? 0) - (usage[a.key] ?? 0));
}
@ -139,12 +138,12 @@ export class PickCommandStep implements QuickPickStep {
}
private async updateCommandUsage(id: string, timestamp: number) {
let usage = this.container.storage.getWorkspace<Usage>(WorkspaceStorageKeys.GitCommandPaletteUsage);
let usage = this.container.storage.getWorkspace(`gitComandPalette:usage`);
if (usage === undefined) {
usage = Object.create(null) as Usage;
}
usage[id] = timestamp;
await this.container.storage.storeWorkspace(WorkspaceStorageKeys.GitCommandPaletteUsage, usage);
await this.container.storage.storeWorkspace(`gitComandPalette:usage`, usage);
}
}

+ 5
- 5
src/container.ts Просмотреть файл

@ -25,7 +25,7 @@ import { GraphWebview } from './plus/webviews/graph/graphWebview';
import { TimelineWebview } from './plus/webviews/timeline/timelineWebview';
import { TimelineWebviewView } from './plus/webviews/timeline/timelineWebviewView';
import { StatusBarController } from './statusbar/statusBarController';
import { Storage } from './storage';
import type { Storage } from './storage';
import { executeCommand } from './system/command';
import { log } from './system/decorators/log';
import { memoize } from './system/decorators/memoize';
@ -68,10 +68,10 @@ export class Container {
},
});
static create(context: ExtensionContext, insiders: boolean) {
static create(context: ExtensionContext, storage: Storage, insiders: boolean) {
if (Container.#instance != null) throw new Error('Container is already initialized');
Container.#instance = new Container(context, insiders);
Container.#instance = new Container(context, storage, insiders);
return Container.#instance;
}
@ -138,12 +138,12 @@ export class Container {
private _configAffectedByModeRegex: RegExp | undefined;
private _terminalLinks: GitTerminalLinkProvider | undefined;
private constructor(context: ExtensionContext, insiders: boolean) {
private constructor(context: ExtensionContext, storage: Storage, insiders: boolean) {
this._context = context;
this._insiders = insiders;
this.ensureModeApplied();
context.subscriptions.push((this._storage = new Storage(this._context)));
context.subscriptions.push((this._storage = storage));
context.subscriptions.push(configuration.onWillChange(this.onConfigurationChanging, this));

+ 2
- 4
src/env/node/git/localGitProvider.ts Просмотреть файл

@ -91,7 +91,6 @@ import {
showGitMissingErrorMessage,
showGitVersionUnsupportedErrorMessage,
} from '../../../messages';
import { WorkspaceStorageKeys } from '../../../storage';
import { countStringLength, filterMap } from '../../../system/array';
import { TimedCancellationSource } from '../../../system/cancellation';
import { gate } from '../../../system/decorators/gate';
@ -264,8 +263,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
void subscribeToScmOpenCloseRepository.call(this);
const potentialGitPaths =
configuration.getAny<string | string[]>('git.path') ??
this.container.storage.getWorkspace(WorkspaceStorageKeys.GitPath, undefined);
configuration.getAny<string | string[]>('git.path') ?? this.container.storage.getWorkspace('gitPath');
const start = hrtime();
@ -289,7 +287,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const location = await any<GitLocation>(findGitPromise, findGitFromSCMPromise);
// Save the found git path, but let things settle first to not impact startup performance
setTimeout(() => {
void this.container.storage.storeWorkspace(WorkspaceStorageKeys.GitPath, location.path);
void this.container.storage.storeWorkspace('gitPath', location.path);
}, 1000);
if (scope != null) {

+ 18
- 19
src/extension.ts Просмотреть файл

@ -19,7 +19,7 @@ import {
showWhatsNewMessage,
} from './messages';
import { registerPartnerActionRunners } from './partners';
import { StorageKeys, SyncedStorageKeys } from './storage';
import { DeprecatedStorageKeys, Storage, SyncedStorageKeys } from './storage';
import { executeCommand, executeCoreCommand, registerCommands } from './system/command';
import { setDefaultDateLocales } from './system/date';
import { once } from './system/event';
@ -94,10 +94,9 @@ export async function activate(context: ExtensionContext): Promise
setKeysForSync(context);
const syncedVersion = context.globalState.get<string>(SyncedStorageKeys.Version);
const localVersion =
context.globalState.get<string>(StorageKeys.Version) ??
context.globalState.get<string>(StorageKeys.Deprecated_Version);
const storage = new Storage(context);
const syncedVersion = storage.get('synced:version');
const localVersion = storage.get('version') ?? context.globalState.get<string>(DeprecatedStorageKeys.Version);
let previousVersion: string | undefined;
if (localVersion == null || syncedVersion == null) {
@ -110,13 +109,13 @@ export async function activate(context: ExtensionContext): Promise
let exitMessage;
if (Logger.enabled(LogLevel.Debug)) {
exitMessage = `syncedVersion=${syncedVersion}, localVersion=${localVersion}, previousVersion=${previousVersion}, welcome=${context.globalState.get<boolean>(
SyncedStorageKeys.HomeViewWelcomeVisible,
exitMessage = `syncedVersion=${syncedVersion}, localVersion=${localVersion}, previousVersion=${previousVersion}, welcome=${storage.get(
'views:welcome:visible',
)}`;
}
if (previousVersion == null) {
void context.globalState.update(SyncedStorageKeys.HomeViewWelcomeVisible, true);
void storage.store('views:welcome:visible', true);
}
Configuration.configure(context);
@ -132,7 +131,7 @@ export async function activate(context: ExtensionContext): Promise
// await migrateSettings(context, previousVersion);
const container = Container.create(context, insiders);
const container = Container.create(context, storage, insiders);
once(container.onReady)(() => {
context.subscriptions.push(...registerCommands(container));
registerBuiltInActionRunners(container);
@ -140,11 +139,11 @@ export async function activate(context: ExtensionContext): Promise
void showWelcomeOrWhatsNew(container, gitlensVersion, previousVersion);
void context.globalState.update(StorageKeys.Version, gitlensVersion);
void storage.store('version', gitlensVersion);
// Only update our synced version if the new version is greater
if (syncedVersion == null || compare(gitlensVersion, syncedVersion) === 1) {
void context.globalState.update(SyncedStorageKeys.Version, gitlensVersion);
void storage.store('synced:version', gitlensVersion);
}
if (outputLevel === OutputLevel.Debug) {
@ -245,19 +244,19 @@ async function showWelcomeOrWhatsNew(container: Container, version: string, prev
if (configuration.get('showWelcomeOnInstall') === false) return;
if (window.state.focused) {
await container.storage.delete(StorageKeys.PendingWelcomeOnFocus);
await container.storage.delete('pendingWelcomeOnFocus');
await executeCommand(Commands.ShowWelcomePage);
} else {
// Save pending on window getting focus
await container.storage.store(StorageKeys.PendingWelcomeOnFocus, true);
await container.storage.store('pendingWelcomeOnFocus', true);
const disposable = window.onDidChangeWindowState(e => {
if (!e.focused) return;
disposable.dispose();
// If the window is now focused and we are pending the welcome, clear the pending state and show the welcome
if (container.storage.get(StorageKeys.PendingWelcomeOnFocus) === true) {
void container.storage.delete(StorageKeys.PendingWelcomeOnFocus);
if (container.storage.get('pendingWelcomeOnFocus') === true) {
void container.storage.delete('pendingWelcomeOnFocus');
if (configuration.get('showWelcomeOnInstall')) {
void executeCommand(Commands.ShowWelcomePage);
}
@ -289,19 +288,19 @@ async function showWelcomeOrWhatsNew(container: Container, version: string, prev
if (configuration.get('showWhatsNewAfterUpgrades')) {
if (window.state.focused) {
await container.storage.delete(StorageKeys.PendingWhatsNewOnFocus);
await container.storage.delete('pendingWhatsNewOnFocus');
await showWhatsNewMessage(version);
} else {
// Save pending on window getting focus
await container.storage.store(StorageKeys.PendingWhatsNewOnFocus, true);
await container.storage.store('pendingWhatsNewOnFocus', true);
const disposable = window.onDidChangeWindowState(e => {
if (!e.focused) return;
disposable.dispose();
// If the window is now focused and we are pending the what's new, clear the pending state and show the what's new
if (container.storage.get(StorageKeys.PendingWhatsNewOnFocus) === true) {
void container.storage.delete(StorageKeys.PendingWhatsNewOnFocus);
if (container.storage.get('pendingWhatsNewOnFocus') === true) {
void container.storage.delete('pendingWhatsNewOnFocus');
if (configuration.get('showWhatsNewAfterUpgrades')) {
void showWhatsNewMessage(version);
}

+ 2
- 5
src/git/gitProviderService.ts Просмотреть файл

@ -21,7 +21,6 @@ import { Logger } from '../logger';
import type { SubscriptionChangeEvent } from '../plus/subscription/subscriptionService';
import type { RepoComparisonKey } from '../repositories';
import { asRepoComparisonKey, Repositories } from '../repositories';
import { WorkspaceStorageKeys } from '../storage';
import type { FreeSubscriptionPlans, RequiredSubscriptionPlans, Subscription } from '../subscription';
import { getSubscriptionPlanPriority, isSubscriptionPaidPlan, SubscriptionPlanId } from '../subscription';
import { groupByFilterMap, groupByMap } from '../system/array';
@ -707,9 +706,7 @@ export class GitProviderService implements Disposable {
let disabled = !enabled;
// If we think we should be disabled during startup, check if we have a saved value from the last time this repo was loaded
if (!enabled && this._initializing) {
disabled = !(
this.container.storage.getWorkspace<boolean>(WorkspaceStorageKeys.AssumeRepositoriesOnStartup) ?? true
);
disabled = !(this.container.storage.getWorkspace('assumeRepositoriesOnStartup') ?? true);
}
if (this._context.enabled === enabled && this._context.disabled === disabled) return;
@ -729,7 +726,7 @@ export class GitProviderService implements Disposable {
await Promise.allSettled(promises);
if (!this._initializing) {
void this.container.storage.storeWorkspace(WorkspaceStorageKeys.AssumeRepositoriesOnStartup, enabled);
void this.container.storage.storeWorkspace('assumeRepositoriesOnStartup', enabled);
}
}

+ 1
- 3
src/git/models/branch.ts Просмотреть файл

@ -1,7 +1,5 @@
import { BranchSorting, configuration, DateStyle } from '../../configuration';
import { Container } from '../../container';
import type { Starred } from '../../storage';
import { WorkspaceStorageKeys } from '../../storage';
import { formatDate, fromNow } from '../../system/date';
import { debug } from '../../system/decorators/log';
import { memoize } from '../../system/decorators/memoize';
@ -181,7 +179,7 @@ export class GitBranch implements GitBranchReference {
}
get starred() {
const starred = Container.instance.storage.getWorkspace<Starred>(WorkspaceStorageKeys.StarredBranches);
const starred = Container.instance.storage.getWorkspace('starred:branches');
return starred !== undefined && starred[this.id] === true;
}

+ 6
- 9
src/git/models/reference.ts Просмотреть файл

@ -53,25 +53,22 @@ export namespace GitRevision {
export function shorten(
ref: string | undefined,
{
force,
strings = {},
}: {
options?: {
force?: boolean;
strings?: { uncommitted?: string; uncommittedStaged?: string; working?: string };
} = {},
},
) {
if (ref === deletedOrMissing) return '(deleted)';
if (!ref) return strings.working ?? '';
if (!ref) return options?.strings?.working ?? '';
if (isUncommitted(ref)) {
return isUncommittedStaged(ref)
? strings.uncommittedStaged ?? 'Index'
: strings.uncommitted ?? 'Working Tree';
? options?.strings?.uncommittedStaged ?? 'Index'
: options?.strings?.uncommitted ?? 'Working Tree';
}
if (GitRevision.isRange(ref)) return ref;
if (!force && !isShaLike(ref)) return ref;
if (!options?.force && !isShaLike(ref)) return ref;
// Don't allow shas to be shortened to less than 5 characters
const len = Math.max(5, configuration.get('advanced.abbreviatedShaLength'));

+ 1
- 2
src/git/models/remote.ts Просмотреть файл

@ -1,5 +1,4 @@
import { Container } from '../../container';
import { WorkspaceStorageKeys } from '../../storage';
import { sortCompare } from '../../system/string';
import type { RemoteProvider } from '../remotes/provider';
import { RichRemoteProvider } from '../remotes/provider';
@ -60,7 +59,7 @@ export class GitRemote
) {}
get default() {
const defaultRemote = Container.instance.storage.getWorkspace<string>(WorkspaceStorageKeys.DefaultRemote);
const defaultRemote = Container.instance.storage.getWorkspace('remote:default');
return this.id === defaultRemote;
}

+ 10
- 10
src/git/models/repository.ts Просмотреть файл

@ -9,8 +9,7 @@ import type { FeatureAccess, Features, PlusFeatures } from '../../features';
import { Logger } from '../../logger';
import { showCreatePullRequestPrompt, showGenericErrorMessage } from '../../messages';
import { asRepoComparisonKey } from '../../repositories';
import type { Starred } from '../../storage';
import { WorkspaceStorageKeys } from '../../storage';
import type { StoredStarred } from '../../storage';
import { filterMap, groupByMap } from '../../system/array';
import { executeActionCommand, executeCoreGitCommand } from '../../system/command';
import { formatDate, fromNow } from '../../system/date';
@ -856,13 +855,13 @@ export class Repository implements Disposable {
}
async setRemoteAsDefault(remote: GitRemote, value: boolean = true) {
await this.container.storage.storeWorkspace(WorkspaceStorageKeys.DefaultRemote, value ? remote.id : undefined);
await this.container.storage.storeWorkspace('remote:default', value ? remote.id : undefined);
this.fireChange(RepositoryChange.Remotes, RepositoryChange.RemoteProviders);
}
get starred() {
const starred = this.container.storage.getWorkspace<Starred>(WorkspaceStorageKeys.StarredRepositories);
const starred = this.container.storage.getWorkspace('starred:repositories');
return starred != null && starred[this.id] === true;
}
@ -932,18 +931,19 @@ export class Repository implements Disposable {
private async updateStarred(star: boolean, branch?: GitBranch) {
if (branch != null) {
await this.updateStarredCore(WorkspaceStorageKeys.StarredBranches, branch.id, star);
await this.updateStarredCore('branches', branch.id, star);
} else {
await this.updateStarredCore(WorkspaceStorageKeys.StarredRepositories, this.id, star);
await this.updateStarredCore('repositories', this.id, star);
}
this.fireChange(RepositoryChange.Starred);
}
private async updateStarredCore(key: WorkspaceStorageKeys, id: string, star: boolean) {
let starred = this.container.storage.getWorkspace<Starred>(key);
private async updateStarredCore(key: 'branches' | 'repositories', id: string, star: boolean) {
const storageKey = `starred:${key}` as const;
let starred = this.container.storage.getWorkspace(storageKey);
if (starred === undefined) {
starred = Object.create(null) as Starred;
starred = Object.create(null) as StoredStarred;
}
if (star) {
@ -952,7 +952,7 @@ export class Repository implements Disposable {
const { [id]: _, ...rest } = starred;
starred = rest;
}
await this.container.storage.storeWorkspace(key, starred);
await this.container.storage.storeWorkspace(storageKey, starred);
this.fireChange(RepositoryChange.Starred);
}

+ 3
- 4
src/git/remotes/provider.ts Просмотреть файл

@ -10,7 +10,6 @@ import { AuthenticationError, ProviderRequestClientError } from '../../errors';
import { Logger } from '../../logger';
import { showIntegrationDisconnectedTooManyFailedRequestsWarningMessage } from '../../messages';
import type { IntegrationAuthenticationSessionDescriptor } from '../../plus/integrationAuthentication';
import { WorkspaceStorageKeys } from '../../storage';
import { gate } from '../../system/decorators/gate';
import { debug, getLogScope, log } from '../../system/decorators/log';
import { encodeUrl } from '../../system/encoding';
@ -310,8 +309,8 @@ export abstract class RichRemoteProvider extends RemoteProvider {
return this.custom ? `${this.name}:${this.domain}` : this.name;
}
private get connectedKey(): `${WorkspaceStorageKeys.ConnectedPrefix}${string}` {
return `${WorkspaceStorageKeys.ConnectedPrefix}${this.key}`;
private get connectedKey(): `connected:${string}` {
return `connected:${this.key}`;
}
get maybeConnected(): boolean | undefined {
@ -664,7 +663,7 @@ export abstract class RichRemoteProvider extends RemoteProvider {
if (createIfNeeded) {
await container.storage.deleteWorkspace(this.connectedKey);
} else if (container.storage.getWorkspace<boolean>(this.connectedKey) === false) {
} else if (container.storage.getWorkspace(this.connectedKey) === false) {
return undefined;
}

+ 2
- 3
src/plus/subscription/authenticationProvider.ts Просмотреть файл

@ -7,7 +7,6 @@ import { authentication, Disposable, EventEmitter, extensions, window } from 'vs
import { uuid } from '@env/crypto';
import type { Container } from '../../container';
import { Logger } from '../../logger';
import { StorageKeys } from '../../storage';
import { debug, getLogScope } from '../../system/decorators/log';
import type { ServerConnection } from './serverConnection';
@ -173,7 +172,7 @@ export class SubscriptionAuthenticationProvider implements AuthenticationProvide
private _migrated: boolean | undefined;
async tryMigrateSession(): Promise<AuthenticationSession | undefined> {
if (this._migrated == null) {
this._migrated = this.container.storage.get<boolean>(StorageKeys.MigratedAuthentication, false);
this._migrated = this.container.storage.get('plus:migratedAuthentication', false);
}
if (this._migrated) return undefined;
@ -209,7 +208,7 @@ export class SubscriptionAuthenticationProvider implements AuthenticationProvide
Logger.error(ex, 'Unable to migrate authentication');
} finally {
this._migrated = true;
void this.container.storage.store<boolean>(StorageKeys.MigratedAuthentication, true);
void this.container.storage.store('plus:migratedAuthentication', true);
}
return session;
}

+ 2
- 8
src/plus/subscription/subscriptionService.ts Просмотреть файл

@ -28,7 +28,6 @@ import { setContext } from '../../context';
import { AccountValidationError } from '../../errors';
import type { RepositoriesChangeEvent } from '../../git/gitProviderService';
import { Logger } from '../../logger';
import { StorageKeys } from '../../storage';
import type { Subscription } from '../../subscription';
import {
computeSubscriptionState,
@ -795,7 +794,7 @@ export class SubscriptionService implements Disposable {
}
private getStoredSubscription(): Subscription | undefined {
const storedSubscription = this.container.storage.get<Stored<Subscription>>(StorageKeys.Subscription);
const storedSubscription = this.container.storage.get('premium:subscription');
const subscription = storedSubscription?.data;
if (subscription != null) {
@ -812,7 +811,7 @@ export class SubscriptionService implements Disposable {
}
private async storeSubscription(subscription: Subscription): Promise<void> {
return this.container.storage.store<Stored<Subscription>>(StorageKeys.Subscription, {
return this.container.storage.store('premium:subscription', {
v: 1,
data: subscription,
});
@ -970,8 +969,3 @@ interface GKUser {
status: 'activated' | 'pending';
firstGitLensCheckIn?: string;
}
interface Stored<T, SchemaVersion extends number = 1> {
v: SchemaVersion;
data: T;
}

+ 9
- 22
src/plus/webviews/graph/graphWebview.ts Просмотреть файл

@ -2,6 +2,7 @@ import type { CommitType } from '@gitkraken/gitkraken-components';
import { commitNodeType, mergeNodeType, stashNodeType } from '@gitkraken/gitkraken-components';
import type { Disposable, Event } from 'vscode';
import { EventEmitter, ViewColumn, window } from 'vscode';
import type { GraphColumnConfig } from '../../../configuration';
import { configuration } from '../../../configuration';
import { Commands } from '../../../constants';
import type { Container } from '../../../container';
@ -14,19 +15,11 @@ import type { GitRemote } from '../../../git/models/remote';
import type { Repository, RepositoryChangeEvent } from '../../../git/models/repository';
import type { GitTag } from '../../../git/models/tag';
import { RepositoryPicker } from '../../../quickpicks/repositoryPicker';
import { WorkspaceStorageKeys } from '../../../storage';
import type { IpcMessage } from '../../../webviews/protocol';
import { onIpc } from '../../../webviews/protocol';
import { WebviewWithConfigBase } from '../../../webviews/webviewWithConfigBase';
import { ensurePlusFeaturesEnabled } from '../../subscription/utils';
import type {
GraphColumnConfig,
GraphColumnConfigDictionary,
GraphCommit,
GraphConfig as GraphConfigWithColumns,
GraphRepository,
State,
} from './protocol';
import type { GraphCommit, GraphCompositeConfig, GraphRepository, State } from './protocol';
import {
ColumnChangeCommandType,
DidChangeCommitsNotificationType,
@ -87,17 +80,13 @@ export class GraphWebview extends WebviewWithConfigBase {
private dismissPreview() {
this.previewBanner = false;
void this.container.storage.storeWorkspace(WorkspaceStorageKeys.GraphPreview, false);
void this.container.storage.storeWorkspace('graph:preview', false);
}
private changeColumn(name: string, config: GraphColumnConfig) {
const columns =
this.container.storage.getWorkspace<GraphColumnConfigDictionary>(WorkspaceStorageKeys.GraphColumns) ?? {};
const columns = this.container.storage.getWorkspace('graph:columns') ?? {};
columns[name] = config;
void this.container.storage.storeWorkspace<GraphColumnConfigDictionary>(
WorkspaceStorageKeys.GraphColumns,
columns,
);
void this.container.storage.storeWorkspace('graph:columns', columns);
void this.notifyDidChangeConfig();
}
@ -274,13 +263,11 @@ export class GraphWebview extends WebviewWithConfigBase {
return repositories.find(r => r.path === repoPath);
}
private getConfig(): GraphConfigWithColumns {
private getConfig(): GraphCompositeConfig {
const settings = configuration.get('graph');
const config: GraphConfigWithColumns = {
const config: GraphCompositeConfig = {
...settings,
columns: this.container.storage.getWorkspace<GraphColumnConfigDictionary>(
WorkspaceStorageKeys.GraphColumns,
),
columns: this.container.storage.getWorkspace('graph:columns'),
};
return config;
}
@ -300,7 +287,7 @@ export class GraphWebview extends WebviewWithConfigBase {
}
if (this.previewBanner == null) {
this.previewBanner = (await this.container.storage.getWorkspace(WorkspaceStorageKeys.GraphPreview)) ?? true;
this.previewBanner = this.container.storage.getWorkspace('graph:preview') ?? true;
}
if (this.selectedRepository === undefined) {

+ 7
- 15
src/plus/webviews/graph/protocol.ts Просмотреть файл

@ -1,10 +1,11 @@
import type { GraphColumnConfig, GraphConfig } from '../../../config';
import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol';
export interface State {
repositories?: GraphRepository[];
selectedRepository?: string;
commits?: GraphCommit[];
config?: GraphConfig;
config?: GraphCompositeConfig;
remotes?: GraphRemote[];
tags?: GraphTag[];
branches?: GraphBranch[];
@ -27,19 +28,10 @@ export type GraphRemote = Record;
export type GraphTag = Record<string, any>;
export type GraphBranch = Record<string, any>;
export interface GraphColumnConfig {
width: number;
}
export interface GraphColumnConfigDictionary {
[key: string]: GraphColumnConfig;
}
export interface GraphConfig {
defaultLimit: number;
pageLimit: number;
columns?: GraphColumnConfigDictionary;
columnColors: string[];
export interface GraphCompositeConfig extends GraphConfig {
columns?: {
[key: string]: GraphColumnConfig;
};
}
export interface CommitListCallback {
@ -77,7 +69,7 @@ export interface DidChangeParams {
export const DidChangeNotificationType = new IpcNotificationType<DidChangeParams>('graph/didChange');
export interface DidChangeConfigParams {
config: GraphConfig;
config: GraphCompositeConfig;
}
export const DidChangeConfigNotificationType = new IpcNotificationType<DidChangeConfigParams>('graph/didChangeConfig');

+ 177
- 75
src/storage.ts Просмотреть файл

@ -1,15 +1,25 @@
import type { Disposable, Event, ExtensionContext, SecretStorageChangeEvent } from 'vscode';
import { EventEmitter } from 'vscode';
import type { ViewShowBranchComparison } from './config';
import type { GraphColumnConfig, ViewShowBranchComparison } from './config';
import type { SearchPattern } from './git/search';
export interface StorageChangeEvent {
/**
* The key of the stored value that has changed.
*/
readonly key: string;
readonly workspace: boolean;
}
import type { Subscription } from './subscription';
import type { CompletedActions } from './webviews/home/protocol';
export type StorageChangeEvent =
| {
/**
* The key of the stored value that has changed.
*/
readonly key: GlobalStoragePath;
readonly workspace: false;
}
| {
/**
* The key of the stored value that has changed.
*/
readonly key: WorkspaceStoragePath;
readonly workspace: true;
};
export class Storage implements Disposable {
private _onDidChange = new EventEmitter<StorageChangeEvent>();
@ -31,19 +41,25 @@ export class Storage implements Disposable {
this._disposable.dispose();
}
get<T>(key: StorageKeys | SyncedStorageKeys): T | undefined;
get<T>(key: StorageKeys | SyncedStorageKeys, defaultValue: T): T;
get<T>(key: StorageKeys | SyncedStorageKeys, defaultValue?: T): T | undefined {
return this.context.globalState.get(key, defaultValue);
get<T extends GlobalStoragePath>(key: T): GlobalStoragePathValue<T>;
get<T extends GlobalStoragePath>(
key: T,
defaultValue: NonNullable<GlobalStoragePathValue<T>>,
): NonNullable<GlobalStoragePathValue<T>>;
get<T extends GlobalStoragePath>(
key: T,
defaultValue?: GlobalStoragePathValue<T>,
): GlobalStoragePathValue<T> | undefined {
return this.context.globalState.get(`gitlens:${key}`, defaultValue);
}
async delete(key: StorageKeys | SyncedStorageKeys): Promise<void> {
await this.context.globalState.update(key, undefined);
async delete<T extends GlobalStoragePath>(key: T): Promise<void> {
await this.context.globalState.update(`gitlens:${key}`, undefined);
this._onDidChange.fire({ key: key, workspace: false });
}
async store<T>(key: StorageKeys | SyncedStorageKeys, value: T): Promise<void> {
await this.context.globalState.update(key, value);
async store<T extends GlobalStoragePath>(key: T, value: GlobalStoragePathValue<T>): Promise<void> {
await this.context.globalState.update(`gitlens:${key}`, value);
this._onDidChange.fire({ key: key, workspace: false });
}
@ -59,100 +75,149 @@ export class Storage implements Disposable {
return this.context.secrets.store(key, value);
}
getWorkspace<T>(key: WorkspaceStorageKeys | `${WorkspaceStorageKeys.ConnectedPrefix}${string}`): T | undefined;
getWorkspace<T>(key: WorkspaceStorageKeys | `${WorkspaceStorageKeys.ConnectedPrefix}${string}`, defaultValue: T): T;
getWorkspace<T>(
key: WorkspaceStorageKeys | `${WorkspaceStorageKeys.ConnectedPrefix}${string}`,
defaultValue?: T,
): T | undefined {
return this.context.workspaceState.get(key, defaultValue);
getWorkspace<T extends WorkspaceStoragePath>(key: T): WorkspaceStoragePathValue<T>;
getWorkspace<T extends WorkspaceStoragePath>(
key: T,
defaultValue: NonNullable<WorkspaceStoragePathValue<T>>,
): NonNullable<WorkspaceStoragePathValue<T>>;
getWorkspace<T extends WorkspaceStoragePath>(
key: T,
defaultValue?: WorkspaceStoragePathValue<T>,
): WorkspaceStoragePathValue<T> | undefined {
return this.context.workspaceState.get(`gitlens:${key}`, defaultValue);
}
async deleteWorkspace(
key: WorkspaceStorageKeys | `${WorkspaceStorageKeys.ConnectedPrefix}${string}`,
): Promise<void> {
await this.context.workspaceState.update(key, undefined);
async deleteWorkspace<T extends WorkspaceStoragePath>(key: T): Promise<void> {
await this.context.workspaceState.update(`gitlens:${key}`, undefined);
this._onDidChange.fire({ key: key, workspace: true });
}
async storeWorkspace<T>(
key: WorkspaceStorageKeys | `${WorkspaceStorageKeys.ConnectedPrefix}${string}`,
value: T,
): Promise<void> {
await this.context.workspaceState.update(key, value);
async storeWorkspace<T extends WorkspaceStoragePath>(key: T, value: WorkspaceStoragePathValue<T>): Promise<void> {
await this.context.workspaceState.update(`gitlens:${key}`, value);
this._onDidChange.fire({ key: key, workspace: true });
}
}
export type SecretKeys = string;
export const enum StorageKeys {
Avatars = 'gitlens:avatars',
PendingWelcomeOnFocus = 'gitlens:pendingWelcomeOnFocus',
PendingWhatsNewOnFocus = 'gitlens:pendingWhatsNewOnFocus',
HomeViewActionsCompleted = 'gitlens:home:actions:completed',
Version = 'gitlens:version',
MigratedAuthentication = 'gitlens:plus:migratedAuthentication',
Subscription = 'gitlens:premium:subscription', // Don't change this key name as its the stored subscription
Deprecated_Version = 'gitlensVersion',
export const enum DeprecatedStorageKeys {
/** @deprecated use `gitlens:version` */
Version = 'gitlensVersion',
/** @deprecated */
DisallowConnectionPrefix = 'gitlens:disallow:connection:',
}
export const enum SyncedStorageKeys {
Version = 'gitlens:synced:version',
HomeViewWelcomeVisible = 'gitlens:views:welcome:visible',
}
Deprecated_DisallowConnectionPrefix = 'gitlens:disallow:connection:',
export interface GlobalStorage {
avatars?: [string, StoredAvatar][];
home: {
actions: {
completed?: CompletedActions[];
};
};
pendingWelcomeOnFocus?: boolean;
pendingWhatsNewOnFocus?: boolean;
plus: {
migratedAuthentication?: boolean;
};
// Don't change this key name ('premium`) as its the stored subscription
premium: {
subscription?: Stored<Subscription>;
};
synced: {
version?: string;
};
version?: string;
views: {
welcome: {
visible?: boolean;
};
};
}
export const enum WorkspaceStorageKeys {
AssumeRepositoriesOnStartup = 'gitlens:assumeRepositoriesOnStartup',
GitPath = 'gitlens:gitPath',
export interface WorkspaceStorage {
assumeRepositoriesOnStartup?: boolean;
branch: {
comparisons?: StoredBranchComparisons;
};
connected: {
[key: string]: boolean;
};
gitComandPalette: {
usage?: Usage;
};
gitPath?: string;
graph: {
columns?: {
[key: string]: GraphColumnConfig;
};
preview?: boolean;
};
remote: {
default?: string;
};
starred: {
branches?: StoredStarred;
repositories?: StoredStarred;
};
views: {
repositories: {
autoRefresh?: boolean;
};
searchAndCompare: {
keepResults?: boolean;
pinned?: StoredPinnedItems;
};
commitDetails: {
autolinksExpanded?: boolean;
};
};
pinned: {
/** @deprecated use `gitlens:views:searchAndCompare:pinned` */
comparisons?: DeprecatedPinnedComparisons;
};
}
BranchComparisons = 'gitlens:branch:comparisons',
ConnectedPrefix = 'gitlens:connected:',
DefaultRemote = 'gitlens:remote:default',
GitCommandPaletteUsage = 'gitlens:gitComandPalette:usage',
StarredBranches = 'gitlens:starred:branches',
StarredRepositories = 'gitlens:starred:repositories',
ViewsRepositoriesAutoRefresh = 'gitlens:views:repositories:autoRefresh',
ViewsSearchAndCompareKeepResults = 'gitlens:views:searchAndCompare:keepResults',
ViewsSearchAndComparePinnedItems = 'gitlens:views:searchAndCompare:pinned',
ViewsCommitDetailsAutolinksExpanded = 'gitlens:views:commitDetails:autolinksExpanded',
GraphColumns = 'gitlens:graph:columns',
GraphPreview = 'gitlens:graph:preview',
export interface Stored<T, SchemaVersion extends number = 1> {
v: SchemaVersion;
data: T;
}
Deprecated_DisallowConnectionPrefix = 'gitlens:disallow:connection:',
Deprecated_PinnedComparisons = 'gitlens:pinned:comparisons',
export interface StoredAvatar {
uri: string;
timestamp: number;
}
export interface BranchComparison {
export interface StoredBranchComparison {
ref: string;
notation: '..' | '...' | undefined;
type: Exclude<ViewShowBranchComparison, false> | undefined;
}
export interface BranchComparisons {
[id: string]: string | BranchComparison;
export interface StoredBranchComparisons {
[id: string]: string | StoredBranchComparison;
}
export interface NamedRef {
export interface StoredNamedRef {
label?: string;
ref: string;
}
export interface PinnedComparison {
export interface StoredPinnedComparison {
type: 'comparison';
timestamp: number;
path: string;
ref1: NamedRef;
ref2: NamedRef;
ref1: StoredNamedRef;
ref2: StoredNamedRef;
notation?: '..' | '...';
}
export interface PinnedSearch {
export interface StoredPinnedSearch {
type: 'search';
timestamp: number;
path: string;
@ -168,16 +233,53 @@ export interface PinnedSearch {
search: SearchPattern;
}
export type PinnedItem = PinnedComparison | PinnedSearch;
export type StoredPinnedItem = StoredPinnedComparison | StoredPinnedSearch;
export interface PinnedItems {
[id: string]: PinnedItem;
export interface StoredPinnedItems {
[id: string]: StoredPinnedItem;
}
export interface Starred {
export interface StoredStarred {
[id: string]: boolean;
}
export interface Usage {
[id: string]: number;
}
interface DeprecatedPinnedComparison {
path: string;
ref1: StoredNamedRef;
ref2: StoredNamedRef;
notation?: '..' | '...';
}
interface DeprecatedPinnedComparisons {
[id: string]: DeprecatedPinnedComparison;
}
type SubPath<T, Key extends keyof T> = Key extends string
? T[Key] extends Record<string, any>
?
| `${Key}:${SubPath<T[Key], Exclude<keyof T[Key], keyof any[]>>}`
| `${Key}:${Exclude<keyof T[Key], keyof any[]> & string}`
: never
: never;
type Path<T> = SubPath<T, keyof T> | keyof T;
type PathValue<T, P extends Path<T>> = P extends `${infer Key}:${infer Rest}`
? Key extends keyof T
? Rest extends Path<T[Key]>
? PathValue<T[Key], Rest>
: never
: never
: P extends keyof T
? T[P]
: never;
type GlobalStoragePath = Path<GlobalStorage>;
type GlobalStoragePathValue<P extends GlobalStoragePath> = PathValue<GlobalStorage, P>;
type WorkspaceStoragePath = Path<WorkspaceStorage>;
type WorkspaceStoragePathValue<P extends WorkspaceStoragePath> = PathValue<WorkspaceStorage, P>;

+ 7
- 12
src/views/nodes/compareBranchNode.ts Просмотреть файл

@ -6,8 +6,7 @@ import type { GitBranch } from '../../git/models/branch';
import { GitRevision } from '../../git/models/reference';
import { CommandQuickPickItem } from '../../quickpicks/items/common';
import { ReferencePicker } from '../../quickpicks/referencePicker';
import type { BranchComparison, BranchComparisons } from '../../storage';
import { WorkspaceStorageKeys } from '../../storage';
import type { StoredBranchComparison, StoredBranchComparisons } from '../../storage';
import { gate } from '../../system/decorators/gate';
import { debug, log } from '../../system/decorators/log';
import { getSettledValue } from '../../system/promise';
@ -30,7 +29,7 @@ export class CompareBranchNode extends ViewNode
}
private _children: ViewNode[] | undefined;
private _compareWith: BranchComparison | undefined;
private _compareWith: StoredBranchComparison | undefined;
constructor(
uri: GitUri,
@ -370,9 +369,7 @@ export class CompareBranchNode extends ViewNode
}
private loadCompareWith() {
const comparisons = this.view.container.storage.getWorkspace<BranchComparisons>(
WorkspaceStorageKeys.BranchComparisons,
);
const comparisons = this.view.container.storage.getWorkspace('branch:comparisons');
const id = `${this.branch.id}${this.branch.current ? '+current' : ''}`;
const compareWith = comparisons?.[id];
@ -387,16 +384,14 @@ export class CompareBranchNode extends ViewNode
}
}
private async updateCompareWith(compareWith: BranchComparison | undefined) {
private async updateCompareWith(compareWith: StoredBranchComparison | undefined) {
this._compareWith = compareWith;
let comparisons = this.view.container.storage.getWorkspace<BranchComparisons>(
WorkspaceStorageKeys.BranchComparisons,
);
let comparisons = this.view.container.storage.getWorkspace('branch:comparisons');
if (comparisons == null) {
if (compareWith == null) return;
comparisons = Object.create(null) as BranchComparisons;
comparisons = Object.create(null) as StoredBranchComparisons;
}
const id = `${this.branch.id}${this.branch.current ? '+current' : ''}`;
@ -409,6 +404,6 @@ export class CompareBranchNode extends ViewNode
const { [id]: _, ...rest } = comparisons;
comparisons = rest;
}
await this.view.container.storage.storeWorkspace(WorkspaceStorageKeys.BranchComparisons, comparisons);
await this.view.container.storage.storeWorkspace('branch:comparisons', comparisons);
}
}

+ 2
- 2
src/views/nodes/comparePickerNode.ts Просмотреть файл

@ -1,14 +1,14 @@
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GlyphChars } from '../../constants';
import { unknownGitUri } from '../../git/gitUri';
import type { NamedRef } from '../../storage';
import type { StoredNamedRef } from '../../storage';
import type { SearchAndCompareView, SearchAndCompareViewNode } from '../searchAndCompareView';
import { ContextValues, ViewNode } from './viewNode';
interface RepoRef {
label: string;
repoPath: string;
ref: string | NamedRef;
ref: string | StoredNamedRef;
}
export class ComparePickerNode extends ViewNode<SearchAndCompareView> {

+ 4
- 4
src/views/nodes/compareResultsNode.ts Просмотреть файл

@ -1,7 +1,7 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, window } from 'vscode';
import { GitUri } from '../../git/gitUri';
import { GitRevision } from '../../git/models/reference';
import type { NamedRef } from '../../storage';
import type { StoredNamedRef } from '../../storage';
import { gate } from '../../system/decorators/gate';
import { debug, log } from '../../system/decorators/log';
import { getSettledValue } from '../../system/promise';
@ -33,8 +33,8 @@ export class CompareResultsNode extends ViewNode {
view: SearchAndCompareView,
parent: ViewNode,
public readonly repoPath: string,
private _ref: NamedRef,
private _compareWith: NamedRef,
private _ref: StoredNamedRef,
private _compareWith: StoredNamedRef,
private _pinned: number = 0,
) {
super(GitUri.fromRepoPath(repoPath), view, parent);
@ -176,7 +176,7 @@ export class CompareResultsNode extends ViewNode {
@gate()
@debug()
async getDiffRefs(): Promise<[string, string]> {
return Promise.resolve([this._compareWith.ref, this._ref.ref]);
return Promise.resolve<[string, string]>([this._compareWith.ref, this._ref.ref]);
}
@log()

+ 3
- 13
src/views/repositoriesView.ts Просмотреть файл

@ -18,7 +18,6 @@ import type {
import { GitReference } from '../git/models/reference';
import type { GitRemote } from '../git/models/remote';
import type { GitWorktree } from '../git/models/worktree';
import { WorkspaceStorageKeys } from '../storage';
import { executeCommand } from '../system/command';
import { gate } from '../system/decorators/gate';
import { BranchesNode } from './nodes/branchesNode';
@ -279,10 +278,7 @@ export class RepositoriesView extends ViewBase
}
get autoRefresh() {
return (
this.config.autoRefresh &&
this.container.storage.getWorkspace<boolean>(WorkspaceStorageKeys.ViewsRepositoriesAutoRefresh, true)
);
return this.config.autoRefresh && this.container.storage.getWorkspace('views:repositories:autoRefresh', true);
}
findBranch(branch: GitBranchReference, token?: CancellationToken) {
@ -855,15 +851,9 @@ export class RepositoriesView extends ViewBase
private async setAutoRefresh(enabled: boolean, workspaceEnabled?: boolean) {
if (enabled) {
if (workspaceEnabled === undefined) {
workspaceEnabled = this.container.storage.getWorkspace<boolean>(
WorkspaceStorageKeys.ViewsRepositoriesAutoRefresh,
true,
);
workspaceEnabled = this.container.storage.getWorkspace('views:repositories:autoRefresh', true);
} else {
await this.container.storage.storeWorkspace(
WorkspaceStorageKeys.ViewsRepositoriesAutoRefresh,
workspaceEnabled,
);
await this.container.storage.storeWorkspace('views:repositories:autoRefresh', workspaceEnabled);
}
}

+ 20
- 47
src/views/searchAndCompareView.ts Просмотреть файл

@ -11,8 +11,7 @@ import { GitRevision } from '../git/models/reference';
import type { SearchPattern } from '../git/search';
import { ReferencePicker, ReferencesQuickPickIncludes } from '../quickpicks/referencePicker';
import { RepositoryPicker } from '../quickpicks/repositoryPicker';
import type { NamedRef, PinnedItem, PinnedItems } from '../storage';
import { WorkspaceStorageKeys } from '../storage';
import type { StoredNamedRef, StoredPinnedItem, StoredPinnedItems } from '../storage';
import { filterMap } from '../system/array';
import { executeCommand } from '../system/command';
import { gate } from '../system/decorators/gate';
@ -25,17 +24,6 @@ import { SearchResultsNode } from './nodes/searchResultsNode';
import { ContextValues, RepositoryFolderNode, ViewNode } from './nodes/viewNode';
import { ViewBase } from './viewBase';
interface DeprecatedPinnedComparison {
path: string;
ref1: NamedRef;
ref2: NamedRef;
notation?: '..' | '...';
}
interface DeprecatedPinnedComparisons {
[id: string]: DeprecatedPinnedComparison;
}
export class SearchAndCompareViewNode extends ViewNode<SearchAndCompareView> {
protected override splatted = true;
private comparePicker: ComparePickerNode | undefined;
@ -134,7 +122,7 @@ export class SearchAndCompareViewNode extends ViewNode {
await Promise.all(promises);
}
async compareWithSelected(repoPath?: string, ref?: string | NamedRef) {
async compareWithSelected(repoPath?: string, ref?: string | StoredNamedRef) {
const selectedRef = this.comparePicker?.selectedRef;
if (selectedRef == null) return;
@ -176,7 +164,7 @@ export class SearchAndCompareViewNode extends ViewNode {
await this.view.compare(repoPath, selectedRef.ref, ref);
}
async selectForCompare(repoPath?: string, ref?: string | NamedRef, options?: { prompt?: boolean }) {
async selectForCompare(repoPath?: string, ref?: string | StoredNamedRef, options?: { prompt?: boolean }) {
if (repoPath == null) {
repoPath = (await RepositoryPicker.getRepositoryOrShow('Compare'))?.path;
}
@ -232,7 +220,7 @@ export class SearchAndCompareViewNode extends ViewNode {
}
}
private getRefName(ref: string | NamedRef) {
private getRefName(ref: string | StoredNamedRef): string {
return typeof ref === 'string'
? GitRevision.shorten(ref, { strings: { working: 'Working Tree' } })!
: ref.label ?? GitRevision.shorten(ref.ref)!;
@ -356,10 +344,7 @@ export class SearchAndCompareView extends ViewBase
}
get keepResults(): boolean {
return this.container.storage.getWorkspace<boolean>(
WorkspaceStorageKeys.ViewsSearchAndCompareKeepResults,
true,
);
return this.container.storage.getWorkspace('views:searchAndCompare:keepResults', true);
}
clear() {
@ -380,7 +365,7 @@ export class SearchAndCompareView extends ViewBase
this.root.dismiss(node);
}
compare(repoPath: string, ref1: string | NamedRef, ref2: string | NamedRef) {
compare(repoPath: string, ref1: string | StoredNamedRef, ref2: string | StoredNamedRef) {
return this.addResults(
new CompareResultsNode(
this,
@ -392,11 +377,11 @@ export class SearchAndCompareView extends ViewBase
);
}
compareWithSelected(repoPath?: string, ref?: string | NamedRef) {
compareWithSelected(repoPath?: string, ref?: string | StoredNamedRef) {
void this.ensureRoot().compareWithSelected(repoPath, ref);
}
selectForCompare(repoPath?: string, ref?: string | NamedRef, options?: { prompt?: boolean }) {
selectForCompare(repoPath?: string, ref?: string | StoredNamedRef, options?: { prompt?: boolean }) {
void this.ensureRoot().selectForCompare(repoPath, ref, options);
}
@ -437,17 +422,13 @@ export class SearchAndCompareView extends ViewBase
}
getPinned() {
let savedPins = this.container.storage.getWorkspace<PinnedItems>(
WorkspaceStorageKeys.ViewsSearchAndComparePinnedItems,
);
let savedPins = this.container.storage.getWorkspace('views:searchAndCompare:pinned');
if (savedPins == null) {
// Migrate any deprecated pinned items
const deprecatedPins = this.container.storage.getWorkspace<DeprecatedPinnedComparisons>(
WorkspaceStorageKeys.Deprecated_PinnedComparisons,
);
const deprecatedPins = this.container.storage.getWorkspace('pinned:comparisons');
if (deprecatedPins == null) return [];
savedPins = Object.create(null) as PinnedItems;
savedPins = Object.create(null) as StoredPinnedItems;
for (const p of Object.values(deprecatedPins)) {
savedPins[CompareResultsNode.getPinnableId(p.path, p.ref1.ref, p.ref2.ref)] = {
type: 'comparison',
@ -458,14 +439,11 @@ export class SearchAndCompareView extends ViewBase
};
}
void this.container.storage.storeWorkspace(
WorkspaceStorageKeys.ViewsSearchAndComparePinnedItems,
savedPins,
);
void this.container.storage.deleteWorkspace(WorkspaceStorageKeys.Deprecated_PinnedComparisons);
void this.container.storage.storeWorkspace('views:searchAndCompare:pinned', savedPins);
void this.container.storage.deleteWorkspace('pinned:comparisons');
}
const migratedPins = Object.create(null) as PinnedItems;
const migratedPins = Object.create(null) as StoredPinnedItems;
let migrated = false;
const root = this.ensureRoot();
@ -505,20 +483,15 @@ export class SearchAndCompareView extends ViewBase
});
if (migrated) {
void this.container.storage.storeWorkspace(
WorkspaceStorageKeys.ViewsSearchAndComparePinnedItems,
migratedPins,
);
void this.container.storage.storeWorkspace('views:searchAndCompare:pinned', migratedPins);
}
return pins;
}
async updatePinned(id: string, pin?: PinnedItem) {
let pinned = this.container.storage.getWorkspace<PinnedItems>(
WorkspaceStorageKeys.ViewsSearchAndComparePinnedItems,
);
async updatePinned(id: string, pin?: StoredPinnedItem) {
let pinned = this.container.storage.getWorkspace('views:searchAndCompare:pinned');
if (pinned == null) {
pinned = Object.create(null) as PinnedItems;
pinned = Object.create(null) as StoredPinnedItems;
}
if (pin != null) {
@ -528,7 +501,7 @@ export class SearchAndCompareView extends ViewBase
pinned = rest;
}
await this.container.storage.storeWorkspace(WorkspaceStorageKeys.ViewsSearchAndComparePinnedItems, pinned);
await this.container.storage.storeWorkspace('views:searchAndCompare:pinned', pinned);
this.triggerNodeChange(this.ensureRoot());
}
@ -573,7 +546,7 @@ export class SearchAndCompareView extends ViewBase
}
private setKeepResults(enabled: boolean) {
void this.container.storage.storeWorkspace(WorkspaceStorageKeys.ViewsSearchAndCompareKeepResults, enabled);
void this.container.storage.storeWorkspace('views:searchAndCompare:keepResults', enabled);
void setContext(ContextKeys.ViewsSearchAndCompareKeepResults, enabled);
}

+ 6
- 4
src/webviews/apps/plus/graph/GraphWrapper.tsx Просмотреть файл

@ -10,12 +10,12 @@ import GraphContainer, {
} from '@gitkraken/gitkraken-components';
import type { ReactElement } from 'react';
import React, { createElement, useEffect, useRef, useState } from 'react';
import type { GraphColumnConfig } from '../../../../config';
import type {
CommitListCallback,
GraphBranch,
GraphColumnConfig,
GraphCommit,
GraphConfig,
GraphCompositeConfig,
GraphRemote,
GraphRepository,
GraphTag,
@ -140,7 +140,7 @@ const defaultGraphColumnsSettings: GKGraphColumnsSettings = {
refZone: { width: 150 },
};
const getGraphColSettingsModel = (config?: GraphConfig): GKGraphColumnsSettings => {
const getGraphColSettingsModel = (config?: GraphCompositeConfig): GKGraphColumnsSettings => {
const columnsSettings: GKGraphColumnsSettings = { ...defaultGraphColumnsSettings };
if (config?.columns !== undefined) {
for (const column of Object.keys(config.columns)) {
@ -382,7 +382,9 @@ export function GraphWrapper({
)}
</div>
</div>
<div className="actionbar__end"><span className="badge">Preview</span></div>
<div className="actionbar__end">
<span className="badge">Preview</span>
</div>
</footer>
</>
);

+ 2
- 8
src/webviews/apps/plus/graph/graph.tsx Просмотреть файл

@ -2,14 +2,8 @@
import type { CssVariables } from '@gitkraken/gitkraken-components';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import type { GraphConfig } from '../../../../config';
import type {
CommitListCallback,
GraphColumnConfig,
GraphCommit,
GraphRepository,
State,
} from '../../../../plus/webviews/graph/protocol';
import type { GraphColumnConfig, GraphConfig } from '../../../../config';
import type { CommitListCallback, GraphCommit, GraphRepository, State } from '../../../../plus/webviews/graph/protocol';
import {
ColumnChangeCommandType,
DidChangeCommitsNotificationType,

+ 2
- 5
src/webviews/commitDetails/commitDetailsWebviewView.ts Просмотреть файл

@ -10,7 +10,6 @@ import { GitFile } from '../../git/models/file';
import type { IssueOrPullRequest } from '../../git/models/issue';
import type { PullRequest } from '../../git/models/pullRequest';
import type { GraphSelectionChangeEvent } from '../../plus/webviews/graph/graphWebview';
import { WorkspaceStorageKeys } from '../../storage';
import { executeCommand } from '../../system/command';
import { debug } from '../../system/decorators/log';
import type { Deferrable } from '../../system/function';
@ -70,9 +69,7 @@ export class CommitDetailsWebviewView extends WebviewViewBase
pinned: false,
commit: undefined,
preferences: {
autolinksExpanded: this.container.storage.getWorkspace(
WorkspaceStorageKeys.ViewsCommitDetailsAutolinksExpanded,
),
autolinksExpanded: this.container.storage.getWorkspace('views:commitDetails:autolinksExpanded'),
},
richStateLoaded: false,
formattedMessage: undefined,
@ -396,7 +393,7 @@ export class CommitDetailsWebviewView extends WebviewViewBase
if (this._context.preferences?.autolinksExpanded === preferences.autolinksExpanded) return;
void this.container.storage.storeWorkspace(
WorkspaceStorageKeys.ViewsCommitDetailsAutolinksExpanded,
'views:commitDetails:autolinksExpanded',
preferences.autolinksExpanded,
);

+ 6
- 12
src/webviews/home/homeWebviewView.ts Просмотреть файл

@ -4,7 +4,6 @@ import { CoreCommands } from '../../constants';
import type { Container } from '../../container';
import type { SubscriptionChangeEvent } from '../../plus/subscription/subscriptionService';
import { ensurePlusFeaturesEnabled } from '../../plus/subscription/utils';
import { StorageKeys, SyncedStorageKeys } from '../../storage';
import type { Subscription } from '../../subscription';
import { executeCoreCommand } from '../../system/command';
import { WebviewViewBase } from '../webviewViewBase';
@ -44,22 +43,19 @@ export class HomeWebviewView extends WebviewViewBase {
commands.registerCommand(`${this.id}.refresh`, () => this.refresh(), this),
commands.registerCommand('gitlens.home.toggleWelcome', async () => {
const welcomeVisible = !this.welcomeVisible;
await this.container.storage.store(SyncedStorageKeys.HomeViewWelcomeVisible, welcomeVisible);
await this.container.storage.store('views:welcome:visible', welcomeVisible);
if (welcomeVisible) {
await this.container.storage.store(StorageKeys.HomeViewActionsCompleted, []);
await this.container.storage.store('home:actions:completed', []);
}
void this.notifyDidChangeData();
}),
commands.registerCommand('gitlens.home.showSCM', async () => {
const completedActions = this.container.storage.get<CompletedActions[]>(
StorageKeys.HomeViewActionsCompleted,
[],
);
const completedActions = this.container.storage.get('home:actions:completed', []);
if (!completedActions.includes(CompletedActions.OpenedSCM)) {
completedActions.push(CompletedActions.OpenedSCM);
await this.container.storage.store(StorageKeys.HomeViewActionsCompleted, completedActions);
await this.container.storage.store('home:actions:completed', completedActions);
void this.notifyDidChangeData();
}
@ -74,14 +70,12 @@ export class HomeWebviewView extends WebviewViewBase {
}
private get welcomeVisible(): boolean {
return this.container.storage.get(SyncedStorageKeys.HomeViewWelcomeVisible, true);
return this.container.storage.get('views:welcome:visible', true);
}
private async getState(subscription?: Subscription): Promise<State> {
// Make sure to make a copy of the array otherwise it will be live to the storage value
const completedActions = [
...this.container.storage.get<CompletedActions[]>(StorageKeys.HomeViewActionsCompleted, []),
];
const completedActions = [...this.container.storage.get('home:actions:completed', [])];
if (!this.welcomeVisible) {
completedActions.push(CompletedActions.DismissedWelcome);
}

Загрузка…
Отмена
Сохранить