From 54b2b16426f560f51858ceb3b8c78e247cf6cd38 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 1 Oct 2023 00:35:52 -0400 Subject: [PATCH 0001/1012] Fixes & improves rebase handling --- package.json | 30 ++- src/commands/quickCommand.steps.ts | 3 +- src/constants.ts | 2 + src/env/node/git/git.ts | 42 ++-- src/env/node/git/localGitProvider.ts | 198 ++++++++++----- src/env/node/git/shell.ts | 6 +- src/git/gitProvider.ts | 19 +- src/git/gitProviderService.ts | 17 +- src/git/models/rebase.ts | 6 +- src/plus/github/github.ts | 76 ++++++ src/plus/github/githubGitProvider.ts | 38 ++- src/system/promise.ts | 40 +-- src/views/branchesView.ts | 1 + src/views/commitsView.ts | 3 +- src/views/nodes/branchNode.ts | 3 +- src/views/nodes/branchesNode.ts | 3 +- src/views/nodes/commitNode.ts | 15 +- src/views/nodes/fileRevisionAsCommitNode.ts | 92 ++++--- .../nodes/mergeConflictCurrentChangesNode.ts | 70 ++++-- src/views/nodes/mergeConflictFilesNode.ts | 55 +++++ .../nodes/mergeConflictIncomingChangesNode.ts | 99 +++++--- src/views/nodes/mergeStatusNode.ts | 65 ++--- src/views/nodes/rebaseCommitNode.ts | 26 ++ src/views/nodes/rebaseStatusNode.ts | 233 +++++------------- src/views/nodes/statusFilesNode.ts | 8 +- src/views/nodes/viewNode.ts | 8 +- src/views/remotesView.ts | 1 + src/views/repositoriesView.ts | 2 + src/views/viewDecorationProvider.ts | 46 +++- 29 files changed, 729 insertions(+), 478 deletions(-) create mode 100644 src/views/nodes/mergeConflictFilesNode.ts create mode 100644 src/views/nodes/rebaseCommitNode.ts diff --git a/package.json b/package.json index f7c04066899a4..753946fb995bf 100644 --- a/package.json +++ b/package.json @@ -4304,6 +4304,24 @@ "highContrast": "#c74e39" } }, + { + "id": "gitlens.decorations.statusMergingOrRebasingConflictForegroundColor", + "description": "Specifies the decoration foreground color of the status during a rebase operation with conflicts", + "defaults": { + "light": "#ad0707", + "dark": "#c74e39", + "highContrast": "#c74e39" + } + }, + { + "id": "gitlens.decorations.statusMergingOrRebasingForegroundColor", + "description": "Specifies the decoration foreground color of the status during a rebase operation", + "defaults": { + "dark": "#D8AF1B", + "light": "#D8AF1B", + "highContrast": "#D8AF1B" + } + }, { "id": "gitlens.decorations.workspaceRepoMissingForegroundColor", "description": "Specifies the decoration foreground color of workspace repos which are missing a local path", @@ -11673,7 +11691,7 @@ }, { "command": "gitlens.views.cherryPick", - "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b(?!.*?\\b\\+current\\b)/", + "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b(?!.*?\\b\\+(current|rebase)\\b)/", "group": "1_gitlens_actions@1" }, { @@ -11698,27 +11716,27 @@ }, { "command": "gitlens.views.resetToCommit", - "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b/", + "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b(?!.*?\\b\\+rebase\\b)/", "group": "1_gitlens_actions@4" }, { "command": "gitlens.views.resetToTip", - "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b/", + "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+rebase\\b)/", "group": "1_gitlens_actions@4" }, { "command": "gitlens.views.resetCommit", - "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b/", + "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b(?!.*?\\b\\+rebase\\b)/", "group": "1_gitlens_actions@5" }, { "command": "gitlens.views.rebaseOntoCommit", - "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b/", + "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b(?!.*?\\b\\+rebase\\b)/", "group": "1_gitlens_actions@6" }, { "command": "gitlens.views.switchToCommit", - "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b/", + "when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:commit\\b(?!.*?\\b\\+rebase\\b)/", "group": "1_gitlens_actions@7" }, { diff --git a/src/commands/quickCommand.steps.ts b/src/commands/quickCommand.steps.ts index eda59355b6aa8..4d7e1f4027c70 100644 --- a/src/commands/quickCommand.steps.ts +++ b/src/commands/quickCommand.steps.ts @@ -1891,8 +1891,7 @@ async function getShowCommitOrStashStepItems< const branch = await Container.instance.git.getBranch(state.repo.path); const [branches, published] = await Promise.all([ branch != null - ? Container.instance.git.getCommitBranches(state.repo.path, state.reference.ref, { - branch: branch.name, + ? Container.instance.git.getCommitBranches(state.repo.path, state.reference.ref, branch.name, { commitDate: isCommit(state.reference) ? state.reference.committer.date : undefined, }) : undefined, diff --git a/src/constants.ts b/src/constants.ts index 6bb7a1ea12677..cd64b2c6e7429 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -72,6 +72,8 @@ export type Colors = | `${typeof extensionPrefix}.decorations.deletedForegroundColor` | `${typeof extensionPrefix}.decorations.ignoredForegroundColor` | `${typeof extensionPrefix}.decorations.modifiedForegroundColor` + | `${typeof extensionPrefix}.decorations.statusMergingOrRebasingConflictForegroundColor` + | `${typeof extensionPrefix}.decorations.statusMergingOrRebasingForegroundColor` | `${typeof extensionPrefix}.decorations.renamedForegroundColor` | `${typeof extensionPrefix}.decorations.untrackedForegroundColor` | `${typeof extensionPrefix}.decorations.workspaceCurrentForegroundColor` diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index 55216e294e90e..f279c26bd9e40 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -20,6 +20,7 @@ import { StashPushErrorReason, WorkspaceUntrustedError, } from '../../../git/errors'; +import type { GitDir } from '../../../git/gitProvider'; import type { GitDiffFilter } from '../../../git/models/diff'; import { isUncommitted, isUncommittedStaged, shortenRevision } from '../../../git/models/reference'; import type { GitUser } from '../../../git/models/user'; @@ -503,22 +504,29 @@ export class Git { ); } - branch__containsOrPointsAt( + branchOrTag__containsOrPointsAt( repoPath: string, ref: string, - { - mode = 'contains', - name = undefined, - remotes = false, - }: { mode?: 'contains' | 'pointsAt'; name?: string; remotes?: boolean } = {}, + options?: { + type?: 'branch' | 'tag'; + all?: boolean; + mode?: 'contains' | 'pointsAt'; + name?: string; + remotes?: boolean; + }, ) { - const params = ['branch']; - if (remotes) { + const params: string[] = [options?.type ?? 'branch']; + if (options?.all) { + params.push('-a'); + } else if (options?.remotes) { params.push('-r'); } - params.push(mode === 'pointsAt' ? `--points-at=${ref}` : `--contains=${ref}`, '--format=%(refname:short)'); - if (name != null) { - params.push(name); + params.push( + options?.mode === 'pointsAt' ? `--points-at=${ref}` : `--contains=${ref}`, + '--format=%(refname:short)', + ); + if (options?.name != null) { + params.push(options.name); } return this.git( @@ -2177,22 +2185,22 @@ export class Git { } async readDotGitFile( - repoPath: string, - paths: string[], + gitDir: GitDir, + pathParts: string[], options?: { numeric?: false; throw?: boolean; trim?: boolean }, ): Promise; async readDotGitFile( - repoPath: string, - path: string[], + gitDir: GitDir, + pathParts: string[], options?: { numeric: true; throw?: boolean; trim?: boolean }, ): Promise; async readDotGitFile( - repoPath: string, + gitDir: GitDir, pathParts: string[], options?: { numeric?: boolean; throw?: boolean; trim?: boolean }, ): Promise { try { - const bytes = await workspace.fs.readFile(Uri.file(joinPaths(repoPath, '.git', ...pathParts))); + const bytes = await workspace.fs.readFile(Uri.joinPath(gitDir.uri, ...pathParts)); let contents = textDecoder.decode(bytes); contents = options?.trim ?? true ? contents.trim() : contents; diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 4b6224b2d7f84..87903b377d007 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -80,7 +80,7 @@ import type { import type { GitLog } from '../../../git/models/log'; import type { GitMergeStatus } from '../../../git/models/merge'; import type { GitRebaseStatus } from '../../../git/models/rebase'; -import type { GitBranchReference } from '../../../git/models/reference'; +import type { GitBranchReference, GitTagReference } from '../../../git/models/reference'; import { createReference, getBranchTrackingWithoutRemote, @@ -240,8 +240,8 @@ export class LocalGitProvider implements GitProvider, Disposable { private readonly _branchesCache = new Map>>(); private readonly _contributorsCache = new Map>(); - private readonly _mergeStatusCache = new Map(); - private readonly _rebaseStatusCache = new Map(); + private readonly _mergeStatusCache = new Map>(); + private readonly _rebaseStatusCache = new Map>(); private readonly _remotesCache = new Map>(); private readonly _repoInfoCache = new Map(); private readonly _stashesCache = new Map(); @@ -1727,6 +1727,7 @@ export class LocalGitProvider implements GitProvider, Disposable { }; } + @gate() @log() async getBranch(repoPath: string): Promise { let { @@ -1741,16 +1742,17 @@ export class LocalGitProvider implements GitProvider, Disposable { const [name, upstream] = data[0].split('\n'); if (isDetachedHead(name)) { - const [rebaseStatus, committerDate] = await Promise.all([ + const [rebaseStatusResult, committerDateResult] = await Promise.allSettled([ this.getRebaseStatus(repoPath), - this.git.log__recent_committerdate(repoPath, commitOrdering), ]); + const committerDate = getSettledValue(committerDateResult); + branch = new GitBranch( this.container, repoPath, - rebaseStatus?.incoming.name ?? name, + getSettledValue(rebaseStatusResult)?.incoming.name ?? name, false, true, committerDate != null ? new Date(Number(committerDate) * 1000) : undefined, @@ -1759,7 +1761,7 @@ export class LocalGitProvider implements GitProvider, Disposable { undefined, undefined, undefined, - rebaseStatus != null, + rebaseStatusResult != null, ); } @@ -1867,19 +1869,21 @@ export class LocalGitProvider implements GitProvider, Disposable { async getCommitBranches( repoPath: string, ref: string, - options?: { branch?: string; commitDate?: Date; mode?: 'contains' | 'pointsAt'; remotes?: boolean }, + branch?: string | undefined, + options?: + | { all?: boolean; commitDate?: Date; mode?: 'contains' | 'pointsAt' } + | { commitDate?: Date; mode?: 'contains' | 'pointsAt'; remotes?: boolean }, ): Promise { - if (options?.branch) { - const data = await this.git.branch__containsOrPointsAt(repoPath, ref, { + if (branch != null) { + const data = await this.git.branchOrTag__containsOrPointsAt(repoPath, ref, { + type: 'branch', mode: 'contains', - name: options.branch, + name: branch, }); - if (!data) return []; - - return [data?.trim()]; + return data ? [data?.trim()] : []; } - const data = await this.git.branch__containsOrPointsAt(repoPath, ref, options); + const data = await this.git.branchOrTag__containsOrPointsAt(repoPath, ref, { type: 'branch', ...options }); if (!data) return []; return filterMap(data.split('\n'), b => b.trim() || undefined); @@ -2451,6 +2455,18 @@ export class LocalGitProvider implements GitProvider, Disposable { return getCommitsForGraphCore.call(this, defaultLimit, selectSha); } + @log() + async getCommitTags( + repoPath: string, + ref: string, + options?: { commitDate?: Date; mode?: 'contains' | 'pointsAt' }, + ): Promise { + const data = await this.git.branchOrTag__containsOrPointsAt(repoPath, ref, { type: 'tag', ...options }); + if (!data) return []; + + return filterMap(data.split('\n'), b => b.trim() || undefined); + } + getConfig(repoPath: string, key: string): Promise { return this.git.config__get(key, repoPath); } @@ -2898,6 +2914,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return files[0]; } + @gate() @debug() async getGitDir(repoPath: string): Promise { const repo = this._repoInfoCache.get(repoPath); @@ -3545,20 +3562,25 @@ export class LocalGitProvider implements GitProvider, Disposable { } } - @gate() @log() async getMergeStatus(repoPath: string): Promise { let status = this.useCaching ? this._mergeStatusCache.get(repoPath) : undefined; - if (status === undefined) { - const merge = await this.git.rev_parse__verify(repoPath, 'MERGE_HEAD'); - if (merge != null) { - const [branch, mergeBase, possibleSourceBranches] = await Promise.all([ + if (status == null) { + async function getCore(this: LocalGitProvider): Promise { + const merge = await this.git.rev_parse__verify(repoPath, 'MERGE_HEAD'); + if (merge == null) return undefined; + + const [branchResult, mergeBaseResult, possibleSourceBranchesResult] = await Promise.allSettled([ this.getBranch(repoPath), this.getMergeBase(repoPath, 'MERGE_HEAD', 'HEAD'), - this.getCommitBranches(repoPath, 'MERGE_HEAD', { mode: 'pointsAt' }), + this.getCommitBranches(repoPath, 'MERGE_HEAD', undefined, { all: true, mode: 'pointsAt' }), ]); - status = { + const branch = getSettledValue(branchResult); + const mergeBase = getSettledValue(mergeBaseResult); + const possibleSourceBranches = getSettledValue(possibleSourceBranchesResult); + + return { type: 'merge', repoPath: repoPath, mergeBase: mergeBase, @@ -3572,66 +3594,110 @@ export class LocalGitProvider implements GitProvider, Disposable { remote: false, }) : undefined, - }; + } satisfies GitMergeStatus; } + status = getCore.call(this); if (this.useCaching) { - this._mergeStatusCache.set(repoPath, status ?? null); + this._mergeStatusCache.set(repoPath, status); } } - return status ?? undefined; + return status; } - @gate() @log() async getRebaseStatus(repoPath: string): Promise { let status = this.useCaching ? this._rebaseStatusCache.get(repoPath) : undefined; - if (status === undefined) { - const rebase = await this.git.rev_parse__verify(repoPath, 'REBASE_HEAD'); - if (rebase != null) { - let [mergeBase, branch, onto, stepsNumber, stepsMessage, stepsTotal] = await Promise.all([ - this.getMergeBase(repoPath, 'REBASE_HEAD', 'HEAD'), - this.git.readDotGitFile(repoPath, ['rebase-merge', 'head-name']), - this.git.readDotGitFile(repoPath, ['rebase-merge', 'onto']), - this.git.readDotGitFile(repoPath, ['rebase-merge', 'msgnum'], { numeric: true }), + if (status == null) { + async function getCore(this: LocalGitProvider): Promise { + const gitDir = await this.getGitDir(repoPath); + const [rebaseMergeHeadResult, rebaseApplyHeadResult] = await Promise.allSettled([ + this.git.readDotGitFile(gitDir, ['rebase-merge', 'head-name']), + this.git.readDotGitFile(gitDir, ['rebase-apply', 'head-name']), + ]); + const rebaseMergeHead = getSettledValue(rebaseMergeHeadResult); + const rebaseApplyHead = getSettledValue(rebaseApplyHeadResult); + + let branch = rebaseApplyHead ?? rebaseMergeHead; + if (branch == null) return undefined; + + const path = rebaseApplyHead != null ? 'rebase-apply' : 'rebase-merge'; + + const [ + rebaseHeadResult, + origHeadResult, + ontoResult, + stepsNumberResult, + stepsTotalResult, + stepsMessageResult, + ] = await Promise.allSettled([ + this.git.rev_parse__verify(repoPath, 'REBASE_HEAD'), + this.git.readDotGitFile(gitDir, [path, 'orig-head']), + this.git.readDotGitFile(gitDir, [path, 'onto']), + this.git.readDotGitFile(gitDir, [path, 'msgnum'], { numeric: true }), + this.git.readDotGitFile(gitDir, [path, 'end'], { numeric: true }), this.git - .readDotGitFile(repoPath, ['rebase-merge', 'message'], { throw: true }) - .catch(() => this.git.readDotGitFile(repoPath, ['rebase-merge', 'message-squashed'])), - this.git.readDotGitFile(repoPath, ['rebase-merge', 'end'], { numeric: true }), + .readDotGitFile(gitDir, [path, 'message'], { throw: true }) + .catch(() => this.git.readDotGitFile(gitDir, [path, 'message-squashed'])), ]); - if (branch == null || onto == null) return undefined; + const origHead = getSettledValue(origHeadResult); + const onto = getSettledValue(ontoResult); + if (origHead == null || onto == null) return undefined; + + let mergeBase; + const rebaseHead = getSettledValue(rebaseHeadResult); + if (rebaseHead != null) { + mergeBase = await this.getMergeBase(repoPath, rebaseHead, 'HEAD'); + } else { + mergeBase = await this.getMergeBase(repoPath, onto, origHead); + } if (branch.startsWith('refs/heads/')) { branch = branch.substr(11).trim(); } - const possibleSourceBranches = await this.getCommitBranches(repoPath, onto, { mode: 'pointsAt' }); + const [branchTipsResult, tagTipsResult] = await Promise.allSettled([ + this.getCommitBranches(repoPath, onto, undefined, { all: true, mode: 'pointsAt' }), + this.getCommitTags(repoPath, onto, { mode: 'pointsAt' }), + ]); + + const branchTips = getSettledValue(branchTipsResult); + const tagTips = getSettledValue(tagTipsResult); - let possibleSourceBranch: string | undefined; - for (const b of possibleSourceBranches) { - if (b.startsWith('(no branch, rebasing')) continue; + let ontoRef: GitBranchReference | GitTagReference | undefined; + if (branchTips != null) { + for (const ref of branchTips) { + if (ref.startsWith('(no branch, rebasing')) continue; - possibleSourceBranch = b; - break; + ontoRef = createReference(ref, repoPath, { + refType: 'branch', + name: ref, + remote: false, + }); + break; + } + } + if (ontoRef == null && tagTips != null) { + for (const ref of tagTips) { + if (ref.startsWith('(no branch, rebasing')) continue; + + ontoRef = createReference(ref, repoPath, { + refType: 'tag', + name: ref, + }); + break; + } } - status = { + return { type: 'rebase', repoPath: repoPath, mergeBase: mergeBase, - HEAD: createReference(rebase, repoPath, { refType: 'revision' }), + HEAD: createReference(rebaseHead ?? origHead, repoPath, { refType: 'revision' }), onto: createReference(onto, repoPath, { refType: 'revision' }), - current: - possibleSourceBranch != null - ? createReference(possibleSourceBranch, repoPath, { - refType: 'branch', - name: possibleSourceBranch, - remote: false, - }) - : undefined, - + current: ontoRef, incoming: createReference(branch, repoPath, { refType: 'branch', name: branch, @@ -3639,23 +3705,27 @@ export class LocalGitProvider implements GitProvider, Disposable { }), steps: { current: { - number: stepsNumber ?? 0, - commit: createReference(rebase, repoPath, { - refType: 'revision', - message: stepsMessage, - }), + number: getSettledValue(stepsNumberResult) ?? 0, + commit: + rebaseHead != null + ? createReference(rebaseHead, repoPath, { + refType: 'revision', + message: getSettledValue(stepsMessageResult), + }) + : undefined, }, - total: stepsTotal ?? 0, + total: getSettledValue(stepsTotalResult) ?? 0, }, - }; + } satisfies GitRebaseStatus; } + status = getCore.call(this); if (this.useCaching) { - this._rebaseStatusCache.set(repoPath, status ?? null); + this._rebaseStatusCache.set(repoPath, status); } } - return status ?? undefined; + return status; } @log() diff --git a/src/env/node/git/shell.ts b/src/env/node/git/shell.ts index 48ef756748172..d289ef8613cf5 100644 --- a/src/env/node/git/shell.ts +++ b/src/env/node/git/shell.ts @@ -1,7 +1,7 @@ import type { ExecException } from 'child_process'; import { exec, execFile } from 'child_process'; import type { Stats } from 'fs'; -import { exists, existsSync, statSync } from 'fs'; +import { access, constants, existsSync, statSync } from 'fs'; import { join as joinPaths } from 'path'; import * as process from 'process'; import type { CancellationToken } from 'vscode'; @@ -290,6 +290,6 @@ export function run( }); } -export function fsExists(path: string) { - return new Promise(resolve => exists(path, exists => resolve(exists))); +export async function fsExists(path: string) { + return new Promise(resolve => access(path, constants.F_OK, err => resolve(err == null))); } diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index cdd28df8c3a61..79ac1f0a3b26c 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -227,13 +227,10 @@ export interface GitProvider extends Disposable { getCommitBranches( repoPath: string, ref: string, - options?: { - branch?: string | undefined; - commitDate?: Date | undefined; - mode?: 'contains' | 'pointsAt' | undefined; - name?: string | undefined; - remotes?: boolean | undefined; - }, + branch?: string | undefined, + options?: + | { all?: boolean; commitDate?: Date; mode?: 'contains' | 'pointsAt' } + | { commitDate?: Date; mode?: 'contains' | 'pointsAt'; remotes?: boolean }, ): Promise; getCommitCount(repoPath: string, ref: string): Promise; getCommitForFile( @@ -255,6 +252,14 @@ export interface GitProvider extends Disposable { ref?: string; }, ): Promise; + getCommitTags( + repoPath: string, + ref: string, + options?: { + commitDate?: Date | undefined; + mode?: 'contains' | 'pointsAt' | undefined; + }, + ): Promise; getConfig?(repoPath: string, key: string): Promise; setConfig?(repoPath: string, key: string, value: string | undefined): Promise; getContributors( diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 30b6a2ca16269..89524da10d917 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -1631,10 +1631,13 @@ export class GitProviderService implements Disposable { getCommitBranches( repoPath: string | Uri, ref: string, - options?: { branch?: string; commitDate?: Date; mode?: 'contains' | 'pointsAt'; remotes?: boolean }, + branch?: string | undefined, + options?: + | { all?: boolean; commitDate?: Date; mode?: 'contains' | 'pointsAt' } + | { commitDate?: Date; mode?: 'contains' | 'pointsAt'; remotes?: boolean }, ): Promise { const { provider, path } = this.getProvider(repoPath); - return provider.getCommitBranches(path, ref, options); + return provider.getCommitBranches(path, ref, branch, options); } @log() @@ -1670,6 +1673,16 @@ export class GitProviderService implements Disposable { return provider.getCommitsForGraph(path, asWebviewUri, options); } + @log() + getCommitTags( + repoPath: string | Uri, + ref: string, + options?: { commitDate?: Date; mode?: 'contains' | 'pointsAt' }, + ): Promise { + const { provider, path } = this.getProvider(repoPath); + return provider.getCommitTags(path, ref, options); + } + @log() async getConfig(repoPath: string | Uri, key: string): Promise { const { provider, path } = this.getProvider(repoPath); diff --git a/src/git/models/rebase.ts b/src/git/models/rebase.ts index 81bf4d3b8a035..ccb8e59bb0d01 100644 --- a/src/git/models/rebase.ts +++ b/src/git/models/rebase.ts @@ -1,4 +1,4 @@ -import type { GitBranchReference, GitRevisionReference } from './reference'; +import type { GitBranchReference, GitRevisionReference, GitTagReference } from './reference'; export interface GitRebaseStatus { type: 'rebase'; @@ -6,11 +6,11 @@ export interface GitRebaseStatus { HEAD: GitRevisionReference; onto: GitRevisionReference; mergeBase: string | undefined; - current: GitBranchReference | undefined; + current: GitBranchReference | GitTagReference | undefined; incoming: GitBranchReference; steps: { - current: { number: number; commit: GitRevisionReference }; + current: { number: number; commit: GitRevisionReference | undefined }; total: number; }; } diff --git a/src/plus/github/github.ts b/src/plus/github/github.ts index 3184c35511513..834194a1246ae 100644 --- a/src/plus/github/github.ts +++ b/src/plus/github/github.ts @@ -1591,6 +1591,82 @@ export class GitHubApi implements Disposable { } } + @debug({ args: { 0: '' } }) + async getCommitTags(token: string, owner: string, repo: string, ref: string, date: Date): Promise { + const scope = getLogScope(); + + interface QueryResult { + repository: { + refs: { + nodes: { + name: string; + target: { + history: { + nodes: { oid: string }[]; + }; + }; + }[]; + }; + }; + } + + try { + const query = `query getCommitTags( + $owner: String! + $repo: String! + $since: GitTimestamp! + $until: GitTimestamp! +) { + repository(owner: $owner, name: $repo) { + refs(first: 20, refPrefix: "refs/tags/") { + nodes { + name + target { + ... on Commit { + history(first: 3, since: $since until: $until) { + nodes { oid } + } + } + } + } + } + } +}`; + const rsp = await this.graphql( + undefined, + token, + query, + { + owner: owner, + repo: repo, + since: date.toISOString(), + until: date.toISOString(), + }, + scope, + ); + + const nodes = rsp?.repository?.refs?.nodes; + if (nodes == null) return []; + + const tags = []; + + for (const tag of nodes) { + for (const commit of tag.target.history.nodes) { + if (commit.oid === ref) { + tags.push(tag.name); + break; + } + } + } + + return tags; + } catch (ex) { + if (ex instanceof ProviderRequestNotFoundError) return []; + + throw this.handleException(ex, undefined, scope); + } + } + @debug({ args: { 0: '' } }) async getNextCommitRefs( token: string, diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index 940c8192c36fb..03cfcea72b3a1 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -1048,7 +1048,10 @@ export class GitHubGitProvider implements GitProvider, Disposable { async getCommitBranches( repoPath: string, ref: string, - options?: { branch?: string; commitDate?: Date; mode?: 'contains' | 'pointsAt'; remotes?: boolean }, + branch?: string | undefined, + options?: + | { all?: boolean; commitDate?: Date; mode?: 'contains' | 'pointsAt' } + | { commitDate?: Date; mode?: 'contains' | 'pointsAt'; remotes?: boolean }, ): Promise { if (repoPath == null || options?.commitDate == null) return []; @@ -1059,12 +1062,12 @@ export class GitHubGitProvider implements GitProvider, Disposable { let branches; - if (options?.branch) { + if (branch) { branches = await github.getCommitOnBranch( session.accessToken, metadata.repo.owner, metadata.repo.name, - options?.branch, + branch, ref, options?.commitDate, ); @@ -1591,6 +1594,35 @@ export class GitHubGitProvider implements GitProvider, Disposable { }; } + @log() + async getCommitTags( + repoPath: string, + ref: string, + options?: { commitDate?: Date; mode?: 'contains' | 'pointsAt' }, + ): Promise { + if (repoPath == null || options?.commitDate == null) return []; + + const scope = getLogScope(); + + try { + const { metadata, github, session } = await this.ensureRepositoryContext(repoPath); + + const tags = await github.getCommitTags( + session.accessToken, + metadata.repo.owner, + metadata.repo.name, + ref, + options?.commitDate, + ); + + return tags; + } catch (ex) { + Logger.error(ex, scope); + debugger; + return []; + } + } + @log() async getContributors( repoPath: string, diff --git a/src/system/promise.ts b/src/system/promise.ts index 09d1ac779f7ca..39e76edd5ae98 100644 --- a/src/system/promise.ts +++ b/src/system/promise.ts @@ -4,29 +4,29 @@ export type PromiseOrValue = Promise | T; export function any(...promises: Promise[]): Promise { return new Promise((resolve, reject) => { - const errors: Error[] = []; let settled = false; + const onFullfilled = (r: T) => { + settled = true; + resolve(r); + }; + + let errors: Error[]; + const onRejected = (ex: Error) => { + if (settled) return; + + if (errors == null) { + errors = [ex]; + } else { + errors.push(ex); + } + + if (promises.length - errors.length < 1) { + reject(new AggregateError(errors)); + } + }; for (const promise of promises) { - // eslint-disable-next-line no-loop-func - void (async () => { - try { - const result = await promise; - if (settled) return; - - resolve(result); - settled = true; - } catch (ex) { - errors.push(ex); - } finally { - if (!settled) { - if (promises.length - errors.length < 1) { - reject(new AggregateError(errors)); - settled = true; - } - } - } - })(); + promise.then(onFullfilled, onRejected); } }); } diff --git a/src/views/branchesView.ts b/src/views/branchesView.ts index fa1170f0b099f..a0de753d9a4c3 100644 --- a/src/views/branchesView.ts +++ b/src/views/branchesView.ts @@ -213,6 +213,7 @@ export class BranchesView extends ViewBase<'branches', BranchesViewNode, Branche const branches = await this.container.git.getCommitBranches( commit.repoPath, commit.ref, + undefined, isCommit(commit) ? { commitDate: commit.committer.date } : undefined, ); if (branches.length === 0) return undefined; diff --git a/src/views/commitsView.ts b/src/views/commitsView.ts index 95a10f683513e..5b9a87f4ca8bf 100644 --- a/src/views/commitsView.ts +++ b/src/views/commitsView.ts @@ -355,8 +355,7 @@ export class CommitsView extends ViewBase<'commits', CommitsViewNode, CommitsVie if (branch == null) return undefined; // Check if the commit exists on the current branch - const branches = await this.container.git.getCommitBranches(commit.repoPath, commit.ref, { - branch: branch.name, + const branches = await this.container.git.getCommitBranches(commit.repoPath, commit.ref, branch.name, { commitDate: isCommit(commit) ? commit.committer.date : undefined, }); if (!branches.length) return undefined; diff --git a/src/views/nodes/branchNode.ts b/src/views/nodes/branchNode.ts index c28d8d14b3ce6..11bfec5eccb96 100644 --- a/src/views/nodes/branchNode.ts +++ b/src/views/nodes/branchNode.ts @@ -17,7 +17,6 @@ import { map } from '../../system/iterable'; import type { Deferred } from '../../system/promise'; import { defer, getSettledValue } from '../../system/promise'; import { pad } from '../../system/string'; -import { RemotesView } from '../remotesView'; import type { ViewsWithBranches } from '../viewBase'; import { BranchTrackingStatusNode } from './branchTrackingStatusNode'; import { CommitNode } from './commitNode'; @@ -216,7 +215,7 @@ export class BranchNode extends ViewRefNode { false, { showComparison: - this.view instanceof RepositoriesView + this.view.type === 'repositories' ? this.view.config.branches.showBranchComparison : this.view.config.showBranchComparison, }, diff --git a/src/views/nodes/commitNode.ts b/src/views/nodes/commitNode.ts index 30dc2f0af3af1..43c2113bf4b88 100644 --- a/src/views/nodes/commitNode.ts +++ b/src/views/nodes/commitNode.ts @@ -20,7 +20,6 @@ import type { Deferred } from '../../system/promise'; import { defer, getSettledValue } from '../../system/promise'; import { sortCompare } from '../../system/string'; import type { FileHistoryView } from '../fileHistoryView'; -import { TagsView } from '../tagsView'; import type { ViewsWithCommits } from '../viewBase'; import { CommitFileNode } from './commitFileNode'; import type { FileNode } from './folderNode'; @@ -39,10 +38,10 @@ export class CommitNode extends ViewRefNode string | undefined, - private readonly _options: { expand?: boolean } = {}, + protected readonly getBranchAndTagTips?: (sha: string, options?: { compact?: boolean }) => string | undefined, + protected readonly _options: { expand?: boolean } = {}, ) { super(commit.getGitUri(), view, parent); @@ -77,7 +76,7 @@ export class CommitNode extends ViewRefNode string | undefined; + unpublished?: boolean; + }, +) { + const [remotesResult, _] = await Promise.allSettled([ + container.git.getBestRemotesWithProviders(commit.repoPath), + commit.message == null ? commit.ensureFullDetails() : undefined, + ]); + + const remotes = getSettledValue(remotesResult, []); + const [remote] = remotes; + + let enrichedAutolinks; + let pr; + + if (remote?.hasRichIntegration()) { + const [enrichedAutolinksResult, prResult] = await Promise.allSettled([ + pauseOnCancelOrTimeoutMapTuplePromise(commit.getEnrichedAutolinks(remote)), + commit.getAssociatedPullRequest(remote), + ]); + + enrichedAutolinks = getSettledValue(enrichedAutolinksResult)?.value; + pr = getSettledValue(prResult); + } + + const status = StatusFileFormatter.fromTemplate( + `\${status}\${ (originalPath)}\${'  •  'changesDetail}`, + file, + ); + return CommitFormatter.fromTemplateAsync(tooltipWithStatusFormat.replace('{{slot-status}}', status), commit, { + enrichedAutolinks: enrichedAutolinks, + dateFormat: configuration.get('defaultDateFormat'), + getBranchAndTagTips: options?.getBranchAndTagTips, + messageAutolinks: true, + messageIndent: 4, + pullRequest: pr, + outputFormat: 'markdown', + remotes: remotes, + unpublished: options?.unpublished, + }); +} diff --git a/src/views/nodes/mergeConflictCurrentChangesNode.ts b/src/views/nodes/mergeConflictCurrentChangesNode.ts index 1fa5db2bb3dc7..796ea794684f4 100644 --- a/src/views/nodes/mergeConflictCurrentChangesNode.ts +++ b/src/views/nodes/mergeConflictCurrentChangesNode.ts @@ -2,8 +2,8 @@ import type { Command } from 'vscode'; import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import type { DiffWithCommandArgs } from '../../commands'; import { Commands, GlyphChars } from '../../constants'; -import { CommitFormatter } from '../../git/formatters/commitFormatter'; import { GitUri } from '../../git/gitUri'; +import type { GitCommit } from '../../git/models/commit'; import type { GitFile } from '../../git/models/file'; import type { GitMergeStatus } from '../../git/models/merge'; import type { GitRebaseStatus } from '../../git/models/rebase'; @@ -13,6 +13,7 @@ import { configuration } from '../../system/configuration'; import type { FileHistoryView } from '../fileHistoryView'; import type { LineHistoryView } from '../lineHistoryView'; import type { ViewsWithCommits } from '../viewBase'; +import { getFileRevisionAsCommitTooltip } from './fileRevisionAsCommitNode'; import { ContextValues, ViewNode } from './viewNode'; export class MergeConflictCurrentChangesNode extends ViewNode { @@ -25,12 +26,20 @@ export class MergeConflictCurrentChangesNode extends ViewNode | undefined; + private async getCommit(): Promise { + if (this._commit == null) { + this._commit = this.view.container.git.getCommit(this.status.repoPath, 'HEAD'); + } + return this._commit; + } + getChildren(): ViewNode[] { return []; } async getTreeItem(): Promise { - const commit = await this.view.container.git.getCommit(this.status.repoPath, 'HEAD'); + const commit = await this.getCommit(); const item = new TreeItem('Current changes', TreeItemCollapsibleState.None); item.contextValue = ContextValues.MergeConflictCurrentChanges; @@ -41,31 +50,6 @@ export class MergeConflictCurrentChangesNode extends ViewNode { + if (item.tooltip == null) { + item.tooltip = await this.getTooltip(); + } + return item; + } + + private async getTooltip() { + const commit = await this.getCommit(); + + const markdown = new MarkdownString( + `Current changes on ${getReferenceLabel(this.status.current, { label: false })}\\\n$(file)${ + GlyphChars.Space + }${this.file.path}`, + true, + ); + + if (commit == null) return markdown; + + const tooltip = await getFileRevisionAsCommitTooltip( + this.view.container, + commit, + this.file, + this.view.config.formats.commits.tooltipWithStatus, + ); + + markdown.appendMarkdown(`\n\n${tooltip}`); + markdown.isTrusted = true; + + return markdown; + } } diff --git a/src/views/nodes/mergeConflictFilesNode.ts b/src/views/nodes/mergeConflictFilesNode.ts new file mode 100644 index 0000000000000..96505b8b79cc8 --- /dev/null +++ b/src/views/nodes/mergeConflictFilesNode.ts @@ -0,0 +1,55 @@ +import { TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { GitUri } from '../../git/gitUri'; +import type { GitMergeStatus } from '../../git/models/merge'; +import type { GitRebaseStatus } from '../../git/models/rebase'; +import type { GitStatusFile } from '../../git/models/status'; +import { makeHierarchical } from '../../system/array'; +import { joinPaths, normalizePath } from '../../system/path'; +import { pluralize, sortCompare } from '../../system/string'; +import type { ViewsWithCommits } from '../viewBase'; +import type { FileNode } from './folderNode'; +import { FolderNode } from './folderNode'; +import { MergeConflictFileNode } from './mergeConflictFileNode'; +import { ViewNode } from './viewNode'; + +export class MergeConflictFilesNode extends ViewNode { + constructor( + view: ViewsWithCommits, + protected override readonly parent: ViewNode, + private readonly status: GitMergeStatus | GitRebaseStatus, + private readonly conflicts: GitStatusFile[], + ) { + super(GitUri.fromRepoPath(status.repoPath), view, parent); + } + + get repoPath(): string { + return this.uri.repoPath!; + } + + getChildren(): ViewNode[] { + let children: (FileNode | FolderNode)[] = this.conflicts.map( + f => new MergeConflictFileNode(this.view, this, f, this.status), + ); + + if (this.view.config.files.layout !== 'list') { + const hierarchy = makeHierarchical( + children as FileNode[], + n => n.uri.relativePath.split('/'), + (...parts: string[]) => normalizePath(joinPaths(...parts)), + this.view.config.files.compact, + ); + + const root = new FolderNode(this.view, this, hierarchy, this.repoPath, '', undefined); + children = root.getChildren(); + } else { + children.sort((a, b) => sortCompare(a.label!, b.label!)); + } + + return children; + } + + getTreeItem(): TreeItem { + const item = new TreeItem(pluralize('conflict', this.conflicts.length), TreeItemCollapsibleState.Expanded); + return item; + } +} diff --git a/src/views/nodes/mergeConflictIncomingChangesNode.ts b/src/views/nodes/mergeConflictIncomingChangesNode.ts index 78aebb0444041..28406b248fa46 100644 --- a/src/views/nodes/mergeConflictIncomingChangesNode.ts +++ b/src/views/nodes/mergeConflictIncomingChangesNode.ts @@ -2,8 +2,8 @@ import type { Command } from 'vscode'; import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import type { DiffWithCommandArgs } from '../../commands'; import { Commands, GlyphChars } from '../../constants'; -import { CommitFormatter } from '../../git/formatters/commitFormatter'; import { GitUri } from '../../git/gitUri'; +import type { GitCommit } from '../../git/models/commit'; import type { GitFile } from '../../git/models/file'; import type { GitMergeStatus } from '../../git/models/merge'; import type { GitRebaseStatus } from '../../git/models/rebase'; @@ -13,6 +13,7 @@ import { configuration } from '../../system/configuration'; import type { FileHistoryView } from '../fileHistoryView'; import type { LineHistoryView } from '../lineHistoryView'; import type { ViewsWithCommits } from '../viewBase'; +import { getFileRevisionAsCommitTooltip } from './fileRevisionAsCommitNode'; import { ContextValues, ViewNode } from './viewNode'; export class MergeConflictIncomingChangesNode extends ViewNode { @@ -25,15 +26,23 @@ export class MergeConflictIncomingChangesNode extends ViewNode | undefined; + private async getCommit(): Promise { + if (this._commit == null) { + const ref = this.status.type === 'rebase' ? this.status.steps.current.commit?.ref : this.status.HEAD.ref; + if (ref == null) return undefined; + + this._commit = this.view.container.git.getCommit(this.status.repoPath, ref); + } + return this._commit; + } + getChildren(): ViewNode[] { return []; } async getTreeItem(): Promise { - const commit = await this.view.container.git.getCommit( - this.status.repoPath, - this.status.type === 'rebase' ? this.status.steps.current.commit.ref : this.status.HEAD.ref, - ); + const commit = await this.getCommit(); const item = new TreeItem('Incoming changes', TreeItemCollapsibleState.None); item.contextValue = ContextValues.MergeConflictIncomingChanges; @@ -49,41 +58,6 @@ export class MergeConflictIncomingChangesNode extends ViewNode { + if (item.tooltip == null) { + item.tooltip = await this.getTooltip(); + } + return item; + } + + private async getTooltip() { + const commit = await this.getCommit(); + + const markdown = new MarkdownString( + `Incoming changes from ${getReferenceLabel(this.status.incoming, { label: false })}\\\n$(file)${ + GlyphChars.Space + }${this.file.path}`, + true, + ); + + if (commit == null) { + markdown.appendMarkdown( + this.status.type === 'rebase' + ? `\n\n${getReferenceLabel(this.status.steps.current.commit, { + capitalize: true, + label: false, + })}` + : `\n\n${getReferenceLabel(this.status.HEAD, { + capitalize: true, + label: false, + })}`, + ); + return markdown; + } + + const tooltip = await getFileRevisionAsCommitTooltip( + this.view.container, + commit, + this.file, + this.view.config.formats.commits.tooltipWithStatus, + ); + + markdown.appendMarkdown(`\n\n${tooltip}`); + markdown.isTrusted = true; + + return markdown; + } } diff --git a/src/views/nodes/mergeStatusNode.ts b/src/views/nodes/mergeStatusNode.ts index fb3404452dff1..9d99486f78209 100644 --- a/src/views/nodes/mergeStatusNode.ts +++ b/src/views/nodes/mergeStatusNode.ts @@ -1,17 +1,13 @@ import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; -import type { CoreColors } from '../../constants'; +import type { Colors } from '../../constants'; import { GitUri } from '../../git/gitUri'; import type { GitBranch } from '../../git/models/branch'; import type { GitMergeStatus } from '../../git/models/merge'; import { getReferenceLabel } from '../../git/models/reference'; import type { GitStatus } from '../../git/models/status'; -import { makeHierarchical } from '../../system/array'; -import { joinPaths, normalizePath } from '../../system/path'; -import { pluralize, sortCompare } from '../../system/string'; +import { pluralize } from '../../system/string'; import type { ViewsWithCommits } from '../viewBase'; -import type { FileNode } from './folderNode'; -import { FolderNode } from './folderNode'; -import { MergeConflictFileNode } from './mergeConflictFileNode'; +import { MergeConflictFilesNode } from './mergeConflictFilesNode'; import { ContextValues, getViewNodeId, ViewNode } from './viewNode'; export class MergeStatusNode extends ViewNode { @@ -26,7 +22,7 @@ export class MergeStatusNode extends ViewNode { ) { super(GitUri.fromRepoPath(mergeStatus.repoPath), view, parent); - this.updateContext({ branch: branch, root: root }); + this.updateContext({ branch: branch, root: root, status: 'merging' }); this._uniqueId = getViewNodeId('merge-status', this.context); } @@ -35,50 +31,43 @@ export class MergeStatusNode extends ViewNode { } getChildren(): ViewNode[] { - if (this.status?.hasConflicts !== true) return []; - - let children: FileNode[] = this.status.conflicts.map( - f => new MergeConflictFileNode(this.view, this, f, this.mergeStatus), - ); - - if (this.view.config.files.layout !== 'list') { - const hierarchy = makeHierarchical( - children, - n => n.uri.relativePath.split('/'), - (...parts: string[]) => normalizePath(joinPaths(...parts)), - this.view.config.files.compact, - ); - - const root = new FolderNode(this.view, this, hierarchy, this.repoPath, '', undefined); - children = root.getChildren() as FileNode[]; - } else { - children.sort((a, b) => sortCompare(a.label!, b.label!)); - } - - return children; + return this.status?.hasConflicts + ? [new MergeConflictFilesNode(this.view, this, this.mergeStatus, this.status.conflicts)] + : []; } getTreeItem(): TreeItem { + const hasConflicts = this.status?.hasConflicts === true; const item = new TreeItem( - `${this.status?.hasConflicts ? 'Resolve conflicts before merging' : 'Merging'} ${ + `${hasConflicts ? 'Resolve conflicts before merging' : 'Merging'} ${ this.mergeStatus.incoming != null ? `${getReferenceLabel(this.mergeStatus.incoming, { expand: false, icon: false })} ` : '' }into ${getReferenceLabel(this.mergeStatus.current, { expand: false, icon: false })}`, - TreeItemCollapsibleState.Expanded, + hasConflicts ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None, ); item.id = this.id; item.contextValue = ContextValues.Merge; - item.description = this.status?.hasConflicts ? pluralize('conflict', this.status.conflicts.length) : undefined; - item.iconPath = this.status?.hasConflicts - ? new ThemeIcon('warning', new ThemeColor('list.warningForeground' satisfies CoreColors)) - : new ThemeIcon('debug-pause', new ThemeColor('list.foreground' satisfies CoreColors)); + item.description = hasConflicts ? pluralize('conflict', this.status.conflicts.length) : undefined; + item.iconPath = hasConflicts + ? new ThemeIcon( + 'warning', + new ThemeColor( + 'gitlens.decorations.statusMergingOrRebasingConflictForegroundColor' satisfies Colors, + ), + ) + : new ThemeIcon( + 'warning', + new ThemeColor('gitlens.decorations.statusMergingOrRebasingForegroundColor' satisfies Colors), + ); const markdown = new MarkdownString( `${`Merging ${ - this.mergeStatus.incoming != null ? getReferenceLabel(this.mergeStatus.incoming) : '' - }into ${getReferenceLabel(this.mergeStatus.current)}`}${ - this.status?.hasConflicts ? `\n\n${pluralize('conflicted file', this.status.conflicts.length)}` : '' + this.mergeStatus.incoming != null ? getReferenceLabel(this.mergeStatus.incoming, { label: false }) : '' + }into ${getReferenceLabel(this.mergeStatus.current, { label: false })}`}${ + hasConflicts + ? `\n\nResolve ${pluralize('conflict', this.status.conflicts.length)} before continuing` + : '' }`, true, ); diff --git a/src/views/nodes/rebaseCommitNode.ts b/src/views/nodes/rebaseCommitNode.ts new file mode 100644 index 0000000000000..b4eff4c6c6125 --- /dev/null +++ b/src/views/nodes/rebaseCommitNode.ts @@ -0,0 +1,26 @@ +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { CommitFormatter } from '../../git/formatters/commitFormatter'; +import { CommitNode } from './commitNode'; +import { ContextValues } from './viewNode'; + +export class RebaseCommitNode extends CommitNode { + // eslint-disable-next-line @typescript-eslint/require-await + override async getTreeItem(): Promise { + const item = new TreeItem( + `Paused at commit ${this.commit.shortSha}`, + this._options.expand ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed, + ); + item.id = this.id; + item.contextValue = `${ContextValues.Commit}+rebase`; + item.description = CommitFormatter.fromTemplate(`\${message}`, this.commit, { + messageTruncateAtNewLine: true, + }); + item.iconPath = new ThemeIcon('debug-pause'); + + return item; + } + + protected override getTooltipTemplate(): string { + return `Rebase paused at ${super.getTooltipTemplate()}`; + } +} diff --git a/src/views/nodes/rebaseStatusNode.ts b/src/views/nodes/rebaseStatusNode.ts index dae9dfaad1241..ee2d39c974550 100644 --- a/src/views/nodes/rebaseStatusNode.ts +++ b/src/views/nodes/rebaseStatusNode.ts @@ -1,29 +1,16 @@ -import type { Command } from 'vscode'; import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; -import type { DiffWithPreviousCommandArgs } from '../../commands'; -import type { CoreColors } from '../../constants'; -import { Commands } from '../../constants'; -import { CommitFormatter } from '../../git/formatters/commitFormatter'; +import type { Colors } from '../../constants'; import { GitUri } from '../../git/gitUri'; import type { GitBranch } from '../../git/models/branch'; -import type { GitCommit } from '../../git/models/commit'; import type { GitRebaseStatus } from '../../git/models/rebase'; -import type { GitRevisionReference } from '../../git/models/reference'; import { getReferenceLabel } from '../../git/models/reference'; import type { GitStatus } from '../../git/models/status'; -import { makeHierarchical } from '../../system/array'; -import { pauseOnCancelOrTimeoutMapTuplePromise } from '../../system/cancellation'; import { executeCoreCommand } from '../../system/command'; -import { configuration } from '../../system/configuration'; -import { joinPaths, normalizePath } from '../../system/path'; -import { getSettledValue } from '../../system/promise'; -import { pluralize, sortCompare } from '../../system/string'; +import { pluralize } from '../../system/string'; import type { ViewsWithCommits } from '../viewBase'; -import { CommitFileNode } from './commitFileNode'; -import type { FileNode } from './folderNode'; -import { FolderNode } from './folderNode'; -import { MergeConflictFileNode } from './mergeConflictFileNode'; -import { ContextValues, getViewNodeId, ViewNode, ViewRefNode } from './viewNode'; +import { MergeConflictFilesNode } from './mergeConflictFilesNode'; +import { RebaseCommitNode } from './rebaseCommitNode'; +import { ContextValues, getViewNodeId, ViewNode } from './viewNode'; export class RebaseStatusNode extends ViewNode { constructor( @@ -37,7 +24,7 @@ export class RebaseStatusNode extends ViewNode { ) { super(GitUri.fromRepoPath(rebaseStatus.repoPath), view, parent); - this.updateContext({ branch: branch, root: root }); + this.updateContext({ branch: branch, root: root, status: 'rebasing' }); this._uniqueId = getViewNodeId('merge-status', this.context); } @@ -46,65 +33,80 @@ export class RebaseStatusNode extends ViewNode { } async getChildren(): Promise { - let children: FileNode[] = - this.status?.conflicts.map(f => new MergeConflictFileNode(this.view, this, f, this.rebaseStatus)) ?? []; - - if (this.view.config.files.layout !== 'list') { - const hierarchy = makeHierarchical( - children, - n => n.uri.relativePath.split('/'), - (...parts: string[]) => normalizePath(joinPaths(...parts)), - this.view.config.files.compact, - ); - - const root = new FolderNode(this.view, this, hierarchy, this.repoPath, '', undefined); - children = root.getChildren() as FileNode[]; - } else { - children.sort((a, b) => sortCompare(a.label!, b.label!)); + const children: (MergeConflictFilesNode | RebaseCommitNode)[] = []; + + const revision = this.rebaseStatus.steps.current.commit; + if (revision != null) { + const commit = + revision != null + ? await this.view.container.git.getCommit(this.rebaseStatus.repoPath, revision.ref) + : undefined; + if (commit != null) { + children.push(new RebaseCommitNode(this.view, this, commit)); + } } - const commit = await this.view.container.git.getCommit( - this.rebaseStatus.repoPath, - this.rebaseStatus.steps.current.commit.ref, - ); - if (commit != null) { - children.unshift(new RebaseCommitNode(this.view, this, commit) as any); + if (this.status?.hasConflicts) { + children.push(new MergeConflictFilesNode(this.view, this, this.rebaseStatus, this.status.conflicts)); } return children; } getTreeItem(): TreeItem { + const started = this.rebaseStatus.steps.total > 0; + const pausedAtCommit = started && this.rebaseStatus.steps.current.commit != null; + const hasConflicts = this.status?.hasConflicts === true; + const item = new TreeItem( - `${this.status?.hasConflicts ? 'Resolve conflicts to continue rebasing' : 'Rebasing'} ${ + `${hasConflicts ? 'Resolve conflicts to continue rebasing' : started ? 'Rebasing' : 'Pending rebase of'} ${ this.rebaseStatus.incoming != null ? `${getReferenceLabel(this.rebaseStatus.incoming, { expand: false, icon: false })}` : '' - } (${this.rebaseStatus.steps.current.number}/${this.rebaseStatus.steps.total})`, - TreeItemCollapsibleState.Expanded, + } onto ${getReferenceLabel(this.rebaseStatus.current ?? this.rebaseStatus.onto, { + expand: false, + icon: false, + })}${started ? ` (${this.rebaseStatus.steps.current.number}/${this.rebaseStatus.steps.total})` : ''}`, + pausedAtCommit ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None, ); item.id = this.id; item.contextValue = ContextValues.Rebase; - item.description = this.status?.hasConflicts ? pluralize('conflict', this.status.conflicts.length) : undefined; - item.iconPath = this.status?.hasConflicts - ? new ThemeIcon('warning', new ThemeColor('list.warningForeground' satisfies CoreColors)) - : new ThemeIcon('debug-pause', new ThemeColor('list.foreground' satisfies CoreColors)); + item.description = hasConflicts ? pluralize('conflict', this.status.conflicts.length) : undefined; + item.iconPath = hasConflicts + ? new ThemeIcon( + 'warning', + new ThemeColor( + 'gitlens.decorations.statusMergingOrRebasingConflictForegroundColor' satisfies Colors, + ), + ) + : new ThemeIcon( + 'warning', + new ThemeColor('gitlens.decorations.statusMergingOrRebasingForegroundColor' satisfies Colors), + ); const markdown = new MarkdownString( - `${`Rebasing ${ - this.rebaseStatus.incoming != null ? getReferenceLabel(this.rebaseStatus.incoming) : '' - }onto ${getReferenceLabel(this.rebaseStatus.current)}`}\n\nStep ${ - this.rebaseStatus.steps.current.number - } of ${this.rebaseStatus.steps.total}\\\nPaused at ${getReferenceLabel( - this.rebaseStatus.steps.current.commit, - { icon: true }, - )}${this.status?.hasConflicts ? `\n\n${pluralize('conflicted file', this.status.conflicts.length)}` : ''}`, + `${`${started ? 'Rebasing' : 'Pending rebase of'} ${ + this.rebaseStatus.incoming != null + ? getReferenceLabel(this.rebaseStatus.incoming, { label: false }) + : '' + } onto ${getReferenceLabel(this.rebaseStatus.current ?? this.rebaseStatus.onto, { label: false })}`}${ + started + ? `\n\nPaused at step ${this.rebaseStatus.steps.current.number} of ${ + this.rebaseStatus.steps.total + }${ + hasConflicts + ? `\\\nResolve ${pluralize('conflict', this.status.conflicts.length)} before continuing` + : '' + }` + : '' + }`, true, ); markdown.supportHtml = true; markdown.isTrusted = true; item.tooltip = markdown; + item.resourceUri = Uri.parse(`gitlens-view://status/rebasing${hasConflicts ? '/conflicts' : ''}`); return item; } @@ -116,124 +118,3 @@ export class RebaseStatusNode extends ViewNode { }); } } - -export class RebaseCommitNode extends ViewRefNode { - constructor( - view: ViewsWithCommits, - parent: ViewNode, - public readonly commit: GitCommit, - ) { - super(commit.getGitUri(), view, parent); - } - - override toClipboard(): string { - return `${this.commit.shortSha}: ${this.commit.summary}`; - } - - get ref(): GitRevisionReference { - return this.commit; - } - - async getChildren(): Promise { - const commit = this.commit; - - const commits = await commit.getCommitsForFiles(); - let children: FileNode[] = commits.map(c => new CommitFileNode(this.view, this, c.file!, c)); - - if (this.view.config.files.layout !== 'list') { - const hierarchy = makeHierarchical( - children, - n => n.uri.relativePath.split('/'), - (...parts: string[]) => normalizePath(joinPaths(...parts)), - this.view.config.files.compact, - ); - - const root = new FolderNode(this.view, this, hierarchy, this.repoPath, '', undefined); - children = root.getChildren() as FileNode[]; - } else { - children.sort((a, b) => sortCompare(a.label!, b.label!)); - } - - return children; - } - - getTreeItem(): TreeItem { - const item = new TreeItem(`Paused at commit ${this.commit.shortSha}`, TreeItemCollapsibleState.Collapsed); - - // item.contextValue = ContextValues.RebaseCommit; - - item.description = CommitFormatter.fromTemplate(`\${message}`, this.commit, { - messageTruncateAtNewLine: true, - }); - item.iconPath = new ThemeIcon('git-commit'); - - return item; - } - - override getCommand(): Command | undefined { - const commandArgs: DiffWithPreviousCommandArgs = { - commit: this.commit, - uri: this.uri, - line: 0, - showOptions: { - preserveFocus: true, - preview: true, - }, - }; - return { - title: 'Open Changes with Previous Revision', - command: Commands.DiffWithPrevious, - arguments: [undefined, commandArgs], - }; - } - - override async resolveTreeItem(item: TreeItem): Promise { - if (item.tooltip == null) { - item.tooltip = await this.getTooltip(); - } - return item; - } - - private async getTooltip() { - const [remotesResult, _] = await Promise.allSettled([ - this.view.container.git.getBestRemotesWithProviders(this.commit.repoPath), - this.commit.message == null ? this.commit.ensureFullDetails() : undefined, - ]); - - const remotes = getSettledValue(remotesResult, []); - const [remote] = remotes; - - let enrichedAutolinks; - let pr; - - if (remote?.hasRichIntegration()) { - const [enrichedAutolinksResult, prResult] = await Promise.allSettled([ - pauseOnCancelOrTimeoutMapTuplePromise(this.commit.getEnrichedAutolinks(remote)), - this.commit.getAssociatedPullRequest(remote), - ]); - - enrichedAutolinks = getSettledValue(enrichedAutolinksResult)?.value; - pr = getSettledValue(prResult); - } - - const tooltip = await CommitFormatter.fromTemplateAsync( - `Rebase paused at ${this.view.config.formats.commits.tooltip}`, - this.commit, - { - enrichedAutolinks: enrichedAutolinks, - dateFormat: configuration.get('defaultDateFormat'), - messageAutolinks: true, - messageIndent: 4, - pullRequest: pr, - outputFormat: 'markdown', - remotes: remotes, - }, - ); - - const markdown = new MarkdownString(tooltip, true); - markdown.supportHtml = true; - markdown.isTrusted = true; - - return markdown; - } -} diff --git a/src/views/nodes/statusFilesNode.ts b/src/views/nodes/statusFilesNode.ts index 5fd5a165f4ed2..156ac0d5c3ac4 100644 --- a/src/views/nodes/statusFilesNode.ts +++ b/src/views/nodes/statusFilesNode.ts @@ -10,7 +10,6 @@ import { filter, flatMap, map } from '../../system/iterable'; import { joinPaths, normalizePath } from '../../system/path'; import { pluralize, sortCompare } from '../../system/string'; import type { ViewsWithWorkingTree } from '../viewBase'; -import { WorktreesView } from '../worktreesView'; import type { FileNode } from './folderNode'; import { FolderNode } from './folderNode'; import { StatusFileNode } from './statusFileNode'; @@ -68,10 +67,7 @@ export class StatusFilesNode extends ViewNode { } } - if ( - (this.view instanceof WorktreesView || this.view.config.includeWorkingTree) && - this.status.files.length !== 0 - ) { + if ((this.view.type === 'worktrees' || this.view.config.includeWorkingTree) && this.status.files.length !== 0) { files.unshift( ...flatMap(this.status.files, f => map(f.getPseudoCommits(this.view.container, undefined), c => this.getFileWithPseudoCommit(f, c)), @@ -113,7 +109,7 @@ export class StatusFilesNode extends ViewNode { async getTreeItem(): Promise { let files = - this.view instanceof WorktreesView || this.view.config.includeWorkingTree ? this.status.files.length : 0; + this.view.type === 'worktrees' || this.view.config.includeWorkingTree ? this.status.files.length : 0; if (this.range != null) { if (this.status.upstream != null && this.status.state.ahead > 0) { diff --git a/src/views/nodes/viewNode.ts b/src/views/nodes/viewNode.ts index 834c322a63837..ddd8d49440d0a 100644 --- a/src/views/nodes/viewNode.ts +++ b/src/views/nodes/viewNode.ts @@ -111,6 +111,7 @@ export interface AmbientContext { readonly repository?: Repository; readonly root?: boolean; readonly searchId?: string; + readonly status?: 'merging' | 'rebasing'; readonly storedComparisonId?: string; readonly tag?: GitTag; readonly workspace?: CloudWorkspace | LocalWorkspace; @@ -145,10 +146,13 @@ export function getViewNodeId(type: string, context: AmbientContext): string { uniqueness += `/branch/${context.branch.id}`; } if (context.branchStatus != null) { - uniqueness += `/status/${context.branchStatus.upstream ?? '-'}`; + uniqueness += `/branch-status/${context.branchStatus.upstream ?? '-'}`; } if (context.branchStatusUpstreamType != null) { - uniqueness += `/status-direction/${context.branchStatusUpstreamType}`; + uniqueness += `/branch-status-direction/${context.branchStatusUpstreamType}`; + } + if (context.status != null) { + uniqueness += `/status/${context.status}`; } if (context.reflog != null) { uniqueness += `/reflog/${context.reflog.sha}+${context.reflog.selector}+${context.reflog.command}+${ diff --git a/src/views/remotesView.ts b/src/views/remotesView.ts index 0ef31cf9a5bd4..82472bcf65f83 100644 --- a/src/views/remotesView.ts +++ b/src/views/remotesView.ts @@ -209,6 +209,7 @@ export class RemotesView extends ViewBase<'remotes', RemotesViewNode, RemotesVie const branches = await this.container.git.getCommitBranches( commit.repoPath, commit.ref, + undefined, isCommit(commit) ? { commitDate: commit.committer.date, remotes: true } : { remotes: true }, ); if (branches.length === 0) return undefined; diff --git a/src/views/repositoriesView.ts b/src/views/repositoriesView.ts index 9ede04c21ba09..20f9c26ffa7bc 100644 --- a/src/views/repositoriesView.ts +++ b/src/views/repositoriesView.ts @@ -329,6 +329,7 @@ export class RepositoriesView extends ViewBase<'repositories', RepositoriesNode, let branches = await this.container.git.getCommitBranches( commit.repoPath, commit.ref, + undefined, isCommit(commit) ? { commitDate: commit.committer.date } : undefined, ); if (branches.length !== 0) { @@ -362,6 +363,7 @@ export class RepositoriesView extends ViewBase<'repositories', RepositoriesNode, branches = await this.container.git.getCommitBranches( commit.repoPath, commit.ref, + undefined, isCommit(commit) ? { commitDate: commit.committer.date, remotes: true } : { remotes: true }, ); if (branches.length === 0) return undefined; diff --git a/src/views/viewDecorationProvider.ts b/src/views/viewDecorationProvider.ts index cfdd93232770d..e2ecfc62b9895 100644 --- a/src/views/viewDecorationProvider.ts +++ b/src/views/viewDecorationProvider.ts @@ -19,19 +19,18 @@ export class ViewFileDecorationProvider implements FileDecorationProvider, Dispo provideFileDecoration: (uri, token) => { if (uri.scheme !== 'gitlens-view') return undefined; - if (uri.authority === 'branch') { - return this.provideBranchCurrentDecoration(uri, token); + switch (uri.authority) { + case 'branch': + return this.provideBranchCurrentDecoration(uri, token); + case 'remote': + return this.provideRemoteDefaultDecoration(uri, token); + case 'status': + return this.provideStatusDecoration(uri, token); + case 'workspaces': + return this.provideWorkspaceDecoration(uri, token); + default: + return undefined; } - - if (uri.authority === 'remote') { - return this.provideRemoteDefaultDecoration(uri, token); - } - - if (uri.authority === 'workspaces') { - return this.provideWorkspaceDecoration(uri, token); - } - - return undefined; }, }), window.registerFileDecorationProvider(this), @@ -233,4 +232,27 @@ export class ViewFileDecorationProvider implements FileDecorationProvider, Dispo tooltip: 'Default Remote', }; } + + provideStatusDecoration(uri: Uri, _token: CancellationToken): FileDecoration | undefined { + const [, status, conflicts] = uri.path.split('/'); + + switch (status) { + case 'rebasing': + if (conflicts) { + return { + badge: '!', + color: new ThemeColor( + 'gitlens.decorations.statusMergingOrRebasingConflictForegroundColor' satisfies Colors, + ), + }; + } + return { + color: new ThemeColor( + 'gitlens.decorations.statusMergingOrRebasingForegroundColor' satisfies Colors, + ), + }; + default: + return undefined; + } + } } From 365e07f7e952591f087f3a70495f7e22789d39f8 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 1 Oct 2023 00:46:44 -0400 Subject: [PATCH 0002/1012] Updates dependencies --- package.json | 6 +- yarn.lock | 428 +++++++++++++++++++++++++-------------------------- 2 files changed, 211 insertions(+), 223 deletions(-) diff --git a/package.json b/package.json index 753946fb995bf..05c7e50664b6c 100644 --- a/package.json +++ b/package.json @@ -14833,8 +14833,8 @@ "@typescript-eslint/eslint-plugin": "6.7.3", "@typescript-eslint/parser": "6.7.3", "@vscode/test-electron": "2.3.4", - "@vscode/test-web": "0.0.45", - "@vscode/vsce": "2.21.0", + "@vscode/test-web": "0.0.46", + "@vscode/vsce": "2.21.1", "circular-dependency-plugin": "5.2.2", "clean-webpack-plugin": "4.0.0", "concurrently": "8.2.1", @@ -14843,7 +14843,7 @@ "css-loader": "6.8.1", "css-minimizer-webpack-plugin": "5.0.1", "cssnano-preset-advanced": "6.0.1", - "esbuild": "0.19.3", + "esbuild": "0.19.4", "esbuild-loader": "4.0.2", "esbuild-sass-plugin": "2.15.0", "eslint": "8.50.0", diff --git a/yarn.lock b/yarn.lock index 731c7b3e69a31..a865f3d2c1b57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -61,115 +61,115 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@esbuild/android-arm64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.3.tgz#91a3b1b4a68c01ffdd5d8ffffb0a83178a366ae0" - integrity sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw== - -"@esbuild/android-arm@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.3.tgz#08bd09f2ebc312422f4e94ae954821f9cf37b39e" - integrity sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA== - -"@esbuild/android-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.3.tgz#b1dffec99ed5505fc57561e8758b449dba4924fe" - integrity sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ== - -"@esbuild/darwin-arm64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.3.tgz#2e0db5ad26313c7f420f2cd76d9d263fc49cb549" - integrity sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw== - -"@esbuild/darwin-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.3.tgz#ebe99f35049180023bb37999bddbe306b076a484" - integrity sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw== - -"@esbuild/freebsd-arm64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.3.tgz#cf8b58ba5173440ea6124a3d0278bfe4ce181c20" - integrity sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg== - -"@esbuild/freebsd-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.3.tgz#3f283099810ef1b8468cd1a9400c042e3f12e2a7" - integrity sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA== - -"@esbuild/linux-arm64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.3.tgz#a8b3aa69653ac504a51aa73739fb06de3a04d1ff" - integrity sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ== - -"@esbuild/linux-arm@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.3.tgz#ff6a2f68d4fc3ab46f614bca667a1a81ed6eea26" - integrity sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ== - -"@esbuild/linux-ia32@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.3.tgz#5813baf70e406304e8931b200e39d0293b488073" - integrity sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA== - -"@esbuild/linux-loong64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.3.tgz#21110f29b5e31dc865c7253fde8a2003f7e8b6fd" - integrity sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A== - -"@esbuild/linux-mips64el@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.3.tgz#4530fc416651eadeb1acc27003c00eac769eb8fd" - integrity sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A== - -"@esbuild/linux-ppc64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.3.tgz#facf910b0d397e391b37b01a1b4f6e363b04e56b" - integrity sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g== - -"@esbuild/linux-riscv64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.3.tgz#4a67abe97a495430d5867340982f5424a64f2aac" - integrity sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA== - -"@esbuild/linux-s390x@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.3.tgz#c5fb47474b9f816d81876c119dbccadf671cc5f6" - integrity sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA== - -"@esbuild/linux-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.3.tgz#f22d659969ab78dc422f1df8d9a79bc1e7b12ee3" - integrity sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ== - -"@esbuild/netbsd-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.3.tgz#e9b046934996991f46b8c1cadac815aa45f84fd4" - integrity sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw== - -"@esbuild/openbsd-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.3.tgz#b287ef4841fc1067bbbd9a60549e8f9cf1b7ee3a" - integrity sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q== - -"@esbuild/sunos-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.3.tgz#b2b8ba7d27907c7245f6e57dc62f3b88693f84b0" - integrity sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw== - -"@esbuild/win32-arm64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.3.tgz#1974c8c180c9add4962235662c569fcc4c8f43dd" - integrity sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A== - -"@esbuild/win32-ia32@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.3.tgz#b02cc2dd8b6aed042069680f01f45fdfd3de5bc4" - integrity sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q== - -"@esbuild/win32-x64@0.19.3": - version "0.19.3" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.3.tgz#e5036be529f757e58d9a7771f2f1b14782986a74" - integrity sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw== +"@esbuild/android-arm64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.4.tgz#74752a09301b8c6b9a415fbda9fb71406a62a7b7" + integrity sha512-mRsi2vJsk4Bx/AFsNBqOH2fqedxn5L/moT58xgg51DjX1la64Z3Npicut2VbhvDFO26qjWtPMsVxCd80YTFVeg== + +"@esbuild/android-arm@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.4.tgz#c27363e1e280e577d9b5c8fa7c7a3be2a8d79bf5" + integrity sha512-uBIbiYMeSsy2U0XQoOGVVcpIktjLMEKa7ryz2RLr7L/vTnANNEsPVAh4xOv7ondGz6ac1zVb0F8Jx20rQikffQ== + +"@esbuild/android-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.4.tgz#6c9ee03d1488973d928618100048b75b147e0426" + integrity sha512-4iPufZ1TMOD3oBlGFqHXBpa3KFT46aLl6Vy7gwed0ZSYgHaZ/mihbYb4t7Z9etjkC9Al3ZYIoOaHrU60gcMy7g== + +"@esbuild/darwin-arm64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.4.tgz#64e2ee945e5932cd49812caa80e8896e937e2f8b" + integrity sha512-Lviw8EzxsVQKpbS+rSt6/6zjn9ashUZ7Tbuvc2YENgRl0yZTktGlachZ9KMJUsVjZEGFVu336kl5lBgDN6PmpA== + +"@esbuild/darwin-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.4.tgz#d8e26e1b965df284692e4d1263ba69a49b39ac7a" + integrity sha512-YHbSFlLgDwglFn0lAO3Zsdrife9jcQXQhgRp77YiTDja23FrC2uwnhXMNkAucthsf+Psr7sTwYEryxz6FPAVqw== + +"@esbuild/freebsd-arm64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.4.tgz#29751a41b242e0a456d89713b228f1da4f45582f" + integrity sha512-vz59ijyrTG22Hshaj620e5yhs2dU1WJy723ofc+KUgxVCM6zxQESmWdMuVmUzxtGqtj5heHyB44PjV/HKsEmuQ== + +"@esbuild/freebsd-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.4.tgz#873edc0f73e83a82432460ea59bf568c1e90b268" + integrity sha512-3sRbQ6W5kAiVQRBWREGJNd1YE7OgzS0AmOGjDmX/qZZecq8NFlQsQH0IfXjjmD0XtUYqr64e0EKNFjMUlPL3Cw== + +"@esbuild/linux-arm64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.4.tgz#659f2fa988d448dbf5010b5cc583be757cc1b914" + integrity sha512-ZWmWORaPbsPwmyu7eIEATFlaqm0QGt+joRE9sKcnVUG3oBbr/KYdNE2TnkzdQwX6EDRdg/x8Q4EZQTXoClUqqA== + +"@esbuild/linux-arm@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.4.tgz#d5b13a7ec1f1c655ce05c8d319b3950797baee55" + integrity sha512-z/4ArqOo9EImzTi4b6Vq+pthLnepFzJ92BnofU1jgNlcVb+UqynVFdoXMCFreTK7FdhqAzH0vmdwW5373Hm9pg== + +"@esbuild/linux-ia32@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.4.tgz#878cd8bf24c9847c77acdb5dd1b2ef6e4fa27a82" + integrity sha512-EGc4vYM7i1GRUIMqRZNCTzJh25MHePYsnQfKDexD8uPTCm9mK56NIL04LUfX2aaJ+C9vyEp2fJ7jbqFEYgO9lQ== + +"@esbuild/linux-loong64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.4.tgz#df890499f6e566b7de3aa2361be6df2b8d5fa015" + integrity sha512-WVhIKO26kmm8lPmNrUikxSpXcgd6HDog0cx12BUfA2PkmURHSgx9G6vA19lrlQOMw+UjMZ+l3PpbtzffCxFDRg== + +"@esbuild/linux-mips64el@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.4.tgz#76eae4e88d2ce9f4f1b457e93892e802851b6807" + integrity sha512-keYY+Hlj5w86hNp5JJPuZNbvW4jql7c1eXdBUHIJGTeN/+0QFutU3GrS+c27L+NTmzi73yhtojHk+lr2+502Mw== + +"@esbuild/linux-ppc64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.4.tgz#c49032f4abbcfa3f747b543a106931fe3dce41ff" + integrity sha512-tQ92n0WMXyEsCH4m32S21fND8VxNiVazUbU4IUGVXQpWiaAxOBvtOtbEt3cXIV3GEBydYsY8pyeRMJx9kn3rvw== + +"@esbuild/linux-riscv64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.4.tgz#0f815a090772138503ee0465a747e16865bf94b1" + integrity sha512-tRRBey6fG9tqGH6V75xH3lFPpj9E8BH+N+zjSUCnFOX93kEzqS0WdyJHkta/mmJHn7MBaa++9P4ARiU4ykjhig== + +"@esbuild/linux-s390x@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.4.tgz#8d2cca20cd4e7c311fde8701d9f1042664f8b92b" + integrity sha512-152aLpQqKZYhThiJ+uAM4PcuLCAOxDsCekIbnGzPKVBRUDlgaaAfaUl5NYkB1hgY6WN4sPkejxKlANgVcGl9Qg== + +"@esbuild/linux-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.4.tgz#f618bec2655de49bff91c588777e37b5e3169d4a" + integrity sha512-Mi4aNA3rz1BNFtB7aGadMD0MavmzuuXNTaYL6/uiYIs08U7YMPETpgNn5oue3ICr+inKwItOwSsJDYkrE9ekVg== + +"@esbuild/netbsd-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.4.tgz#7889744ca4d60f1538d62382b95e90a49687cef2" + integrity sha512-9+Wxx1i5N/CYo505CTT7T+ix4lVzEdz0uCoYGxM5JDVlP2YdDC1Bdz+Khv6IbqmisT0Si928eAxbmGkcbiuM/A== + +"@esbuild/openbsd-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.4.tgz#c3e436eb9271a423d2e8436fcb120e3fd90e2b01" + integrity sha512-MFsHleM5/rWRW9EivFssop+OulYVUoVcqkyOkjiynKBCGBj9Lihl7kh9IzrreDyXa4sNkquei5/DTP4uCk25xw== + +"@esbuild/sunos-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.4.tgz#f63f5841ba8c8c1a1c840d073afc99b53e8ce740" + integrity sha512-6Xq8SpK46yLvrGxjp6HftkDwPP49puU4OF0hEL4dTxqCbfx09LyrbUj/D7tmIRMj5D5FCUPksBbxyQhp8tmHzw== + +"@esbuild/win32-arm64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.4.tgz#80be69cec92da4da7781cf7a8351b95cc5a236b0" + integrity sha512-PkIl7Jq4mP6ke7QKwyg4fD4Xvn8PXisagV/+HntWoDEdmerB2LTukRZg728Yd1Fj+LuEX75t/hKXE2Ppk8Hh1w== + +"@esbuild/win32-ia32@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.4.tgz#15dc0ed83d2794872b05d8edc4a358fecf97eb54" + integrity sha512-ga676Hnvw7/ycdKB53qPusvsKdwrWzEyJ+AtItHGoARszIqvjffTwaaW3b2L6l90i7MO9i+dlAW415INuRhSGg== + +"@esbuild/win32-x64@0.19.4": + version "0.19.4" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.4.tgz#d46a6e220a717f31f39ae80f49477cc3220be0f0" + integrity sha512-HP0GDNla1T3ZL8Ko/SHAS2GgtjOg+VmWnnYLhuTksr++EnduYB0f3Y2LzHsUwb2iQ13JGoY6G3R8h6Du/WG6uA== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" @@ -179,9 +179,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz#8c4bb756cc2aa7eaf13cfa5e69c83afb3260c20c" - integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ== + version "4.9.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.0.tgz#7ccb5f58703fa61ffdcbf39e2c604a109e781162" + integrity sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ== "@eslint/eslintrc@^2.1.2": version "2.1.2" @@ -238,9 +238,9 @@ react-onclickoutside "^6.13.0" "@gitkraken/shared-web-components@^0.1.1-rc.6": - version "0.1.1-rc.9" - resolved "https://registry.yarnpkg.com/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.9.tgz#a05991017d8d7d2586350ba6ef4c2aba8c6da669" - integrity sha512-oY1LGtPHyllD32dbVf1FdoKesFDNGpTgS64b7a9fRb4q0MRgzvhAAQg7uyx3SA1epwYPUwJqyyrzEaKzolwCHQ== + version "0.1.1-rc.10" + resolved "https://registry.yarnpkg.com/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.10.tgz#bed7021a0e6912ae3196e06078169950f0616bed" + integrity sha512-2GoM9Gg473zbtTL5u5YTiDeU8mzACj2hMQBk+7iruiiVoJLGxvi1bT95MyXHakhv4zk4lI5OVWP6TU4ZAaoDLQ== dependencies: "@floating-ui/dom" "^1.4.2" typescript "^4.9.5" @@ -573,6 +573,13 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@playwright/browser-chromium@^1.38.1": + version "1.38.1" + resolved "https://registry.yarnpkg.com/@playwright/browser-chromium/-/browser-chromium-1.38.1.tgz#daf0ed3f7a8f9ad6ca731c73be3682b7cce8d5ff" + integrity sha512-HRhcBGtk1XaGAQjOben/04PNHxWAY3DBHT97egraR5lx5SQSLOREIiYu/j7WlvQBz4QJP+XL2JsvoxFBJfXmAw== + dependencies: + playwright-core "1.38.1" + "@polka/url@^1.0.0-next.20": version "1.0.0-next.23" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.23.tgz#498e41218ab3b6a1419c735e5c6ae2c5ed609b6c" @@ -650,16 +657,16 @@ integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== "@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#412e0725ef41cde73bfa03e0e833eaff41e0fd63" + integrity sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.2.tgz#edc8e421991a3b4df875036d381fc0a5a982f549" + integrity sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A== dependencies: "@types/istanbul-lib-report" "*" @@ -679,9 +686,9 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/minimist@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.3.tgz#dd249cef80c6fff2ba6a0d4e5beca913e04e25f8" + integrity sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A== "@types/mocha@10.0.1": version "10.0.1" @@ -689,9 +696,9 @@ integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== "@types/node@*": - version "20.6.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.5.tgz#4c6a79adf59a8e8193ac87a0e522605b16587258" - integrity sha512-2qGq5LAOTh9izcc0+F+dToFigBWiK1phKPt7rNhOqJSr35y8rlIBjDwGtFSgAI6MGIhjwOVNSQZVdJsZJ2uR1w== + version "20.8.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.0.tgz#10ddf0119cf20028781c06d7115562934e53f745" + integrity sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ== "@types/node@16.11.47": version "16.11.47" @@ -730,9 +737,9 @@ csstype "^3.0.2" "@types/react@^17": - version "17.0.65" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.65.tgz#95f6a2ab61145ffb69129d07982d047f9e0870cd" - integrity sha512-oxur785xZYHvnI7TRS61dXbkIhDPnGfsXKv0cNXR/0ml4SipRIFpSMzA7HMEfOywFwJ5AOnPrXYTEiTRUQeGlQ== + version "17.0.66" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.66.tgz#4b3bfd6dd5ee37835f60d4a9325cff974b064126" + integrity sha512-azQzO1tuioq9M4vVKzzdBgG5KfLhyocYkRlJMBDcrJ7bUzyjR7QIGbZk2zH7sB5KpXRWoZJQ3CznVyhDS/swxA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -769,9 +776,9 @@ integrity sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ== "@types/yargs@^17.0.8": - version "17.0.25" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.25.tgz#3edd102803c97356fb4c805b2bbaf7dfc9ab6abc" - integrity sha512-gy7iPgwnzNvxgAEi2bXOHWCVOG6f7xsprVJH4MjlAWeBmJ7vh/Y1kwMtUrs64ztf24zVIRCpr3n/z6gm9QIkgg== + version "17.0.26" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.26.tgz#388e5002a8b284ad7b4599ba89920a6d74d8d79a" + integrity sha512-Y3vDy2X6zw/ZCumcwLpdhM5L7jmyGpmBCTYMHDLqT2IKVMYRRLdv6ZakA+wxhra6Z/3bwhNbNl9bDGXaFU+6rw== dependencies: "@types/yargs-parser" "*" @@ -875,29 +882,30 @@ jszip "^3.10.1" semver "^7.5.2" -"@vscode/test-web@0.0.45": - version "0.0.45" - resolved "https://registry.yarnpkg.com/@vscode/test-web/-/test-web-0.0.45.tgz#e0b23a67ec0081f69173565db93847ab3aec0a8e" - integrity sha512-yPJgxEbbxDlKGGpLzNQ8PDPOOUKUVo7Epg/3o+y7mKtjbg3nktIReJ/pPtOHrZxsNC8FkzTNBoTh5DMBHX/LGg== +"@vscode/test-web@0.0.46": + version "0.0.46" + resolved "https://registry.yarnpkg.com/@vscode/test-web/-/test-web-0.0.46.tgz#ad42bcaa5fbbf7929dcc629db6285fd7580753ad" + integrity sha512-s5rKDtCvIWN6kJpjXzBoWpLvftjH3m2r2MQNGUGsdY1+mOJ06lbbHeJn+g30+p0ec4Vh7PpBZGECflrRW+oH4Q== dependencies: "@koa/cors" "^4.0.0" "@koa/router" "^12.0.0" + "@playwright/browser-chromium" "^1.38.1" gunzip-maybe "^1.4.2" http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.1" + https-proxy-agent "^7.0.2" koa "^2.14.2" koa-morgan "^1.0.1" koa-mount "^4.0.0" koa-static "^5.0.0" minimist "^1.2.8" - playwright "^1.37.1" + playwright "^1.38.1" tar-fs "^3.0.4" vscode-uri "^3.0.7" -"@vscode/vsce@2.21.0": - version "2.21.0" - resolved "https://registry.yarnpkg.com/@vscode/vsce/-/vsce-2.21.0.tgz#572e66db79cff383b9ac39f71710aa62e6392330" - integrity sha512-KuxYqScqUY/duJbkj9eE2tN2X/WJoGAy54hHtxT3ZBkM6IzrOg7H7CXGUPBxNlmqku2w/cAjOUSrgIHlzz0mbA== +"@vscode/vsce@2.21.1": + version "2.21.1" + resolved "https://registry.yarnpkg.com/@vscode/vsce/-/vsce-2.21.1.tgz#793c78d992483b428611a3927211a9640041be14" + integrity sha512-f45/aT+HTubfCU2oC7IaWnH9NjOWp668ML002QiFObFRVUCoLtcwepp9mmql/ArFUy+HCHp54Xrq4koTcOD6TA== dependencies: azure-devops-node-api "^11.0.1" chalk "^2.4.2" @@ -1497,12 +1505,12 @@ browserify-zlib@^0.1.4: pako "~0.2.0" browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.21.10, browserslist@^4.21.4: - version "4.21.11" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.11.tgz#35f74a3e51adc4d193dcd76ea13858de7b8fecb8" - integrity sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ== + version "4.22.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" + integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== dependencies: - caniuse-lite "^1.0.30001538" - electron-to-chromium "^1.4.526" + caniuse-lite "^1.0.30001541" + electron-to-chromium "^1.4.535" node-releases "^2.0.13" update-browserslist-db "^1.0.13" @@ -1603,10 +1611,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538: - version "1.0.30001539" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz#325a387ab1ed236df2c12dc6cd43a4fff9903a44" - integrity sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: + version "1.0.30001541" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" + integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== capital-case@^1.0.4: version "1.0.4" @@ -2586,10 +2594,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.526: - version "1.4.528" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz#7c900fd73d9d2e8bb0dab0e301f25f0f4776ef2c" - integrity sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA== +electron-to-chromium@^1.4.535: + version "1.4.537" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.537.tgz#aac4101db53066be1e49baedd000a26bc754adc9" + integrity sha512-W1+g9qs9hviII0HAwOdehGYkr+zt7KKdmCcJcjH0mYg6oL8+ioT3Skjmt7BLoAQqXhjf40AXd+HlR4oAWMlXjA== emoji-regex@^8.0.0: version "8.0.0" @@ -2799,33 +2807,33 @@ esbuild-sass-plugin@2.15.0: resolve "^1.22.2" sass "^1.65.1" -esbuild@0.19.3, esbuild@^0.19.0: - version "0.19.3" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.3.tgz#d9268cd23358eef9d76146f184e0c55ff8da7bb6" - integrity sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw== +esbuild@0.19.4, esbuild@^0.19.0: + version "0.19.4" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.4.tgz#cdf5c4c684956d550bc3c6d0c01dac7fef6c75b1" + integrity sha512-x7jL0tbRRpv4QUyuDMjONtWFciygUxWaUM1kMX2zWxI0X2YWOt7MSA0g4UdeSiHM8fcYVzpQhKYOycZwxTdZkA== optionalDependencies: - "@esbuild/android-arm" "0.19.3" - "@esbuild/android-arm64" "0.19.3" - "@esbuild/android-x64" "0.19.3" - "@esbuild/darwin-arm64" "0.19.3" - "@esbuild/darwin-x64" "0.19.3" - "@esbuild/freebsd-arm64" "0.19.3" - "@esbuild/freebsd-x64" "0.19.3" - "@esbuild/linux-arm" "0.19.3" - "@esbuild/linux-arm64" "0.19.3" - "@esbuild/linux-ia32" "0.19.3" - "@esbuild/linux-loong64" "0.19.3" - "@esbuild/linux-mips64el" "0.19.3" - "@esbuild/linux-ppc64" "0.19.3" - "@esbuild/linux-riscv64" "0.19.3" - "@esbuild/linux-s390x" "0.19.3" - "@esbuild/linux-x64" "0.19.3" - "@esbuild/netbsd-x64" "0.19.3" - "@esbuild/openbsd-x64" "0.19.3" - "@esbuild/sunos-x64" "0.19.3" - "@esbuild/win32-arm64" "0.19.3" - "@esbuild/win32-ia32" "0.19.3" - "@esbuild/win32-x64" "0.19.3" + "@esbuild/android-arm" "0.19.4" + "@esbuild/android-arm64" "0.19.4" + "@esbuild/android-x64" "0.19.4" + "@esbuild/darwin-arm64" "0.19.4" + "@esbuild/darwin-x64" "0.19.4" + "@esbuild/freebsd-arm64" "0.19.4" + "@esbuild/freebsd-x64" "0.19.4" + "@esbuild/linux-arm" "0.19.4" + "@esbuild/linux-arm64" "0.19.4" + "@esbuild/linux-ia32" "0.19.4" + "@esbuild/linux-loong64" "0.19.4" + "@esbuild/linux-mips64el" "0.19.4" + "@esbuild/linux-ppc64" "0.19.4" + "@esbuild/linux-riscv64" "0.19.4" + "@esbuild/linux-s390x" "0.19.4" + "@esbuild/linux-x64" "0.19.4" + "@esbuild/netbsd-x64" "0.19.4" + "@esbuild/openbsd-x64" "0.19.4" + "@esbuild/sunos-x64" "0.19.4" + "@esbuild/win32-arm64" "0.19.4" + "@esbuild/win32-ia32" "0.19.4" + "@esbuild/win32-x64" "0.19.4" escalade@^3.1.1: version "3.1.1" @@ -3274,9 +3282,9 @@ fs-minipass@^3.0.0: minipass "^7.0.3" fs-monkey@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.4.tgz#ee8c1b53d3fe8bb7e5d2c5c5dfc0168afdd2f747" - integrity sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ== + version "1.0.5" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.5.tgz#fe450175f0db0d7ea758102e1d84096acb925788" + integrity sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew== fs.realpath@^1.0.0: version "1.0.0" @@ -3386,7 +3394,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@10.3.10: +glob@10.3.10, glob@^10.2.2: version "10.3.10" resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== @@ -3409,17 +3417,6 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^10.2.2: - version "10.3.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.7.tgz#d5bd30a529c8c9b262fb4b217941f64ad90e25ac" - integrity sha512-wCMbE1m9Nx5yD9LYtgsVWq5VhHlk5WzJirw594qZR6AIvQYuHrdDtIktUVjQItalD53y7dqoedu9xP0u0WaxIQ== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.0.3" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" - glob@^7.0.3, glob@^7.0.6, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -3767,7 +3764,7 @@ https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.1: +https-proxy-agent@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== @@ -4159,19 +4156,10 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -jackspeak@^2.0.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.3.tgz#95e4cbcc03b3eb357bf6bcce14a903fb3d1151e1" - integrity sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - jackspeak@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.5.tgz#443f237f9eeeb0d7c6ec34835ef5289bb4acb068" - integrity sha512-Ratx+B8WeXLAtRJn26hrhY8S1+Jz6pxPMrkrdkgb/NstTNiqMhX0/oFVu5wX+g5n6JlEu2LPsDJmY8nRP4+alw== + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -4860,9 +4848,9 @@ minipass@^5.0.0: integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.3.tgz#05ea638da44e475037ed94d1c7efcc76a25e1974" - integrity sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg== + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" @@ -5464,7 +5452,7 @@ playwright-core@1.38.1: resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.38.1.tgz#75a3c470aa9576b7d7c4e274de3d79977448ba08" integrity sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg== -playwright@^1.37.1: +playwright@^1.38.1: version "1.38.1" resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.38.1.tgz#82ecd9bc4f4f64dbeee8a11c31793748e2528130" integrity sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow== @@ -5745,9 +5733,9 @@ postcss-zindex@^6.0.0: integrity sha512-lNim6f01ClwALn0J50yyoR+qOu10GXub+xucEB7+x8VwXl+iNJSj/QgXg45XpSoLsWD5HIofVrG/pPrMFcdbig== postcss@^8.4.21, postcss@^8.4.24: - version "8.4.30" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" - integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" @@ -6271,9 +6259,9 @@ sass@1.68.0, sass@^1.65.1: source-map-js ">=0.6.2 <2.0.0" sax@>=0.6.0, sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + version "1.3.0" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" + integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== scheduler@^0.13.4: version "0.13.6" From 0f83de4acf2d51ed4d694855cc28f78b947610c8 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:10:37 -0700 Subject: [PATCH 0003/1012] Adds workspace deep link support (#2942) --- package.json | 17 +++- src/commands/base.ts | 9 ++ src/commands/copyDeepLink.ts | 15 +++ src/constants.ts | 1 + src/uris/deepLinks/deepLink.ts | 44 +++++++-- src/uris/deepLinks/deepLinkService.ts | 137 ++++++++++++++++---------- src/views/viewBase.ts | 28 +++++- src/views/workspacesView.ts | 40 +++++++- 8 files changed, 224 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index 05c7e50664b6c..330baea348e6c 100644 --- a/package.json +++ b/package.json @@ -5411,6 +5411,12 @@ "category": "GitLens", "icon": "$(copy)" }, + { + "command": "gitlens.copyDeepLinkToWorkspace", + "title": "Copy Link to Workspace", + "category": "GitLens", + "icon": "$(copy)" + }, { "command": "gitlens.copyDeepLinkToTag", "title": "Copy Link to Tag", @@ -8555,6 +8561,10 @@ "command": "gitlens.copyDeepLinkToTag", "when": "false" }, + { + "command": "gitlens.copyDeepLinkToWorkspace", + "when": "false" + }, { "command": "gitlens.copyRemoteBranchUrl", "when": "false" @@ -11777,7 +11787,7 @@ }, { "submenu": "gitlens/share", - "when": "viewItem =~ /gitlens:(branch|commit|compare:results(?!:)|remote|repo-folder|repository|stash|tag|file\\b(?=.*?\\b\\+committed\\b))\\b/", + "when": "viewItem =~ /gitlens:(branch|commit|compare:results(?!:)|remote|repo-folder|repository|stash|tag|workspace|file\\b(?=.*?\\b\\+committed\\b))\\b/", "group": "7_gitlens_a_share@1" }, { @@ -13203,6 +13213,11 @@ "when": "viewItem =~ /gitlens:compare:results(?!:)\\b/", "group": "1_gitlens@25" }, + { + "command": "gitlens.copyDeepLinkToWorkspace", + "when": "viewItem =~ /gitlens:workspace\\b/", + "group": "1_gitlens@25" + }, { "command": "gitlens.copyRemoteFileUrlWithoutRange", "when": "gitlens:hasRemotes && viewItem =~ /gitlens:(file\\b(?=.*?\\b\\+committed\\b)|history:(file|line)|status:file)\\b/", diff --git a/src/commands/base.ts b/src/commands/base.ts index 6d29bda2cda98..de0f1e7e5e421 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -21,6 +21,7 @@ import { GitRemote } from '../git/models/remote'; import { Repository } from '../git/models/repository'; import type { GitTag } from '../git/models/tag'; import { isTag } from '../git/models/tag'; +import { CloudWorkspace, LocalWorkspace } from '../plus/workspaces/models'; import { registerCommand } from '../system/command'; import { sequentialize } from '../system/function'; import { ViewNode, ViewRefFileNode, ViewRefNode } from '../views/nodes/viewNode'; @@ -212,6 +213,14 @@ export function isCommandContextViewNodeHasTag( return isTag((context.node as ViewNode & { tag: GitTag }).tag); } +export function isCommandContextViewNodeHasWorkspace( + context: CommandContext, +): context is CommandViewNodeContext & { node: ViewNode & { workspace: CloudWorkspace | LocalWorkspace } } { + if (context.type !== 'viewItem') return false; + const workspace = (context.node as ViewNode & { workspace?: CloudWorkspace | LocalWorkspace }).workspace; + return workspace instanceof CloudWorkspace || workspace instanceof LocalWorkspace; +} + export type CommandContext = | CommandEditorLineContext | CommandGitTimelineItemContext diff --git a/src/commands/copyDeepLink.ts b/src/commands/copyDeepLink.ts index fbf548caa9832..93cc1be74571f 100644 --- a/src/commands/copyDeepLink.ts +++ b/src/commands/copyDeepLink.ts @@ -20,6 +20,7 @@ import { isCommandContextViewNodeHasComparison, isCommandContextViewNodeHasRemote, isCommandContextViewNodeHasTag, + isCommandContextViewNodeHasWorkspace, } from './base'; export interface CopyDeepLinkCommandArgs { @@ -28,6 +29,7 @@ export interface CopyDeepLinkCommandArgs { compareWithRef?: StoredNamedRef; remote?: string; prePickRemote?: boolean; + workspaceId?: string; } @command() @@ -39,6 +41,7 @@ export class CopyDeepLinkCommand extends ActiveEditorCommand { Commands.CopyDeepLinkToRepo, Commands.CopyDeepLinkToTag, Commands.CopyDeepLinkToComparison, + Commands.CopyDeepLinkToWorkspace, ]); } @@ -58,6 +61,8 @@ export class CopyDeepLinkCommand extends ActiveEditorCommand { compareRef: context.node.compareRef, compareWithRef: context.node.compareWithRef, }; + } else if (isCommandContextViewNodeHasWorkspace(context)) { + args = { workspaceId: context.node.workspace.id }; } } @@ -67,6 +72,16 @@ export class CopyDeepLinkCommand extends ActiveEditorCommand { async execute(editor?: TextEditor, uri?: Uri, args?: CopyDeepLinkCommandArgs) { args = { ...args }; + if (args.workspaceId != null) { + try { + await this.container.deepLinks.copyDeepLinkUrl(args.workspaceId); + } catch (ex) { + Logger.error(ex, 'CopyDeepLinkCommand'); + void showGenericErrorMessage('Unable to copy link'); + } + return; + } + let type; let repoPath; if (args?.refOrRepoPath == null) { diff --git a/src/constants.ts b/src/constants.ts index cd64b2c6e7429..818be5ef60522 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -126,6 +126,7 @@ export const enum Commands { CopyDeepLinkToComparison = 'gitlens.copyDeepLinkToComparison', CopyDeepLinkToRepo = 'gitlens.copyDeepLinkToRepo', CopyDeepLinkToTag = 'gitlens.copyDeepLinkToTag', + CopyDeepLinkToWorkspace = 'gitlens.copyDeepLinkToWorkspace', CopyMessageToClipboard = 'gitlens.copyMessageToClipboard', CopyRemoteBranchesUrl = 'gitlens.copyRemoteBranchesUrl', CopyRemoteBranchUrl = 'gitlens.copyRemoteBranchUrl', diff --git a/src/uris/deepLinks/deepLink.ts b/src/uris/deepLinks/deepLink.ts index eac1e8ee3ae20..4b7910dbfe541 100644 --- a/src/uris/deepLinks/deepLink.ts +++ b/src/uris/deepLinks/deepLink.ts @@ -11,6 +11,7 @@ export enum DeepLinkType { Comparison = 'compare', Repository = 'r', Tag = 't', + Workspace = 'workspace', } export function deepLinkTypeToString(type: DeepLinkType): string { @@ -25,6 +26,8 @@ export function deepLinkTypeToString(type: DeepLinkType): string { return 'Repository'; case DeepLinkType.Tag: return 'Tag'; + case DeepLinkType.Workspace: + return 'Workspace'; default: debugger; return 'Unknown'; @@ -46,7 +49,7 @@ export function refTypeToDeepLinkType(refType: GitReference['refType']): DeepLin export interface DeepLink { type: DeepLinkType; - repoId: string; + mainId: string; remoteUrl?: string; repoPath?: string; targetId?: string; @@ -58,8 +61,10 @@ export function parseDeepLinkUri(uri: Uri): DeepLink | undefined { // The link target id is everything after the link target. // For example, if the uri is /link/r/{repoId}/b/{branchName}?url={remoteUrl}, // the link target id is {branchName} - const [, type, prefix, repoId, target, ...rest] = uri.path.split('/'); - if (type !== 'link' || prefix !== DeepLinkType.Repository) return undefined; + const [, type, prefix, mainId, target, ...rest] = uri.path.split('/'); + if (type !== 'link' || (prefix !== DeepLinkType.Repository && prefix !== DeepLinkType.Workspace)) { + return undefined; + } const urlParams = new URLSearchParams(uri.query); let remoteUrl = urlParams.get('url') ?? undefined; @@ -70,12 +75,18 @@ export function parseDeepLinkUri(uri: Uri): DeepLink | undefined { if (repoPath != null) { repoPath = decodeURIComponent(repoPath); } - if (!remoteUrl && !repoPath) return undefined; + if (!remoteUrl && !repoPath && prefix !== DeepLinkType.Workspace) return undefined; + if (prefix === DeepLinkType.Workspace) { + return { + type: DeepLinkType.Workspace, + mainId: mainId, + }; + } if (target == null) { return { type: DeepLinkType.Repository, - repoId: repoId, + mainId: mainId, remoteUrl: remoteUrl, repoPath: repoPath, }; @@ -103,7 +114,7 @@ export function parseDeepLinkUri(uri: Uri): DeepLink | undefined { return { type: target as DeepLinkType, - repoId: repoId, + mainId: mainId, remoteUrl: remoteUrl, repoPath: repoPath, targetId: targetId, @@ -114,6 +125,7 @@ export function parseDeepLinkUri(uri: Uri): DeepLink | undefined { export const enum DeepLinkServiceState { Idle, + TypeMatch, RepoMatch, CloneOrAddRepo, OpeningRepo, @@ -125,6 +137,7 @@ export const enum DeepLinkServiceState { FetchedTargetMatch, OpenGraph, OpenComparison, + OpenWorkspace, } export const enum DeepLinkServiceAction { @@ -133,6 +146,8 @@ export const enum DeepLinkServiceAction { DeepLinkResolved, DeepLinkStored, DeepLinkErrored, + LinkIsRepoType, + LinkIsWorkspaceType, OpenRepo, RepoMatched, RepoMatchedInLocalMapping, @@ -154,7 +169,7 @@ export type DeepLinkRepoOpenType = 'clone' | 'folder' | 'workspace' | 'current'; export interface DeepLinkServiceContext { state: DeepLinkServiceState; url?: string | undefined; - repoId?: string | undefined; + mainId?: string | undefined; repo?: Repository | undefined; remoteUrl?: string | undefined; remote?: GitRemote | undefined; @@ -170,7 +185,14 @@ export interface DeepLinkServiceContext { export const deepLinkStateTransitionTable: Record> = { [DeepLinkServiceState.Idle]: { - [DeepLinkServiceAction.DeepLinkEventFired]: DeepLinkServiceState.RepoMatch, + [DeepLinkServiceAction.DeepLinkEventFired]: DeepLinkServiceState.TypeMatch, + [DeepLinkServiceAction.DeepLinkCancelled]: DeepLinkServiceState.Idle, + }, + [DeepLinkServiceState.TypeMatch]: { + [DeepLinkServiceAction.DeepLinkErrored]: DeepLinkServiceState.Idle, + [DeepLinkServiceAction.DeepLinkCancelled]: DeepLinkServiceState.Idle, + [DeepLinkServiceAction.LinkIsRepoType]: DeepLinkServiceState.RepoMatch, + [DeepLinkServiceAction.LinkIsWorkspaceType]: DeepLinkServiceState.OpenWorkspace, }, [DeepLinkServiceState.RepoMatch]: { [DeepLinkServiceAction.DeepLinkErrored]: DeepLinkServiceState.Idle, @@ -229,6 +251,10 @@ export const deepLinkStateTransitionTable: Record = { [DeepLinkServiceState.Idle]: { message: 'Done.', increment: 100 }, + [DeepLinkServiceState.TypeMatch]: { message: 'Matching link type...', increment: 5 }, [DeepLinkServiceState.RepoMatch]: { message: 'Finding a matching repository...', increment: 10 }, [DeepLinkServiceState.CloneOrAddRepo]: { message: 'Adding repository...', increment: 20 }, [DeepLinkServiceState.OpeningRepo]: { message: 'Opening repository...', increment: 30 }, @@ -249,4 +276,5 @@ export const deepLinkStateToProgress: Record = { [DeepLinkServiceState.FetchedTargetMatch]: { message: 'Finding a matching target...', increment: 90 }, [DeepLinkServiceState.OpenGraph]: { message: 'Opening graph...', increment: 95 }, [DeepLinkServiceState.OpenComparison]: { message: 'Opening comparison...', increment: 95 }, + [DeepLinkServiceState.OpenWorkspace]: { message: 'Opening workspace...', increment: 95 }, }; diff --git a/src/uris/deepLinks/deepLinkService.ts b/src/uris/deepLinks/deepLinkService.ts index 22b4481780d45..3a9cfd27155bb 100644 --- a/src/uris/deepLinks/deepLinkService.ts +++ b/src/uris/deepLinks/deepLinkService.ts @@ -21,6 +21,7 @@ import { deepLinkStateToProgress, deepLinkStateTransitionTable, DeepLinkType, + deepLinkTypeToString, parseDeepLinkUri, } from './deepLink'; @@ -46,7 +47,7 @@ export class DeepLinkService implements Disposable { await this.container.git.isDiscoveringRepositories; } - if (!link.type || (!link.repoId && !link.remoteUrl && !link.repoPath)) { + if (!link.type || (!link.mainId && !link.remoteUrl && !link.repoPath)) { void window.showErrorMessage('Unable to resolve link'); Logger.warn(`Unable to resolve link - missing basic properties: ${uri.toString()}`); return; @@ -58,9 +59,9 @@ export class DeepLinkService implements Disposable { return; } - if (link.type !== DeepLinkType.Repository && link.targetId == null) { + if (link.type !== DeepLinkType.Repository && link.targetId == null && link.mainId == null) { void window.showErrorMessage('Unable to resolve link'); - Logger.warn(`Unable to resolve link - no target id provided: ${uri.toString()}`); + Logger.warn(`Unable to resolve link - no main/target id provided: ${uri.toString()}`); return; } @@ -92,7 +93,7 @@ export class DeepLinkService implements Disposable { this._context = { state: DeepLinkServiceState.Idle, url: undefined, - repoId: undefined, + mainId: undefined, repo: undefined, remoteUrl: undefined, remote: undefined, @@ -109,7 +110,7 @@ export class DeepLinkService implements Disposable { private setContextFromDeepLink(link: DeepLink, url: string) { this._context = { ...this._context, - repoId: link.repoId, + mainId: link.mainId, targetType: link.type, url: url, remoteUrl: link.remoteUrl, @@ -359,9 +360,13 @@ export class DeepLinkService implements Disposable { ): Promise { let message = ''; let action = initialAction; + if (action === DeepLinkServiceAction.DeepLinkCancelled && this._context.state === DeepLinkServiceState.Idle) { + return; + } //Repo match let matchingLocalRepoPaths: string[] = []; + const { targetType } = this._context; queueMicrotask( () => @@ -369,7 +374,7 @@ export class DeepLinkService implements Disposable { { cancellable: true, location: ProgressLocation.Notification, - title: `Opening repository for link: ${this._context.url}}`, + title: `Opening ${deepLinkTypeToString(targetType ?? DeepLinkType.Repository)} link...`, }, (progress, token) => { progress.report({ increment: 0 }); @@ -379,14 +384,12 @@ export class DeepLinkService implements Disposable { resolve(); }); - this._disposables.push( - this._onDeepLinkProgressUpdated.event(({ message, increment }) => { - progress.report({ message: message, increment: increment }); - if (increment === 100) { - resolve(); - } - }), - ); + this._onDeepLinkProgressUpdated.event(({ message, increment }) => { + progress.report({ message: message, increment: increment }); + if (increment === 100) { + resolve(); + } + }); }); }, ), @@ -396,7 +399,7 @@ export class DeepLinkService implements Disposable { this._context.state = deepLinkStateTransitionTable[this._context.state][action]; const { state, - repoId, + mainId, repo, url, remoteUrl, @@ -422,9 +425,18 @@ export class DeepLinkService implements Disposable { this.resetContext(); return; } + case DeepLinkServiceState.TypeMatch: { + if (targetType === DeepLinkType.Workspace) { + action = DeepLinkServiceAction.LinkIsWorkspaceType; + } else { + action = DeepLinkServiceAction.LinkIsRepoType; + } + + break; + } case DeepLinkServiceState.RepoMatch: case DeepLinkServiceState.AddedRepoMatch: { - if (!repoId && !remoteUrl && !repoPath) { + if (!mainId && !remoteUrl && !repoPath) { action = DeepLinkServiceAction.DeepLinkErrored; message = 'No repository id, remote url or path was provided.'; break; @@ -459,10 +471,10 @@ export class DeepLinkService implements Disposable { } } - if (repoId != null && repoId !== '-') { + if (mainId != null && mainId !== '-') { // Repo ID can be any valid SHA in the repo, though standard practice is to use the // first commit SHA. - if (await this.container.git.validateReference(repo.path, repoId)) { + if (await this.container.git.validateReference(repo.path, mainId)) { this._context.repo = repo; action = DeepLinkServiceAction.RepoMatched; break; @@ -506,7 +518,7 @@ export class DeepLinkService implements Disposable { break; } case DeepLinkServiceState.CloneOrAddRepo: { - if (!repoId && !remoteUrl && !repoPath) { + if (!mainId && !remoteUrl && !repoPath) { action = DeepLinkServiceAction.DeepLinkErrored; message = 'Missing repository id, remote url and path.'; break; @@ -872,6 +884,22 @@ export class DeepLinkService implements Disposable { action = DeepLinkServiceAction.DeepLinkResolved; break; } + case DeepLinkServiceState.OpenWorkspace: { + if (!mainId) { + action = DeepLinkServiceAction.DeepLinkErrored; + message = 'Missing workspace id.'; + break; + } + + await this.container.workspacesView.revealWorkspaceNode(mainId, { + select: true, + focus: true, + expand: true, + }); + + action = DeepLinkServiceAction.DeepLinkResolved; + break; + } default: { action = DeepLinkServiceAction.DeepLinkErrored; message = 'Unknown state.'; @@ -881,6 +909,7 @@ export class DeepLinkService implements Disposable { } } + async copyDeepLinkUrl(workspaceId: string): Promise; async copyDeepLinkUrl(ref: GitReference, remoteUrl: string): Promise; async copyDeepLinkUrl( repoPath: string, @@ -889,17 +918,20 @@ export class DeepLinkService implements Disposable { compareWithRef?: StoredNamedRef, ): Promise; async copyDeepLinkUrl( - refOrRepoPath: string | GitReference, - remoteUrl: string, + refOrIdOrRepoPath: string | GitReference, + remoteUrl?: string, compareRef?: StoredNamedRef, compareWithRef?: StoredNamedRef, ): Promise { - const url = await (typeof refOrRepoPath === 'string' - ? this.generateDeepLinkUrl(refOrRepoPath, remoteUrl, compareRef, compareWithRef) - : this.generateDeepLinkUrl(refOrRepoPath, remoteUrl)); + const url = await (typeof refOrIdOrRepoPath === 'string' + ? remoteUrl != null + ? this.generateDeepLinkUrl(refOrIdOrRepoPath, remoteUrl, compareRef, compareWithRef) + : this.generateDeepLinkUrl(refOrIdOrRepoPath) + : this.generateDeepLinkUrl(refOrIdOrRepoPath, remoteUrl!)); await env.clipboard.writeText(url.toString()); } + async generateDeepLinkUrl(workspaceId: string): Promise; async generateDeepLinkUrl(ref: GitReference, remoteUrl: string): Promise; async generateDeepLinkUrl( repoPath: string, @@ -908,37 +940,50 @@ export class DeepLinkService implements Disposable { compareWithRef?: StoredNamedRef, ): Promise; async generateDeepLinkUrl( - refOrRepoPath: string | GitReference, - remoteUrl: string, + refOrIdOrRepoPath: string | GitReference, + remoteUrl?: string, compareRef?: StoredNamedRef, compareWithRef?: StoredNamedRef, ): Promise { - const repoPath = typeof refOrRepoPath !== 'string' ? refOrRepoPath.repoPath : refOrRepoPath; - let repoId; + let repoId: string | undefined; + let targetType: DeepLinkType | undefined; + let targetId: string | undefined; + let compareWithTargetId: string | undefined; + const schemeOverride = configuration.get('deepLinks.schemeOverride'); + const scheme = !schemeOverride ? 'vscode' : schemeOverride === true ? env.uriScheme : schemeOverride; + let modePrefixString = ''; + if (this.container.env === 'dev') { + modePrefixString = 'dev.'; + } else if (this.container.env === 'staging') { + modePrefixString = 'staging.'; + } + + if (remoteUrl == null && typeof refOrIdOrRepoPath === 'string') { + return new URL(`https://${modePrefixString}gitkraken.dev/link/workspaces/${refOrIdOrRepoPath}`); + } + + const repoPath = typeof refOrIdOrRepoPath !== 'string' ? refOrIdOrRepoPath.repoPath : refOrIdOrRepoPath; try { repoId = await this.container.git.getUniqueRepositoryId(repoPath); } catch { repoId = '-'; } - let targetType: DeepLinkType | undefined; - let targetId: string | undefined; - let compareWithTargetId: string | undefined; - if (typeof refOrRepoPath !== 'string') { - switch (refOrRepoPath.refType) { + if (typeof refOrIdOrRepoPath !== 'string') { + switch (refOrIdOrRepoPath.refType) { case 'branch': targetType = DeepLinkType.Branch; - targetId = refOrRepoPath.remote - ? getBranchNameWithoutRemote(refOrRepoPath.name) - : refOrRepoPath.name; + targetId = refOrIdOrRepoPath.remote + ? getBranchNameWithoutRemote(refOrIdOrRepoPath.name) + : refOrIdOrRepoPath.name; break; case 'revision': targetType = DeepLinkType.Commit; - targetId = refOrRepoPath.ref; + targetId = refOrIdOrRepoPath.ref; break; case 'tag': targetType = DeepLinkType.Tag; - targetId = refOrRepoPath.name; + targetId = refOrIdOrRepoPath.name; break; } } @@ -949,9 +994,6 @@ export class DeepLinkService implements Disposable { compareWithTargetId = compareWithRef.label ?? compareWithRef.ref; } - const schemeOverride = configuration.get('deepLinks.schemeOverride'); - - const scheme = !schemeOverride ? 'vscode' : schemeOverride === true ? env.uriScheme : schemeOverride; let target; if (targetType === DeepLinkType.Comparison) { target = `/${targetType}/${compareWithTargetId}...${targetId}`; @@ -968,16 +1010,9 @@ export class DeepLinkService implements Disposable { }/${repoId}${target}`, ); - // Add the remote URL as a query parameter - deepLink.searchParams.set('url', remoteUrl); - const params = new URLSearchParams(); - params.set('url', remoteUrl); - - let modePrefixString = ''; - if (this.container.env === 'dev') { - modePrefixString = 'dev.'; - } else if (this.container.env === 'staging') { - modePrefixString = 'staging.'; + if (remoteUrl != null) { + // Add the remote URL as a query parameter + deepLink.searchParams.set('url', remoteUrl); } const deepLinkRedirectUrl = new URL( diff --git a/src/views/viewBase.ts b/src/views/viewBase.ts index 696c94d1f24ce..68bf794a497b1 100644 --- a/src/views/viewBase.ts +++ b/src/views/viewBase.ts @@ -115,6 +115,9 @@ export abstract class ViewBase< return `gitlens.views.${this.type}`; } + protected _onDidInitialize = new EventEmitter(); + private initialized = false; + protected _onDidChangeTreeData = new EventEmitter(); get onDidChangeTreeData(): Event { return this._onDidChangeTreeData.event; @@ -348,7 +351,22 @@ export abstract class ViewBase< if (node != null) return node.getChildren(); const root = this.ensureRoot(); - return root.getChildren(); + const children = root.getChildren(); + if (!this.initialized) { + if (isPromise(children)) { + void children.then(() => { + if (!this.initialized) { + this.initialized = true; + setTimeout(() => this._onDidInitialize.fire(), 1); + } + }); + } else { + this.initialized = true; + setTimeout(() => this._onDidInitialize.fire(), 1); + } + } + + return children; } getParent(node: ViewNode): ViewNode | undefined { @@ -455,12 +473,14 @@ export abstract class ViewBase< } } - if (this.root != null) return find.call(this); + if (this.initialized) return find.call(this); // If we have no root (e.g. never been initialized) force it so the tree will load properly - await this.show({ preserveFocus: true }); + void this.show({ preserveFocus: true }); // Since we have to show the view, give the view time to load and let the callstack unwind before we try to find the node - return new Promise(resolve => setTimeout(() => resolve(find.call(this)), 100)); + return new Promise(resolve => + once(this._onDidInitialize.event)(() => resolve(find.call(this)), this), + ); } private async findNodeCoreBFS( diff --git a/src/views/workspacesView.ts b/src/views/workspacesView.ts index 634736a5ed710..1cbe086fcab2e 100644 --- a/src/views/workspacesView.ts +++ b/src/views/workspacesView.ts @@ -1,4 +1,4 @@ -import type { Disposable } from 'vscode'; +import type { CancellationToken, Disposable } from 'vscode'; import { env, ProgressLocation, Uri, window } from 'vscode'; import type { RepositoriesViewConfig } from '../config'; import { Commands } from '../constants'; @@ -45,8 +45,42 @@ export class WorkspacesView extends ViewBase<'workspaces', WorkspacesViewNode, R return super.show(options); } - override get canReveal(): boolean { - return false; + async findWorkspaceNode(workspaceId: string, token?: CancellationToken) { + return this.findNode((n: any) => n.workspace?.id === workspaceId, { + allowPaging: false, + maxDepth: 2, + canTraverse: n => { + if (n instanceof WorkspacesViewNode) return true; + + return false; + }, + token: token, + }); + } + + async revealWorkspaceNode( + workspaceId: string, + options?: { + select?: boolean; + focus?: boolean; + expand?: boolean | number; + }, + ) { + return window.withProgress( + { + location: ProgressLocation.Notification, + title: `Revealing workspace ${workspaceId} in the side bar...`, + cancellable: true, + }, + async (progress, token) => { + const node = await this.findWorkspaceNode(workspaceId, token); + if (node == null) return undefined; + + await this.ensureRevealNode(node, options); + + return node; + }, + ); } protected registerCommands(): Disposable[] { From 6181285a97346a1430a91649b09631d613dcda46 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 5 Sep 2023 14:53:57 -0400 Subject: [PATCH 0004/1012] Adds a focus service (wip) --- src/container.ts | 10 ++++ src/plus/focus/focusService.ts | 90 ++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 src/plus/focus/focusService.ts diff --git a/src/container.ts b/src/container.ts index 58dda4ab72ae2..ff8014a711d2f 100644 --- a/src/container.ts +++ b/src/container.ts @@ -21,6 +21,7 @@ import { GitLabAuthenticationProvider } from './git/remotes/gitlab'; import { RichRemoteProviderService } from './git/remotes/remoteProviderService'; import { LineHoverController } from './hovers/lineHoverController'; import type { RepositoryPathMappingProvider } from './pathMapping/repositoryPathMappingProvider'; +import { FocusService } from './plus/focus/focusService'; import { AccountAuthenticationProvider } from './plus/gk/authenticationProvider'; import { ServerConnection } from './plus/gk/serverConnection'; import { IntegrationAuthenticationService } from './plus/integrationAuthentication'; @@ -436,6 +437,15 @@ export class Container { return this._deepLinks; } + private _focus: FocusService | undefined; + get focus() { + if (this._focus == null) { + this._disposables.push((this._focus = new FocusService(this, new ServerConnection(this)))); + } + + return this._focus; + } + private _github: Promise | undefined; get github() { if (this._github == null) { diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts new file mode 100644 index 0000000000000..454199a064767 --- /dev/null +++ b/src/plus/focus/focusService.ts @@ -0,0 +1,90 @@ +import type { Disposable } from 'vscode'; +import { Uri } from 'vscode'; +import type { Container } from '../../container'; +import type { ServerConnection } from '../gk/serverConnection'; + +export interface FocusItem { + provider: string; + type: 'issue' | 'pr'; + id: string; + repositoryId: string; + repositoryName: string; + repositoryOwner: string; +} + +export interface EnrichedItem { + id: string; + userId: string; + type: 'pinned' | 'snoozed'; + + provider: string; + entityType: 'issue' | 'pr'; + entityId: string; + repositoryId: string; + repositoryName: string; + repositoryOwner: string; + + createdAt: number; + updatedAt: number; +} + +export class FocusService implements Disposable { + constructor( + private readonly container: Container, + private readonly connection: ServerConnection, + ) {} + + dispose(): void {} + + async pinItem(item: FocusItem): Promise { + type Result = { data: EnrichedItem }; + + const rsp = await this.connection.fetch( + Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/pin').toString(), + { + method: 'POST', + body: JSON.stringify(item), + }, + ); + const result = (await rsp.json()) as Result; + return result.data; + } + + async snoozeItem(item: FocusItem): Promise { + type Result = { data: EnrichedItem }; + + const rsp = await this.connection.fetch( + Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/snooze').toString(), + { + method: 'POST', + body: JSON.stringify(item), + }, + ); + const result = (await rsp.json()) as Result; + return result.data; + } + + async getPins(): Promise { + const data = await this.getAll(); + return data.filter(i => i.type === 'pinned'); + } + + async getSnoozed(): Promise { + const data = await this.getAll(); + return data.filter(i => i.type === 'snoozed'); + } + + async getAll(): Promise { + type Result = { data: EnrichedItem[] }; + + const rsp = await this.connection.fetch( + Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items').toString(), + { + method: 'GET', + }, + ); + + const result = (await rsp.json()) as Result; + return result.data.map(i => i); + } +} From 1019f861e374b491a20ae97e9f0de8170eaeb508 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 5 Sep 2023 15:23:00 -0400 Subject: [PATCH 0005/1012] Adds unpin/unsnooze & delete --- src/plus/focus/focusService.ts | 120 +++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 34 deletions(-) diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index 454199a064767..32178f598012f 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -4,29 +4,62 @@ import type { Container } from '../../container'; import type { ServerConnection } from '../gk/serverConnection'; export interface FocusItem { - provider: string; - type: 'issue' | 'pr'; + provider: EnrichedItemResponse['provider']; + type: EnrichedItemResponse['entityType']; id: string; - repositoryId: string; repositoryName: string; repositoryOwner: string; } -export interface EnrichedItem { +export type EnrichedItem = { id: string; userId: string; - type: 'pinned' | 'snoozed'; + type: EnrichedItemResponse['type']; - provider: string; + provider: EnrichedItemResponse['provider']; + entityType: EnrichedItemResponse['entityType']; + entityId: string; + + createdAt: number; + updatedAt: number; +} & ( + | { repositoryId: string } + | { + repositoryName: string; + repositoryOwner: string; + } +); + +type EnrichedItemRequest = { + provider: EnrichedItemResponse['provider']; + type: EnrichedItemResponse['entityType']; + id: string; +} & ( + | { repositoryId: string } + | { + repositoryName: string; + repositoryOwner: string; + } +); + +type EnrichedItemResponse = { + id: string; + userId: string; + type: 'pin' | 'snooze'; + + provider: 'azure' | 'bitbucket' | 'github' | 'gitlab' | 'gitkraken'; entityType: 'issue' | 'pr'; entityId: string; - repositoryId: string; - repositoryName: string; - repositoryOwner: string; createdAt: number; updatedAt: number; -} +} & ( + | { repositoryId: string } + | { + repositoryName: string; + repositoryOwner: string; + } +); export class FocusService implements Disposable { constructor( @@ -36,55 +69,74 @@ export class FocusService implements Disposable { dispose(): void {} - async pinItem(item: FocusItem): Promise { - type Result = { data: EnrichedItem }; + private async delete(id: string): Promise { + const rsp = await this.connection.fetch( + Uri.joinPath(this.connection.baseGkApiUri, `v1/enrich-items/${id}`).toString(), + { + method: 'DELETE', + }, + ); + if (!rsp.ok) { + debugger; + throw new Error(`Unable to delete enrichment: ${rsp.statusText}`); + } + } + + async get(type?: EnrichedItemResponse['type']): Promise { + type Result = { data: EnrichedItemResponse[] }; const rsp = await this.connection.fetch( - Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/pin').toString(), + Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items').toString(), { - method: 'POST', - body: JSON.stringify(item), + method: 'GET', }, ); + const result = (await rsp.json()) as Result; - return result.data; + return type == null ? result.data : result.data.filter(i => i.type === type); } - async snoozeItem(item: FocusItem): Promise { - type Result = { data: EnrichedItem }; + getPins(): Promise { + return this.get('pin'); + } + + getSnoozed(): Promise { + return this.get('snooze'); + } + + async pinItem(item: FocusItem): Promise { + type Result = { data: EnrichedItemResponse }; const rsp = await this.connection.fetch( - Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/snooze').toString(), + Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/pin').toString(), { method: 'POST', - body: JSON.stringify(item), + body: JSON.stringify(item satisfies EnrichedItemRequest), }, ); const result = (await rsp.json()) as Result; return result.data; } - async getPins(): Promise { - const data = await this.getAll(); - return data.filter(i => i.type === 'pinned'); + unpinItem(id: string): Promise { + return this.delete(id); } - async getSnoozed(): Promise { - const data = await this.getAll(); - return data.filter(i => i.type === 'snoozed'); - } - - async getAll(): Promise { - type Result = { data: EnrichedItem[] }; + async snoozeItem(item: FocusItem): Promise { + type Result = { data: EnrichedItemResponse }; const rsp = await this.connection.fetch( - Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items').toString(), + Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/snooze').toString(), { - method: 'GET', + method: 'POST', + body: JSON.stringify(item satisfies EnrichedItemRequest), }, ); - const result = (await rsp.json()) as Result; - return result.data.map(i => i); + return result.data; + } + + unsnoozeItem(id: string): Promise { + return this.delete(id); } } From c39e7e7c38ed126e706fbb6e073eb10913a5e57b Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 7 Sep 2023 19:12:58 -0400 Subject: [PATCH 0006/1012] Adds basic error handling --- src/plus/focus/focusService.ts | 111 ++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index 32178f598012f..9d987b7e5d8f5 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -1,6 +1,8 @@ import type { Disposable } from 'vscode'; -import { Uri } from 'vscode'; import type { Container } from '../../container'; +import { log } from '../../system/decorators/log'; +import { Logger } from '../../system/logger'; +import { getLogScope } from '../../system/logger.scope'; import type { ServerConnection } from '../gk/serverConnection'; export interface FocusItem { @@ -69,74 +71,109 @@ export class FocusService implements Disposable { dispose(): void {} - private async delete(id: string): Promise { - const rsp = await this.connection.fetch( - Uri.joinPath(this.connection.baseGkApiUri, `v1/enrich-items/${id}`).toString(), - { - method: 'DELETE', - }, - ); - if (!rsp.ok) { + private async delete(id: string, context: 'unpin' | 'unsnooze'): Promise { + const scope = getLogScope(); + + try { + const rsp = await this.connection.fetchGkDevApi(`v1/enrich-items/${id}`, { method: 'DELETE' }); + + if (!rsp.ok) throw new Error(`Unable to ${context} item '${id}': (${rsp.status}) ${rsp.statusText}`); + } catch (ex) { + Logger.error(ex, scope); debugger; - throw new Error(`Unable to delete enrichment: ${rsp.statusText}`); + throw ex; } } + @log() async get(type?: EnrichedItemResponse['type']): Promise { - type Result = { data: EnrichedItemResponse[] }; + const scope = getLogScope(); + + try { + type Result = { data: EnrichedItemResponse[] }; - const rsp = await this.connection.fetch( - Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items').toString(), - { - method: 'GET', - }, - ); + const rsp = await this.connection.fetchGkDevApi('v1/enrich-items', { method: 'GET' }); - const result = (await rsp.json()) as Result; - return type == null ? result.data : result.data.filter(i => i.type === type); + const result = (await rsp.json()) as Result; + return type == null ? result.data : result.data.filter(i => i.type === type); + } catch (ex) { + Logger.error(ex, scope); + debugger; + throw ex; + } } + @log() getPins(): Promise { return this.get('pin'); } + @log() getSnoozed(): Promise { return this.get('snooze'); } + @log() async pinItem(item: FocusItem): Promise { - type Result = { data: EnrichedItemResponse }; + const scope = getLogScope(); + + try { + type Result = { data: EnrichedItemResponse }; - const rsp = await this.connection.fetch( - Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/pin').toString(), - { + const rsp = await this.connection.fetchGkDevApi('v1/enrich-items/pin', { method: 'POST', body: JSON.stringify(item satisfies EnrichedItemRequest), - }, - ); - const result = (await rsp.json()) as Result; - return result.data; + }); + + if (!rsp.ok) { + throw new Error( + `Unable to pin item '${item.provider}|${item.repositoryOwner}/${item.repositoryName}#${item.id}': (${rsp.status}) ${rsp.statusText}`, + ); + } + + const result = (await rsp.json()) as Result; + return result.data; + } catch (ex) { + Logger.error(ex, scope); + debugger; + throw ex; + } } + @log() unpinItem(id: string): Promise { - return this.delete(id); + return this.delete(id, 'unpin'); } + @log() async snoozeItem(item: FocusItem): Promise { - type Result = { data: EnrichedItemResponse }; + const scope = getLogScope(); + + try { + type Result = { data: EnrichedItemResponse }; - const rsp = await this.connection.fetch( - Uri.joinPath(this.connection.baseGkApiUri, 'v1/enrich-items/snooze').toString(), - { + const rsp = await this.connection.fetchGkDevApi('v1/enrich-items/snooze', { method: 'POST', body: JSON.stringify(item satisfies EnrichedItemRequest), - }, - ); - const result = (await rsp.json()) as Result; - return result.data; + }); + + if (!rsp.ok) { + throw new Error( + `Unable to snooze item '${item.provider}|${item.repositoryOwner}/${item.repositoryName}#${item.id}': (${rsp.status}) ${rsp.statusText}`, + ); + } + + const result = (await rsp.json()) as Result; + return result.data; + } catch (ex) { + Logger.error(ex, scope); + debugger; + throw ex; + } } + @log() unsnoozeItem(id: string): Promise { - return this.delete(id); + return this.delete(id, 'unsnooze'); } } From 1ba08fa38f5ba4da343965ce45cf98fa7d05737f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 1 Oct 2023 00:52:15 -0400 Subject: [PATCH 0007/1012] Adds pin and snooze UI --- package.json | 2 +- src/plus/focus/focusService.ts | 79 ++++-- src/plus/webviews/focus/focusWebview.ts | 262 +++++++++++++++--- src/plus/webviews/focus/protocol.ts | 31 +++ .../apps/plus/focus/components/focus-app.ts | 82 +++++- .../plus/focus/components/gk-issue-row.ts | 60 ++++ .../focus/components/gk-pull-request-row.ts | 62 ++++- src/webviews/apps/plus/focus/focus.ts | 45 +++ yarn.lock | 2 +- 9 files changed, 554 insertions(+), 71 deletions(-) diff --git a/package.json b/package.json index 330baea348e6c..1cbf1d0329410 100644 --- a/package.json +++ b/package.json @@ -14816,7 +14816,7 @@ }, "dependencies": { "@gitkraken/gitkraken-components": "10.1.25", - "@gitkraken/shared-web-components": "^0.1.1-rc.6", + "@gitkraken/shared-web-components": "^0.1.1-rc.9", "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", "@octokit/graphql": "7.0.2", diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index 9d987b7e5d8f5..8ea0725bfe94d 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -1,21 +1,21 @@ import type { Disposable } from 'vscode'; import type { Container } from '../../container'; +import type { GitRemote } from '../../git/models/remote'; +import type { RichRemoteProvider } from '../../git/remotes/richRemoteProvider'; import { log } from '../../system/decorators/log'; import { Logger } from '../../system/logger'; import { getLogScope } from '../../system/logger.scope'; import type { ServerConnection } from '../gk/serverConnection'; export interface FocusItem { - provider: EnrichedItemResponse['provider']; type: EnrichedItemResponse['entityType']; id: string; - repositoryName: string; - repositoryOwner: string; + remote?: GitRemote; } export type EnrichedItem = { id: string; - userId: string; + userId?: string; type: EnrichedItemResponse['type']; provider: EnrichedItemResponse['provider']; @@ -25,28 +25,45 @@ export type EnrichedItem = { createdAt: number; updatedAt: number; } & ( - | { repositoryId: string } + | { gitRepositoryId: string } | { repositoryName: string; repositoryOwner: string; } ); -type EnrichedItemRequest = { - provider: EnrichedItemResponse['provider']; - type: EnrichedItemResponse['entityType']; - id: string; -} & ( - | { repositoryId: string } +type GitRepositoryDataRequest = | { - repositoryName: string; - repositoryOwner: string; + readonly initialCommitSha: string; + readonly remoteUrl?: undefined; + readonly remoteDomain?: undefined; + readonly remotePath?: undefined; } -); + | ({ + readonly initialCommitSha?: string; + readonly remoteUrl: string; + readonly remoteDomain: string; + readonly remotePath: string; + } & ( + | { readonly remoteProvider?: undefined } + | { + readonly remoteProvider: string; + readonly remoteProviderRepoDomain: string; + readonly remoteProviderRepoName: string; + readonly remoteProviderRepoOwnerDomain?: string; + } + )); + +type EnrichedItemRequest = { + provider: EnrichedItemResponse['provider']; + entityType: EnrichedItemResponse['entityType']; + entityId: string; + gitRepoData: GitRepositoryDataRequest; +}; type EnrichedItemResponse = { id: string; - userId: string; + userId?: string; type: 'pin' | 'snooze'; provider: 'azure' | 'bitbucket' | 'github' | 'gitlab' | 'gitkraken'; @@ -56,7 +73,7 @@ type EnrichedItemResponse = { createdAt: number; updatedAt: number; } & ( - | { repositoryId: string } + | { gitRepositoryId: string } | { repositoryName: string; repositoryOwner: string; @@ -120,14 +137,25 @@ export class FocusService implements Disposable { try { type Result = { data: EnrichedItemResponse }; + const rq: EnrichedItemRequest = { + provider: item.remote!.provider.id as EnrichedItemResponse['provider'], + entityType: item.type, + entityId: item.id, + gitRepoData: { + remoteUrl: item.remote!.url, + remotePath: item.remote!.provider.path, + remoteDomain: item.remote!.provider.domain, + }, + }; + const rsp = await this.connection.fetchGkDevApi('v1/enrich-items/pin', { method: 'POST', - body: JSON.stringify(item satisfies EnrichedItemRequest), + body: JSON.stringify(rq), }); if (!rsp.ok) { throw new Error( - `Unable to pin item '${item.provider}|${item.repositoryOwner}/${item.repositoryName}#${item.id}': (${rsp.status}) ${rsp.statusText}`, + `Unable to pin item '${rq.provider}|${rq.gitRepoData.remoteDomain}/${rq.gitRepoData.remotePath}#${item.id}': (${rsp.status}) ${rsp.statusText}`, ); } @@ -152,14 +180,25 @@ export class FocusService implements Disposable { try { type Result = { data: EnrichedItemResponse }; + const rq: EnrichedItemRequest = { + provider: item.remote!.provider.id as EnrichedItemResponse['provider'], + entityType: item.type, + entityId: item.id, + gitRepoData: { + remoteUrl: item.remote!.url, + remotePath: item.remote!.provider.path, + remoteDomain: item.remote!.provider.domain, + }, + }; + const rsp = await this.connection.fetchGkDevApi('v1/enrich-items/snooze', { method: 'POST', - body: JSON.stringify(item satisfies EnrichedItemRequest), + body: JSON.stringify(rq), }); if (!rsp.ok) { throw new Error( - `Unable to snooze item '${item.provider}|${item.repositoryOwner}/${item.repositoryName}#${item.id}': (${rsp.status}) ${rsp.statusText}`, + `Unable to snooze item '${rq.provider}|${rq.gitRepoData.remoteDomain}/${rq.gitRepoData.remotePath}#${item.id}': (${rsp.status}) ${rsp.statusText}`, ); } diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index ce943c10a392a..7156de3db6207 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -27,13 +27,27 @@ import { getSettledValue } from '../../../system/promise'; import type { IpcMessage } from '../../../webviews/protocol'; import { onIpc } from '../../../webviews/protocol'; import type { WebviewController, WebviewProvider } from '../../../webviews/webviewController'; +import type { EnrichedItem, FocusItem } from '../../focus/focusService'; import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService'; import type { ShowInCommitGraphCommandArgs } from '../graph/protocol'; -import type { OpenBranchParams, OpenWorktreeParams, State, SwitchToBranchParams } from './protocol'; +import type { + OpenBranchParams, + OpenWorktreeParams, + PinIssueParams, + PinPrParams, + SnoozeIssueParams, + SnoozePrParams, + State, + SwitchToBranchParams, +} from './protocol'; import { DidChangeNotificationType, OpenBranchCommandType, OpenWorktreeCommandType, + PinIssueCommandType, + PinPrCommandType, + SnoozeIssueCommandType, + SnoozePrCommandType, SwitchToBranchCommandType, } from './protocol'; @@ -51,15 +65,21 @@ interface SearchedPullRequestWithRemote extends SearchedPullRequest { isCurrentBranch?: boolean; hasWorktree?: boolean; isCurrentWorktree?: boolean; + rank: number; +} + +interface SearchedIssueWithRank extends SearchedIssue { + rank: number; } export class FocusWebviewProvider implements WebviewProvider { private _pullRequests: SearchedPullRequestWithRemote[] = []; - private _issues: SearchedIssue[] = []; + private _issues: SearchedIssueWithRank[] = []; private readonly _disposable: Disposable; private _etagSubscription?: number; private _repositoryEventsDisposable?: Disposable; private _repos?: RepoWithRichRemote[]; + private _enrichedItems?: EnrichedItem[]; constructor( private readonly container: Container, @@ -90,7 +110,115 @@ export class FocusWebviewProvider implements WebviewProvider { case OpenWorktreeCommandType.method: onIpc(OpenWorktreeCommandType, e, params => this.onOpenWorktree(params)); break; + case SnoozePrCommandType.method: + onIpc(SnoozePrCommandType, e, params => this.onSnoozePr(params)); + break; + case PinPrCommandType.method: + onIpc(PinPrCommandType, e, params => this.onPinPr(params)); + break; + case SnoozeIssueCommandType.method: + onIpc(SnoozeIssueCommandType, e, params => this.onSnoozeIssue(params)); + break; + case PinIssueCommandType.method: + onIpc(PinIssueCommandType, e, params => this.onPinIssue(params)); + break; + } + } + + private async onPinIssue({ issue, pin }: PinIssueParams) { + const issueWithRemote = this._issues?.find(r => r.issue.id === issue.id); + if (issueWithRemote == null) return; + + if (pin) { + await this.container.focus.unpinItem(issueWithRemote.issue.id); + this._enrichedItems = this._enrichedItems?.filter(e => e.id !== pin); + } else { + const focusItem: FocusItem = { + type: 'issue', + id: issueWithRemote.issue.id, + // remote: issueWithRemote.issue.remote, + }; + const enrichedItem = await this.container.focus.pinItem(focusItem); + if (enrichedItem == null) return; + if (this._enrichedItems == null) { + this._enrichedItems = []; + } + this._enrichedItems.push(enrichedItem); + } + + void this.notifyDidChangeState(); + } + + private async onSnoozeIssue({ issue, snooze }: SnoozeIssueParams) { + const issueWithRemote = this._issues?.find(r => r.issue.id === issue.id); + if (issueWithRemote == null) return; + + if (snooze) { + await this.container.focus.unsnoozeItem(snooze); + this._enrichedItems = this._enrichedItems?.filter(e => e.id !== snooze); + } else { + const focusItem: FocusItem = { + type: 'issue', + id: issueWithRemote.issue.id, + // remote: issueWithRemote.issue.remote, + }; + const enrichedItem = await this.container.focus.snoozeItem(focusItem); + if (enrichedItem == null) return; + if (this._enrichedItems == null) { + this._enrichedItems = []; + } + this._enrichedItems.push(enrichedItem); } + + void this.notifyDidChangeState(); + } + + private async onPinPr({ pullRequest, pin }: PinPrParams) { + const prWithRemote = this._pullRequests?.find(r => r.pullRequest.id === pullRequest.id); + if (prWithRemote == null) return; + + if (pin) { + await this.container.focus.unpinItem(pin); + this._enrichedItems = this._enrichedItems?.filter(e => e.id !== pin); + } else { + const focusItem: FocusItem = { + type: 'pr', + id: prWithRemote.pullRequest.id, + remote: prWithRemote.repoAndRemote.remote, + }; + const enrichedItem = await this.container.focus.pinItem(focusItem); + if (enrichedItem == null) return; + if (this._enrichedItems == null) { + this._enrichedItems = []; + } + this._enrichedItems.push(enrichedItem); + } + + void this.notifyDidChangeState(); + } + + private async onSnoozePr({ pullRequest, snooze }: SnoozePrParams) { + const prWithRemote = this._pullRequests?.find(r => r.pullRequest.id === pullRequest.id); + if (prWithRemote == null) return; + + if (snooze) { + await this.container.focus.unsnoozeItem(snooze); + this._enrichedItems = this._enrichedItems?.filter(e => e.id !== snooze); + } else { + const focusItem: FocusItem = { + type: 'pr', + id: prWithRemote.pullRequest.id, + remote: prWithRemote.repoAndRemote.remote, + }; + const enrichedItem = await this.container.focus.snoozeItem(focusItem); + if (enrichedItem == null) return; + if (this._enrichedItems == null) { + this._enrichedItems = []; + } + this._enrichedItems.push(enrichedItem); + } + + void this.notifyDidChangeState(); } private findSearchedPullRequest(pullRequest: PullRequestShape): SearchedPullRequestWithRemote | undefined { @@ -273,10 +401,11 @@ export class FocusWebviewProvider implements WebviewProvider { const statePromise = Promise.allSettled([ this.getMyPullRequests(connectedRepos), this.getMyIssues(connectedRepos), + this.getEnrichedItems(), ]); async function getStateCore() { - const [prsResult, issuesResult] = await statePromise; + const [prsResult, issuesResult, enrichedItems] = await statePromise; return { webviewId: webviewId, timestamp: Date.now(), @@ -289,10 +418,14 @@ export class FocusWebviewProvider implements WebviewProvider { isCurrentWorktree: pr.isCurrentWorktree ?? false, hasWorktree: pr.hasWorktree ?? false, hasLocalBranch: pr.hasLocalBranch ?? false, + enriched: findEnrichedItem(pr, getSettledValue(enrichedItems)), + rank: pr.rank, })), issues: getSettledValue(issuesResult)?.map(issue => ({ issue: serializeIssue(issue.issue), reasons: issue.reasons, + enriched: findEnrichedItem(issue, getSettledValue(enrichedItems)), + rank: issue.rank, })), }; } @@ -374,6 +507,7 @@ export class FocusWebviewProvider implements WebviewProvider { repoAndRemote: richRepo, isCurrentWorktree: false, isCurrentBranch: false, + rank: getPrRank(pr), }; const remoteBranchName = `${entry.pullRequest.refs!.head.owner}/${entry.pullRequest.refs!.head.branch}`; // TODO@eamodio really need to check for upstream url rather than name @@ -397,36 +531,9 @@ export class FocusWebviewProvider implements WebviewProvider { } } - function getScore(pr: SearchedPullRequest) { - let score = 0; - if (pr.reasons.includes('authored')) { - score += 1000; - } else if (pr.reasons.includes('assigned')) { - score += 900; - } else if (pr.reasons.includes('review-requested')) { - score += 800; - } else if (pr.reasons.includes('mentioned')) { - score += 700; - } - - if (pr.pullRequest.reviewDecision === PullRequestReviewDecision.Approved) { - if (pr.pullRequest.mergeableState === PullRequestMergeableState.Mergeable) { - score += 100; - } else if (pr.pullRequest.mergeableState === PullRequestMergeableState.Conflicting) { - score += 90; - } else { - score += 80; - } - } else if (pr.pullRequest.reviewDecision === PullRequestReviewDecision.ChangesRequested) { - score += 70; - } - - return score; - } - this._pullRequests = allPrs.sort((a, b) => { - const scoreA = getScore(a); - const scoreB = getScore(b); + const scoreA = a.rank; + const scoreB = b.rank; if (scoreA === scoreB) { return a.pullRequest.date.getTime() - b.pullRequest.date.getTime(); @@ -437,26 +544,113 @@ export class FocusWebviewProvider implements WebviewProvider { return this._pullRequests; } - private async getMyIssues(richRepos: RepoWithRichRemote[]): Promise { + private async getMyIssues(richRepos: RepoWithRichRemote[]): Promise { const allIssues = []; for (const { remote } of richRepos) { const issues = await this.container.git.getMyIssues(remote); if (issues == null) { continue; } - allIssues.push(...issues.filter(pr => pr.reasons.length > 0)); + + for (const issue of issues) { + if (issue.reasons.length === 0) { + continue; + } + allIssues.push({ + ...issue, + rank: 0, // getIssueRank(issue), + }); + } } + // this._issues = allIssues.sort((a, b) => { + // const scoreA = a.rank; + // const scoreB = b.rank; + + // if (scoreA === scoreB) { + // return b.issue.updatedDate.getTime() - a.issue.updatedDate.getTime(); + // } + // return (scoreB ?? 0) - (scoreA ?? 0); + // }); + this._issues = allIssues.sort((a, b) => b.issue.updatedDate.getTime() - a.issue.updatedDate.getTime()); return this._issues; } + private async getEnrichedItems(): Promise { + // TODO needs cache invalidation + if (this._enrichedItems == null) { + const enrichedItems = await this.container.focus.get(); + this._enrichedItems = enrichedItems; + } + return this._enrichedItems; + } + private async notifyDidChangeState(deferState?: boolean) { void this.host.notify(DidChangeNotificationType, { state: await this.getState(deferState) }); } } +function findEnrichedItem(item: SearchedPullRequestWithRemote | SearchedIssue, enrichedItems?: EnrichedItem[]) { + if (enrichedItems == null || enrichedItems.length === 0) return; + + let result; + // TODO: filter by entity id, type, and gitRepositoryId + if ((item as SearchedPullRequestWithRemote).pullRequest != null) { + result = enrichedItems.find(e => e.entityId === (item as SearchedPullRequestWithRemote).pullRequest.id); + } else { + result = enrichedItems.find(e => e.entityId === (item as SearchedIssue).issue.id); + } + + if (result == null) return; + + return { + id: result.id, + type: result.type, + }; +} + +function getPrRank(pr: SearchedPullRequest) { + let score = 0; + if (pr.reasons.includes('authored')) { + score += 1000; + } else if (pr.reasons.includes('assigned')) { + score += 900; + } else if (pr.reasons.includes('review-requested')) { + score += 800; + } else if (pr.reasons.includes('mentioned')) { + score += 700; + } + + if (pr.pullRequest.reviewDecision === PullRequestReviewDecision.Approved) { + if (pr.pullRequest.mergeableState === PullRequestMergeableState.Mergeable) { + score += 100; + } else if (pr.pullRequest.mergeableState === PullRequestMergeableState.Conflicting) { + score += 90; + } else { + score += 80; + } + } else if (pr.pullRequest.reviewDecision === PullRequestReviewDecision.ChangesRequested) { + score += 70; + } + + return score; +} + +// function getIssueRank(issue: SearchedIssue) { +// let score = 0; +// if (issue.reasons.includes('authored')) { +// score += 1000; +// } else if (issue.reasons.includes('assigned')) { +// score += 900; +// } else if (issue.reasons.includes('mentioned')) { +// score += 700; +// } + +// return score; +// } + function filterGithubRepos(list: RepoWithRichRemote[]): RepoWithRichRemote[] { return list.filter(entry => entry.isGitHub); } diff --git a/src/plus/webviews/focus/protocol.ts b/src/plus/webviews/focus/protocol.ts index df1063e2e28b3..f422ec9c2af04 100644 --- a/src/plus/webviews/focus/protocol.ts +++ b/src/plus/webviews/focus/protocol.ts @@ -3,6 +3,7 @@ import type { FeatureAccess } from '../../../features'; import type { IssueShape } from '../../../git/models/issue'; import type { PullRequestShape } from '../../../git/models/pullRequest'; import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol'; +import type { EnrichedItem } from '../../focus/focusService'; export interface State { webviewId: WebviewIds | WebviewViewIds; @@ -16,6 +17,12 @@ export interface State { export interface SearchResultBase { reasons: string[]; + rank?: number; + // TODO: convert to array of EnrichedItem + enriched?: { + id: EnrichedItem['id']; + type: EnrichedItem['type']; + }; } export interface IssueResult extends SearchResultBase { @@ -53,6 +60,30 @@ export interface SwitchToBranchParams { } export const SwitchToBranchCommandType = new IpcCommandType('focus/pr/switchToBranch'); +export interface SnoozePrParams { + pullRequest: PullRequestShape; + snooze?: string; +} +export const SnoozePrCommandType = new IpcCommandType('focus/pr/snooze'); + +export interface PinPrParams { + pullRequest: PullRequestShape; + pin?: string; +} +export const PinPrCommandType = new IpcCommandType('focus/pr/pin'); + +export interface SnoozeIssueParams { + issue: IssueShape; + snooze?: string; +} +export const SnoozeIssueCommandType = new IpcCommandType('focus/issue/snooze'); + +export interface PinIssueParams { + issue: IssueShape; + pin?: string; +} +export const PinIssueCommandType = new IpcCommandType('focus/issue/pin'); + // Notifications export interface DidChangeParams { diff --git a/src/webviews/apps/plus/focus/components/focus-app.ts b/src/webviews/apps/plus/focus/components/focus-app.ts index 93996d09715f1..9adce0f9085cd 100644 --- a/src/webviews/apps/plus/focus/components/focus-app.ts +++ b/src/webviews/apps/plus/focus/components/focus-app.ts @@ -28,11 +28,12 @@ import './gk-issue-row'; @customElement('gl-focus-app') export class GlFocusApp extends LitElement { static override styles = [themeProperties]; - private readonly tabFilters = ['prs', 'issues']; + private readonly tabFilters = ['prs', 'issues', 'snoozed']; private readonly tabFilterOptions = [ { label: 'All', value: '' }, { label: 'PRs', value: 'prs' }, { label: 'Issues', value: 'issues' }, + { label: 'Later', value: 'snoozed' }, ]; private readonly mineFilters = ['authored', 'assigned', 'review-requested', 'mentioned']; private readonly mineFilterOptions = [ @@ -98,11 +99,30 @@ export class GlFocusApp extends LitElement { return []; } - const items: { isPullrequest: boolean; rank: number; state: Record; tags: string[] }[] = []; + const items: { + isPullrequest: boolean; + rank: number; + state: Record; + tags: string[]; + isPinned: boolean; + isSnoozed: boolean; + enrichedId?: string; + }[] = []; - let rank = 0; this.state?.pullRequests?.forEach( - ({ pullRequest, reasons, isCurrentBranch, isCurrentWorktree, hasWorktree, hasLocalBranch }) => { + ({ + pullRequest, + reasons, + isCurrentBranch, + isCurrentWorktree, + hasWorktree, + hasLocalBranch, + rank, + enriched, + }) => { + const isPinned = enriched?.type === 'pin'; + const isSnoozed = enriched?.type === 'snooze'; + items.push({ isPullrequest: true, state: { @@ -112,19 +132,28 @@ export class GlFocusApp extends LitElement { hasWorktree: hasWorktree, hasLocalBranch: hasLocalBranch, }, - rank: ++rank, + rank: rank ?? 0, tags: reasons, + isPinned: isPinned, + isSnoozed: isSnoozed, + enrichedId: enriched?.id, }); }, ); - this.state?.issues?.forEach(({ issue, reasons }) => { + this.state?.issues?.forEach(({ issue, reasons, rank, enriched }) => { + const isPinned = enriched?.type === 'pin'; + const isSnoozed = enriched?.type === 'snooze'; + items.push({ isPullrequest: false, - rank: ++rank, + rank: rank ?? 0, state: { issue: issue, }, tags: reasons, + isPinned: isPinned, + isSnoozed: isSnoozed, + enrichedId: enriched?.id, }); }); @@ -135,8 +164,8 @@ export class GlFocusApp extends LitElement { const counts: Record = {}; this.tabFilters.forEach(f => (counts[f] = 0)); - this.items.forEach(({ isPullrequest }) => { - const key = isPullrequest ? 'prs' : 'issues'; + this.items.forEach(({ isPullrequest, isSnoozed }) => { + const key = isSnoozed ? 'snoozed' : isPullrequest ? 'prs' : 'issues'; if (counts[key] != null) { counts[key]++; } @@ -190,6 +219,15 @@ export class GlFocusApp extends LitElement { }); } + get sortedItems() { + return this.filteredItems.sort((a, b) => { + if (a.isPinned === b.isPinned) { + return a.rank - b.rank; + } + return a.isPinned ? -1 : 1; + }); + } + get isLoading() { return this.state?.pullRequests == null || this.state?.issues == null; } @@ -207,7 +245,7 @@ export class GlFocusApp extends LitElement { return this.loadingContent(); } - if (this.filteredItems.length === 0) { + if (this.sortedItems.length === 0) { return html`
None found @@ -217,9 +255,12 @@ export class GlFocusApp extends LitElement { return html` ${repeat( - this.filteredItems, - item => item.rank, - ({ isPullrequest, rank, state }) => + this.sortedItems, + (item, i) => + `item-${i}-${ + item.isPullrequest ? `pr-${item.state.pullRequest.id}` : `issue-${item.state.issue.id}` + }`, + ({ isPullrequest, rank, state, isPinned, isSnoozed }) => when( isPullrequest, () => @@ -230,8 +271,18 @@ export class GlFocusApp extends LitElement { .isCurrentWorktree=${state.isCurrentWorktree} .hasWorktree=${state.hasWorktree} .hasLocalBranch=${state.hasLocalBranch} + .pinned=${isPinned} + .snoozed=${isSnoozed} + .enrichedId=${state.enrichedId} >`, - () => html``, + () => + html``, ), )} `; @@ -341,6 +392,9 @@ export class GlFocusApp extends LitElement {
+ + + Repo / Branch diff --git a/src/webviews/apps/plus/focus/components/gk-issue-row.ts b/src/webviews/apps/plus/focus/components/gk-issue-row.ts index a88e87a18a956..ddf3a00fefd6d 100644 --- a/src/webviews/apps/plus/focus/components/gk-issue-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-issue-row.ts @@ -90,6 +90,21 @@ export class GkIssueRow extends LitElement { display: inline-block; min-width: 1.6rem; } + + .pin { + opacity: 0.4; + } + .pin:hover { + opacity: 0.64; + } + + gk-focus-row:not(:hover):not(:focus-within) .pin:not(.is-active) { + opacity: 0; + } + + .pin.is-active { + opacity: 1; + } `, ]; @@ -99,6 +114,15 @@ export class GkIssueRow extends LitElement { @property({ type: Object }) public issue?: IssueShape; + @property({ type: Boolean }) + public pinned = false; + + @property({ type: Boolean }) + public snoozed = false; + + @property({ attribute: 'enriched-id' }) + public enrichedId?: string; + constructor() { super(); @@ -132,6 +156,26 @@ export class GkIssueRow extends LitElement { return html` + + + + Pin + + + + Mark for Later + +

@@ -199,4 +243,20 @@ export class GkIssueRow extends LitElement { `; } + + onSnoozeClick(_e: Event) { + this.dispatchEvent( + new CustomEvent('snooze-item', { + detail: { item: this.issue!, snooze: this.snoozed ? this.enrichedId : undefined }, + }), + ); + } + + onPinClick(_e: Event) { + this.dispatchEvent( + new CustomEvent('pin-item', { + detail: { item: this.issue!, pin: this.pinned ? this.enrichedId : undefined }, + }), + ); + } } diff --git a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts index 6c99cfbda5b6c..483ffb9dea6ba 100644 --- a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts @@ -97,7 +97,7 @@ export class GkPullRequestRow extends LitElement { .row-type { --gk-badge-outline-padding: 0.3rem 0.8rem; --gk-badge-font-size: 1.1rem; - opacity: 0.5; + opacity: 0.4; vertical-align: middle; } @@ -119,6 +119,21 @@ export class GkPullRequestRow extends LitElement { display: inline-block; min-width: 1.6rem; } + + .pin { + opacity: 0.4; + } + .pin:hover { + opacity: 0.64; + } + + gk-focus-row:not(:hover):not(:focus-within) .pin:not(.is-active) { + opacity: 0; + } + + .pin.is-active { + opacity: 1; + } `, ]; @@ -140,6 +155,15 @@ export class GkPullRequestRow extends LitElement { @property({ type: Boolean }) public hasLocalBranch = false; + @property({ type: Boolean }) + public pinned = false; + + @property({ type: Boolean }) + public snoozed = false; + + @property({ attribute: 'enriched-id' }) + public enrichedId?: string; + constructor() { super(); @@ -196,6 +220,26 @@ export class GkPullRequestRow extends LitElement { return html` + + + + ${this.pinned ? 'Unpinned' : 'Pin'} + + + + ${this.snoozed ? 'Watch' : 'Mark for Later'} + + ${when( this.indicator === 'changes', @@ -347,4 +391,20 @@ export class GkPullRequestRow extends LitElement { } this.dispatchEvent(new CustomEvent('switch-branch', { detail: this.pullRequest! })); } + + onSnoozeClick(_e: Event) { + this.dispatchEvent( + new CustomEvent('snooze-item', { + detail: { item: this.pullRequest!, snooze: this.snoozed ? this.enrichedId : undefined }, + }), + ); + } + + onPinClick(_e: Event) { + this.dispatchEvent( + new CustomEvent('pin-item', { + detail: { item: this.pullRequest!, pin: this.pinned ? this.enrichedId : undefined }, + }), + ); + } } diff --git a/src/webviews/apps/plus/focus/focus.ts b/src/webviews/apps/plus/focus/focus.ts index 65cefbac668d6..dbe34377a7038 100644 --- a/src/webviews/apps/plus/focus/focus.ts +++ b/src/webviews/apps/plus/focus/focus.ts @@ -1,9 +1,14 @@ +import type { IssueShape } from '../../../../git/models/issue'; import type { PullRequestShape } from '../../../../git/models/pullRequest'; import type { State } from '../../../../plus/webviews/focus/protocol'; import { DidChangeNotificationType, OpenBranchCommandType, OpenWorktreeCommandType, + PinIssueCommandType, + PinPrCommandType, + SnoozeIssueCommandType, + SnoozePrCommandType, SwitchToBranchCommandType, } from '../../../../plus/webviews/focus/protocol'; import type { IpcMessage } from '../../../protocol'; @@ -11,6 +16,7 @@ import { onIpc } from '../../../protocol'; import { App } from '../../shared/appBase'; import { DOM } from '../../shared/dom'; import type { GlFocusApp } from './components/focus-app'; +import type { GkIssueRow } from './components/gk-issue-row'; import type { GkPullRequestRow } from './components/gk-pull-request-row'; import './components/focus-app'; import './focus.scss'; @@ -41,6 +47,26 @@ export class FocusApp extends App { 'switch-branch', (e, target: HTMLElement) => this.onSwitchBranch(e, target), ), + DOM.on( + 'gk-pull-request-row', + 'snooze-item', + (e, _target: HTMLElement) => this.onSnoozeItem(e, false), + ), + DOM.on( + 'gk-pull-request-row', + 'pin-item', + (e, _target: HTMLElement) => this.onPinItem(e, false), + ), + DOM.on( + 'gk-issue-row', + 'snooze-item', + (e, _target: HTMLElement) => this.onSnoozeItem(e, true), + ), + DOM.on( + 'gk-issue-row', + 'pin-item', + (e, _target: HTMLElement) => this.onPinItem(e, true), + ), ); return disposables; @@ -73,6 +99,25 @@ export class FocusApp extends App { this.sendCommand(OpenWorktreeCommandType, { pullRequest: e.detail }); } + private onSnoozeItem(e: CustomEvent<{ item: PullRequestShape | IssueShape; snooze?: string }>, isIssue: boolean) { + if (isIssue) { + this.sendCommand(SnoozeIssueCommandType, { issue: e.detail.item as IssueShape, snooze: e.detail.snooze }); + } else { + this.sendCommand(SnoozePrCommandType, { + pullRequest: e.detail.item as PullRequestShape, + snooze: e.detail.snooze, + }); + } + } + + private onPinItem(e: CustomEvent<{ item: PullRequestShape | IssueShape; pin?: string }>, isIssue: boolean) { + if (isIssue) { + this.sendCommand(PinIssueCommandType, { issue: e.detail.item as IssueShape, pin: e.detail.pin }); + } else { + this.sendCommand(PinPrCommandType, { pullRequest: e.detail.item as PullRequestShape, pin: e.detail.pin }); + } + } + protected override onMessageReceived(e: MessageEvent) { const msg = e.data as IpcMessage; this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); diff --git a/yarn.lock b/yarn.lock index a865f3d2c1b57..cfefe9c82cc60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -237,7 +237,7 @@ react-dragula "1.1.17" react-onclickoutside "^6.13.0" -"@gitkraken/shared-web-components@^0.1.1-rc.6": +"@gitkraken/shared-web-components@^0.1.1-rc.9": version "0.1.1-rc.10" resolved "https://registry.yarnpkg.com/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.10.tgz#bed7021a0e6912ae3196e06078169950f0616bed" integrity sha512-2GoM9Gg473zbtTL5u5YTiDeU8mzACj2hMQBk+7iruiiVoJLGxvi1bT95MyXHakhv4zk4lI5OVWP6TU4ZAaoDLQ== From 63770851f498015f9d3d5c5542d04aeb02b01398 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 11 Sep 2023 17:33:57 -0400 Subject: [PATCH 0008/1012] Updates focus enrichment types --- src/plus/webviews/focus/focusWebview.ts | 16 +++++---- src/plus/webviews/focus/protocol.ts | 2 +- .../apps/plus/focus/components/focus-app.ts | 35 ++++++++++--------- .../plus/focus/components/gk-issue-row.ts | 11 +++--- .../focus/components/gk-pull-request-row.ts | 15 ++++---- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 7156de3db6207..dc5378ebd823b 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -418,13 +418,13 @@ export class FocusWebviewProvider implements WebviewProvider { isCurrentWorktree: pr.isCurrentWorktree ?? false, hasWorktree: pr.hasWorktree ?? false, hasLocalBranch: pr.hasLocalBranch ?? false, - enriched: findEnrichedItem(pr, getSettledValue(enrichedItems)), + enriched: findEnrichedItems(pr, getSettledValue(enrichedItems)), rank: pr.rank, })), issues: getSettledValue(issuesResult)?.map(issue => ({ issue: serializeIssue(issue.issue), reasons: issue.reasons, - enriched: findEnrichedItem(issue, getSettledValue(enrichedItems)), + enriched: findEnrichedItems(issue, getSettledValue(enrichedItems)), rank: issue.rank, })), }; @@ -592,7 +592,7 @@ export class FocusWebviewProvider implements WebviewProvider { } } -function findEnrichedItem(item: SearchedPullRequestWithRemote | SearchedIssue, enrichedItems?: EnrichedItem[]) { +function findEnrichedItems(item: SearchedPullRequestWithRemote | SearchedIssue, enrichedItems?: EnrichedItem[]) { if (enrichedItems == null || enrichedItems.length === 0) return; let result; @@ -605,10 +605,12 @@ function findEnrichedItem(item: SearchedPullRequestWithRemote | SearchedIssue, e if (result == null) return; - return { - id: result.id, - type: result.type, - }; + return [ + { + id: result.id, + type: result.type, + }, + ]; } function getPrRank(pr: SearchedPullRequest) { diff --git a/src/plus/webviews/focus/protocol.ts b/src/plus/webviews/focus/protocol.ts index f422ec9c2af04..956e2c40bbb80 100644 --- a/src/plus/webviews/focus/protocol.ts +++ b/src/plus/webviews/focus/protocol.ts @@ -22,7 +22,7 @@ export interface SearchResultBase { enriched?: { id: EnrichedItem['id']; type: EnrichedItem['type']; - }; + }[]; } export interface IssueResult extends SearchResultBase { diff --git a/src/webviews/apps/plus/focus/components/focus-app.ts b/src/webviews/apps/plus/focus/components/focus-app.ts index 9adce0f9085cd..d75b95ae74932 100644 --- a/src/webviews/apps/plus/focus/components/focus-app.ts +++ b/src/webviews/apps/plus/focus/components/focus-app.ts @@ -104,9 +104,8 @@ export class GlFocusApp extends LitElement { rank: number; state: Record; tags: string[]; - isPinned: boolean; - isSnoozed: boolean; - enrichedId?: string; + isPinned?: string; + isSnoozed?: string; }[] = []; this.state?.pullRequests?.forEach( @@ -120,8 +119,8 @@ export class GlFocusApp extends LitElement { rank, enriched, }) => { - const isPinned = enriched?.type === 'pin'; - const isSnoozed = enriched?.type === 'snooze'; + const isPinned = enriched?.find(item => item.type === 'pin')?.id; + const isSnoozed = enriched?.find(item => item.type === 'snooze')?.id; items.push({ isPullrequest: true, @@ -136,13 +135,12 @@ export class GlFocusApp extends LitElement { tags: reasons, isPinned: isPinned, isSnoozed: isSnoozed, - enrichedId: enriched?.id, }); }, ); this.state?.issues?.forEach(({ issue, reasons, rank, enriched }) => { - const isPinned = enriched?.type === 'pin'; - const isSnoozed = enriched?.type === 'snooze'; + const isPinned = enriched?.find(item => item.type === 'pin')?.id; + const isSnoozed = enriched?.find(item => item.type === 'snooze')?.id; items.push({ isPullrequest: false, @@ -153,7 +151,6 @@ export class GlFocusApp extends LitElement { tags: reasons, isPinned: isPinned, isSnoozed: isSnoozed, - enrichedId: enriched?.id, }); }); @@ -188,16 +185,21 @@ export class GlFocusApp extends LitElement { const hasMineFilter = this.selectedMineFilter != null && this.selectedMineFilter !== ''; const hasTabFilter = this.selectedTabFilter != null && this.selectedTabFilter !== ''; if (!hasSearch && !hasMineFilter && !hasTabFilter) { - return this.items; + return this.items.filter(i => i.isSnoozed == null); } const searchText = this.searchText?.toLowerCase(); return this.items.filter(i => { - if ( - hasTabFilter && - ((i.isPullrequest === true && this.selectedTabFilter === 'issues') || - (i.isPullrequest === false && this.selectedTabFilter === 'prs')) - ) { + if (hasTabFilter) { + if ( + (i.isSnoozed != null && this.selectedTabFilter !== 'snoozed') || + (i.isSnoozed == null && this.selectedTabFilter == 'snoozed') || + (i.isPullrequest === true && this.selectedTabFilter === 'issues') || + (i.isPullrequest === false && this.selectedTabFilter === 'prs') + ) { + return false; + } + } else if (i.isSnoozed != null) { return false; } @@ -222,7 +224,8 @@ export class GlFocusApp extends LitElement { get sortedItems() { return this.filteredItems.sort((a, b) => { if (a.isPinned === b.isPinned) { - return a.rank - b.rank; + return 0; + // return a.rank - b.rank; } return a.isPinned ? -1 : 1; }); diff --git a/src/webviews/apps/plus/focus/components/gk-issue-row.ts b/src/webviews/apps/plus/focus/components/gk-issue-row.ts index ddf3a00fefd6d..30ab7ab902e8a 100644 --- a/src/webviews/apps/plus/focus/components/gk-issue-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-issue-row.ts @@ -114,15 +114,12 @@ export class GkIssueRow extends LitElement { @property({ type: Object }) public issue?: IssueShape; - @property({ type: Boolean }) + @property() public pinned = false; - @property({ type: Boolean }) + @property() public snoozed = false; - @property({ attribute: 'enriched-id' }) - public enrichedId?: string; - constructor() { super(); @@ -247,7 +244,7 @@ export class GkIssueRow extends LitElement { onSnoozeClick(_e: Event) { this.dispatchEvent( new CustomEvent('snooze-item', { - detail: { item: this.issue!, snooze: this.snoozed ? this.enrichedId : undefined }, + detail: { item: this.issue!, snooze: this.snoozed }, }), ); } @@ -255,7 +252,7 @@ export class GkIssueRow extends LitElement { onPinClick(_e: Event) { this.dispatchEvent( new CustomEvent('pin-item', { - detail: { item: this.issue!, pin: this.pinned ? this.enrichedId : undefined }, + detail: { item: this.issue!, pin: this.pinned }, }), ); } diff --git a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts index 483ffb9dea6ba..2705e63841b72 100644 --- a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts @@ -155,14 +155,11 @@ export class GkPullRequestRow extends LitElement { @property({ type: Boolean }) public hasLocalBranch = false; - @property({ type: Boolean }) - public pinned = false; - - @property({ type: Boolean }) - public snoozed = false; + @property() + public pinned?: string; - @property({ attribute: 'enriched-id' }) - public enrichedId?: string; + @property() + public snoozed?: string; constructor() { super(); @@ -395,7 +392,7 @@ export class GkPullRequestRow extends LitElement { onSnoozeClick(_e: Event) { this.dispatchEvent( new CustomEvent('snooze-item', { - detail: { item: this.pullRequest!, snooze: this.snoozed ? this.enrichedId : undefined }, + detail: { item: this.pullRequest!, snooze: this.snoozed }, }), ); } @@ -403,7 +400,7 @@ export class GkPullRequestRow extends LitElement { onPinClick(_e: Event) { this.dispatchEvent( new CustomEvent('pin-item', { - detail: { item: this.pullRequest!, pin: this.pinned ? this.enrichedId : undefined }, + detail: { item: this.pullRequest!, pin: this.pinned }, }), ); } From 985a511633aaf234195d4b55500c1a1aa52af7df Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 11 Sep 2023 17:51:22 -0400 Subject: [PATCH 0009/1012] Updates multiple enrichment items --- src/plus/webviews/focus/focusWebview.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index dc5378ebd823b..52e94e0e15ef2 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -598,19 +598,19 @@ function findEnrichedItems(item: SearchedPullRequestWithRemote | SearchedIssue, let result; // TODO: filter by entity id, type, and gitRepositoryId if ((item as SearchedPullRequestWithRemote).pullRequest != null) { - result = enrichedItems.find(e => e.entityId === (item as SearchedPullRequestWithRemote).pullRequest.id); + result = enrichedItems.filter(e => e.entityId === (item as SearchedPullRequestWithRemote).pullRequest.id); } else { - result = enrichedItems.find(e => e.entityId === (item as SearchedIssue).issue.id); + result = enrichedItems.filter(e => e.entityId === (item as SearchedIssue).issue.id); } - if (result == null) return; + if (result.length === 0) return; - return [ - { + return result.map(result => { + return { id: result.id, type: result.type, - }, - ]; + }; + }); } function getPrRank(pr: SearchedPullRequest) { From 7b3376812904ce049c04856fdc2ab17a2de0381a Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 11 Sep 2023 18:17:55 -0400 Subject: [PATCH 0010/1012] Updates remote info for enriching issues --- src/plus/focus/focusService.ts | 18 +++++------ src/plus/webviews/focus/focusWebview.ts | 40 +++++++++++++++++++++---- src/plus/webviews/focus/protocol.ts | 11 +++---- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index 8ea0725bfe94d..fe9eacc385b55 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -10,7 +10,7 @@ import type { ServerConnection } from '../gk/serverConnection'; export interface FocusItem { type: EnrichedItemResponse['entityType']; id: string; - remote?: GitRemote; + remote: GitRemote; } export type EnrichedItem = { @@ -138,13 +138,13 @@ export class FocusService implements Disposable { type Result = { data: EnrichedItemResponse }; const rq: EnrichedItemRequest = { - provider: item.remote!.provider.id as EnrichedItemResponse['provider'], + provider: item.remote.provider.id as EnrichedItemResponse['provider'], entityType: item.type, entityId: item.id, gitRepoData: { - remoteUrl: item.remote!.url, - remotePath: item.remote!.provider.path, - remoteDomain: item.remote!.provider.domain, + remoteUrl: item.remote.url, + remotePath: item.remote.provider.path, + remoteDomain: item.remote.provider.domain, }, }; @@ -181,13 +181,13 @@ export class FocusService implements Disposable { type Result = { data: EnrichedItemResponse }; const rq: EnrichedItemRequest = { - provider: item.remote!.provider.id as EnrichedItemResponse['provider'], + provider: item.remote.provider.id as EnrichedItemResponse['provider'], entityType: item.type, entityId: item.id, gitRepoData: { - remoteUrl: item.remote!.url, - remotePath: item.remote!.provider.path, - remoteDomain: item.remote!.provider.domain, + remoteUrl: item.remote.url, + remotePath: item.remote.provider.path, + remoteDomain: item.remote.provider.domain, }, }; diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 52e94e0e15ef2..e03e0a6d664bd 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -66,10 +66,13 @@ interface SearchedPullRequestWithRemote extends SearchedPullRequest { hasWorktree?: boolean; isCurrentWorktree?: boolean; rank: number; + enriched?: EnrichedItem[]; } interface SearchedIssueWithRank extends SearchedIssue { + repoAndRemote: RepoWithRichRemote; rank: number; + enriched?: EnrichedItem[]; } export class FocusWebviewProvider implements WebviewProvider { @@ -132,11 +135,12 @@ export class FocusWebviewProvider implements WebviewProvider { if (pin) { await this.container.focus.unpinItem(issueWithRemote.issue.id); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== pin); + issueWithRemote.enriched = issueWithRemote.enriched?.filter(e => e.id !== pin); } else { const focusItem: FocusItem = { type: 'issue', id: issueWithRemote.issue.id, - // remote: issueWithRemote.issue.remote, + remote: issueWithRemote.repoAndRemote.remote, }; const enrichedItem = await this.container.focus.pinItem(focusItem); if (enrichedItem == null) return; @@ -144,6 +148,10 @@ export class FocusWebviewProvider implements WebviewProvider { this._enrichedItems = []; } this._enrichedItems.push(enrichedItem); + if (issueWithRemote.enriched == null) { + issueWithRemote.enriched = []; + } + issueWithRemote.enriched.push(enrichedItem); } void this.notifyDidChangeState(); @@ -156,11 +164,12 @@ export class FocusWebviewProvider implements WebviewProvider { if (snooze) { await this.container.focus.unsnoozeItem(snooze); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== snooze); + issueWithRemote.enriched = issueWithRemote.enriched?.filter(e => e.id !== snooze); } else { const focusItem: FocusItem = { type: 'issue', id: issueWithRemote.issue.id, - // remote: issueWithRemote.issue.remote, + remote: issueWithRemote.repoAndRemote.remote, }; const enrichedItem = await this.container.focus.snoozeItem(focusItem); if (enrichedItem == null) return; @@ -168,6 +177,10 @@ export class FocusWebviewProvider implements WebviewProvider { this._enrichedItems = []; } this._enrichedItems.push(enrichedItem); + if (issueWithRemote.enriched == null) { + issueWithRemote.enriched = []; + } + issueWithRemote.enriched.push(enrichedItem); } void this.notifyDidChangeState(); @@ -180,6 +193,7 @@ export class FocusWebviewProvider implements WebviewProvider { if (pin) { await this.container.focus.unpinItem(pin); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== pin); + prWithRemote.enriched = prWithRemote.enriched?.filter(e => e.id !== pin); } else { const focusItem: FocusItem = { type: 'pr', @@ -192,6 +206,10 @@ export class FocusWebviewProvider implements WebviewProvider { this._enrichedItems = []; } this._enrichedItems.push(enrichedItem); + if (prWithRemote.enriched == null) { + prWithRemote.enriched = []; + } + prWithRemote.enriched.push(enrichedItem); } void this.notifyDidChangeState(); @@ -204,6 +222,7 @@ export class FocusWebviewProvider implements WebviewProvider { if (snooze) { await this.container.focus.unsnoozeItem(snooze); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== snooze); + prWithRemote.enriched = prWithRemote.enriched?.filter(e => e.id !== snooze); } else { const focusItem: FocusItem = { type: 'pr', @@ -216,6 +235,10 @@ export class FocusWebviewProvider implements WebviewProvider { this._enrichedItems = []; } this._enrichedItems.push(enrichedItem); + if (prWithRemote.enriched == null) { + prWithRemote.enriched = []; + } + prWithRemote.enriched.push(enrichedItem); } void this.notifyDidChangeState(); @@ -546,7 +569,8 @@ export class FocusWebviewProvider implements WebviewProvider { private async getMyIssues(richRepos: RepoWithRichRemote[]): Promise { const allIssues = []; - for (const { remote } of richRepos) { + for (const richRepo of richRepos) { + const remote = richRepo.remote; const issues = await this.container.git.getMyIssues(remote); if (issues == null) { continue; @@ -558,6 +582,7 @@ export class FocusWebviewProvider implements WebviewProvider { } allIssues.push({ ...issue, + repoAndRemote: richRepo, rank: 0, // getIssueRank(issue), }); } @@ -592,7 +617,10 @@ export class FocusWebviewProvider implements WebviewProvider { } } -function findEnrichedItems(item: SearchedPullRequestWithRemote | SearchedIssue, enrichedItems?: EnrichedItem[]) { +function findEnrichedItems( + item: SearchedPullRequestWithRemote | SearchedIssueWithRank, + enrichedItems?: EnrichedItem[], +) { if (enrichedItems == null || enrichedItems.length === 0) return; let result; @@ -600,11 +628,13 @@ function findEnrichedItems(item: SearchedPullRequestWithRemote | SearchedIssue, if ((item as SearchedPullRequestWithRemote).pullRequest != null) { result = enrichedItems.filter(e => e.entityId === (item as SearchedPullRequestWithRemote).pullRequest.id); } else { - result = enrichedItems.filter(e => e.entityId === (item as SearchedIssue).issue.id); + result = enrichedItems.filter(e => e.entityId === (item as SearchedIssueWithRank).issue.id); } if (result.length === 0) return; + item.enriched = result; + return result.map(result => { return { id: result.id, diff --git a/src/plus/webviews/focus/protocol.ts b/src/plus/webviews/focus/protocol.ts index 956e2c40bbb80..f40778ce4eb5b 100644 --- a/src/plus/webviews/focus/protocol.ts +++ b/src/plus/webviews/focus/protocol.ts @@ -18,11 +18,12 @@ export interface State { export interface SearchResultBase { reasons: string[]; rank?: number; - // TODO: convert to array of EnrichedItem - enriched?: { - id: EnrichedItem['id']; - type: EnrichedItem['type']; - }[]; + enriched?: EnrichedItemSummary[]; +} + +export interface EnrichedItemSummary { + id: EnrichedItem['id']; + type: EnrichedItem['type']; } export interface IssueResult extends SearchResultBase { From 1d1a189b9175924da4b2d6f37af3168f45b6344a Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Tue, 12 Sep 2023 12:14:37 -0400 Subject: [PATCH 0011/1012] Updates pin snooze action styles --- .../apps/plus/focus/components/common.css.ts | 123 ++++++++++++++ .../plus/focus/components/gk-issue-row.ts | 118 +++---------- .../focus/components/gk-pull-request-row.ts | 158 ++++-------------- src/webviews/apps/plus/focus/focus.scss | 1 + 4 files changed, 171 insertions(+), 229 deletions(-) create mode 100644 src/webviews/apps/plus/focus/components/common.css.ts diff --git a/src/webviews/apps/plus/focus/components/common.css.ts b/src/webviews/apps/plus/focus/components/common.css.ts new file mode 100644 index 0000000000000..9e085829f1801 --- /dev/null +++ b/src/webviews/apps/plus/focus/components/common.css.ts @@ -0,0 +1,123 @@ +import { css } from 'lit'; + +export const rowBaseStyles = css` + :host { + display: block; + } + + p { + margin: 0; + } + + a { + color: var(--vscode-textLink-foreground); + text-decoration: none; + } + a:hover { + text-decoration: underline; + } + a:focus { + outline: 1px solid var(--vscode-focusBorder); + outline-offset: -1px; + } + + .actions gk-tooltip { + display: inline-block; + } + + .actions a { + box-sizing: border-box; + display: inline-flex; + justify-content: center; + align-items: center; + width: 3.2rem; + height: 3.2rem; + border-radius: 0.5rem; + color: inherit; + padding: 0.2rem; + vertical-align: text-bottom; + text-decoration: none; + cursor: pointer; + } + .actions a:hover { + background-color: var(--vscode-toolbar-hoverBackground); + } + .actions a:active { + background-color: var(--vscode-toolbar-activeBackground); + } + .actions a[tabindex='-1'] { + opacity: 0.5; + cursor: default; + } + + .actions a code-icon { + font-size: 1.6rem; + } + + .indicator-info { + color: var(--vscode-problemsInfoIcon-foreground); + } + .indicator-warning { + color: var(--vscode-problemsWarningIcon-foreground); + } + .indicator-error { + color: var(--vscode-problemsErrorIcon-foreground); + } + .indicator-neutral { + color: var(--color-alert-neutralBorder); + } + + .row-type { + --gk-badge-outline-padding: 0.3rem 0.8rem; + --gk-badge-font-size: 1.1rem; + opacity: 0.4; + vertical-align: middle; + } + + .title { + font-size: 1.4rem; + } + + .add-delete { + margin-left: 0.4rem; + margin-right: 0.2rem; + } + + .key { + z-index: 1; + position: relative; + } + + .date { + display: inline-block; + min-width: 1.6rem; + } + + .icon { + box-sizing: border-box; + display: inline-flex; + justify-content: center; + align-items: center; + width: 2.4rem; + height: 2.4rem; + } + + .pin { + color: inherit; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + } + .pin:hover { + opacity: 0.64; + text-decoration: none; + } + + gk-focus-row:not(:hover):not(:focus-within) .pin:not(.is-active) { + opacity: 0; + } + + .pin.is-active { + opacity: 1; + } +`; diff --git a/src/webviews/apps/plus/focus/components/gk-issue-row.ts b/src/webviews/apps/plus/focus/components/gk-issue-row.ts index 30ab7ab902e8a..e451f84d68ec5 100644 --- a/src/webviews/apps/plus/focus/components/gk-issue-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-issue-row.ts @@ -15,98 +15,14 @@ import { when } from 'lit/directives/when.js'; import type { IssueMember, IssueShape } from '../../../../../git/models/issue'; import { elementBase } from '../../../shared/components/styles/lit/base.css'; import { repoBranchStyles } from './branch-tag.css'; +import { rowBaseStyles } from './common.css'; import { dateAgeStyles } from './date-styles.css'; import { themeProperties } from './gk-theme.css'; import { fromDateRange } from './helpers'; @customElement('gk-issue-row') export class GkIssueRow extends LitElement { - static override styles = [ - themeProperties, - elementBase, - dateAgeStyles, - repoBranchStyles, - css` - :host { - display: block; - } - - p { - margin: 0; - } - - a { - color: var(--vscode-textLink-foreground); - text-decoration: none; - } - a:hover { - text-decoration: underline; - } - a:focus { - outline: 1px solid var(--vscode-focusBorder); - outline-offset: -1px; - } - - .actions { - } - - .actions a { - box-sizing: border-box; - display: inline-flex; - justify-content: center; - align-items: center; - width: 3.2rem; - height: 3.2rem; - border-radius: 0.5rem; - color: inherit; - padding: 0.2rem; - vertical-align: text-bottom; - text-decoration: none; - cursor: pointer; - } - .actions a:hover { - background-color: var(--vscode-toolbar-hoverBackground); - } - .actions a:active { - background-color: var(--vscode-toolbar-activeBackground); - } - - .actions a code-icon { - font-size: 1.6rem; - } - - .row-type { - --gk-badge-outline-padding: 0.3rem 0.8rem; - --gk-badge-font-size: 1.1rem; - opacity: 0.5; - vertical-align: middle; - } - - .title { - font-size: 1.4rem; - } - - .date { - display: inline-block; - min-width: 1.6rem; - } - - .pin { - opacity: 0.4; - } - .pin:hover { - opacity: 0.64; - } - - gk-focus-row:not(:hover):not(:focus-within) .pin:not(.is-active) { - opacity: 0; - } - - .pin.is-active { - opacity: 1; - } - `, - ]; + static override styles = [themeProperties, elementBase, dateAgeStyles, repoBranchStyles, rowBaseStyles, css``]; @property({ type: Number }) public rank?: number; @@ -155,24 +71,29 @@ export class GkIssueRow extends LitElement { - + > Pin - + > Mark for Later + + +

@@ -221,9 +142,6 @@ export class GkIssueRow extends LitElement { )} - - -

@@ -241,7 +159,8 @@ export class GkIssueRow extends LitElement { `; } - onSnoozeClick(_e: Event) { + onSnoozeClick(e: Event) { + e.preventDefault(); this.dispatchEvent( new CustomEvent('snooze-item', { detail: { item: this.issue!, snooze: this.snoozed }, @@ -249,7 +168,8 @@ export class GkIssueRow extends LitElement { ); } - onPinClick(_e: Event) { + onPinClick(e: Event) { + e.preventDefault(); this.dispatchEvent( new CustomEvent('pin-item', { detail: { item: this.issue!, pin: this.pinned }, diff --git a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts index 2705e63841b72..05806405f980f 100644 --- a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts @@ -16,126 +16,14 @@ import { when } from 'lit/directives/when.js'; import type { PullRequestMember, PullRequestShape } from '../../../../../git/models/pullRequest'; import { elementBase } from '../../../shared/components/styles/lit/base.css'; import { repoBranchStyles } from './branch-tag.css'; +import { rowBaseStyles } from './common.css'; import { dateAgeStyles } from './date-styles.css'; import { themeProperties } from './gk-theme.css'; import { fromDateRange } from './helpers'; @customElement('gk-pull-request-row') export class GkPullRequestRow extends LitElement { - static override styles = [ - themeProperties, - elementBase, - dateAgeStyles, - repoBranchStyles, - css` - :host { - display: block; - } - - p { - margin: 0; - } - - a { - color: var(--vscode-textLink-foreground); - text-decoration: none; - } - a:hover { - text-decoration: underline; - } - a:focus { - outline: 1px solid var(--vscode-focusBorder); - outline-offset: -1px; - } - - .actions gk-tooltip { - display: inline-block; - } - - .actions a { - box-sizing: border-box; - display: inline-flex; - justify-content: center; - align-items: center; - width: 3.2rem; - height: 3.2rem; - border-radius: 0.5rem; - color: inherit; - padding: 0.2rem; - vertical-align: text-bottom; - text-decoration: none; - cursor: pointer; - } - .actions a:hover { - background-color: var(--vscode-toolbar-hoverBackground); - } - .actions a:active { - background-color: var(--vscode-toolbar-activeBackground); - } - .actions a[tabindex='-1'] { - opacity: 0.5; - cursor: default; - } - - .actions a code-icon { - font-size: 1.6rem; - } - - .indicator-info { - color: var(--vscode-problemsInfoIcon-foreground); - } - .indicator-warning { - color: var(--vscode-problemsWarningIcon-foreground); - } - .indicator-error { - color: var(--vscode-problemsErrorIcon-foreground); - } - .indicator-neutral { - color: var(--color-alert-neutralBorder); - } - - .row-type { - --gk-badge-outline-padding: 0.3rem 0.8rem; - --gk-badge-font-size: 1.1rem; - opacity: 0.4; - vertical-align: middle; - } - - .title { - font-size: 1.4rem; - } - - .add-delete { - margin-left: 0.4rem; - margin-right: 0.2rem; - } - - .key { - z-index: 1; - position: relative; - } - - .date { - display: inline-block; - min-width: 1.6rem; - } - - .pin { - opacity: 0.4; - } - .pin:hover { - opacity: 0.64; - } - - gk-focus-row:not(:hover):not(:focus-within) .pin:not(.is-active) { - opacity: 0; - } - - .pin.is-active { - opacity: 1; - } - `, - ]; + static override styles = [themeProperties, elementBase, dateAgeStyles, repoBranchStyles, rowBaseStyles, css``]; @property({ type: Number }) public rank?: number; @@ -219,30 +107,37 @@ export class GkPullRequestRow extends LitElement { - + > ${this.pinned ? 'Unpinned' : 'Pin'} - + > ${this.snoozed ? 'Watch' : 'Mark for Later'} + + + ${when( this.indicator === 'changes', () => html` - + changes requested `, )} @@ -250,7 +145,9 @@ export class GkPullRequestRow extends LitElement { this.indicator === 'ready', () => html` - + approved and ready to merge `, )} @@ -258,7 +155,9 @@ export class GkPullRequestRow extends LitElement { this.indicator === 'conflicting', () => html` - + cannot be merged due to merge conflicts `, )} @@ -312,9 +211,6 @@ export class GkPullRequestRow extends LitElement { )} - - -
@@ -389,7 +285,8 @@ export class GkPullRequestRow extends LitElement { this.dispatchEvent(new CustomEvent('switch-branch', { detail: this.pullRequest! })); } - onSnoozeClick(_e: Event) { + onSnoozeClick(e: Event) { + e.preventDefault(); this.dispatchEvent( new CustomEvent('snooze-item', { detail: { item: this.pullRequest!, snooze: this.snoozed }, @@ -397,7 +294,8 @@ export class GkPullRequestRow extends LitElement { ); } - onPinClick(_e: Event) { + onPinClick(e: Event) { + e.preventDefault(); this.dispatchEvent( new CustomEvent('pin-item', { detail: { item: this.pullRequest!, pin: this.pinned }, diff --git a/src/webviews/apps/plus/focus/focus.scss b/src/webviews/apps/plus/focus/focus.scss index c51477192f644..d1df9989fed7a 100644 --- a/src/webviews/apps/plus/focus/focus.scss +++ b/src/webviews/apps/plus/focus/focus.scss @@ -39,6 +39,7 @@ body { --gk-tooltip-padding: 0.4rem 0.8rem; --gk-focus-background-color-hover: var(--background-05); --gk-divider-color: var(--background-05); + --gk-focus-row-pin-min-width: 52px; } .vscode-high-contrast, From e77c7f7987eb5b5e8c48514824d86a5ab3d5faba Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 13 Sep 2023 13:01:34 -0400 Subject: [PATCH 0012/1012] Updates snooze labelling --- src/webviews/apps/plus/focus/components/common.css.ts | 1 + src/webviews/apps/plus/focus/components/focus-app.ts | 2 +- src/webviews/apps/plus/focus/components/gk-issue-row.ts | 4 ++-- .../apps/plus/focus/components/gk-pull-request-row.ts | 4 ++-- src/webviews/apps/plus/focus/focus.scss | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/webviews/apps/plus/focus/components/common.css.ts b/src/webviews/apps/plus/focus/components/common.css.ts index 9e085829f1801..bc2a94df2459e 100644 --- a/src/webviews/apps/plus/focus/components/common.css.ts +++ b/src/webviews/apps/plus/focus/components/common.css.ts @@ -91,6 +91,7 @@ export const rowBaseStyles = css` .date { display: inline-block; min-width: 1.6rem; + line-height: 2.4rem; } .icon { diff --git a/src/webviews/apps/plus/focus/components/focus-app.ts b/src/webviews/apps/plus/focus/components/focus-app.ts index d75b95ae74932..701661f4804a4 100644 --- a/src/webviews/apps/plus/focus/components/focus-app.ts +++ b/src/webviews/apps/plus/focus/components/focus-app.ts @@ -33,7 +33,7 @@ export class GlFocusApp extends LitElement { { label: 'All', value: '' }, { label: 'PRs', value: 'prs' }, { label: 'Issues', value: 'issues' }, - { label: 'Later', value: 'snoozed' }, + { label: 'Snoozed', value: 'snoozed' }, ]; private readonly mineFilters = ['authored', 'assigned', 'review-requested', 'mentioned']; private readonly mineFilterOptions = [ diff --git a/src/webviews/apps/plus/focus/components/gk-issue-row.ts b/src/webviews/apps/plus/focus/components/gk-issue-row.ts index e451f84d68ec5..6e1c8736d7adc 100644 --- a/src/webviews/apps/plus/focus/components/gk-issue-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-issue-row.ts @@ -78,7 +78,7 @@ export class GkIssueRow extends LitElement { @click="${this.onPinClick}" > - Pin + ${this.pinned ? 'Unpin' : 'Pin'} - Mark for Later + ${this.snoozed ? 'Unsnooze' : 'Snooze'} diff --git a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts index 05806405f980f..e46566fc4cfa7 100644 --- a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts @@ -114,7 +114,7 @@ export class GkPullRequestRow extends LitElement { @click="${this.onPinClick}" > - ${this.pinned ? 'Unpinned' : 'Pin'} + ${this.pinned ? 'Unpin' : 'Pin'} - ${this.snoozed ? 'Watch' : 'Mark for Later'} + ${this.snoozed ? 'Unsnooze' : 'Snooze'} diff --git a/src/webviews/apps/plus/focus/focus.scss b/src/webviews/apps/plus/focus/focus.scss index d1df9989fed7a..1ba69b9a07388 100644 --- a/src/webviews/apps/plus/focus/focus.scss +++ b/src/webviews/apps/plus/focus/focus.scss @@ -39,7 +39,7 @@ body { --gk-tooltip-padding: 0.4rem 0.8rem; --gk-focus-background-color-hover: var(--background-05); --gk-divider-color: var(--background-05); - --gk-focus-row-pin-min-width: 52px; + --gk-focus-row-pin-min-width: 64px; } .vscode-high-contrast, From 648a4071f77116904c0445501fffaf18d64d9416 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 13 Sep 2023 13:01:51 -0400 Subject: [PATCH 0013/1012] Updates repo column sizing --- src/webviews/apps/plus/focus/focus.scss | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/webviews/apps/plus/focus/focus.scss b/src/webviews/apps/plus/focus/focus.scss index 1ba69b9a07388..890478e6c736c 100644 --- a/src/webviews/apps/plus/focus/focus.scss +++ b/src/webviews/apps/plus/focus/focus.scss @@ -40,6 +40,7 @@ body { --gk-focus-background-color-hover: var(--background-05); --gk-divider-color: var(--background-05); --gk-focus-row-pin-min-width: 64px; + --gk-focus-item-repo-min-width: 150px; } .vscode-high-contrast, @@ -66,6 +67,18 @@ body { --popover-bg: var(--color-background--darken-15); } +@media (min-width: 1200px) { + body { + --gk-focus-item-repo-min-width: 240px; + } +} + +@media (min-width: 1400px) { + body { + --gk-focus-item-repo-min-width: 320px; + } +} + :root { font-size: 62.5%; font-family: var(--font-family); From de6a0bb3a9df4ece829ecc2d136076ae17d2dd4c Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 18 Sep 2023 17:27:09 -0400 Subject: [PATCH 0014/1012] Updates EnrichedItem with entityUrl --- src/plus/focus/focusService.ts | 59 +++++-------------------- src/plus/webviews/focus/focusWebview.ts | 4 ++ 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index fe9eacc385b55..ccfabd227935c 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -11,6 +11,7 @@ export interface FocusItem { type: EnrichedItemResponse['entityType']; id: string; remote: GitRemote; + url: string; } export type EnrichedItem = { @@ -21,44 +22,17 @@ export type EnrichedItem = { provider: EnrichedItemResponse['provider']; entityType: EnrichedItemResponse['entityType']; entityId: string; + entityUrl: string; createdAt: number; updatedAt: number; -} & ( - | { gitRepositoryId: string } - | { - repositoryName: string; - repositoryOwner: string; - } -); - -type GitRepositoryDataRequest = - | { - readonly initialCommitSha: string; - readonly remoteUrl?: undefined; - readonly remoteDomain?: undefined; - readonly remotePath?: undefined; - } - | ({ - readonly initialCommitSha?: string; - readonly remoteUrl: string; - readonly remoteDomain: string; - readonly remotePath: string; - } & ( - | { readonly remoteProvider?: undefined } - | { - readonly remoteProvider: string; - readonly remoteProviderRepoDomain: string; - readonly remoteProviderRepoName: string; - readonly remoteProviderRepoOwnerDomain?: string; - } - )); +}; type EnrichedItemRequest = { provider: EnrichedItemResponse['provider']; entityType: EnrichedItemResponse['entityType']; entityId: string; - gitRepoData: GitRepositoryDataRequest; + entityUrl: string; }; type EnrichedItemResponse = { @@ -69,16 +43,11 @@ type EnrichedItemResponse = { provider: 'azure' | 'bitbucket' | 'github' | 'gitlab' | 'gitkraken'; entityType: 'issue' | 'pr'; entityId: string; + entityUrl: string; createdAt: number; updatedAt: number; -} & ( - | { gitRepositoryId: string } - | { - repositoryName: string; - repositoryOwner: string; - } -); +}; export class FocusService implements Disposable { constructor( @@ -141,11 +110,7 @@ export class FocusService implements Disposable { provider: item.remote.provider.id as EnrichedItemResponse['provider'], entityType: item.type, entityId: item.id, - gitRepoData: { - remoteUrl: item.remote.url, - remotePath: item.remote.provider.path, - remoteDomain: item.remote.provider.domain, - }, + entityUrl: item.url, }; const rsp = await this.connection.fetchGkDevApi('v1/enrich-items/pin', { @@ -155,7 +120,7 @@ export class FocusService implements Disposable { if (!rsp.ok) { throw new Error( - `Unable to pin item '${rq.provider}|${rq.gitRepoData.remoteDomain}/${rq.gitRepoData.remotePath}#${item.id}': (${rsp.status}) ${rsp.statusText}`, + `Unable to pin item '${rq.provider}|${rq.entityUrl}#${item.id}': (${rsp.status}) ${rsp.statusText}`, ); } @@ -184,11 +149,7 @@ export class FocusService implements Disposable { provider: item.remote.provider.id as EnrichedItemResponse['provider'], entityType: item.type, entityId: item.id, - gitRepoData: { - remoteUrl: item.remote.url, - remotePath: item.remote.provider.path, - remoteDomain: item.remote.provider.domain, - }, + entityUrl: item.url, }; const rsp = await this.connection.fetchGkDevApi('v1/enrich-items/snooze', { @@ -198,7 +159,7 @@ export class FocusService implements Disposable { if (!rsp.ok) { throw new Error( - `Unable to snooze item '${rq.provider}|${rq.gitRepoData.remoteDomain}/${rq.gitRepoData.remotePath}#${item.id}': (${rsp.status}) ${rsp.statusText}`, + `Unable to snooze item '${rq.provider}|${rq.entityUrl}#${item.id}': (${rsp.status}) ${rsp.statusText}`, ); } diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index e03e0a6d664bd..0717dbb8e1211 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -141,6 +141,7 @@ export class FocusWebviewProvider implements WebviewProvider { type: 'issue', id: issueWithRemote.issue.id, remote: issueWithRemote.repoAndRemote.remote, + url: issueWithRemote.issue.url, }; const enrichedItem = await this.container.focus.pinItem(focusItem); if (enrichedItem == null) return; @@ -170,6 +171,7 @@ export class FocusWebviewProvider implements WebviewProvider { type: 'issue', id: issueWithRemote.issue.id, remote: issueWithRemote.repoAndRemote.remote, + url: issueWithRemote.issue.url, }; const enrichedItem = await this.container.focus.snoozeItem(focusItem); if (enrichedItem == null) return; @@ -199,6 +201,7 @@ export class FocusWebviewProvider implements WebviewProvider { type: 'pr', id: prWithRemote.pullRequest.id, remote: prWithRemote.repoAndRemote.remote, + url: prWithRemote.pullRequest.url, }; const enrichedItem = await this.container.focus.pinItem(focusItem); if (enrichedItem == null) return; @@ -228,6 +231,7 @@ export class FocusWebviewProvider implements WebviewProvider { type: 'pr', id: prWithRemote.pullRequest.id, remote: prWithRemote.repoAndRemote.remote, + url: prWithRemote.pullRequest.url, }; const enrichedItem = await this.container.focus.snoozeItem(focusItem); if (enrichedItem == null) return; From ad4ccb5444e7416e22d182d8059da3f44584db9b Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 2 Oct 2023 15:33:48 -0400 Subject: [PATCH 0015/1012] adds nodeId to issues and PRs --- src/git/models/issue.ts | 4 ++++ src/git/models/pullRequest.ts | 2 ++ src/plus/github/github.ts | 5 +++++ src/plus/github/models.ts | 6 ++++++ src/plus/gitlab/gitlab.ts | 3 +++ src/plus/gitlab/models.ts | 1 + src/webviews/settings/settingsWebview.ts | 1 + 7 files changed, 22 insertions(+) diff --git a/src/git/models/issue.ts b/src/git/models/issue.ts index 1860991000896..a3a427297c6b8 100644 --- a/src/git/models/issue.ts +++ b/src/git/models/issue.ts @@ -9,6 +9,7 @@ export interface IssueOrPullRequest { readonly type: IssueOrPullRequestType; readonly provider: RemoteProviderReference; readonly id: string; + readonly nodeId: string | undefined; readonly title: string; readonly url: string; readonly date: Date; @@ -58,6 +59,7 @@ export function serializeIssueOrPullRequest(value: IssueOrPullRequest): IssueOrP icon: value.provider.icon, }, id: value.id, + nodeId: value.nodeId, title: value.title, url: value.url, date: value.date, @@ -183,6 +185,7 @@ export function serializeIssue(value: IssueShape): IssueShape { icon: value.provider.icon, }, id: value.id, + nodeId: value.nodeId, title: value.title, url: value.url, date: value.date, @@ -223,6 +226,7 @@ export class Issue implements IssueShape { constructor( public readonly provider: RemoteProviderReference, public readonly id: string, + public readonly nodeId: string | undefined, public readonly title: string, public readonly url: string, public readonly date: Date, diff --git a/src/git/models/pullRequest.ts b/src/git/models/pullRequest.ts index b78ed86ee30e8..3222100a3e679 100644 --- a/src/git/models/pullRequest.ts +++ b/src/git/models/pullRequest.ts @@ -73,6 +73,7 @@ export function serializePullRequest(value: PullRequest): PullRequestShape { icon: value.provider.icon, }, id: value.id, + nodeId: value.nodeId, title: value.title, url: value.url, date: value.date, @@ -133,6 +134,7 @@ export class PullRequest implements PullRequestShape { readonly url: string; }, public readonly id: string, + public readonly nodeId: string | undefined, public readonly title: string, public readonly url: string, public readonly state: PullRequestState, diff --git a/src/plus/github/github.ts b/src/plus/github/github.ts index 834194a1246ae..12e1dcf20fbdf 100644 --- a/src/plus/github/github.ts +++ b/src/plus/github/github.ts @@ -103,6 +103,7 @@ headRepository { url } permalink +id number title state @@ -155,6 +156,7 @@ const issueNodeProperties = ` comments { totalCount } + id number title url @@ -488,6 +490,7 @@ export class GitHubApi implements Disposable { createdAt closed closedAt + id title url state @@ -496,6 +499,7 @@ export class GitHubApi implements Disposable { createdAt closed closedAt + id title url state @@ -524,6 +528,7 @@ export class GitHubApi implements Disposable { provider: provider, type: issue.type, id: String(number), + nodeId: issue.id, date: new Date(issue.createdAt), title: issue.title, closed: issue.closed, diff --git a/src/plus/github/models.ts b/src/plus/github/models.ts index 6ad2707592a03..41aa614ef3c50 100644 --- a/src/plus/github/models.ts +++ b/src/plus/github/models.ts @@ -45,6 +45,8 @@ export interface GitHubCommitRef { export type GitHubContributor = Endpoints['GET /repos/{owner}/{repo}/contributors']['response']['data'][0]; export interface GitHubIssueOrPullRequest { + id: string; + nodeId: string; type: IssueOrPullRequestType; number: number; createdAt: string; @@ -76,6 +78,7 @@ export interface GitHubPullRequest { }; permalink: string; number: number; + id: string; title: string; state: GitHubPullRequestState; updatedAt: string; @@ -172,6 +175,7 @@ export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: RichRemot url: pr.author.url, }, String(pr.number), + pr.id, pr.title, pr.permalink, fromGitHubPullRequestState(pr.state), @@ -253,6 +257,7 @@ export function fromGitHubPullRequestDetailed( url: pr.author.url, }, String(pr.number), + pr.id, pr.title, pr.permalink, fromGitHubPullRequestState(pr.state), @@ -309,6 +314,7 @@ export function fromGitHubIssueDetailed(value: GitHubIssueDetailed, provider: Ri icon: provider.icon, }, String(value.number), + value.id, value.title, value.url, new Date(value.createdAt), diff --git a/src/plus/gitlab/gitlab.ts b/src/plus/gitlab/gitlab.ts index 0c14952ab330c..0b35ea574aae8 100644 --- a/src/plus/gitlab/gitlab.ts +++ b/src/plus/gitlab/gitlab.ts @@ -320,6 +320,7 @@ export class GitLabApi implements Disposable { provider: provider, type: 'issue', id: issue.iid, + nodeId: undefined, date: new Date(issue.createdAt), title: issue.title, closed: issue.state === 'closed', @@ -335,6 +336,7 @@ export class GitLabApi implements Disposable { provider: provider, type: 'pullrequest', id: mergeRequest.iid, + nodeId: undefined, date: new Date(mergeRequest.createdAt), title: mergeRequest.title, closed: mergeRequest.state === 'closed', @@ -487,6 +489,7 @@ export class GitLabApi implements Disposable { url: pr.author?.webUrl ?? '', }, String(pr.iid), + undefined, pr.title, pr.webUrl, fromGitLabMergeRequestState(pr.state), diff --git a/src/plus/gitlab/models.ts b/src/plus/gitlab/models.ts index f319ac1d67cd9..9742f911f9c25 100644 --- a/src/plus/gitlab/models.ts +++ b/src/plus/gitlab/models.ts @@ -98,6 +98,7 @@ export function fromGitLabMergeRequestREST(pr: GitLabMergeRequestREST, provider: url: pr.author?.web_url ?? '', }, String(pr.iid), + undefined, pr.title, pr.web_url, fromGitLabMergeRequestState(pr.state), diff --git a/src/webviews/settings/settingsWebview.ts b/src/webviews/settings/settingsWebview.ts index cc81537ad8766..0b1d004b87d73 100644 --- a/src/webviews/settings/settingsWebview.ts +++ b/src/webviews/settings/settingsWebview.ts @@ -200,6 +200,7 @@ export class SettingsWebviewProvider implements WebviewProvider { url: 'https://github.com/eamodio', }, '1', + undefined, 'Supercharged', 'https://github.com/gitkraken/vscode-gitlens/pulls/1', 'merged', From 50c9a4383989180083103fb1767c362386fafef2 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 2 Oct 2023 16:16:51 -0400 Subject: [PATCH 0016/1012] Updates focus view to use nodeId --- src/plus/webviews/focus/focusWebview.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 0717dbb8e1211..df389f98373ea 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -129,7 +129,7 @@ export class FocusWebviewProvider implements WebviewProvider { } private async onPinIssue({ issue, pin }: PinIssueParams) { - const issueWithRemote = this._issues?.find(r => r.issue.id === issue.id); + const issueWithRemote = this._issues?.find(r => r.issue.nodeId === issue.nodeId); if (issueWithRemote == null) return; if (pin) { @@ -139,7 +139,7 @@ export class FocusWebviewProvider implements WebviewProvider { } else { const focusItem: FocusItem = { type: 'issue', - id: issueWithRemote.issue.id, + id: issueWithRemote.issue.nodeId!, remote: issueWithRemote.repoAndRemote.remote, url: issueWithRemote.issue.url, }; @@ -159,7 +159,7 @@ export class FocusWebviewProvider implements WebviewProvider { } private async onSnoozeIssue({ issue, snooze }: SnoozeIssueParams) { - const issueWithRemote = this._issues?.find(r => r.issue.id === issue.id); + const issueWithRemote = this._issues?.find(r => r.issue.nodeId === issue.nodeId); if (issueWithRemote == null) return; if (snooze) { @@ -169,7 +169,7 @@ export class FocusWebviewProvider implements WebviewProvider { } else { const focusItem: FocusItem = { type: 'issue', - id: issueWithRemote.issue.id, + id: issueWithRemote.issue.nodeId!, remote: issueWithRemote.repoAndRemote.remote, url: issueWithRemote.issue.url, }; @@ -189,7 +189,7 @@ export class FocusWebviewProvider implements WebviewProvider { } private async onPinPr({ pullRequest, pin }: PinPrParams) { - const prWithRemote = this._pullRequests?.find(r => r.pullRequest.id === pullRequest.id); + const prWithRemote = this._pullRequests?.find(r => r.pullRequest.nodeId === pullRequest.nodeId); if (prWithRemote == null) return; if (pin) { @@ -199,7 +199,7 @@ export class FocusWebviewProvider implements WebviewProvider { } else { const focusItem: FocusItem = { type: 'pr', - id: prWithRemote.pullRequest.id, + id: prWithRemote.pullRequest.nodeId!, remote: prWithRemote.repoAndRemote.remote, url: prWithRemote.pullRequest.url, }; @@ -219,7 +219,7 @@ export class FocusWebviewProvider implements WebviewProvider { } private async onSnoozePr({ pullRequest, snooze }: SnoozePrParams) { - const prWithRemote = this._pullRequests?.find(r => r.pullRequest.id === pullRequest.id); + const prWithRemote = this._pullRequests?.find(r => r.pullRequest.nodeId === pullRequest.nodeId); if (prWithRemote == null) return; if (snooze) { @@ -229,7 +229,7 @@ export class FocusWebviewProvider implements WebviewProvider { } else { const focusItem: FocusItem = { type: 'pr', - id: prWithRemote.pullRequest.id, + id: prWithRemote.pullRequest.nodeId!, remote: prWithRemote.repoAndRemote.remote, url: prWithRemote.pullRequest.url, }; @@ -630,9 +630,9 @@ function findEnrichedItems( let result; // TODO: filter by entity id, type, and gitRepositoryId if ((item as SearchedPullRequestWithRemote).pullRequest != null) { - result = enrichedItems.filter(e => e.entityId === (item as SearchedPullRequestWithRemote).pullRequest.id); + result = enrichedItems.filter(e => e.entityId === (item as SearchedPullRequestWithRemote).pullRequest.nodeId); } else { - result = enrichedItems.filter(e => e.entityId === (item as SearchedIssueWithRank).issue.id); + result = enrichedItems.filter(e => e.entityId === (item as SearchedIssueWithRank).issue.nodeId); } if (result.length === 0) return; From 3e54c1f1fdf89d4bf66bf43a7aed9b690037dcd7 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 2 Oct 2023 22:42:48 -0400 Subject: [PATCH 0017/1012] Fixes focus view tooltips --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1cbf1d0329410..7974d885027a1 100644 --- a/package.json +++ b/package.json @@ -14816,7 +14816,7 @@ }, "dependencies": { "@gitkraken/gitkraken-components": "10.1.25", - "@gitkraken/shared-web-components": "^0.1.1-rc.9", + "@gitkraken/shared-web-components": "^0.1.1-rc.11", "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", "@octokit/graphql": "7.0.2", diff --git a/yarn.lock b/yarn.lock index cfefe9c82cc60..35c0cc154850a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -237,10 +237,10 @@ react-dragula "1.1.17" react-onclickoutside "^6.13.0" -"@gitkraken/shared-web-components@^0.1.1-rc.9": - version "0.1.1-rc.10" - resolved "https://registry.yarnpkg.com/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.10.tgz#bed7021a0e6912ae3196e06078169950f0616bed" - integrity sha512-2GoM9Gg473zbtTL5u5YTiDeU8mzACj2hMQBk+7iruiiVoJLGxvi1bT95MyXHakhv4zk4lI5OVWP6TU4ZAaoDLQ== +"@gitkraken/shared-web-components@^0.1.1-rc.11": + version "0.1.1-rc.11" + resolved "https://registry.npmjs.org/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.11.tgz#0d588af0a9c92a6ccf2339a341787c6d9d60227c" + integrity sha512-lslDHNgU2znzoLydkLudETHP0WlRBLdV25YgRSTcm724Elah5nFfqUdJZ8lQCKehxJBnlWtll5uTxuM+7wxVDw== dependencies: "@floating-ui/dom" "^1.4.2" typescript "^4.9.5" From 276688689d8338159c1ceeeb098d46f4649e20eb Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 4 Oct 2023 10:18:42 -0400 Subject: [PATCH 0018/1012] Fixes assignee name in PRs --- src/plus/github/models.ts | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/plus/github/models.ts b/src/plus/github/models.ts index 41aa614ef3c50..ca1ceae729611 100644 --- a/src/plus/github/models.ts +++ b/src/plus/github/models.ts @@ -11,6 +11,12 @@ export interface GitHubBlame { viewer?: string; } +export interface GitHubMember { + login: string; + avatarUrl: string; + url: string; +} + export interface GitHubBlameRange { startingLine: number; endingLine: number; @@ -95,12 +101,8 @@ export interface GitHubPullRequest { export interface GitHubIssueDetailed extends GitHubIssueOrPullRequest { date: Date; updatedAt: Date; - author: { - login: string; - avatarUrl: string; - url: string; - }; - assignees: { nodes: IssueMember[] }; + author: GitHubMember; + assignees: { nodes: GitHubMember[] }; repository: { name: string; owner: { @@ -150,19 +152,11 @@ export interface GitHubDetailedPullRequest extends GitHubPullRequest { reviewRequests: { nodes: { asCodeOwner: boolean; - requestedReviewer: { - login: string; - avatarUrl: string; - url: string; - }; + requestedReviewer: GitHubMember; }[]; }; assignees: { - nodes: { - login: string; - avatarUrl: string; - url: string; - }[]; + nodes: GitHubMember[]; }; } @@ -331,7 +325,7 @@ export function fromGitHubIssueDetailed(value: GitHubIssueDetailed, provider: Ri repo: value.repository.name, }, value.assignees.nodes.map(assignee => ({ - name: assignee.name, + name: assignee.login, avatarUrl: assignee.avatarUrl, url: assignee.url, })), From b90de792b4c336af7fb896ca350481f9f86f849b Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 4 Oct 2023 10:19:19 -0400 Subject: [PATCH 0019/1012] Adds reviewers to focus view items --- .../focus/components/gk-pull-request-row.ts | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts index e46566fc4cfa7..39c6ac57590b9 100644 --- a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts @@ -100,6 +100,32 @@ export class GkPullRequestRow extends LitElement { return `indicator-${fromDateRange(this.lastUpdatedDate).status}`; } + get participants() { + const participants: { member: PullRequestMember; roles: string[] }[] = []; + function addMember(member: PullRequestMember, role: string) { + const participant = participants.find(p => p.member.name === member.name); + if (participant != null) { + participant.roles.push(role); + } else { + participants.push({ member: member, roles: [role] }); + } + } + + if (this.pullRequest?.author != null) { + addMember(this.pullRequest.author, 'author'); + } + + if (this.pullRequest?.assignees != null) { + this.pullRequest.assignees.forEach(m => addMember(m, 'assigned')); + } + + if (this.pullRequest?.reviewRequests != null) { + this.pullRequest.reviewRequests.forEach(m => addMember(m.reviewer, 'reviewer')); + } + + return participants; + } + override render() { if (!this.pullRequest) return undefined; @@ -188,23 +214,17 @@ export class GkPullRequestRow extends LitElement { ${when( - this.pullRequest.author != null, - () => - html``, - )} - ${when( - this.assignees.length > 0, + this.participants.length > 0, () => html` ${repeat( - this.assignees, - item => item.url, + this.participants, + item => item.member.url, item => html``, )} `, From f674841720b639a9bc77d14e84f6c317687fce88 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Wed, 4 Oct 2023 12:04:30 -0700 Subject: [PATCH 0020/1012] Updates CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9326fb48adbc0..09bf4aea68ffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed - Relaxes PR autolink detection for Azure DevOps to use `PR ` instead of `Merged PR ` — closes [#2908](https://github.com/gitkraken/vscode-gitlens/issues/2908) +- Replaces VSCode git operations (`fetch`, `push`, `pull`) with GitLens' own implementations to avoid issues with VSCode's git extension. This can be reverted by setting `"gitlens.experimental.nativeGit"` to `"false"` in settings. +- Adds deep link support for workspaces in the _GitKraken Workspaces_ view + - Deep link format: `https://gitkraken.dev/link/workspaces/{workspaceId}` + - Adds a _Share_ submenu with a _Copy Link to Workspace_ command to workspaces in the _GitKraken Workspaces_ view ### Fixed @@ -17,6 +21,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Fixes [#2928](https://github.com/gitkraken/vscode-gitlens/issues/2928) - Apply Changes should create new files when needed - Fixes [#2896](https://github.com/gitkraken/vscode-gitlens/issues/2896) - Repositories view stuck in loading state - Fixes issue with "View as [List|Tree]" toggle not working in the _Commit Details_ view +- Fixes an issue with deep links sometimes failing to properly resolve when a matching repository without the remote is found +- Fixes an issue in the _Commit Graph_ where commits not in the history of a merge commit were showing in the same column ## [14.3.0] - 2023-09-07 From 6c036b4153c1e79522436bae78ba9c00c8f82edd Mon Sep 17 00:00:00 2001 From: ericf-axosoft <90025366+ericf-axosoft@users.noreply.github.com> Date: Thu, 5 Oct 2023 18:44:27 +0200 Subject: [PATCH 0021/1012] Add new service-specific ref icons (#2936) * Added service-specific ref icons * Added "hostingServiceType" property to the GK Graph remote type to be able to get icons * Added better icons for Gitlab and Bitbucket services * Added missing icons * Bump GK Graph dependency to v10.1.27 * Fixed build * Refactor: isolate the component imports to one file * Formatting --------- Co-authored-by: Ramin Tadayon --- package.json | 2 +- src/env/node/git/localGitProvider.ts | 2 ++ src/git/models/graph.ts | 12 ++++++- src/plus/github/githubGitProvider.ts | 3 ++ src/webviews/apps/plus/graph/GraphWrapper.tsx | 7 +++++ src/webviews/apps/plus/graph/graph.scss | 31 +++++++++++++++++++ yarn.lock | 8 ++--- 7 files changed, 59 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 7974d885027a1..60509b15fc2a0 100644 --- a/package.json +++ b/package.json @@ -14815,7 +14815,7 @@ "vscode:prepublish": "yarn run bundle" }, "dependencies": { - "@gitkraken/gitkraken-components": "10.1.25", + "@gitkraken/gitkraken-components": "10.1.27", "@gitkraken/shared-web-components": "^0.1.1-rc.11", "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 87903b377d007..1573c4721c33b 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -69,6 +69,7 @@ import type { GitFile, GitFileStatus } from '../../../git/models/file'; import { GitFileChange } from '../../../git/models/file'; import type { GitGraph, + GitGraphHostingServiceType, GitGraphRow, GitGraphRowContexts, GitGraphRowHead, @@ -2201,6 +2202,7 @@ export class LocalGitProvider implements GitProvider, Disposable { avatarUrl: avatarUrl, context: serializeWebviewItemContext(context), current: tip === headRefUpstreamName, + hostingServiceType: remote.provider?.id as GitGraphHostingServiceType, }; refRemoteHeads.push(refRemoteHead); diff --git a/src/git/models/graph.ts b/src/git/models/graph.ts index ebaa95f64ad52..4fb4adcd7ab26 100644 --- a/src/git/models/graph.ts +++ b/src/git/models/graph.ts @@ -1,7 +1,17 @@ -import type { GraphRow, Head, Remote, RowContexts, RowStats, Tag } from '@gitkraken/gitkraken-components'; +import type { + GraphRow, + Head, + HostingServiceType, + Remote, + RowContexts, + RowStats, + Tag, +} from '@gitkraken/gitkraken-components'; import type { GitBranch } from './branch'; import type { GitRemote } from './remote'; +export type GitGraphHostingServiceType = HostingServiceType; + export type GitGraphRowHead = Head; export type GitGraphRowRemoteHead = Remote; export type GitGraphRowTag = Tag; diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index 03cfcea72b3a1..b202a368c366c 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -48,6 +48,7 @@ import type { GitFile } from '../../git/models/file'; import { GitFileChange, GitFileIndexStatus } from '../../git/models/file'; import type { GitGraph, + GitGraphHostingServiceType, GitGraphRow, GitGraphRowContexts, GitGraphRowHead, @@ -1409,6 +1410,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { avatarUrl: avatarUrl, context: serializeWebviewItemContext(context), current: true, + hostingServiceType: remote.provider?.id as GitGraphHostingServiceType, }, ]; @@ -1460,6 +1462,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { url: remote.url, avatarUrl: avatarUrl, context: serializeWebviewItemContext(context), + hostingServiceType: remote.provider?.id as GitGraphHostingServiceType, }); } } diff --git a/src/webviews/apps/plus/graph/GraphWrapper.tsx b/src/webviews/apps/plus/graph/GraphWrapper.tsx index f3e969d51678a..c342f2e6c2947 100644 --- a/src/webviews/apps/plus/graph/GraphWrapper.tsx +++ b/src/webviews/apps/plus/graph/GraphWrapper.tsx @@ -111,6 +111,13 @@ const createIconElements = (): Record => { const iconList = [ 'head', 'remote', + 'remote-github', + 'remote-githubEnterprise', + 'remote-gitlab', + 'remote-gitlabSelfHosted', + 'remote-bitbucket', + 'remote-bitbucketServer', + 'remote-azureDevops', 'tag', 'stash', 'check', diff --git a/src/webviews/apps/plus/graph/graph.scss b/src/webviews/apps/plus/graph/graph.scss index 266fea363ddca..b1a0ef1a0de2d 100644 --- a/src/webviews/apps/plus/graph/graph.scss +++ b/src/webviews/apps/plus/graph/graph.scss @@ -622,6 +622,37 @@ button:not([disabled]), content: '\ebaa'; } } + &--remote-github, + &--remote-githubEnterprise { + &::before { + // codicon-github-inverted + font-family: codicon; + content: '\eba1'; + } + } + &--remote-gitlab, + &--remote-gitlabSelfHosted { + &::before { + // glicon-provider-gitlab + font-family: 'glicons'; + content: '\f123'; + } + } + &--remote-bitbucket, + &--remote-bitbucketServer { + &::before { + // glicon-provider-bitbucket + font-family: 'glicons'; + content: '\f11f'; + } + } + &--remote-azureDevops { + &::before { + // glicon-provider-azdo + font-family: 'glicons'; + content: '\f11e'; + } + } &--tag { &::before { // codicon-tag diff --git a/yarn.lock b/yarn.lock index 35c0cc154850a..411114e95b2ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -223,10 +223,10 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.4.tgz#19654d1026cc410975d46445180e70a5089b3e7d" integrity sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA== -"@gitkraken/gitkraken-components@10.1.25": - version "10.1.25" - resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.25.tgz#0e710ae118c4c70982b730fb1a00f3c16328678b" - integrity sha512-UeZVdnVEyL/yEtD9fhCTHUXFogJeRVjglbswp1Gf5ekuzDtuRZqAmyU1MOhMKdIa9X6XOufTJg7z/FyNyuNELw== +"@gitkraken/gitkraken-components@10.1.27": + version "10.1.27" + resolved "https://registry.npmjs.org/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.27.tgz#18a9430678d7cef6a6476f8fcab956ea26dca76e" + integrity sha512-NiQ6M7J2sfrGfB2RRaIzMuM9l67GXY5BbgNVnQJajHa3zmuPN3ImLZ92Qxn0nn/0ZsrvVDaY6ZShnPRBNnbmeA== dependencies: "@axosoft/react-virtualized" "9.22.3-gitkraken.3" classnames "2.3.2" From 77beea79561595a088d63a6526b8d0ccf8502ca0 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Thu, 5 Oct 2023 09:57:12 -0700 Subject: [PATCH 0022/1012] Updates license strings (#2945) * Updates 'GitLens X' and 'Pro trial' patterns * Updates base/default plan name --- README.md | 12 ++++++------ package.json | 14 +++++++------- src/git/remotes/richRemoteProvider.ts | 2 +- src/plus/subscription/subscriptionService.ts | 6 +++--- src/plus/workspaces/workspacesService.ts | 2 +- src/quickpicks/items/directive.ts | 2 +- src/subscription.ts | 14 +++++++------- .../plus/account/components/account-content.ts | 14 +++++++------- .../shared/components/feature-gate-plus-state.ts | 11 +++++++---- src/webviews/apps/welcome/welcome.html | 2 +- 10 files changed, 41 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 19ef4e0bfe781..7f7a05ba0fd39 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ See the [FAQ](#is-gitlens-free-to-use 'Jump to FAQ') for more details. [Features](#discover-powerful-features 'Jump to Discover Powerful Features') | [Labs](#gitkraken-labs 'Jump to GitKraken Labs') -| [Pro](#ready-for-gitlens-pro 'Jump to Ready for GitLens Pro?') +| [Pro](#ready-for-gitlens-pro 'Jump to Ready for GitKraken Pro?') | [FAQ](#faq 'Jump to FAQ') | [Support and Community](#support-and-community 'Jump to Support and Community') | [Contributing](#contributing 'Jump to Contributing') @@ -257,11 +257,11 @@ Use the Explain panel on the **Commit Details** view to leverage AI to help you Use the `Generate Commit Message` command from the Source Control view's context menu to automatically generate a commit message for your staged changes by leveraging AI. -# Ready for GitLens Pro? +# Ready for GitKraken Pro? -When you're ready to unlock the full potential of GitLens and enjoy all the benefits on your privately hosted repos, consider upgrading to GitLens Pro. With GitLens Pro, you'll gain access to ✨ features on privately hosted repos and ☁️ features based on the Pro plan. +When you're ready to unlock the full potential of GitLens and enjoy all the benefits on your privately hosted repos, consider upgrading to GitKraken Pro. With GitKraken Pro, you'll gain access to ✨ features on privately hosted repos and ☁️ features based on the Pro plan. -To learn more about the pricing and the additional ✨ and ☁️ features offered with GitLens Pro, visit the [GitLens Pricing page](https://www.gitkraken.com/gitlens/pricing). Upgrade to GitLens Pro today and take your Git workflow to the next level! +To learn more about the pricing and the additional ✨ and ☁️ features offered with GitKraken Pro, visit the [GitLens Pricing page](https://www.gitkraken.com/gitlens/pricing). Upgrade to GitKraken Pro today and take your Git workflow to the next level! # FAQ @@ -274,7 +274,7 @@ Yes. All features are free to use on all repos, **except** for features, While GitLens offers a remarkable set of free features, a subset of features tailored for professional developers and teams, marked with a ✨, require a trial or paid plan for use on privately hosted repos — use on local or publicly hosted repos is free for everyone. Additionally some features marked with a ☁️, rely on GitKraken Dev Services which requires an account and access is based on your plan, e.g. Free, Pro, etc. -Preview ✨ features instantly for free for 3 days without an account, or start a free Pro trial to get an additional 7 days and gain access to ☁️ features to experience the full power of GitLens. +Preview ✨ features instantly for free for 3 days without an account, or start a free GitKraken trial to get an additional 7 days and gain access to ☁️ features to experience the full power of GitLens. ## Are ✨ and ☁️ features free to use? @@ -300,7 +300,7 @@ Join the GitLens community on [GitHub Discussions](https://github.com/gitkraken/ For any issues or inquiries related to GitLens, you can reach out to the GitKraken support team via the [official support page](https://support.gitkraken.com/). They will be happy to assist you with any problems you may encounter. -With GitLens Pro, you gain access to priority email support from our customer success team, ensuring higher priority and faster response times. Custom onboarding and training are also available to help you and your team quickly get up and running with a GitLens Pro plan. +With GitKraken Pro, you gain access to priority email support from our customer success team, ensuring higher priority and faster response times. Custom onboarding and training are also available to help you and your team quickly get up and running with a GitKraken Pro plan. # Contributing diff --git a/package.json b/package.json index 60509b15fc2a0..03f696f902711 100644 --- a/package.json +++ b/package.json @@ -14448,7 +14448,7 @@ }, { "view": "gitlens.views.workspaces", - "contents": "[Start Free Pro Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free 7-day Pro trial to use GitKraken Workspaces, or [sign in](command:gitlens.plus.loginOrSignUp).\n☁️ Requires an account and access is based on your plan, e.g. Free, Pro, etc", + "contents": "[Start Free GitKraken Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free 7-day GitKraken trial to use GitKraken Workspaces, or [sign in](command:gitlens.plus.loginOrSignUp).\n☁️ Requires an account and access is based on your plan, e.g. Free, Pro, etc", "when": "!gitlens:plus" }, { @@ -14468,17 +14468,17 @@ }, { "view": "gitlens.views.worktrees", - "contents": "[Preview Pro](command:gitlens.plus.startPreviewTrial)\n\nPreview Pro for 3 days, or [sign in](command:gitlens.plus.loginOrSignUp) to start a full 7-day Pro trial.\n✨ A trial or paid plan is required to use this on privately hosted repos.", + "contents": "[Preview Pro](command:gitlens.plus.startPreviewTrial)\n\nPreview Pro for 3 days, or [sign in](command:gitlens.plus.loginOrSignUp) to start a full 7-day GitKraken trial.\n✨ A trial or paid plan is required to use this on privately hosted repos.", "when": "gitlens:plus:required && gitlens:plus:state == 0" }, { "view": "gitlens.views.worktrees", - "contents": "Your 3-day Pro preview has ended, start a free Pro trial to get an additional 7 days, or [sign in](command:gitlens.plus.loginOrSignUp).\n\n[Start Free Pro Trial](command:gitlens.plus.loginOrSignUp)\n✨ A trial or paid plan is required to use this on privately hosted repos.", + "contents": "Your 3-day Pro preview has ended, start a free GitKraken trial to get an additional 7 days, or [sign in](command:gitlens.plus.loginOrSignUp).\n\n[Start Free GitKraken Trial](command:gitlens.plus.loginOrSignUp)\n✨ A trial or paid plan is required to use this on privately hosted repos.", "when": "gitlens:plus:required && gitlens:plus:state == 2" }, { "view": "gitlens.views.worktrees", - "contents": "Your Pro trial has ended, please upgrade to continue to use this on privately hosted repos.\n\n[Upgrade to Pro](command:gitlens.plus.purchase)\n✨ A paid plan is required to use this on privately hosted repos.", + "contents": "Your GitKraken trial has ended, please upgrade to continue to use this on privately hosted repos.\n\n[Upgrade to Pro](command:gitlens.plus.purchase)\n✨ A paid plan is required to use this on privately hosted repos.", "when": "gitlens:plus:required && gitlens:plus:state == 4" } ], @@ -14732,8 +14732,8 @@ }, { "id": "gitlens.welcome.preview", - "title": "Previewing GitLens Pro", - "description": "During your preview, you have access to ✨ features on privately hosted repos. [Learn more](https://www.gitkraken.com/gitlens/pro-features)\n\n[Start Free Pro Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free Pro trial to get an additional 7 days.", + "title": "Previewing GitKraken Pro", + "description": "During your preview, you have access to ✨ features on privately hosted repos. [Learn more](https://www.gitkraken.com/gitlens/pro-features)\n\n[Start Free GitKraken Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free GitKraken trial to get an additional 7 days.", "media": { "markdown": "walkthroughs/welcome/preview.md" }, @@ -14741,7 +14741,7 @@ }, { "id": "gitlens.welcome.trial", - "title": "Trialing GitLens Pro", + "title": "Trialing GitKraken Pro", "description": "During your trial, you have access to ✨ features on privately hosted repos and ☁️ features based on the Pro plan. [Learn more](https://www.gitkraken.com/gitlens/pro-features)\n\n[Upgrade to Pro](command:gitlens.plus.purchase)", "media": { "markdown": "walkthroughs/welcome/trial.md" diff --git a/src/git/remotes/richRemoteProvider.ts b/src/git/remotes/richRemoteProvider.ts index 9c552f3ae284c..ed3464d56d163 100644 --- a/src/git/remotes/richRemoteProvider.ts +++ b/src/git/remotes/richRemoteProvider.ts @@ -578,7 +578,7 @@ export async function ensurePaidPlan(providerName: string, container: Container) void container.subscription.startPreviewTrial(); break; } else if (subscription.account == null) { - const signIn = { title: 'Start Free Pro Trial' }; + const signIn = { title: 'Start Free GitKraken Trial' }; const cancel = { title: 'Cancel', isCloseAffordance: true }; const result = await window.showWarningMessage( `${title}\n\nDo you want to continue to use ✨ features on privately hosted repos, free for an additional 7 days?`, diff --git a/src/plus/subscription/subscriptionService.ts b/src/plus/subscription/subscriptionService.ts index 0f9359d2f5def..759bf4d53cbeb 100644 --- a/src/plus/subscription/subscriptionService.ts +++ b/src/plus/subscription/subscriptionService.ts @@ -419,10 +419,10 @@ export class SubscriptionService implements Disposable { void this.showAccountView(); if (!silent && plan.effective.id === SubscriptionPlanId.Free) { - const confirm: MessageItem = { title: 'Start Free Pro Trial', isCloseAffordance: true }; + const confirm: MessageItem = { title: 'Start Free GitKraken Trial', isCloseAffordance: true }; const cancel: MessageItem = { title: 'Cancel' }; const result = await window.showInformationMessage( - 'Your 3-day Pro preview has ended, start a free Pro trial to get an additional 7 days.\n\n✨ A trial or paid plan is required to use Pro features on privately hosted repos.', + 'Your 3-day Pro preview has ended, start a free GitKraken trial to get an additional 7 days.\n\n✨ A trial or paid plan is required to use Pro features on privately hosted repos.', { modal: true }, confirm, cancel, @@ -475,7 +475,7 @@ export class SubscriptionService implements Disposable { `You can now preview Pro features for ${pluralize( 'day', days, - )}. After which, you can start a free Pro trial for an additional 7 days.`, + )}. After which, you can start a free GitKraken trial for an additional 7 days.`, confirm, learn, ); diff --git a/src/plus/workspaces/workspacesService.ts b/src/plus/workspaces/workspacesService.ts index 0f209981699ec..df9b9041c9fe4 100644 --- a/src/plus/workspaces/workspacesService.ts +++ b/src/plus/workspaces/workspacesService.ts @@ -163,7 +163,7 @@ export class WorkspacesService implements Disposable { cloudWorkspaces: cloudWorkspaces, cloudWorkspaceInfo: filteredSharedWorkspaceCount > 0 - ? `${filteredSharedWorkspaceCount} shared workspaces hidden - upgrade to GitLens Pro to access.` + ? `${filteredSharedWorkspaceCount} shared workspaces hidden - upgrade to GitKraken Pro to access.` : undefined, }; } diff --git a/src/quickpicks/items/directive.ts b/src/quickpicks/items/directive.ts index c3b942649d05b..ebdbacdd503e9 100644 --- a/src/quickpicks/items/directive.ts +++ b/src/quickpicks/items/directive.ts @@ -47,7 +47,7 @@ export function createDirectiveQuickPickItem( detail = 'Preview Pro for 3-days to use this on privately hosted repos'; break; case Directive.ExtendTrial: - label = 'Start Free Pro Trial'; + label = 'Start Free GitKraken Trial'; detail = 'Continue to use this on privately hosted repos, free for an additional 7 days'; break; case Directive.RequiresVerification: diff --git a/src/subscription.ts b/src/subscription.ts index c2719718b4974..3cb3732804b3f 100644 --- a/src/subscription.ts +++ b/src/subscription.ts @@ -131,16 +131,16 @@ export function getSubscriptionPlan( export function getSubscriptionPlanName(id: SubscriptionPlanId) { switch (id) { case SubscriptionPlanId.FreePlus: - return 'GitLens Free'; + return 'GitKraken Free'; case SubscriptionPlanId.Pro: - return 'GitLens Pro'; + return 'GitKraken Pro'; case SubscriptionPlanId.Teams: - return 'GitLens Teams'; + return 'GitKraken Teams'; case SubscriptionPlanId.Enterprise: - return 'GitLens Enterprise'; + return 'GitKraken Enterprise'; case SubscriptionPlanId.Free: default: - return 'GitLens'; + return 'GitKraken'; } } @@ -153,14 +153,14 @@ export function getSubscriptionStatePlanName(state: SubscriptionState | undefine case SubscriptionState.FreePlusInTrial: return `${getSubscriptionPlanName(id ?? SubscriptionPlanId.Pro)} (Trial)`; case SubscriptionState.VerificationRequired: - return `GitLens (Unverified)`; + return `GitKraken (Unverified)`; case SubscriptionState.Paid: return getSubscriptionPlanName(id ?? SubscriptionPlanId.Pro); case SubscriptionState.Free: case SubscriptionState.FreePreviewTrialExpired: case null: default: - return 'GitLens'; + return 'GitKraken'; } } diff --git a/src/webviews/apps/plus/account/components/account-content.ts b/src/webviews/apps/plus/account/components/account-content.ts index 8ed47c64c4f89..5ca90b1929504 100644 --- a/src/webviews/apps/plus/account/components/account-content.ts +++ b/src/webviews/apps/plus/account/components/account-content.ts @@ -97,10 +97,10 @@ export class AccountContent extends LitElement { case SubscriptionState.Free: case SubscriptionState.FreePreviewTrialExpired: case SubscriptionState.FreePlusTrialExpired: - return 'GitLens Free'; + return 'GitKraken Free'; case SubscriptionState.FreeInPreviewTrial: case SubscriptionState.FreePlusInTrial: - return 'GitLens Pro (Trial)'; + return 'GitKraken Pro (Trial)'; case SubscriptionState.VerificationRequired: return `${this.plan} (Unverified)`; default: @@ -171,14 +171,14 @@ export class AccountContent extends LitElement { Sign Up -

Signing up starts a free 7-day Pro trial.

+

Signing up starts a free 7-day GitKraken trial.

`; case SubscriptionState.FreePlusTrialExpired: return html`

- Your Pro trial has ended, please upgrade to continue to use ✨ features on privately hosted - repos. + Your GitKraken trial has ended, please upgrade to continue to use ✨ features on privately + hosted repos.

Upgrade to Pro @@ -192,8 +192,8 @@ export class AccountContent extends LitElement { case SubscriptionState.FreePlusInTrial: return html`

- Your have ${this.daysRemaining} remaining in your Pro trial. Once your trial ends, you'll need a - paid plan to continue using ✨ features. + Your have ${this.daysRemaining} remaining in your GitKraken trial. Once your trial ends, you'll + need a paid plan to continue using ✨ features.

Upgrade to Pro diff --git a/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts b/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts index 11c2db015b5aa..c29c371361184 100644 --- a/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts +++ b/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts @@ -76,7 +76,7 @@ export class FeatureGatePlusState extends LitElement { >

Preview Pro for 3 days, or - sign in to start a full 7-day Pro trial. + sign in to start a full 7-day GitKraken trial.

✨ A trial or paid plan is required to use this on privately hosted repos.

`; @@ -84,18 +84,21 @@ export class FeatureGatePlusState extends LitElement { case SubscriptionState.FreePreviewTrialExpired: return html`

- Your 3-day Pro preview has ended, start a free Pro trial to get an additional 7 days, or + Your 3-day Pro preview has ended, start a free GitKraken trial to get an additional 7 days, or sign in.

Start Free Pro TrialStart Free GitKraken Trial

✨ A trial or paid plan is required to use this on privately hosted repos.

`; case SubscriptionState.FreePlusTrialExpired: return html` -

Your Pro trial has ended, please upgrade to continue to use this on privately hosted repos.

+

+ Your GitKraken trial has ended, please upgrade to continue to use this on privately hosted + repos. +

Upgrade to Pro diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html index 85fc68bda28de..8349e0713a255 100644 --- a/src/webviews/apps/welcome/welcome.html +++ b/src/webviews/apps/welcome/welcome.html @@ -392,7 +392,7 @@

Try Pro ✨

Unlock the full power of GitLens ✨ and ☁️ features

Start a Pro trialStart a GitKraken trial  or sign in

From 414edb15f44fb14da70e5641c9a586563c9e9838 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Thu, 5 Oct 2023 10:06:23 -0700 Subject: [PATCH 0023/1012] Fixes lint --- src/plus/github/models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plus/github/models.ts b/src/plus/github/models.ts index ca1ceae729611..5627ae443c912 100644 --- a/src/plus/github/models.ts +++ b/src/plus/github/models.ts @@ -1,6 +1,6 @@ import type { Endpoints } from '@octokit/types'; import { GitFileIndexStatus } from '../../git/models/file'; -import type { IssueLabel, IssueMember, IssueOrPullRequestType } from '../../git/models/issue'; +import type { IssueLabel, IssueOrPullRequestType } from '../../git/models/issue'; import { Issue } from '../../git/models/issue'; import type { PullRequestState } from '../../git/models/pullRequest'; import { PullRequest, PullRequestMergeableState, PullRequestReviewDecision } from '../../git/models/pullRequest'; From 7dcfedfc4586174b198560c5b7537a353c3ac5fd Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 5 Oct 2023 22:17:18 -0400 Subject: [PATCH 0024/1012] Updates enrichment to match by url --- src/plus/webviews/focus/focusWebview.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index df389f98373ea..b1eb111969f9b 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -630,9 +630,9 @@ function findEnrichedItems( let result; // TODO: filter by entity id, type, and gitRepositoryId if ((item as SearchedPullRequestWithRemote).pullRequest != null) { - result = enrichedItems.filter(e => e.entityId === (item as SearchedPullRequestWithRemote).pullRequest.nodeId); + result = enrichedItems.filter(e => e.entityUrl === (item as SearchedPullRequestWithRemote).pullRequest.url); } else { - result = enrichedItems.filter(e => e.entityId === (item as SearchedIssueWithRank).issue.nodeId); + result = enrichedItems.filter(e => e.entityUrl === (item as SearchedIssueWithRank).issue.url); } if (result.length === 0) return; From 4f9fb3cd167ccb6061a42380f17fd63f6900e78a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 6 Oct 2023 13:48:13 -0400 Subject: [PATCH 0025/1012] Updates dependencies & TypeScript 5.3-beta --- package.json | 14 +-- yarn.lock | 244 +++++++++++++++++++++++++-------------------------- 2 files changed, 128 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index 03f696f902711..cece2f619b4fe 100644 --- a/package.json +++ b/package.json @@ -14816,7 +14816,7 @@ }, "dependencies": { "@gitkraken/gitkraken-components": "10.1.27", - "@gitkraken/shared-web-components": "^0.1.1-rc.11", + "@gitkraken/shared-web-components": "0.1.1-rc.11", "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", "@octokit/graphql": "7.0.2", @@ -14845,9 +14845,9 @@ "@types/react-dom": "17.0.17", "@types/sortablejs": "1.15.2", "@types/vscode": "1.80.0", - "@typescript-eslint/eslint-plugin": "6.7.3", - "@typescript-eslint/parser": "6.7.3", - "@vscode/test-electron": "2.3.4", + "@typescript-eslint/eslint-plugin": "6.7.4", + "@typescript-eslint/parser": "6.7.4", + "@vscode/test-electron": "2.3.5", "@vscode/test-web": "0.0.46", "@vscode/vsce": "2.21.1", "circular-dependency-plugin": "5.2.2", @@ -14860,7 +14860,7 @@ "cssnano-preset-advanced": "6.0.1", "esbuild": "0.19.4", "esbuild-loader": "4.0.2", - "esbuild-sass-plugin": "2.15.0", + "esbuild-sass-plugin": "2.16.0", "eslint": "8.50.0", "eslint-cli": "1.1.1", "eslint-config-prettier": "9.0.0", @@ -14880,7 +14880,7 @@ "mini-css-extract-plugin": "2.7.6", "mocha": "10.2.0", "prettier": "3.0.3", - "sass": "1.68.0", + "sass": "1.69.0", "sass-loader": "13.3.2", "schema-utils": "4.2.0", "sharp": "0.32.6", @@ -14888,7 +14888,7 @@ "terser-webpack-plugin": "5.3.9", "ts-loader": "9.4.4", "tsc-alias": "1.8.8", - "typescript": "5.2.2", + "typescript": "5.3.0-beta", "webpack": "5.88.2", "webpack-bundle-analyzer": "4.9.1", "webpack-cli": "5.1.4", diff --git a/yarn.lock b/yarn.lock index 411114e95b2ec..5574288dfb238 100644 --- a/yarn.lock +++ b/yarn.lock @@ -179,9 +179,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.9.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.0.tgz#7ccb5f58703fa61ffdcbf39e2c604a109e781162" - integrity sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ== + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" + integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== "@eslint/eslintrc@^2.1.2": version "2.1.2" @@ -219,13 +219,13 @@ "@floating-ui/utils" "^0.1.3" "@floating-ui/utils@^0.1.3": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.4.tgz#19654d1026cc410975d46445180e70a5089b3e7d" - integrity sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA== + version "0.1.6" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" + integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== "@gitkraken/gitkraken-components@10.1.27": version "10.1.27" - resolved "https://registry.npmjs.org/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.27.tgz#18a9430678d7cef6a6476f8fcab956ea26dca76e" + resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.27.tgz#18a9430678d7cef6a6476f8fcab956ea26dca76e" integrity sha512-NiQ6M7J2sfrGfB2RRaIzMuM9l67GXY5BbgNVnQJajHa3zmuPN3ImLZ92Qxn0nn/0ZsrvVDaY6ZShnPRBNnbmeA== dependencies: "@axosoft/react-virtualized" "9.22.3-gitkraken.3" @@ -237,9 +237,9 @@ react-dragula "1.1.17" react-onclickoutside "^6.13.0" -"@gitkraken/shared-web-components@^0.1.1-rc.11": +"@gitkraken/shared-web-components@0.1.1-rc.11": version "0.1.1-rc.11" - resolved "https://registry.npmjs.org/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.11.tgz#0d588af0a9c92a6ccf2339a341787c6d9d60227c" + resolved "https://registry.yarnpkg.com/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.11.tgz#0d588af0a9c92a6ccf2339a341787c6d9d60227c" integrity sha512-lslDHNgU2znzoLydkLudETHP0WlRBLdV25YgRSTcm724Elah5nFfqUdJZ8lQCKehxJBnlWtll5uTxuM+7wxVDw== dependencies: "@floating-ui/dom" "^1.4.2" @@ -696,9 +696,9 @@ integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== "@types/node@*": - version "20.8.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.0.tgz#10ddf0119cf20028781c06d7115562934e53f745" - integrity sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ== + version "20.8.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.2.tgz#d76fb80d87d0d8abfe334fc6d292e83e5524efc4" + integrity sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w== "@types/node@16.11.47": version "16.11.47" @@ -716,9 +716,9 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*": - version "15.7.7" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.7.tgz#f9361f7b87fd5d8188b2c998db0a1f47e9fb391a" - integrity sha512-FbtmBWCcSa2J4zL781Zf1p5YUBXQomPEcep9QZCfRfQgTxz3pJWiDFLebohZ9fFntX5ibzOkSsrJ0TEew8cAog== + version "15.7.8" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.8.tgz#805eae6e8f41bd19e88917d2ea200dc992f405d3" + integrity sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ== "@types/react-dom@17.0.17": version "17.0.17" @@ -782,16 +782,16 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz#d98046e9f7102d49a93d944d413c6055c47fafd7" - integrity sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA== +"@typescript-eslint/eslint-plugin@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d" + integrity sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/type-utils" "6.7.3" - "@typescript-eslint/utils" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/scope-manager" "6.7.4" + "@typescript-eslint/type-utils" "6.7.4" + "@typescript-eslint/utils" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -799,72 +799,72 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.3.tgz#aaf40092a32877439e5957e18f2d6a91c82cc2fd" - integrity sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ== +"@typescript-eslint/parser@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.4.tgz#23d1dd4fe5d295c7fa2ab651f5406cd9ad0bd435" + integrity sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA== dependencies: - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/typescript-estree" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/scope-manager" "6.7.4" + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/typescript-estree" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz#07e5709c9bdae3eaf216947433ef97b3b8b7d755" - integrity sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ== +"@typescript-eslint/scope-manager@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz#a484a17aa219e96044db40813429eb7214d7b386" + integrity sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A== dependencies: - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" -"@typescript-eslint/type-utils@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz#c2c165c135dda68a5e70074ade183f5ad68f3400" - integrity sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw== +"@typescript-eslint/type-utils@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz#847cd3b59baf948984499be3e0a12ff07373e321" + integrity sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ== dependencies: - "@typescript-eslint/typescript-estree" "6.7.3" - "@typescript-eslint/utils" "6.7.3" + "@typescript-eslint/typescript-estree" "6.7.4" + "@typescript-eslint/utils" "6.7.4" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.3.tgz#0402b5628a63f24f2dc9d4a678e9a92cc50ea3e9" - integrity sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw== +"@typescript-eslint/types@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.4.tgz#5d358484d2be986980c039de68e9f1eb62ea7897" + integrity sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA== -"@typescript-eslint/typescript-estree@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz#ec5bb7ab4d3566818abaf0e4a8fa1958561b7279" - integrity sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g== +"@typescript-eslint/typescript-estree@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz#f2baece09f7bb1df9296e32638b2e1130014ef1a" + integrity sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ== dependencies: - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.3.tgz#96c655816c373135b07282d67407cb577f62e143" - integrity sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg== +"@typescript-eslint/utils@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.4.tgz#2236f72b10e38277ee05ef06142522e1de470ff2" + integrity sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/typescript-estree" "6.7.3" + "@typescript-eslint/scope-manager" "6.7.4" + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/typescript-estree" "6.7.4" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz#83809631ca12909bd2083558d2f93f5747deebb2" - integrity sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg== +"@typescript-eslint/visitor-keys@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz#80dfecf820fc67574012375859085f91a4dff043" + integrity sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA== dependencies: - "@typescript-eslint/types" "6.7.3" + "@typescript-eslint/types" "6.7.4" eslint-visitor-keys "^3.4.1" "@vscode/codicons@0.0.33": @@ -872,10 +872,10 @@ resolved "https://registry.yarnpkg.com/@vscode/codicons/-/codicons-0.0.33.tgz#a56243ab5492801fff04e53c0aab0d18a6521751" integrity sha512-VdgpnD75swH9hpXjd34VBgQ2w2quK63WljodlUcOoJDPKiV+rPjHrcUc2sjLCNKxhl6oKqmsZgwOWcDAY2GKKQ== -"@vscode/test-electron@2.3.4": - version "2.3.4" - resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.3.4.tgz#d0ed1de72d347221cdf71426b0c7e21136f4791f" - integrity sha512-eWzIqXMhvlcoXfEFNWrVu/yYT5w6De+WZXR/bafUQhAp8+8GkQo95Oe14phwiRUPv8L+geAKl/QM2+PoT3YW3g== +"@vscode/test-electron@2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.3.5.tgz#c472c5bdce1329aeb4762b8aa7a2cbe7aa783aac" + integrity sha512-lAW7nQ0HuPqJnGJrtCzEKZCICtRizeP6qNanyCrjmdCOAAWjX3ixiG8RVPwqsYPQBWLPgYuE12qQlwXsOR/2fQ== dependencies: http-proxy-agent "^4.0.1" https-proxy-agent "^5.0.0" @@ -1612,9 +1612,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001541" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" - integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== + version "1.0.30001546" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz#10fdad03436cfe3cc632d3af7a99a0fb497407f0" + integrity sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw== capital-case@^1.0.4: version "1.0.4" @@ -1716,9 +1716,9 @@ chrome-trace-event@^1.0.2: integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== circular-dependency-plugin@5.2.2: version "5.2.2" @@ -2595,9 +2595,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.535: - version "1.4.537" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.537.tgz#aac4101db53066be1e49baedd000a26bc754adc9" - integrity sha512-W1+g9qs9hviII0HAwOdehGYkr+zt7KKdmCcJcjH0mYg6oL8+ioT3Skjmt7BLoAQqXhjf40AXd+HlR4oAWMlXjA== + version "1.4.543" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.543.tgz#51116ffc9fba1ee93514d6a40d34676aa6d7d1c4" + integrity sha512-t2ZP4AcGE0iKCCQCBx/K2426crYdxD3YU6l0uK2EO3FZH0pbC4pFz/sZm2ruZsND6hQBTcDWWlo/MLpiOdif5g== emoji-regex@^8.0.0: version "8.0.0" @@ -2799,13 +2799,13 @@ esbuild-loader@4.0.2: loader-utils "^2.0.4" webpack-sources "^1.4.3" -esbuild-sass-plugin@2.15.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/esbuild-sass-plugin/-/esbuild-sass-plugin-2.15.0.tgz#268a31617a79ee92ae30db4b91ce3603bfa687ce" - integrity sha512-T0GCHVfeuGBBgY5k19RbExd7vVuC3lzrK8IZbXOqZftw6N9lTBnZuqKhnhdAJBcu6wek7K/fXJ2zzY6KrcNtAg== +esbuild-sass-plugin@2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/esbuild-sass-plugin/-/esbuild-sass-plugin-2.16.0.tgz#2908ab5e104cfc980118c46d0b409cbab8aa32dd" + integrity sha512-mGCe9MxNYvZ+j77Q/QFO+rwUGA36mojDXkOhtVmoyz1zwYbMaNrtVrmXwwYDleS/UMKTNU3kXuiTtPiAD3K+Pw== dependencies: - resolve "^1.22.2" - sass "^1.65.1" + resolve "^1.22.6" + sass "^1.7.3" esbuild@0.19.4, esbuild@^0.19.0: version "0.19.4" @@ -3190,11 +3190,11 @@ find-up@^4.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.1.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f" - integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== + version "3.1.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" + integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== dependencies: - flatted "^3.2.7" + flatted "^3.2.9" keyv "^4.5.3" rimraf "^3.0.2" @@ -3203,7 +3203,7 @@ flat@^5.0.2: resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^3.2.7: +flatted@^3.2.9: version "3.2.9" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== @@ -3430,9 +3430,9 @@ glob@^7.0.3, glob@^7.0.6, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: path-is-absolute "^1.0.0" globals@^13.19.0: - version "13.22.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.22.0.tgz#0c9fcb9c48a2494fbb5edbfee644285543eba9d8" - integrity sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw== + version "13.23.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== dependencies: type-fest "^0.20.2" @@ -3587,11 +3587,9 @@ has-unicode@^2.0.1: integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" + version "1.0.4" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" + integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== he@1.2.0, he@^1.2.0: version "1.2.0" @@ -5462,11 +5460,11 @@ playwright@^1.38.1: fsevents "2.3.2" plimit-lit@^1.2.6: - version "1.5.0" - resolved "https://registry.yarnpkg.com/plimit-lit/-/plimit-lit-1.5.0.tgz#f66df8a7041de1e965c4f1c0697ab486968a92a5" - integrity sha512-Eb/MqCb1Iv/ok4m1FqIXqvUKPISufcjZ605hl3KM/n8GaX8zfhtgdLwZU3vKjuHGh2O9Rjog/bHTq8ofIShdng== + version "1.6.1" + resolved "https://registry.yarnpkg.com/plimit-lit/-/plimit-lit-1.6.1.tgz#a34594671b31ee8e93c72d505dfb6852eb72374a" + integrity sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA== dependencies: - queue-lit "^1.5.0" + queue-lit "^1.5.1" postcss-calc@^9.0.0: version "9.0.1" @@ -5844,10 +5842,10 @@ qs@^6.9.1: dependencies: side-channel "^1.0.4" -queue-lit@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/queue-lit/-/queue-lit-1.5.0.tgz#8197fdafda1edd615c8a0fc14c48353626e5160a" - integrity sha512-IslToJ4eiCEE9xwMzq3viOO5nH8sUWUCwoElrhNMozzr9IIt2qqvB4I+uHu/zJTQVqc9R5DFwok4ijNK1pU3fA== +queue-lit@^1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/queue-lit/-/queue-lit-1.5.2.tgz#83c24d4f4764802377b05a6e5c73017caf3f8747" + integrity sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw== queue-microtask@^1.2.2: version "1.2.3" @@ -6156,7 +6154,7 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4, resolve@^1.3.3: +resolve@^1.20.0, resolve@^1.22.4, resolve@^1.22.6, resolve@^1.3.3: version "1.22.6" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== @@ -6249,10 +6247,10 @@ sass-loader@13.3.2: dependencies: neo-async "^2.6.2" -sass@1.68.0, sass@^1.65.1: - version "1.68.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.68.0.tgz#0034b0cc9a50248b7d1702ac166fd25990023669" - integrity sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA== +sass@1.69.0, sass@^1.7.3: + version "1.69.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.0.tgz#5195075371c239ed556280cf2f5944d234f42679" + integrity sha512-l3bbFpfTOGgQZCLU/gvm1lbsQ5mC/WnLz3djL2v4WCJBDrWm58PO+jgngcGRNnKUh6wSsdm50YaovTqskZ0xDQ== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -6574,9 +6572,9 @@ spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.15" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz#142460aabaca062bc7cd4cc87b7d50725ed6a4ba" - integrity sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ== + version "3.0.16" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz#a14f64e0954f6e25cc6587bd4f392522db0d998f" + integrity sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw== spdx-ranges@^2.0.0: version "2.1.1" @@ -6886,9 +6884,9 @@ terser-webpack-plugin@5.3.9, terser-webpack-plugin@^5.3.7: terser "^5.16.8" terser@^5.10.0, terser@^5.15.1, terser@^5.16.8: - version "5.20.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.20.0.tgz#ea42aea62578703e33def47d5c5b93c49772423e" - integrity sha512-e56ETryaQDyebBwJIWYB2TT6f2EZ0fL0sW/JRXNMN26zZdKi2u/E/5my5lG6jNxym6qsrVXfFRmOdV42zlAgLQ== + version "5.21.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.21.0.tgz#d2b27e92b5e56650bc83b6defa00a110f0b124b2" + integrity sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -7138,10 +7136,10 @@ typed-rest-client@^1.8.4: tunnel "0.0.6" underscore "^1.12.1" -typescript@5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" - integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +typescript@5.3.0-beta: + version "5.3.0-beta" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.0-beta.tgz#20c29bff9ba381a2120a5705bd87a0c8a2104b54" + integrity sha512-SiTeC1C8wAS6v2SD05iyfojeuIkUZIbb8suZz0d4BR+RErwpG+05iolat+VjM9hqXSrjb3xutEBzh4X3NJ7Jgw== typescript@^4.9.5: version "4.9.5" @@ -7269,9 +7267,9 @@ vary@^1.1.2: integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== vscode-uri@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8" - integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA== + version "3.0.8" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f" + integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== warning@^3.0.0: version "3.0.0" From d7925410ce63f0561003c0446813ec651abe52c7 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Fri, 6 Oct 2023 11:31:48 -0700 Subject: [PATCH 0026/1012] Updates CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09bf4aea68ffc..cb261af610c19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed +- Improves performance when working with connected remotes - Relaxes PR autolink detection for Azure DevOps to use `PR ` instead of `Merged PR ` — closes [#2908](https://github.com/gitkraken/vscode-gitlens/issues/2908) - Replaces VSCode git operations (`fetch`, `push`, `pull`) with GitLens' own implementations to avoid issues with VSCode's git extension. This can be reverted by setting `"gitlens.experimental.nativeGit"` to `"false"` in settings. - Adds deep link support for workspaces in the _GitKraken Workspaces_ view - Deep link format: `https://gitkraken.dev/link/workspaces/{workspaceId}` - Adds a _Share_ submenu with a _Copy Link to Workspace_ command to workspaces in the _GitKraken Workspaces_ view +- Changes wording on `Reset Stored OpenAI Key` command to `Reset Stored AI Key` to reflect support for other providers ### Fixed @@ -23,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Fixes issue with "View as [List|Tree]" toggle not working in the _Commit Details_ view - Fixes an issue with deep links sometimes failing to properly resolve when a matching repository without the remote is found - Fixes an issue in the _Commit Graph_ where commits not in the history of a merge commit were showing in the same column +- Fixes `Reset Stored AI Key` command to work for the current provider ## [14.3.0] - 2023-09-07 From 5aa1e48730b704ac2377f5a6050a15bf2bed5ac1 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 6 Oct 2023 18:12:12 -0400 Subject: [PATCH 0027/1012] Fixes issue w/ parsing some log renames --- CHANGELOG.md | 1 + src/git/parsers/logParser.ts | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb261af610c19..8bef1e10db60f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Fixes an issue with deep links sometimes failing to properly resolve when a matching repository without the remote is found - Fixes an issue in the _Commit Graph_ where commits not in the history of a merge commit were showing in the same column - Fixes `Reset Stored AI Key` command to work for the current provider +- Fixes an issue with parsing some renames in log output ## [14.3.0] - 2023-09-07 diff --git a/src/git/parsers/logParser.ts b/src/git/parsers/logParser.ts index 98abbccadb254..c47af411e93da 100644 --- a/src/git/parsers/logParser.ts +++ b/src/git/parsers/logParser.ts @@ -19,7 +19,7 @@ const diffRangeRegex = /^@@ -(\d+?),(\d+?) \+(\d+?),(\d+?) @@/; export const fileStatusRegex = /(\S)\S*\t([^\t\n]+)(?:\t(.+))?/; const fileStatusAndSummaryRegex = /^(\d+?|-)\s+?(\d+?|-)\s+?(.*)(?:\n\s(delete|rename|copy|create))?/; const fileStatusAndSummaryRenamedFileRegex = /(.+)\s=>\s(.+)/; -const fileStatusAndSummaryRenamedFilePathRegex = /(.*?){(.+?)\s=>\s(.*?)}(.*)/; +const fileStatusAndSummaryRenamedFilePathRegex = /(.*?){(.+?)?\s=>\s(.*?)?}(.*)/; const logFileSimpleRegex = /^ (.*)\s*(?:(?:diff --git a\/(.*) b\/(.*))|(?:(\S)\S*\t([^\t\n]+)(?:\t(.+))?))/gm; const logFileSimpleRenamedRegex = /^ (\S+)\s*(.*)$/s; @@ -656,12 +656,27 @@ export class GitLogParser { renamedMatch = fileStatusAndSummaryRenamedFilePathRegex.exec(renamedFileName); if (renamedMatch != null) { + const [, start, from, to, end] = renamedMatch; // If there is no new path, the path part was removed so ensure we don't end up with // - entry.path = - renamedMatch[3] === '' - ? `${renamedMatch[1]}${renamedMatch[4]}`.replace('//', '/') - : `${renamedMatch[1]}${renamedMatch[3]}${renamedMatch[4]}`; - entry.originalPath = `${renamedMatch[1]}${renamedMatch[2]}${renamedMatch[4]}`; + if (!to) { + entry.path = `${ + start.endsWith('/') && end.startsWith('/') + ? start.slice(0, -1) + : start + }${end}`; + } else { + entry.path = `${start}${to}${end}`; + } + + if (!from) { + entry.originalPath = `${ + start.endsWith('/') && end.startsWith('/') + ? start.slice(0, -1) + : start + }${end}`; + } else { + entry.originalPath = `${start}${from}${end}`; + } } else { renamedMatch = fileStatusAndSummaryRenamedFileRegex.exec(renamedFileName); From d2fc1c1e7dfe1b591e56e51701e4a232e577fe56 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 6 Oct 2023 18:13:23 -0400 Subject: [PATCH 0028/1012] Removes unused flag --- src/env/node/git/localGitProvider.ts | 15 ++++++--------- src/git/gitProvider.ts | 1 - src/git/gitProviderService.ts | 3 +-- src/plus/github/githubGitProvider.ts | 1 - 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 1573c4721c33b..98dad369057e5 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -3856,7 +3856,6 @@ export class LocalGitProvider implements GitProvider, Disposable { uri: Uri, ref: string | undefined, skip: number = 0, - firstParent: boolean = false, ): Promise { if (ref === deletedOrMissing) return undefined; @@ -3886,13 +3885,13 @@ export class LocalGitProvider implements GitProvider, Disposable { return { // Diff staged with HEAD (or prior if more skips) current: GitUri.fromFile(relativePath, repoPath, uncommittedStaged), - previous: await this.getPreviousUri(repoPath, uri, ref, skip - 1, undefined, firstParent), + previous: await this.getPreviousUri(repoPath, uri, ref, skip - 1), }; } else if (status.workingTreeStatus != null) { if (skip === 0) { return { current: GitUri.fromFile(relativePath, repoPath, undefined), - previous: await this.getPreviousUri(repoPath, uri, undefined, skip, undefined, firstParent), + previous: await this.getPreviousUri(repoPath, uri, undefined, skip), }; } } @@ -3905,12 +3904,12 @@ export class LocalGitProvider implements GitProvider, Disposable { const current = skip === 0 ? GitUri.fromFile(relativePath, repoPath, ref) - : (await this.getPreviousUri(repoPath, uri, undefined, skip - 1, undefined, firstParent))!; + : (await this.getPreviousUri(repoPath, uri, undefined, skip - 1))!; if (current == null || current.sha === deletedOrMissing) return undefined; return { current: current, - previous: await this.getPreviousUri(repoPath, uri, undefined, skip, undefined, firstParent), + previous: await this.getPreviousUri(repoPath, uri, undefined, skip), }; } @@ -3918,12 +3917,12 @@ export class LocalGitProvider implements GitProvider, Disposable { const current = skip === 0 ? GitUri.fromFile(relativePath, repoPath, ref) - : (await this.getPreviousUri(repoPath, uri, ref, skip - 1, undefined, firstParent))!; + : (await this.getPreviousUri(repoPath, uri, ref, skip - 1))!; if (current == null || current.sha === deletedOrMissing) return undefined; return { current: current, - previous: await this.getPreviousUri(repoPath, uri, ref, skip, undefined, firstParent), + previous: await this.getPreviousUri(repoPath, uri, ref, skip), }; } @@ -4053,7 +4052,6 @@ export class LocalGitProvider implements GitProvider, Disposable { ref?: string, skip: number = 0, editorLine?: number, - firstParent: boolean = false, ): Promise { if (ref === deletedOrMissing) return undefined; @@ -4071,7 +4069,6 @@ export class LocalGitProvider implements GitProvider, Disposable { data = await this.git.log__file(repoPath, relativePath, ref, { argsOrFormat: GitLogParser.simpleFormat, fileMode: 'simple', - firstParent: firstParent, limit: skip + 2, ordering: configuration.get('advanced.commitOrdering'), startLine: editorLine != null ? editorLine + 1 : undefined, diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 79ac1f0a3b26c..8ad2b5cf119c8 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -372,7 +372,6 @@ export interface GitProvider extends Disposable { uri: Uri, ref: string | undefined, skip?: number, - firstParent?: boolean, ): Promise; getPreviousComparisonUrisForLine( repoPath: string, diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 89524da10d917..ec811edc09766 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -1911,12 +1911,11 @@ export class GitProviderService implements Disposable { uri: Uri, ref: string | undefined, skip: number = 0, - firstParent: boolean = false, ): Promise { if (ref === deletedOrMissing) return Promise.resolve(undefined); const { provider, path } = this.getProvider(repoPath); - return provider.getPreviousComparisonUris(path, uri, ref, skip, firstParent); + return provider.getPreviousComparisonUris(path, uri, ref, skip); } @log() diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index b202a368c366c..6832633347fa1 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -2413,7 +2413,6 @@ export class GitHubGitProvider implements GitProvider, Disposable { uri: Uri, ref: string | undefined, skip: number = 0, - _firstParent: boolean = false, ): Promise { if (ref === deletedOrMissing) return undefined; From e5c9a0d307a7db7e02f5c6ce5de1119f3758031c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 6 Oct 2023 19:15:39 -0400 Subject: [PATCH 0029/1012] Fixes #2104, #2944 filter merge commits in history - Changes File History view to follow renames by default - Adds [Show|Hide] Merge Commits toggle to File History - Adds `advanced.fileHistoryShowMergeCommits` setting --- CHANGELOG.md | 6 +++ package.json | 43 ++++++++++++++-- src/config.ts | 1 + src/constants.ts | 1 + src/env/node/git/git.ts | 17 +++---- src/env/node/git/localGitProvider.ts | 73 ++++++++++++++++------------ src/views/fileHistoryView.ts | 17 ++++++- 7 files changed, 113 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bef1e10db60f..16c1ff1aeec2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Added + +- Adds a _[Show|Hide] Merge Commits_ toggle to the _File History_ view — closes [#2104](https://github.com/gitkraken/vscode-gitlens/issues/2104) & [#2944](https://github.com/gitkraken/vscode-gitlens/issues/2944) + - Adds a `gitlens.advanced.fileHistoryShowMergeCommits` setting to specify whether merge commits will be show in file histories + ### Changed - Improves performance when working with connected remotes +- Changes the _File History_ view to follow renames and filters out merge commits by default — closes [#2104](https://github.com/gitkraken/vscode-gitlens/issues/2104) & [#2944](https://github.com/gitkraken/vscode-gitlens/issues/2944) - Relaxes PR autolink detection for Azure DevOps to use `PR ` instead of `Merged PR ` — closes [#2908](https://github.com/gitkraken/vscode-gitlens/issues/2908) - Replaces VSCode git operations (`fetch`, `push`, `pull`) with GitLens' own implementations to avoid issues with VSCode's git extension. This can be reverted by setting `"gitlens.experimental.nativeGit"` to `"false"` in settings. - Adds deep link support for workspaces in the _GitKraken Workspaces_ view diff --git a/package.json b/package.json index cece2f619b4fe..94d6d0f2152f6 100644 --- a/package.json +++ b/package.json @@ -1194,8 +1194,8 @@ }, "gitlens.advanced.fileHistoryFollowsRenames": { "type": "boolean", - "default": false, - "markdownDescription": "Specifies whether file histories will follow renames — will affect how merge commits are shown in histories", + "default": true, + "markdownDescription": "Specifies whether file histories will follow renames", "scope": "window", "order": 100 }, @@ -1205,6 +1205,13 @@ "markdownDescription": "Specifies whether file histories will show commits from all branches", "scope": "window", "order": 101 + }, + "gitlens.advanced.fileHistoryShowMergeCommits": { + "type": "boolean", + "default": false, + "markdownDescription": "Specifies whether file histories will show merge commits", + "scope": "window", + "order": 102 } } }, @@ -6569,6 +6576,16 @@ "title": "View History for Current Branch Only", "category": "GitLens" }, + { + "command": "gitlens.views.fileHistory.setShowMergeCommitsOn", + "title": "Show Merge Commits", + "category": "GitLens" + }, + { + "command": "gitlens.views.fileHistory.setShowMergeCommitsOff", + "title": "Hide Merge Commits", + "category": "GitLens" + }, { "command": "gitlens.views.fileHistory.setShowAvatarsOn", "title": "Show Avatars", @@ -9317,6 +9334,14 @@ "command": "gitlens.views.fileHistory.setShowAllBranchesOff", "when": "false" }, + { + "command": "gitlens.views.fileHistory.setShowMergeCommitsOn", + "when": "false" + }, + { + "command": "gitlens.views.fileHistory.setShowMergeCommitsOff", + "when": "false" + }, { "command": "gitlens.views.fileHistory.setShowAvatarsOn", "when": "false" @@ -10848,15 +10873,25 @@ "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && !config.gitlens.advanced.fileHistoryShowAllBranches && config.gitlens.advanced.fileHistoryFollowsRenames", "group": "3_gitlens@1" }, + { + "command": "gitlens.views.fileHistory.setShowMergeCommitsOn", + "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && !config.gitlens.advanced.fileHistoryShowMergeCommits", + "group": "3_gitlens@2" + }, + { + "command": "gitlens.views.fileHistory.setShowMergeCommitsOff", + "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && config.gitlens.advanced.fileHistoryShowMergeCommits", + "group": "3_gitlens@2" + }, { "command": "gitlens.views.fileHistory.setShowAllBranchesOn", "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && !config.gitlens.advanced.fileHistoryShowAllBranches", - "group": "3_gitlens@2" + "group": "3_gitlens@3" }, { "command": "gitlens.views.fileHistory.setShowAllBranchesOff", "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && config.gitlens.advanced.fileHistoryShowAllBranches", - "group": "3_gitlens@2" + "group": "3_gitlens@3" }, { "command": "gitlens.views.fileHistory.setShowAvatarsOn", diff --git a/src/config.ts b/src/config.ts index e53907bdc7418..c25369e3459e7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -303,6 +303,7 @@ export interface AdvancedConfig { readonly externalDirectoryDiffTool: string | null; readonly fileHistoryFollowsRenames: boolean; readonly fileHistoryShowAllBranches: boolean; + readonly fileHistoryShowMergeCommits: boolean; readonly maxListItems: number; readonly maxSearchItems: number; readonly messages: { [key in SuppressedMessages]: boolean }; diff --git a/src/constants.ts b/src/constants.ts index 818be5ef60522..db3461afd9707 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -353,6 +353,7 @@ export type TreeViewCommands = `gitlens.views.${ | `setEditorFollowing${'On' | 'Off'}` | `setRenameFollowing${'On' | 'Off'}` | `setShowAllBranches${'On' | 'Off'}` + | `setShowMergeCommits${'On' | 'Off'}` | `setShowAvatars${'On' | 'Off'}`}` | `lineHistory.${ | 'copy' diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index f279c26bd9e40..f772c2d13549a 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -1213,8 +1213,8 @@ export class Git { // TODO@eamodio remove this in favor of argsOrFormat fileMode = 'full', filters, - firstParent = false, limit, + merges = false, ordering, renames = true, reverse = false, @@ -1228,8 +1228,8 @@ export class Git { // TODO@eamodio remove this in favor of argsOrFormat fileMode?: 'full' | 'simple' | 'none'; filters?: GitDiffFilter[]; - firstParent?: boolean; limit?: number; + merges?: boolean; ordering?: 'date' | 'author-date' | 'topo' | null; renames?: boolean; reverse?: boolean; @@ -1271,18 +1271,17 @@ export class Git { params.push('--all', '--single-worktree'); } + if (merges) { + params.push('--first-parent'); + } + // Can't allow rename detection (`--follow`) if `all` or a `startLine` is specified if (renames && (all || startLine != null)) { renames = false; } - params.push(renames ? '--follow' : '-m'); - if (/*renames ||*/ firstParent) { - params.push('--first-parent'); - // In Git >= 2.29.0 `--first-parent` implies `-m`, so lets include it for consistency - if (renames) { - params.push('-m'); - } + if (renames) { + params.push('--follow'); } if (filters != null && filters.length !== 0) { diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 98dad369057e5..ae3ecdd5ebd0f 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -3277,47 +3277,58 @@ export class LocalGitProvider implements GitProvider, Disposable { throw new Error(`File name cannot match the repository path; path=${relativePath}`); } - options = { reverse: false, ...options }; + const opts: typeof options & Parameters[2] = { + reverse: false, + ...options, + }; + + if (opts.renames == null) { + opts.renames = configuration.get('advanced.fileHistoryFollowsRenames'); + } - if (options.renames == null) { - options.renames = configuration.get('advanced.fileHistoryFollowsRenames'); + if (opts.merges == null) { + opts.merges = configuration.get('advanced.fileHistoryShowMergeCommits'); } let key = 'log'; - if (options.ref != null) { - key += `:${options.ref}`; + if (opts.ref != null) { + key += `:${opts.ref}`; } - if (options.all == null) { - options.all = configuration.get('advanced.fileHistoryShowAllBranches'); + if (opts.all == null) { + opts.all = configuration.get('advanced.fileHistoryShowAllBranches'); } - if (options.all) { + if (opts.all) { key += ':all'; } - options.limit = options.limit ?? configuration.get('advanced.maxListItems') ?? 0; - if (options.limit) { - key += `:n${options.limit}`; + opts.limit = opts.limit ?? configuration.get('advanced.maxListItems') ?? 0; + if (opts.limit) { + key += `:n${opts.limit}`; } - if (options.renames) { + if (opts.merges) { + key += ':merges'; + } + + if (opts.renames) { key += ':follow'; } - if (options.reverse) { + if (opts.reverse) { key += ':reverse'; } - if (options.since) { - key += `:since=${options.since}`; + if (opts.since) { + key += `:since=${opts.since}`; } - if (options.skip) { - key += `:skip${options.skip}`; + if (opts.skip) { + key += `:skip${opts.skip}`; } - const doc = await this.container.tracker.getOrAdd(GitUri.fromFile(relativePath, repoPath, options.ref)); - if (!options.force && this.useCaching && options.range == null) { + const doc = await this.container.tracker.getOrAdd(GitUri.fromFile(relativePath, repoPath, opts.ref)); + if (!opts.force && this.useCaching && opts.range == null) { if (doc.state != null) { const cachedLog = doc.state.getLog(key); if (cachedLog != null) { @@ -3325,20 +3336,20 @@ export class LocalGitProvider implements GitProvider, Disposable { return cachedLog.item; } - if (options.ref != null || (options.limit != null && options.limit !== 0)) { + if (opts.ref != null || (opts.limit != null && opts.limit !== 0)) { // Since we are looking for partial log, see if we have the log of the whole file const cachedLog = doc.state.getLog( - `log${options.renames ? ':follow' : ''}${options.reverse ? ':reverse' : ''}`, + `log${opts.renames ? ':follow' : ''}${opts.reverse ? ':reverse' : ''}`, ); if (cachedLog != null) { - if (options.ref == null) { + if (opts.ref == null) { Logger.debug(scope, `Cache hit: ~'${key}'`); return cachedLog.item; } Logger.debug(scope, `Cache ?: '${key}'`); let log = await cachedLog.item; - if (log != null && !log.hasMore && log.commits.has(options.ref)) { + if (log != null && !log.hasMore && log.commits.has(opts.ref)) { Logger.debug(scope, `Cache hit: '${key}'`); // Create a copy of the log starting at the requested commit @@ -3349,12 +3360,12 @@ export class LocalGitProvider implements GitProvider, Disposable { log.commits.entries(), ([ref, c]) => { if (skip) { - if (ref !== options?.ref) return undefined; + if (ref !== opts?.ref) return undefined; skip = false; } i++; - if (options?.limit != null && i > options.limit) { + if (opts?.limit != null && i > opts.limit) { return undefined; } @@ -3363,14 +3374,14 @@ export class LocalGitProvider implements GitProvider, Disposable { ), ); - const opts = { ...options }; + const optsCopy = { ...opts }; log = { ...log, - limit: options.limit, + limit: optsCopy.limit, count: commits.size, commits: commits, query: (limit: number | undefined) => - this.getLogForFile(repoPath, pathOrUri, { ...opts, limit: limit }), + this.getLogForFile(repoPath, pathOrUri, { ...optsCopy, limit: limit }), }; return log; @@ -3386,9 +3397,9 @@ export class LocalGitProvider implements GitProvider, Disposable { } } - const promise = this.getLogForFileCore(repoPath, relativePath, options, doc, key, scope); + const promise = this.getLogForFileCore(repoPath, relativePath, opts, doc, key, scope); - if (doc.state != null && options.range == null) { + if (doc.state != null && opts.range == null) { Logger.debug(scope, `Cache add: '${key}'`); const value: CachedLog = { @@ -3411,6 +3422,7 @@ export class LocalGitProvider implements GitProvider, Disposable { all?: boolean; cursor?: string; limit?: number; + merges?: boolean; ordering?: 'date' | 'author-date' | 'topo' | null; range?: Range; ref?: string; @@ -3439,7 +3451,6 @@ export class LocalGitProvider implements GitProvider, Disposable { const data = await this.git.log__file(root, relativePath, ref, { ordering: configuration.get('advanced.commitOrdering'), ...options, - firstParent: options.renames, startLine: range == null ? undefined : range.start.line + 1, endLine: range == null ? undefined : range.end.line + 1, }); diff --git a/src/views/fileHistoryView.ts b/src/views/fileHistoryView.ts index a6b97a089f1f6..eb11d76e81775 100644 --- a/src/views/fileHistoryView.ts +++ b/src/views/fileHistoryView.ts @@ -89,6 +89,16 @@ export class FileHistoryView extends ViewBase< () => this.setShowAllBranches(false), this, ), + registerViewCommand( + this.getQualifiedCommand('setShowMergeCommitsOn'), + () => this.setShowMergeCommits(true), + this, + ), + registerViewCommand( + this.getQualifiedCommand('setShowMergeCommitsOff'), + () => this.setShowMergeCommits(false), + this, + ), registerViewCommand(this.getQualifiedCommand('setShowAvatarsOn'), () => this.setShowAvatars(true), this), registerViewCommand(this.getQualifiedCommand('setShowAvatarsOff'), () => this.setShowAvatars(false), this), ]; @@ -106,7 +116,8 @@ export class FileHistoryView extends ViewBase< !configuration.changed(e, 'defaultGravatarsStyle') && !configuration.changed(e, 'defaultTimeFormat') && !configuration.changed(e, 'advanced.fileHistoryFollowsRenames') && - !configuration.changed(e, 'advanced.fileHistoryShowAllBranches') + !configuration.changed(e, 'advanced.fileHistoryShowAllBranches') && + !configuration.changed(e, 'advanced.fileHistoryShowMergeCommits') ) { return false; } @@ -180,6 +191,10 @@ export class FileHistoryView extends ViewBase< return configuration.updateEffective('advanced.fileHistoryShowAllBranches', enabled); } + private setShowMergeCommits(enabled: boolean) { + return configuration.updateEffective('advanced.fileHistoryShowMergeCommits', enabled); + } + private setShowAvatars(enabled: boolean) { return configuration.updateEffective(`views.${this.configKey}.avatars` as const, enabled); } From 4501529ab0a3d2c7ae977c1a7554715bbc261b86 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 6 Oct 2023 19:21:04 -0400 Subject: [PATCH 0030/1012] Updates CHANGELOG --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16c1ff1aeec2d..fd868b81cb6cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,16 +10,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Adds a _[Show|Hide] Merge Commits_ toggle to the _File History_ view — closes [#2104](https://github.com/gitkraken/vscode-gitlens/issues/2104) & [#2944](https://github.com/gitkraken/vscode-gitlens/issues/2944) - Adds a `gitlens.advanced.fileHistoryShowMergeCommits` setting to specify whether merge commits will be show in file histories +- Adds deep link support for workspaces in the _GitKraken Workspaces_ view + - Deep link format: `https://gitkraken.dev/link/workspaces/{workspaceId}` + - Adds a _Share_ submenu with a _Copy Link to Workspace_ command to workspaces in the _GitKraken Workspaces_ view ### Changed -- Improves performance when working with connected remotes +- Improves performance of inline blame, status bar blame, and hovers especially when working with remotes with connected integrations - Changes the _File History_ view to follow renames and filters out merge commits by default — closes [#2104](https://github.com/gitkraken/vscode-gitlens/issues/2104) & [#2944](https://github.com/gitkraken/vscode-gitlens/issues/2944) +- Changes to use our own implementation of `fetch`, `push`, and `pull` Git operations, rather than delegating to VS Code to avoid limitations especially with GitKraken Workspaces. Please report any issues and you can revert this (for now) by setting `"gitlens.experimental.nativeGit"` to `"false"` in your settings - Relaxes PR autolink detection for Azure DevOps to use `PR ` instead of `Merged PR ` — closes [#2908](https://github.com/gitkraken/vscode-gitlens/issues/2908) -- Replaces VSCode git operations (`fetch`, `push`, `pull`) with GitLens' own implementations to avoid issues with VSCode's git extension. This can be reverted by setting `"gitlens.experimental.nativeGit"` to `"false"` in settings. -- Adds deep link support for workspaces in the _GitKraken Workspaces_ view - - Deep link format: `https://gitkraken.dev/link/workspaces/{workspaceId}` - - Adds a _Share_ submenu with a _Copy Link to Workspace_ command to workspaces in the _GitKraken Workspaces_ view - Changes wording on `Reset Stored OpenAI Key` command to `Reset Stored AI Key` to reflect support for other providers ### Fixed From d758cc0a046ecd24c423f24b3eabbbcf4ddbeac4 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 9 Oct 2023 17:30:04 -0400 Subject: [PATCH 0031/1012] Fixes id for unpinning issues --- src/plus/webviews/focus/focusWebview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index b1eb111969f9b..8d16b37b90d2f 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -133,7 +133,7 @@ export class FocusWebviewProvider implements WebviewProvider { if (issueWithRemote == null) return; if (pin) { - await this.container.focus.unpinItem(issueWithRemote.issue.id); + await this.container.focus.unpinItem(pin); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== pin); issueWithRemote.enriched = issueWithRemote.enriched?.filter(e => e.id !== pin); } else { From 1b447ffdfa8fbfa6234c35a95088bf23d0794752 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 9 Oct 2023 23:49:32 -0400 Subject: [PATCH 0032/1012] Removes re-exports to limit import scopes --- src/annotations/annotationProvider.ts | 3 ++- src/annotations/blameAnnotationProvider.ts | 3 ++- src/annotations/fileAnnotationController.ts | 7 ++----- src/annotations/gutterChangesAnnotationProvider.ts | 3 ++- src/annotations/lineAnnotationController.ts | 3 ++- src/codelens/codeLensController.ts | 7 ++----- src/env/node/git/localGitProvider.ts | 3 ++- src/hovers/lineHoverController.ts | 2 +- src/statusbar/statusBarController.ts | 3 ++- src/trackers/documentTracker.ts | 9 ++++++--- src/trackers/gitDocumentTracker.ts | 2 -- src/trackers/gitLineTracker.ts | 6 ++---- src/trackers/trackedDocument.ts | 9 ++------- src/views/nodes/lineHistoryTrackerNode.ts | 2 +- 14 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/annotations/annotationProvider.ts b/src/annotations/annotationProvider.ts index 702ebf7cdd342..62eda4dd4bc9f 100644 --- a/src/annotations/annotationProvider.ts +++ b/src/annotations/annotationProvider.ts @@ -11,7 +11,8 @@ import { Disposable, window } from 'vscode'; import type { FileAnnotationType } from '../config'; import { setContext } from '../system/context'; import { Logger } from '../system/logger'; -import type { GitDocumentState, TrackedDocument } from '../trackers/gitDocumentTracker'; +import type { GitDocumentState } from '../trackers/gitDocumentTracker'; +import type { TrackedDocument } from '../trackers/trackedDocument'; export type AnnotationStatus = 'computing' | 'computed'; diff --git a/src/annotations/blameAnnotationProvider.ts b/src/annotations/blameAnnotationProvider.ts index 3facb384c196f..3c8b47de9dd83 100644 --- a/src/annotations/blameAnnotationProvider.ts +++ b/src/annotations/blameAnnotationProvider.ts @@ -8,7 +8,8 @@ import type { GitCommit } from '../git/models/commit'; import { changesMessage, detailsMessage } from '../hovers/hovers'; import { configuration } from '../system/configuration'; import { log } from '../system/decorators/log'; -import type { GitDocumentState, TrackedDocument } from '../trackers/gitDocumentTracker'; +import type { GitDocumentState } from '../trackers/gitDocumentTracker'; +import type { TrackedDocument } from '../trackers/trackedDocument'; import { AnnotationProviderBase } from './annotationProvider'; import type { ComputedHeatmap } from './annotations'; import { getHeatmapColors } from './annotations'; diff --git a/src/annotations/fileAnnotationController.ts b/src/annotations/fileAnnotationController.ts index ba787da453d36..d883707f9eaea 100644 --- a/src/annotations/fileAnnotationController.ts +++ b/src/annotations/fileAnnotationController.ts @@ -32,11 +32,8 @@ import type { KeyboardScope } from '../system/keyboard'; import { Logger } from '../system/logger'; import { basename } from '../system/path'; import { isTextEditor } from '../system/utils'; -import type { - DocumentBlameStateChangeEvent, - DocumentDirtyStateChangeEvent, - GitDocumentState, -} from '../trackers/gitDocumentTracker'; +import type { DocumentBlameStateChangeEvent, DocumentDirtyStateChangeEvent } from '../trackers/documentTracker'; +import type { GitDocumentState } from '../trackers/gitDocumentTracker'; import type { AnnotationContext, AnnotationProviderBase, TextEditorCorrelationKey } from './annotationProvider'; import { getEditorCorrelationKey } from './annotationProvider'; import type { ChangesAnnotationContext } from './gutterChangesAnnotationProvider'; diff --git a/src/annotations/gutterChangesAnnotationProvider.ts b/src/annotations/gutterChangesAnnotationProvider.ts index 0ae6605d30e09..6539b0b60149e 100644 --- a/src/annotations/gutterChangesAnnotationProvider.ts +++ b/src/annotations/gutterChangesAnnotationProvider.ts @@ -15,7 +15,8 @@ import { configuration } from '../system/configuration'; import { log } from '../system/decorators/log'; import { getLogScope } from '../system/logger.scope'; import { maybeStopWatch } from '../system/stopwatch'; -import type { GitDocumentState, TrackedDocument } from '../trackers/gitDocumentTracker'; +import type { GitDocumentState } from '../trackers/gitDocumentTracker'; +import type { TrackedDocument } from '../trackers/trackedDocument'; import type { AnnotationContext } from './annotationProvider'; import { AnnotationProviderBase } from './annotationProvider'; import { Decorations } from './fileAnnotationController'; diff --git a/src/annotations/lineAnnotationController.ts b/src/annotations/lineAnnotationController.ts index 5a976e1ab4897..c1a9980505e73 100644 --- a/src/annotations/lineAnnotationController.ts +++ b/src/annotations/lineAnnotationController.ts @@ -15,7 +15,8 @@ import { Logger } from '../system/logger'; import { getLogScope, setLogScopeExit } from '../system/logger.scope'; import { getSettledValue } from '../system/promise'; import { isTextEditor } from '../system/utils'; -import type { GitLineState, LinesChangeEvent } from '../trackers/gitLineTracker'; +import type { GitLineState } from '../trackers/gitLineTracker'; +import type { LinesChangeEvent } from '../trackers/lineTracker'; import { getInlineDecoration } from './annotations'; const annotationDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({ diff --git a/src/codelens/codeLensController.ts b/src/codelens/codeLensController.ts index 1208362fa0277..e1cee391a4d62 100644 --- a/src/codelens/codeLensController.ts +++ b/src/codelens/codeLensController.ts @@ -5,11 +5,8 @@ import { configuration } from '../system/configuration'; import { setContext } from '../system/context'; import { once } from '../system/event'; import { Logger } from '../system/logger'; -import type { - DocumentBlameStateChangeEvent, - DocumentDirtyIdleTriggerEvent, - GitDocumentState, -} from '../trackers/gitDocumentTracker'; +import type { DocumentBlameStateChangeEvent, DocumentDirtyIdleTriggerEvent } from '../trackers/documentTracker'; +import type { GitDocumentState } from '../trackers/gitDocumentTracker'; export class GitCodeLensController implements Disposable { private _canToggle: boolean = false; diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index ae3ecdd5ebd0f..053fc2ff36b8c 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -173,8 +173,9 @@ import { equalsIgnoreCase, getDurationMilliseconds, interpolate, splitSingle } f import { PathTrie } from '../../../system/trie'; import { compare, fromString } from '../../../system/version'; import { serializeWebviewItemContext } from '../../../system/webview'; -import type { CachedBlame, CachedDiff, CachedLog, TrackedDocument } from '../../../trackers/gitDocumentTracker'; +import type { CachedBlame, CachedDiff, CachedLog } from '../../../trackers/gitDocumentTracker'; import { GitDocumentState } from '../../../trackers/gitDocumentTracker'; +import type { TrackedDocument } from '../../../trackers/trackedDocument'; import type { Git } from './git'; import { getShaInLogRegex, diff --git a/src/hovers/lineHoverController.ts b/src/hovers/lineHoverController.ts index 15b589564aea5..73cc6ab322ecd 100644 --- a/src/hovers/lineHoverController.ts +++ b/src/hovers/lineHoverController.ts @@ -6,7 +6,7 @@ import { configuration } from '../system/configuration'; import { debug } from '../system/decorators/log'; import { once } from '../system/event'; import { Logger } from '../system/logger'; -import type { LinesChangeEvent } from '../trackers/gitLineTracker'; +import type { LinesChangeEvent } from '../trackers/lineTracker'; import { changesMessage, detailsMessage } from './hovers'; const maxSmallIntegerV8 = 2 ** 30; // Max number that can be stored in V8's smis (small integers) diff --git a/src/statusbar/statusBarController.ts b/src/statusbar/statusBarController.ts index 217716a4cf3c0..85600a3ee8d52 100644 --- a/src/statusbar/statusBarController.ts +++ b/src/statusbar/statusBarController.ts @@ -17,7 +17,8 @@ import { Logger } from '../system/logger'; import { getLogScope } from '../system/logger.scope'; import { getSettledValue } from '../system/promise'; import { isTextEditor } from '../system/utils'; -import type { GitLineState, LinesChangeEvent } from '../trackers/gitLineTracker'; +import type { GitLineState } from '../trackers/gitLineTracker'; +import type { LinesChangeEvent } from '../trackers/lineTracker'; export class StatusBarController implements Disposable { private _cancellation: CancellationTokenSource | undefined; diff --git a/src/trackers/documentTracker.ts b/src/trackers/documentTracker.ts index e35f851cc399c..067e9084e8520 100644 --- a/src/trackers/documentTracker.ts +++ b/src/trackers/documentTracker.ts @@ -24,17 +24,20 @@ import type { Deferrable } from '../system/function'; import { debounce } from '../system/function'; import { filter, join, map } from '../system/iterable'; import { findTextDocument, isActiveDocument, isTextEditor } from '../system/utils'; -import type { DocumentBlameStateChangeEvent } from './trackedDocument'; import { TrackedDocument } from './trackedDocument'; -export * from './trackedDocument'; - export interface DocumentContentChangeEvent { readonly editor: TextEditor; readonly document: TrackedDocument; readonly contentChanges: readonly TextDocumentContentChangeEvent[]; } +export interface DocumentBlameStateChangeEvent { + readonly editor: TextEditor; + readonly document: TrackedDocument; + readonly blameable: boolean; +} + export interface DocumentDirtyStateChangeEvent { readonly editor: TextEditor; readonly document: TrackedDocument; diff --git a/src/trackers/gitDocumentTracker.ts b/src/trackers/gitDocumentTracker.ts index 4f76867b3ddba..9f63fbf2210df 100644 --- a/src/trackers/gitDocumentTracker.ts +++ b/src/trackers/gitDocumentTracker.ts @@ -4,8 +4,6 @@ import type { GitDiffFile } from '../git/models/diff'; import type { GitLog } from '../git/models/log'; import { DocumentTracker } from './documentTracker'; -export * from './documentTracker'; - interface CachedItem { item: Promise; errorMessage?: string; diff --git a/src/trackers/gitLineTracker.ts b/src/trackers/gitLineTracker.ts index ab28fd00911af..d6fd18c7134cb 100644 --- a/src/trackers/gitLineTracker.ts +++ b/src/trackers/gitLineTracker.ts @@ -11,13 +11,11 @@ import type { DocumentContentChangeEvent, DocumentDirtyIdleTriggerEvent, DocumentDirtyStateChangeEvent, - GitDocumentState, -} from './gitDocumentTracker'; +} from './documentTracker'; +import type { GitDocumentState } from './gitDocumentTracker'; import type { LinesChangeEvent, LineSelection } from './lineTracker'; import { LineTracker } from './lineTracker'; -export * from './lineTracker'; - export interface GitLineState { commit: GitCommit; } diff --git a/src/trackers/trackedDocument.ts b/src/trackers/trackedDocument.ts index 3a990528ef8f4..63a8ef0383347 100644 --- a/src/trackers/trackedDocument.ts +++ b/src/trackers/trackedDocument.ts @@ -1,4 +1,4 @@ -import type { Disposable, Event, TextDocument, TextEditor } from 'vscode'; +import type { Disposable, Event, TextDocument } from 'vscode'; import { EventEmitter } from 'vscode'; import type { Container } from '../container'; import { GitUri } from '../git/gitUri'; @@ -8,12 +8,7 @@ import type { Deferrable } from '../system/function'; import { debounce } from '../system/function'; import { Logger } from '../system/logger'; import { getEditorIfActive, isActiveDocument } from '../system/utils'; - -export interface DocumentBlameStateChangeEvent { - readonly editor: TextEditor; - readonly document: TrackedDocument; - readonly blameable: boolean; -} +import type { DocumentBlameStateChangeEvent } from './documentTracker'; export class TrackedDocument implements Disposable { static async create( diff --git a/src/views/nodes/lineHistoryTrackerNode.ts b/src/views/nodes/lineHistoryTrackerNode.ts index d49bc62582ab2..2ec74458dfb2e 100644 --- a/src/views/nodes/lineHistoryTrackerNode.ts +++ b/src/views/nodes/lineHistoryTrackerNode.ts @@ -12,7 +12,7 @@ import { debug, log } from '../../system/decorators/log'; import { debounce } from '../../system/function'; import { Logger } from '../../system/logger'; import { getLogScope, setLogScopeExit } from '../../system/logger.scope'; -import type { LinesChangeEvent } from '../../trackers/gitLineTracker'; +import type { LinesChangeEvent } from '../../trackers/lineTracker'; import type { FileHistoryView } from '../fileHistoryView'; import type { LineHistoryView } from '../lineHistoryView'; import { LineHistoryNode } from './lineHistoryNode'; From 0efdc3e209b6e802ba3e657bb30ccdd38ed574e9 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 9 Oct 2023 23:49:42 -0400 Subject: [PATCH 0033/1012] Removes re-exports to limit import scopes --- src/commands/git/branch.ts | 10 ++++++---- src/commands/git/cherry-pick.ts | 13 ++----------- src/commands/git/coauthors.ts | 3 ++- src/commands/git/fetch.ts | 11 ++--------- src/commands/git/log.ts | 10 ++-------- src/commands/git/merge.ts | 14 +++----------- src/commands/git/pull.ts | 12 +++--------- src/commands/git/push.ts | 13 +++---------- src/commands/git/rebase.ts | 14 +++----------- src/commands/git/remote.ts | 10 ++++++---- src/commands/git/reset.ts | 11 ++--------- src/commands/git/revert.ts | 11 ++--------- src/commands/git/search.ts | 12 +++--------- src/commands/git/show.ts | 6 ++---- src/commands/git/stash.ts | 7 ++----- src/commands/git/status.ts | 3 ++- src/commands/git/switch.ts | 7 ++----- src/commands/git/tag.ts | 10 ++++++---- src/commands/git/worktree.ts | 10 ++++++---- src/commands/quickCommand.steps.ts | 6 ++++-- src/commands/quickCommand.ts | 3 --- src/quickpicks/referencePicker.ts | 7 ++----- 22 files changed, 65 insertions(+), 138 deletions(-) diff --git a/src/commands/git/branch.ts b/src/commands/git/branch.ts index 6e21781eeb16a..b6c8a6b939fe1 100644 --- a/src/commands/git/branch.ts +++ b/src/commands/git/branch.ts @@ -18,19 +18,21 @@ import type { StepState, } from '../quickCommand'; import { - appendReposToTitle, canPickStepContinue, createConfirmStep, createPickStep, endSteps, + QuickCommand, + StepResultBreak, +} from '../quickCommand'; +import { + appendReposToTitle, inputBranchNameStep, pickBranchesStep, pickBranchOrTagStep, pickBranchStep, pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +} from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/cherry-pick.ts b/src/commands/git/cherry-pick.ts index c3f1116581e7e..b1528a8c38e99 100644 --- a/src/commands/git/cherry-pick.ts +++ b/src/commands/git/cherry-pick.ts @@ -16,17 +16,8 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - createConfirmStep, - endSteps, - pickBranchOrTagStep, - pickCommitsStep, - pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, createConfirmStep, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { appendReposToTitle, pickBranchOrTagStep, pickCommitsStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/coauthors.ts b/src/commands/git/coauthors.ts index cc8b1430e61f0..e065c7b41a382 100644 --- a/src/commands/git/coauthors.ts +++ b/src/commands/git/coauthors.ts @@ -5,7 +5,8 @@ import { executeCoreCommand } from '../../system/command'; import { normalizePath } from '../../system/path'; import type { ViewsWithRepositoryFolders } from '../../views/viewBase'; import type { PartialStepState, StepGenerator, StepState } from '../quickCommand'; -import { endSteps, pickContributorsStep, pickRepositoryStep, QuickCommand, StepResultBreak } from '../quickCommand'; +import { endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { pickContributorsStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/fetch.ts b/src/commands/git/fetch.ts index f2d0b2512ac59..32657b68e77ce 100644 --- a/src/commands/git/fetch.ts +++ b/src/commands/git/fetch.ts @@ -17,15 +17,8 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - createConfirmStep, - endSteps, - pickRepositoriesStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, createConfirmStep, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { appendReposToTitle, pickRepositoriesStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/log.ts b/src/commands/git/log.ts index a822b5221354b..fc6cb3d409bd5 100644 --- a/src/commands/git/log.ts +++ b/src/commands/git/log.ts @@ -11,14 +11,8 @@ import { pad } from '../../system/string'; import type { ViewsWithRepositoryFolders } from '../../views/viewBase'; import { getSteps } from '../gitCommands.utils'; import type { PartialStepState, StepGenerator, StepResult } from '../quickCommand'; -import { - endSteps, - pickBranchOrTagStep, - pickCommitStep, - pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { pickBranchOrTagStep, pickCommitStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/merge.ts b/src/commands/git/merge.ts index 176306c0386ef..dd3e742f6f32e 100644 --- a/src/commands/git/merge.ts +++ b/src/commands/git/merge.ts @@ -19,17 +19,9 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - endSteps, - pickBranchOrTagStep, - pickCommitStep, - PickCommitToggleQuickInputButton, - pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { PickCommitToggleQuickInputButton } from '../quickCommand.buttons'; +import { appendReposToTitle, pickBranchOrTagStep, pickCommitStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/pull.ts b/src/commands/git/pull.ts index 100d906244a63..73f6f731d5c53 100644 --- a/src/commands/git/pull.ts +++ b/src/commands/git/pull.ts @@ -19,15 +19,9 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - endSteps, - FetchQuickInputButton, - pickRepositoriesStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { FetchQuickInputButton } from '../quickCommand.buttons'; +import { appendReposToTitle, pickRepositoriesStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/push.ts b/src/commands/git/push.ts index 96df8d58c9463..90568608d3b33 100644 --- a/src/commands/git/push.ts +++ b/src/commands/git/push.ts @@ -21,16 +21,9 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - endSteps, - FetchQuickInputButton, - pickRepositoriesStep, - pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { FetchQuickInputButton } from '../quickCommand.buttons'; +import { appendReposToTitle, pickRepositoriesStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/rebase.ts b/src/commands/git/rebase.ts index 5592d86ab9c8a..78f606abb4ff2 100644 --- a/src/commands/git/rebase.ts +++ b/src/commands/git/rebase.ts @@ -20,17 +20,9 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - endSteps, - pickBranchOrTagStep, - pickCommitStep, - PickCommitToggleQuickInputButton, - pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { PickCommitToggleQuickInputButton } from '../quickCommand.buttons'; +import { appendReposToTitle, pickBranchOrTagStep, pickCommitStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/remote.ts b/src/commands/git/remote.ts index ed9ca4619d630..188be17934abc 100644 --- a/src/commands/git/remote.ts +++ b/src/commands/git/remote.ts @@ -19,18 +19,20 @@ import type { StepState, } from '../quickCommand'; import { - appendReposToTitle, canPickStepContinue, createConfirmStep, createPickStep, endSteps, + QuickCommand, + StepResultBreak, +} from '../quickCommand'; +import { + appendReposToTitle, inputRemoteNameStep, inputRemoteUrlStep, pickRemoteStep, pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +} from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/reset.ts b/src/commands/git/reset.ts index f98aeac4e5483..c28640ca3706c 100644 --- a/src/commands/git/reset.ts +++ b/src/commands/git/reset.ts @@ -16,15 +16,8 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - endSteps, - pickCommitStep, - pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { appendReposToTitle, pickCommitStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/revert.ts b/src/commands/git/revert.ts index 6756d84e28568..0acf8e6cf298d 100644 --- a/src/commands/git/revert.ts +++ b/src/commands/git/revert.ts @@ -16,15 +16,8 @@ import type { StepSelection, StepState, } from '../quickCommand'; -import { - appendReposToTitle, - canPickStepContinue, - endSteps, - pickCommitsStep, - pickRepositoryStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +import { canPickStepContinue, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { appendReposToTitle, pickCommitsStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/search.ts b/src/commands/git/search.ts index 60690fbc6edd3..2f75df2615980 100644 --- a/src/commands/git/search.ts +++ b/src/commands/git/search.ts @@ -22,20 +22,14 @@ import type { StepSelection, StepState, } from '../quickCommand'; +import { canPickStepContinue, createPickStep, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; import { - appendReposToTitle, - canPickStepContinue, - createPickStep, - endSteps, MatchAllToggleQuickInputButton, MatchCaseToggleQuickInputButton, MatchRegexToggleQuickInputButton, - pickCommitStep, - pickRepositoryStep, - QuickCommand, ShowResultsInSideBarQuickInputButton, - StepResultBreak, -} from '../quickCommand'; +} from '../quickCommand.buttons'; +import { appendReposToTitle, pickCommitStep, pickRepositoryStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/show.ts b/src/commands/git/show.ts index 4f9d24484c731..d6a389bb231e7 100644 --- a/src/commands/git/show.ts +++ b/src/commands/git/show.ts @@ -8,16 +8,14 @@ import { CommandQuickPickItem } from '../../quickpicks/items/common'; import { GitCommandQuickPickItem } from '../../quickpicks/items/gitCommands'; import type { ViewsWithRepositoryFolders } from '../../views/viewBase'; import type { PartialStepState, StepGenerator } from '../quickCommand'; +import { endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; import { - endSteps, pickCommitStep, pickRepositoryStep, - QuickCommand, showCommitOrStashFilesStep, showCommitOrStashFileStep, showCommitOrStashStep, - StepResultBreak, -} from '../quickCommand'; +} from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/stash.ts b/src/commands/git/stash.ts index 07b5a4c1d7752..cf5b97e47d75d 100644 --- a/src/commands/git/stash.ts +++ b/src/commands/git/stash.ts @@ -29,20 +29,17 @@ import type { StepState, } from '../quickCommand'; import { - appendReposToTitle, canInputStepContinue, canPickStepContinue, canStepContinue, createInputStep, createPickStep, endSteps, - pickRepositoryStep, - pickStashStep, QuickCommand, - RevealInSideBarQuickInputButton, - ShowDetailsViewQuickInputButton, StepResultBreak, } from '../quickCommand'; +import { RevealInSideBarQuickInputButton, ShowDetailsViewQuickInputButton } from '../quickCommand.buttons'; +import { appendReposToTitle, pickRepositoryStep, pickStashStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/status.ts b/src/commands/git/status.ts index 4735e43c9f064..b82ff4d1d1eb4 100644 --- a/src/commands/git/status.ts +++ b/src/commands/git/status.ts @@ -8,7 +8,8 @@ import { GitCommandQuickPickItem } from '../../quickpicks/items/gitCommands'; import { pad } from '../../system/string'; import type { ViewsWithRepositoryFolders } from '../../views/viewBase'; import type { PartialStepState, StepGenerator, StepState } from '../quickCommand'; -import { endSteps, pickRepositoryStep, QuickCommand, showRepositoryStatusStep, StepResultBreak } from '../quickCommand'; +import { endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; +import { pickRepositoryStep, showRepositoryStatusStep } from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/switch.ts b/src/commands/git/switch.ts index 4cb844526e034..90453cfdd6581 100644 --- a/src/commands/git/switch.ts +++ b/src/commands/git/switch.ts @@ -14,16 +14,13 @@ import type { StepSelection, StepState, } from '../quickCommand'; +import { canPickStepContinue, endSteps, QuickCommand, StepResultBreak } from '../quickCommand'; import { appendReposToTitle, - canPickStepContinue, - endSteps, inputBranchNameStep, pickBranchOrTagStepMultiRepo, pickRepositoriesStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +} from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/tag.ts b/src/commands/git/tag.ts index 10d2a2fc657dd..3e45da570ce3a 100644 --- a/src/commands/git/tag.ts +++ b/src/commands/git/tag.ts @@ -18,7 +18,6 @@ import type { StepState, } from '../quickCommand'; import { - appendReposToTitle, canInputStepContinue, canPickStepContinue, canStepContinue, @@ -26,13 +25,16 @@ import { createInputStep, createPickStep, endSteps, + QuickCommand, + StepResultBreak, +} from '../quickCommand'; +import { + appendReposToTitle, inputTagNameStep, pickBranchOrTagStep, pickRepositoryStep, pickTagsStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +} from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/git/worktree.ts b/src/commands/git/worktree.ts index be138f8f12be5..b90bff3bf3f83 100644 --- a/src/commands/git/worktree.ts +++ b/src/commands/git/worktree.ts @@ -36,7 +36,6 @@ import type { StepState, } from '../quickCommand'; import { - appendReposToTitle, canInputStepContinue, canPickStepContinue, canStepContinue, @@ -44,15 +43,18 @@ import { createCustomStep, createPickStep, endSteps, + QuickCommand, + StepResultBreak, +} from '../quickCommand'; +import { + appendReposToTitle, ensureAccessStep, inputBranchNameStep, pickBranchOrTagStep, pickRepositoryStep, pickWorktreesStep, pickWorktreeStep, - QuickCommand, - StepResultBreak, -} from '../quickCommand'; +} from '../quickCommand.steps'; interface Context { repos: Repository[]; diff --git a/src/commands/quickCommand.steps.ts b/src/commands/quickCommand.steps.ts index 4d7e1f4027c70..2a0aae893e1c4 100644 --- a/src/commands/quickCommand.steps.ts +++ b/src/commands/quickCommand.steps.ts @@ -117,6 +117,9 @@ import { createInputStep, createPickStep, endSteps, + StepResultBreak, +} from './quickCommand'; +import { LoadMoreQuickInputButton, OpenChangesViewQuickInputButton, OpenInNewWindowQuickInputButton, @@ -124,8 +127,7 @@ import { RevealInSideBarQuickInputButton, ShowDetailsViewQuickInputButton, ShowTagsToggleQuickInputButton, - StepResultBreak, -} from './quickCommand'; +} from './quickCommand.buttons'; export function appendReposToTitle< State extends { repo: Repository } | { repos: Repository[] }, diff --git a/src/commands/quickCommand.ts b/src/commands/quickCommand.ts index f2f655eeffe60..b2aa8553c337a 100644 --- a/src/commands/quickCommand.ts +++ b/src/commands/quickCommand.ts @@ -5,9 +5,6 @@ import type { DirectiveQuickPickItem } from '../quickpicks/items/directive'; import { createDirectiveQuickPickItem, Directive, isDirective } from '../quickpicks/items/directive'; import { configuration } from '../system/configuration'; -export * from './quickCommand.buttons'; -export * from './quickCommand.steps'; - export interface CustomStep { ignoreFocusOut?: boolean; diff --git a/src/quickpicks/referencePicker.ts b/src/quickpicks/referencePicker.ts index df4d3586f6a8b..7e083d86fd436 100644 --- a/src/quickpicks/referencePicker.ts +++ b/src/quickpicks/referencePicker.ts @@ -1,10 +1,7 @@ import type { Disposable, QuickPick } from 'vscode'; import { CancellationTokenSource, window } from 'vscode'; -import { - getBranchesAndOrTags, - getValidateGitReferenceFn, - RevealInSideBarQuickInputButton, -} from '../commands/quickCommand'; +import { RevealInSideBarQuickInputButton } from '../commands/quickCommand.buttons'; +import { getBranchesAndOrTags, getValidateGitReferenceFn } from '../commands/quickCommand.steps'; import type { Keys } from '../constants'; import { GlyphChars } from '../constants'; import { Container } from '../container'; From 56cdfe048d0e7fef7411fb4a5d2b339a4353455a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 10 Oct 2023 00:01:50 -0400 Subject: [PATCH 0034/1012] Avoids using commands as a "barrel" file --- src/codelens/codeLensProvider.ts | 16 +-- src/commands.ts | 134 +++++++++--------- src/container.ts | 2 +- src/extension.ts | 4 +- src/git/actions.ts | 7 +- src/git/actions/commit.ts | 18 ++- src/git/formatters/commitFormatter.ts | 16 +-- src/hovers/hovers.ts | 3 +- src/partners.ts | 2 +- src/plus/webviews/focus/focusWebview.ts | 2 +- src/plus/webviews/graph/graphWebview.ts | 14 +- src/quickpicks/items/commits.ts | 2 +- src/quickpicks/remoteProviderPicker.ts | 2 +- src/terminal/linkProvider.ts | 10 +- src/views/nodes/UncommittedFileNode.ts | 2 +- src/views/nodes/commitFileNode.ts | 2 +- src/views/nodes/commitNode.ts | 2 +- src/views/nodes/fileRevisionAsCommitNode.ts | 2 +- .../nodes/mergeConflictCurrentChangesNode.ts | 2 +- .../nodes/mergeConflictIncomingChangesNode.ts | 2 +- src/views/nodes/resultsFileNode.ts | 2 +- src/views/nodes/statusFileNode.ts | 2 +- src/views/viewCommands.ts | 10 +- .../commitDetails/commitDetailsWebview.ts | 2 +- src/webviews/rebase/rebaseEditor.ts | 2 +- 25 files changed, 125 insertions(+), 137 deletions(-) diff --git a/src/codelens/codeLensProvider.ts b/src/codelens/codeLensProvider.ts index 4e7ed32e1b0ca..e2c8e416e2a98 100644 --- a/src/codelens/codeLensProvider.ts +++ b/src/codelens/codeLensProvider.ts @@ -9,15 +9,13 @@ import type { Uri, } from 'vscode'; import { CodeLens, EventEmitter, Location, Position, Range, SymbolInformation, SymbolKind } from 'vscode'; -import type { - DiffWithPreviousCommandArgs, - OpenOnRemoteCommandArgs, - ShowCommitsInViewCommandArgs, - ShowQuickCommitCommandArgs, - ShowQuickCommitFileCommandArgs, - ShowQuickFileHistoryCommandArgs, - ToggleFileChangesAnnotationCommandArgs, -} from '../commands'; +import type { DiffWithPreviousCommandArgs } from '../commands/diffWithPrevious'; +import type { OpenOnRemoteCommandArgs } from '../commands/openOnRemote'; +import type { ShowCommitsInViewCommandArgs } from '../commands/showCommitsInView'; +import type { ShowQuickCommitCommandArgs } from '../commands/showQuickCommit'; +import type { ShowQuickCommitFileCommandArgs } from '../commands/showQuickCommitFile'; +import type { ShowQuickFileHistoryCommandArgs } from '../commands/showQuickFileHistory'; +import type { ToggleFileChangesAnnotationCommandArgs } from '../commands/toggleFileAnnotations'; import type { CodeLensConfig, CodeLensLanguageScope } from '../config'; import { CodeLensCommand } from '../config'; import { Commands, Schemes } from '../constants'; diff --git a/src/commands.ts b/src/commands.ts index 8384f9c267e52..0f67c26b621de 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -1,67 +1,67 @@ -export * from './commands/addAuthors'; -export * from './commands/browseRepoAtRevision'; -export * from './commands/closeUnchangedFiles'; -export * from './commands/compareWith'; -export * from './commands/copyCurrentBranch'; -export * from './commands/copyDeepLink'; -export * from './commands/copyMessageToClipboard'; -export * from './commands/copyShaToClipboard'; -export * from './commands/copyRelativePathToClipboard'; -export * from './commands/createPullRequestOnRemote'; -export * from './commands/openDirectoryCompare'; -export * from './commands/diffLineWithPrevious'; -export * from './commands/diffLineWithWorking'; -export * from './commands/diffWith'; -export * from './commands/diffWithNext'; -export * from './commands/diffWithPrevious'; -export * from './commands/diffWithRevision'; -export * from './commands/diffWithRevisionFrom'; -export * from './commands/diffWithWorking'; -export * from './commands/externalDiff'; -export * from './commands/generateCommitMessage'; -export * from './commands/ghpr/openOrCreateWorktree'; -export * from './commands/gitCommands'; -export * from './commands/inviteToLiveShare'; -export * from './commands/logging'; -export * from './commands/openAssociatedPullRequestOnRemote'; -export * from './commands/openBranchesOnRemote'; -export * from './commands/openBranchOnRemote'; -export * from './commands/openCurrentBranchOnRemote'; -export * from './commands/openChangedFiles'; -export * from './commands/openCommitOnRemote'; -export * from './commands/openComparisonOnRemote'; -export * from './commands/openFileFromRemote'; -export * from './commands/openFileOnRemote'; -export * from './commands/openFileAtRevision'; -export * from './commands/openFileAtRevisionFrom'; -export * from './commands/openOnRemote'; -export * from './commands/openIssueOnRemote'; -export * from './commands/openPullRequestOnRemote'; -export * from './commands/openRepoOnRemote'; -export * from './commands/openRevisionFile'; -export * from './commands/openWorkingFile'; -export * from './commands/rebaseEditor'; -export * from './commands/refreshHover'; -export * from './commands/remoteProviders'; -export * from './commands/repositories'; -export * from './commands/resets'; -export * from './commands/resetViewsLayout'; -export * from './commands/searchCommits'; -export * from './commands/showCommitsInView'; -export * from './commands/showLastQuickPick'; -export * from './commands/openOnlyChangedFiles'; -export * from './commands/showQuickBranchHistory'; -export * from './commands/showQuickCommit'; -export * from './commands/showQuickCommitFile'; -export * from './commands/showQuickFileHistory'; -export * from './commands/showQuickRepoStatus'; -export * from './commands/showQuickStashList'; -export * from './commands/showView'; -export * from './commands/stashApply'; -export * from './commands/stashSave'; -export * from './commands/switchAIModel'; -export * from './commands/switchMode'; -export * from './commands/toggleCodeLens'; -export * from './commands/toggleFileAnnotations'; -export * from './commands/toggleLineBlame'; -export * from './commands/walkthroughs'; +import './commands/addAuthors'; +import './commands/browseRepoAtRevision'; +import './commands/closeUnchangedFiles'; +import './commands/compareWith'; +import './commands/copyCurrentBranch'; +import './commands/copyDeepLink'; +import './commands/copyMessageToClipboard'; +import './commands/copyShaToClipboard'; +import './commands/copyRelativePathToClipboard'; +import './commands/createPullRequestOnRemote'; +import './commands/openDirectoryCompare'; +import './commands/diffLineWithPrevious'; +import './commands/diffLineWithWorking'; +import './commands/diffWith'; +import './commands/diffWithNext'; +import './commands/diffWithPrevious'; +import './commands/diffWithRevision'; +import './commands/diffWithRevisionFrom'; +import './commands/diffWithWorking'; +import './commands/externalDiff'; +import './commands/generateCommitMessage'; +import './commands/ghpr/openOrCreateWorktree'; +import './commands/gitCommands'; +import './commands/inviteToLiveShare'; +import './commands/logging'; +import './commands/openAssociatedPullRequestOnRemote'; +import './commands/openBranchesOnRemote'; +import './commands/openBranchOnRemote'; +import './commands/openCurrentBranchOnRemote'; +import './commands/openChangedFiles'; +import './commands/openCommitOnRemote'; +import './commands/openComparisonOnRemote'; +import './commands/openFileFromRemote'; +import './commands/openFileOnRemote'; +import './commands/openFileAtRevision'; +import './commands/openFileAtRevisionFrom'; +import './commands/openOnRemote'; +import './commands/openIssueOnRemote'; +import './commands/openPullRequestOnRemote'; +import './commands/openRepoOnRemote'; +import './commands/openRevisionFile'; +import './commands/openWorkingFile'; +import './commands/rebaseEditor'; +import './commands/refreshHover'; +import './commands/remoteProviders'; +import './commands/repositories'; +import './commands/resets'; +import './commands/resetViewsLayout'; +import './commands/searchCommits'; +import './commands/showCommitsInView'; +import './commands/showLastQuickPick'; +import './commands/openOnlyChangedFiles'; +import './commands/showQuickBranchHistory'; +import './commands/showQuickCommit'; +import './commands/showQuickCommitFile'; +import './commands/showQuickFileHistory'; +import './commands/showQuickRepoStatus'; +import './commands/showQuickStashList'; +import './commands/showView'; +import './commands/stashApply'; +import './commands/stashSave'; +import './commands/switchAIModel'; +import './commands/switchMode'; +import './commands/toggleCodeLens'; +import './commands/toggleFileAnnotations'; +import './commands/toggleLineBlame'; +import './commands/walkthroughs'; diff --git a/src/container.ts b/src/container.ts index ff8014a711d2f..e7744880de8fb 100644 --- a/src/container.ts +++ b/src/container.ts @@ -9,7 +9,7 @@ import { ActionRunners } from './api/actionRunners'; import { setDefaultGravatarsStyle } from './avatars'; import { CacheProvider } from './cache'; import { GitCodeLensController } from './codelens/codeLensController'; -import type { ToggleFileAnnotationCommandArgs } from './commands'; +import type { ToggleFileAnnotationCommandArgs } from './commands/toggleFileAnnotations'; import type { DateStyle, FileAnnotationType, ModeConfig } from './config'; import { fromOutputLevel } from './config'; import { Commands, extensionPrefix } from './constants'; diff --git a/src/extension.ts b/src/extension.ts index 362eeaffbaa62..95d026bdc9f35 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,7 +4,8 @@ import { hrtime } from '@env/hrtime'; import { isWeb } from '@env/platform'; import { Api } from './api/api'; import type { CreatePullRequestActionContext, GitLensApi, OpenPullRequestActionContext } from './api/gitlens'; -import type { CreatePullRequestOnRemoteCommandArgs, OpenPullRequestOnRemoteCommandArgs } from './commands'; +import type { CreatePullRequestOnRemoteCommandArgs } from './commands/createPullRequestOnRemote'; +import type { OpenPullRequestOnRemoteCommandArgs } from './commands/openPullRequestOnRemote'; import { fromOutputLevel } from './config'; import { Commands, SyncedStorageKeys } from './constants'; import { Container } from './container'; @@ -26,6 +27,7 @@ import { Stopwatch } from './system/stopwatch'; import { Storage } from './system/storage'; import { compare, fromString, satisfies } from './system/version'; import { isViewNode } from './views/nodes/viewNode'; +import './commands'; export async function activate(context: ExtensionContext): Promise { const gitlensVersion: string = context.extension.packageJSON.version; diff --git a/src/git/actions.ts b/src/git/actions.ts index e3052e133a762..833500f8e6360 100644 --- a/src/git/actions.ts +++ b/src/git/actions.ts @@ -1,9 +1,6 @@ import type { Uri } from 'vscode'; -import type { - BrowseRepoAtRevisionCommandArgs, - GitCommandsCommandArgs, - GitCommandsCommandArgsWithCompletion, -} from '../commands'; +import type { BrowseRepoAtRevisionCommandArgs } from '../commands/browseRepoAtRevision'; +import type { GitCommandsCommandArgs, GitCommandsCommandArgsWithCompletion } from '../commands/gitCommands'; import { Commands } from '../constants'; import { executeCommand, executeEditorCommand } from '../system/command'; import { defer } from '../system/promise'; diff --git a/src/git/actions/commit.ts b/src/git/actions/commit.ts index 3393bf5e82240..f7e124dbc124b 100644 --- a/src/git/actions/commit.ts +++ b/src/git/actions/commit.ts @@ -1,15 +1,13 @@ import type { TextDocumentShowOptions } from 'vscode'; import { env, Range, Uri, window } from 'vscode'; -import type { - DiffWithCommandArgs, - DiffWithPreviousCommandArgs, - DiffWithWorkingCommandArgs, - OpenFileOnRemoteCommandArgs, - OpenOnlyChangedFilesCommandArgs, - OpenWorkingFileCommandArgs, - ShowQuickCommitCommandArgs, - ShowQuickCommitFileCommandArgs, -} from '../../commands'; +import type { DiffWithCommandArgs } from '../../commands/diffWith'; +import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPrevious'; +import type { DiffWithWorkingCommandArgs } from '../../commands/diffWithWorking'; +import type { OpenFileOnRemoteCommandArgs } from '../../commands/openFileOnRemote'; +import type { OpenOnlyChangedFilesCommandArgs } from '../../commands/openOnlyChangedFiles'; +import type { OpenWorkingFileCommandArgs } from '../../commands/openWorkingFile'; +import type { ShowQuickCommitCommandArgs } from '../../commands/showQuickCommit'; +import type { ShowQuickCommitFileCommandArgs } from '../../commands/showQuickCommitFile'; import type { FileAnnotationType } from '../../config'; import { Commands } from '../../constants'; import { Container } from '../../container'; diff --git a/src/git/formatters/commitFormatter.ts b/src/git/formatters/commitFormatter.ts index c85673df833e1..5b0b5b9e89c1d 100644 --- a/src/git/formatters/commitFormatter.ts +++ b/src/git/formatters/commitFormatter.ts @@ -7,16 +7,14 @@ import type { OpenPullRequestActionContext, } from '../../api/gitlens'; import { getPresenceDataUri } from '../../avatars'; -import type { ShowQuickCommitCommandArgs } from '../../commands'; -import { - ConnectRemoteProviderCommand, - DiffWithCommand, - OpenCommitOnRemoteCommand, - OpenFileAtRevisionCommand, - ShowCommitsInViewCommand, - ShowQuickCommitFileCommand, -} from '../../commands'; import { Command } from '../../commands/base'; +import { DiffWithCommand } from '../../commands/diffWith'; +import { OpenCommitOnRemoteCommand } from '../../commands/openCommitOnRemote'; +import { OpenFileAtRevisionCommand } from '../../commands/openFileAtRevision'; +import { ConnectRemoteProviderCommand } from '../../commands/remoteProviders'; +import { ShowCommitsInViewCommand } from '../../commands/showCommitsInView'; +import type { ShowQuickCommitCommandArgs } from '../../commands/showQuickCommit'; +import { ShowQuickCommitFileCommand } from '../../commands/showQuickCommitFile'; import type { DateStyle } from '../../config'; import { Commands, GlyphChars } from '../../constants'; import { Container } from '../../container'; diff --git a/src/hovers/hovers.ts b/src/hovers/hovers.ts index 6debcc6bc89fc..8a6071f316dda 100644 --- a/src/hovers/hovers.ts +++ b/src/hovers/hovers.ts @@ -1,7 +1,8 @@ import type { CancellationToken, TextDocument } from 'vscode'; import { MarkdownString } from 'vscode'; import type { EnrichedAutolink } from '../annotations/autolinks'; -import { DiffWithCommand, ShowQuickCommitCommand } from '../commands'; +import { DiffWithCommand } from '../commands/diffWith'; +import { ShowQuickCommitCommand } from '../commands/showQuickCommit'; import { GlyphChars } from '../constants'; import type { Container } from '../container'; import { CommitFormatter } from '../git/formatters/commitFormatter'; diff --git a/src/partners.ts b/src/partners.ts index 4be6fa2f06c77..64462177f2fe6 100644 --- a/src/partners.ts +++ b/src/partners.ts @@ -1,7 +1,7 @@ import type { CancellationTokenSource, Extension, ExtensionContext, Uri } from 'vscode'; import { extensions } from 'vscode'; import type { ActionContext, HoverCommandsActionContext } from './api/gitlens'; -import type { InviteToLiveShareCommandArgs } from './commands'; +import type { InviteToLiveShareCommandArgs } from './commands/inviteToLiveShare'; import { Commands } from './constants'; import { Container } from './container'; import { executeCommand, executeCoreCommand } from './system/command'; diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 8d16b37b90d2f..71c84b1875391 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -1,5 +1,5 @@ import { Disposable, Uri, window } from 'vscode'; -import type { GHPRPullRequest } from '../../../commands'; +import type { GHPRPullRequest } from '../../../commands/ghpr/openOrCreateWorktree'; import { Commands } from '../../../constants'; import type { Container } from '../../../container'; import { PlusFeatures } from '../../../features'; diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index e2783acff2c84..84a9993a7991f 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -2,15 +2,13 @@ import type { ColorTheme, ConfigurationChangeEvent, Uri, ViewColumn } from 'vsco import { CancellationTokenSource, Disposable, env, window } from 'vscode'; import type { CreatePullRequestActionContext } from '../../../api/gitlens'; import { getAvatarUri } from '../../../avatars'; -import type { - CopyDeepLinkCommandArgs, - CopyMessageToClipboardCommandArgs, - CopyShaToClipboardCommandArgs, - OpenOnRemoteCommandArgs, - OpenPullRequestOnRemoteCommandArgs, - ShowCommitsInViewCommandArgs, -} from '../../../commands'; import { parseCommandContext } from '../../../commands/base'; +import type { CopyDeepLinkCommandArgs } from '../../../commands/copyDeepLink'; +import type { CopyMessageToClipboardCommandArgs } from '../../../commands/copyMessageToClipboard'; +import type { CopyShaToClipboardCommandArgs } from '../../../commands/copyShaToClipboard'; +import type { OpenOnRemoteCommandArgs } from '../../../commands/openOnRemote'; +import type { OpenPullRequestOnRemoteCommandArgs } from '../../../commands/openPullRequestOnRemote'; +import type { ShowCommitsInViewCommandArgs } from '../../../commands/showCommitsInView'; import type { Config, GraphMinimapMarkersAdditionalTypes, GraphScrollMarkersAdditionalTypes } from '../../../config'; import type { StoredGraphFilters, StoredGraphIncludeOnlyRef, StoredGraphRefType } from '../../../constants'; import { Commands, GlyphChars } from '../../../constants'; diff --git a/src/quickpicks/items/commits.ts b/src/quickpicks/items/commits.ts index a2d80860a8a10..ad18b94243ad3 100644 --- a/src/quickpicks/items/commits.ts +++ b/src/quickpicks/items/commits.ts @@ -1,7 +1,7 @@ import type { QuickPickItem } from 'vscode'; import { window } from 'vscode'; -import type { OpenOnlyChangedFilesCommandArgs } from '../../commands'; import type { OpenChangedFilesCommandArgs } from '../../commands/openChangedFiles'; +import type { OpenOnlyChangedFilesCommandArgs } from '../../commands/openOnlyChangedFiles'; import { RevealInSideBarQuickInputButton, ShowDetailsViewQuickInputButton } from '../../commands/quickCommand.buttons'; import type { Keys } from '../../constants'; import { Commands, GlyphChars } from '../../constants'; diff --git a/src/quickpicks/remoteProviderPicker.ts b/src/quickpicks/remoteProviderPicker.ts index bc1aaf9a66ec6..f44f51e50b9eb 100644 --- a/src/quickpicks/remoteProviderPicker.ts +++ b/src/quickpicks/remoteProviderPicker.ts @@ -1,6 +1,6 @@ import type { Disposable, QuickInputButton } from 'vscode'; import { env, Uri, window } from 'vscode'; -import type { OpenOnRemoteCommandArgs } from '../commands'; +import type { OpenOnRemoteCommandArgs } from '../commands/openOnRemote'; import { SetRemoteAsDefaultQuickInputButton } from '../commands/quickCommand.buttons'; import type { Keys } from '../constants'; import { Commands, GlyphChars } from '../constants'; diff --git a/src/terminal/linkProvider.ts b/src/terminal/linkProvider.ts index 1e061fe09f39d..44c1f39aa07e0 100644 --- a/src/terminal/linkProvider.ts +++ b/src/terminal/linkProvider.ts @@ -1,11 +1,9 @@ import type { Disposable, TerminalLink, TerminalLinkContext, TerminalLinkProvider } from 'vscode'; import { commands, window } from 'vscode'; -import type { - GitCommandsCommandArgs, - ShowCommitsInViewCommandArgs, - ShowQuickBranchHistoryCommandArgs, - ShowQuickCommitCommandArgs, -} from '../commands'; +import type { GitCommandsCommandArgs } from '../commands/gitCommands'; +import type { ShowCommitsInViewCommandArgs } from '../commands/showCommitsInView'; +import type { ShowQuickBranchHistoryCommandArgs } from '../commands/showQuickBranchHistory'; +import type { ShowQuickCommitCommandArgs } from '../commands/showQuickCommit'; import { Commands } from '../constants'; import type { Container } from '../container'; import type { PagedResult } from '../git/gitProvider'; diff --git a/src/views/nodes/UncommittedFileNode.ts b/src/views/nodes/UncommittedFileNode.ts index 2cf23d743e7c4..8d9b25771f710 100644 --- a/src/views/nodes/UncommittedFileNode.ts +++ b/src/views/nodes/UncommittedFileNode.ts @@ -1,6 +1,6 @@ import type { Command } from 'vscode'; import { TreeItem, TreeItemCollapsibleState } from 'vscode'; -import type { DiffWithPreviousCommandArgs } from '../../commands'; +import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPrevious'; import { Commands } from '../../constants'; import { StatusFileFormatter } from '../../git/formatters/statusFormatter'; import { GitUri } from '../../git/gitUri'; diff --git a/src/views/nodes/commitFileNode.ts b/src/views/nodes/commitFileNode.ts index 84860c19462c9..299ec58e5c05c 100644 --- a/src/views/nodes/commitFileNode.ts +++ b/src/views/nodes/commitFileNode.ts @@ -1,6 +1,6 @@ import type { Command, Selection } from 'vscode'; import { MarkdownString, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; -import type { DiffWithPreviousCommandArgs } from '../../commands'; +import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPrevious'; import { Commands, Schemes } from '../../constants'; import { StatusFileFormatter } from '../../git/formatters/statusFormatter'; import { GitUri } from '../../git/gitUri'; diff --git a/src/views/nodes/commitNode.ts b/src/views/nodes/commitNode.ts index 43c2113bf4b88..c2a3a60dd15f1 100644 --- a/src/views/nodes/commitNode.ts +++ b/src/views/nodes/commitNode.ts @@ -1,6 +1,6 @@ import type { Command } from 'vscode'; import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; -import type { DiffWithPreviousCommandArgs } from '../../commands'; +import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPrevious'; import type { Colors } from '../../constants'; import { Commands } from '../../constants'; import { CommitFormatter } from '../../git/formatters/commitFormatter'; diff --git a/src/views/nodes/fileRevisionAsCommitNode.ts b/src/views/nodes/fileRevisionAsCommitNode.ts index e358252c16457..5fd72fbbd735a 100644 --- a/src/views/nodes/fileRevisionAsCommitNode.ts +++ b/src/views/nodes/fileRevisionAsCommitNode.ts @@ -1,6 +1,6 @@ import type { Command, Selection } from 'vscode'; import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; -import type { DiffWithPreviousCommandArgs } from '../../commands'; +import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPrevious'; import type { Colors } from '../../constants'; import { Commands } from '../../constants'; import type { Container } from '../../container'; diff --git a/src/views/nodes/mergeConflictCurrentChangesNode.ts b/src/views/nodes/mergeConflictCurrentChangesNode.ts index 796ea794684f4..601be5b683a0f 100644 --- a/src/views/nodes/mergeConflictCurrentChangesNode.ts +++ b/src/views/nodes/mergeConflictCurrentChangesNode.ts @@ -1,6 +1,6 @@ import type { Command } from 'vscode'; import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; -import type { DiffWithCommandArgs } from '../../commands'; +import type { DiffWithCommandArgs } from '../../commands/diffWith'; import { Commands, GlyphChars } from '../../constants'; import { GitUri } from '../../git/gitUri'; import type { GitCommit } from '../../git/models/commit'; diff --git a/src/views/nodes/mergeConflictIncomingChangesNode.ts b/src/views/nodes/mergeConflictIncomingChangesNode.ts index 28406b248fa46..a8f3047b9cc28 100644 --- a/src/views/nodes/mergeConflictIncomingChangesNode.ts +++ b/src/views/nodes/mergeConflictIncomingChangesNode.ts @@ -1,6 +1,6 @@ import type { Command } from 'vscode'; import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; -import type { DiffWithCommandArgs } from '../../commands'; +import type { DiffWithCommandArgs } from '../../commands/diffWith'; import { Commands, GlyphChars } from '../../constants'; import { GitUri } from '../../git/gitUri'; import type { GitCommit } from '../../git/models/commit'; diff --git a/src/views/nodes/resultsFileNode.ts b/src/views/nodes/resultsFileNode.ts index 74d57c84b61ef..da974ff214e6c 100644 --- a/src/views/nodes/resultsFileNode.ts +++ b/src/views/nodes/resultsFileNode.ts @@ -1,6 +1,6 @@ import type { Command } from 'vscode'; import { TreeItem, TreeItemCheckboxState, TreeItemCollapsibleState } from 'vscode'; -import type { DiffWithCommandArgs } from '../../commands'; +import type { DiffWithCommandArgs } from '../../commands/diffWith'; import { Commands } from '../../constants'; import { StatusFileFormatter } from '../../git/formatters/statusFormatter'; import { GitUri } from '../../git/gitUri'; diff --git a/src/views/nodes/statusFileNode.ts b/src/views/nodes/statusFileNode.ts index eec927a202665..834f21edd6423 100644 --- a/src/views/nodes/statusFileNode.ts +++ b/src/views/nodes/statusFileNode.ts @@ -1,6 +1,6 @@ import type { Command } from 'vscode'; import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; -import type { DiffWithCommandArgs } from '../../commands'; +import type { DiffWithCommandArgs } from '../../commands/diffWith'; import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPrevious'; import { Commands } from '../../constants'; import { StatusFileFormatter } from '../../git/formatters/statusFormatter'; diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts index 66d9e727d822e..8326aec363d24 100644 --- a/src/views/viewCommands.ts +++ b/src/views/viewCommands.ts @@ -1,12 +1,10 @@ import type { Disposable, TextDocumentShowOptions } from 'vscode'; import { env, Uri, window } from 'vscode'; import type { CreatePullRequestActionContext, OpenPullRequestActionContext } from '../api/gitlens'; -import type { - DiffWithCommandArgs, - DiffWithPreviousCommandArgs, - DiffWithWorkingCommandArgs, - OpenFileAtRevisionCommandArgs, -} from '../commands'; +import type { DiffWithCommandArgs } from '../commands/diffWith'; +import type { DiffWithPreviousCommandArgs } from '../commands/diffWithPrevious'; +import type { DiffWithWorkingCommandArgs } from '../commands/diffWithWorking'; +import type { OpenFileAtRevisionCommandArgs } from '../commands/openFileAtRevision'; import type { ViewShowBranchComparison } from '../config'; import { Commands } from '../constants'; import type { Container } from '../container'; diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index e61216f0104be..e108f3ecae58e 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -2,7 +2,7 @@ import type { CancellationToken, ConfigurationChangeEvent, TextDocumentShowOptio import { CancellationTokenSource, Disposable, Uri, window } from 'vscode'; import type { MaybeEnrichedAutolink } from '../../annotations/autolinks'; import { serializeAutolink } from '../../annotations/autolinks'; -import type { CopyShaToClipboardCommandArgs } from '../../commands'; +import type { CopyShaToClipboardCommandArgs } from '../../commands/copyShaToClipboard'; import type { CoreConfiguration } from '../../constants'; import { Commands } from '../../constants'; import type { Container } from '../../container'; diff --git a/src/webviews/rebase/rebaseEditor.ts b/src/webviews/rebase/rebaseEditor.ts index 48a3859f0317b..1085a86d99428 100644 --- a/src/webviews/rebase/rebaseEditor.ts +++ b/src/webviews/rebase/rebaseEditor.ts @@ -7,7 +7,7 @@ import type { } from 'vscode'; import { ConfigurationTarget, Disposable, Position, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode'; import { getNonce } from '@env/crypto'; -import { ShowCommitsInViewCommand } from '../../commands'; +import { ShowCommitsInViewCommand } from '../../commands/showCommitsInView'; import type { CoreConfiguration } from '../../constants'; import type { Container } from '../../container'; import { emojify } from '../../emojis'; From 77598859d1d9b123b7de93771076b6626f58ee4f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 10 Oct 2023 13:33:02 -0400 Subject: [PATCH 0035/1012] Updates dependencies --- ThirdPartyNotices.txt | 6 +- package.json | 22 +-- yarn.lock | 380 +++++++++++++++++++++--------------------- 3 files changed, 206 insertions(+), 202 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index c63263d6fa585..ea8988ae6e39e 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -6,10 +6,10 @@ This project incorporates components from the projects listed below. 1. @microsoft/fast-element version 1.12.0 (https://github.com/Microsoft/fast) 2. @microsoft/fast-react-wrapper version 0.3.19 (https://github.com/Microsoft/fast) 3. @octokit/graphql version 7.0.2 (https://github.com/octokit/graphql.js) -4. @octokit/request version 8.1.2 (https://github.com/octokit/request.js) +4. @octokit/request version 8.1.4 (https://github.com/octokit/request.js) 5. @opentelemetry/api version 1.6.0 (https://github.com/open-telemetry/opentelemetry-js) -6. @opentelemetry/exporter-trace-otlp-http version 0.43.0 (https://github.com/open-telemetry/opentelemetry-js) -7. @opentelemetry/sdk-trace-base version 1.17.0 (https://github.com/open-telemetry/opentelemetry-js) +6. @opentelemetry/exporter-trace-otlp-http version 0.44.0 (https://github.com/open-telemetry/opentelemetry-js) +7. @opentelemetry/sdk-trace-base version 1.17.1 (https://github.com/open-telemetry/opentelemetry-js) 8. @vscode/codicons version 0.0.33 (https://github.com/microsoft/vscode-codicons) 9. @vscode/webview-ui-toolkit version 1.2.2 (https://github.com/microsoft/vscode-webview-ui-toolkit) 10. ansi-regex version 6.0.1 (https://github.com/chalk/ansi-regex) diff --git a/package.json b/package.json index 94d6d0f2152f6..51452738ab756 100644 --- a/package.json +++ b/package.json @@ -14855,10 +14855,10 @@ "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", "@octokit/graphql": "7.0.2", - "@octokit/request": "8.1.2", + "@octokit/request": "8.1.4", "@opentelemetry/api": "1.6.0", - "@opentelemetry/exporter-trace-otlp-http": "0.43.0", - "@opentelemetry/sdk-trace-base": "1.17.0", + "@opentelemetry/exporter-trace-otlp-http": "0.44.0", + "@opentelemetry/sdk-trace-base": "1.17.1", "@vscode/codicons": "0.0.33", "@vscode/webview-ui-toolkit": "1.2.2", "ansi-regex": "6.0.1", @@ -14876,12 +14876,12 @@ "devDependencies": { "@types/mocha": "10.0.1", "@types/node": "16.11.47", - "@types/react": "17.0.47", - "@types/react-dom": "17.0.17", - "@types/sortablejs": "1.15.2", + "@types/react": "17.0.67", + "@types/react-dom": "17.0.21", + "@types/sortablejs": "1.15.3", "@types/vscode": "1.80.0", - "@typescript-eslint/eslint-plugin": "6.7.4", - "@typescript-eslint/parser": "6.7.4", + "@typescript-eslint/eslint-plugin": "6.7.5", + "@typescript-eslint/parser": "6.7.5", "@vscode/test-electron": "2.3.5", "@vscode/test-web": "0.0.46", "@vscode/vsce": "2.21.1", @@ -14896,7 +14896,7 @@ "esbuild": "0.19.4", "esbuild-loader": "4.0.2", "esbuild-sass-plugin": "2.16.0", - "eslint": "8.50.0", + "eslint": "8.51.0", "eslint-cli": "1.1.1", "eslint-config-prettier": "9.0.0", "eslint-import-resolver-typescript": "3.6.1", @@ -14915,13 +14915,13 @@ "mini-css-extract-plugin": "2.7.6", "mocha": "10.2.0", "prettier": "3.0.3", - "sass": "1.69.0", + "sass": "1.69.1", "sass-loader": "13.3.2", "schema-utils": "4.2.0", "sharp": "0.32.6", "svgo": "3.0.2", "terser-webpack-plugin": "5.3.9", - "ts-loader": "9.4.4", + "ts-loader": "9.5.0", "tsc-alias": "1.8.8", "typescript": "5.3.0-beta", "webpack": "5.88.2", diff --git a/yarn.lock b/yarn.lock index 5574288dfb238..6413bf22cec5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -198,10 +198,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.50.0": - version "8.50.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" - integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== +"@eslint/js@8.51.0": + version "8.51.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" + integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== "@floating-ui/core@^1.4.2": version "1.5.0" @@ -353,9 +353,9 @@ path-to-regexp "^6.2.1" "@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.1.tgz#64df34e2f12e68e78ac57e571d25ec07fa460ca9" - integrity sha512-kXOeFbfCm4fFf2A3WwVEeQj55tMZa8c8/f9AKHMobQMkzNUfUj+antR3fRPaZJawsa1aZiP/Da3ndpZrwEe4rQ== + version "1.1.2" + resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz#d693d972974a354034454ec1317eb6afd0b00312" + integrity sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g== "@lit/reactive-element@^1.3.0", "@lit/reactive-element@^1.6.0": version "1.6.3" @@ -462,10 +462,10 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@8.1.2", "@octokit/request@^8.0.1": - version "8.1.2" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.1.2.tgz#26763e2001da1c98fa89c7df4d6414246bb1564b" - integrity sha512-A0RJJfzjlZQwb+39eDm5UM23dkxbp28WEG4p2ueH+Q2yY4p349aRK/vcUlEuIB//ggcrHJceoYYkBP/LYCoXEg== +"@octokit/request@8.1.4", "@octokit/request@^8.0.1": + version "8.1.4" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.1.4.tgz#12dfaebdb2ea375eaabb41d39d45182531ac2857" + integrity sha512-M0aaFfpGPEKrg7XoA/gwgRvc9MSXHRO2Ioki1qrPDbl1e9YhjIwVoHE7HIKmv/m3idzldj//xBujcFNqGX6ENA== dependencies: "@octokit/endpoint" "^9.0.0" "@octokit/request-error" "^5.0.0" @@ -480,10 +480,10 @@ dependencies: "@octokit/openapi-types" "^19.0.0" -"@opentelemetry/api-logs@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.43.0.tgz#472dacbf91488ad6f6b9de39a6f5038b450bdbc6" - integrity sha512-0CXMOYPXgAdLM2OzVkiUfAL6QQwWVhnMfUXCqLsITY42FZ9TxAhZIHkoc4mfVxvPuXsBnRYGR8UQZX86p87z4A== +"@opentelemetry/api-logs@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.44.0.tgz#4bbb04e9043234c240b3a9129732281f1ceae759" + integrity sha512-OctojdKGmXHKAJa4/Ml+Nf7MD9jtYXvZyP64xTh0pNTmtgaTdWW3FURri2DdB/+l7YxRy0tYYZS3/tYEM1pj3w== dependencies: "@opentelemetry/api" "^1.0.0" @@ -492,81 +492,81 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.6.0.tgz#de2c6823203d6f319511898bb5de7e70f5267e19" integrity sha512-OWlrQAnWn9577PhVgqjUvMr1pg57Bc4jv0iL4w0PRuOSRvq67rvHW9Ie/dZVMvCzhSCB+UxhcY/PmCmFj33Q+g== -"@opentelemetry/core@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.17.0.tgz#6a72425f5f953dc68b4c7c66d947c018173d30d2" - integrity sha512-tfnl3h+UefCgx1aeN2xtrmr6BmdWGKXypk0pflQR0urFS40aE88trnkOMc2HTJZbMrqEEl4HsaBeFhwLVXsrJg== - dependencies: - "@opentelemetry/semantic-conventions" "1.17.0" - -"@opentelemetry/exporter-trace-otlp-http@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.43.0.tgz#4d0a3587a1d372d19c883d9a4720f6eeb7dc9671" - integrity sha512-X6RGl4RTWC13EBrFstAbTh4vKqVqf6afpvFcud9qYhvl2A53OZ5RTAQP+9MrAMhthiKQaftNsEDdB2/0Sq+Xkw== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/otlp-exporter-base" "0.43.0" - "@opentelemetry/otlp-transformer" "0.43.0" - "@opentelemetry/resources" "1.17.0" - "@opentelemetry/sdk-trace-base" "1.17.0" - -"@opentelemetry/otlp-exporter-base@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.43.0.tgz#3ac36e959897050ceba8838bb2af7145a9e73d2c" - integrity sha512-LXNtRFVuPRXB9q0qdvrLikQ3NtT9Jmv255Idryz3RJPhOh/Fa03sBASQoj3D55OH3xazmA90KFHfhJ/d8D8y4A== - dependencies: - "@opentelemetry/core" "1.17.0" - -"@opentelemetry/otlp-transformer@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.43.0.tgz#d4b12ba52d5193a35840d9e1a5e646c4e7e06a5b" - integrity sha512-KXYmgzWdVBOD5NvPmGW1nEMJjyQ8gK3N8r6pi4HvmEhTp0v4T13qDSax4q0HfsqmbPJR355oqQSJUnu1dHNutw== - dependencies: - "@opentelemetry/api-logs" "0.43.0" - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" - "@opentelemetry/sdk-logs" "0.43.0" - "@opentelemetry/sdk-metrics" "1.17.0" - "@opentelemetry/sdk-trace-base" "1.17.0" - -"@opentelemetry/resources@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.17.0.tgz#ee29144cfd7d194c69698c8153dbadec7fe6819f" - integrity sha512-+u0ciVnj8lhuL/qGRBPeVYvk7fL+H/vOddfvmOeJaA1KC+5/3UED1c9KoZQlRsNT5Kw1FaK8LkY2NVLYfOVZQw== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/semantic-conventions" "1.17.0" - -"@opentelemetry/sdk-logs@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.43.0.tgz#ad40803f0e8893d1839af3a32756d5f46f0f7bbe" - integrity sha512-JyJ2BBRKm37Mc4cSEhFmsMl5ASQn1dkGhEWzAAMSlhPtLRTv5PfvJwhR+Mboaic/eDLAlciwsgijq8IFlf6IgQ== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" - -"@opentelemetry/sdk-metrics@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.17.0.tgz#e51d39e0bb749780d17f9b1df12f0490438dec1a" - integrity sha512-HlWM27yGmYuwCoVRe3yg2PqKnIsq0kEF0HQgvkeDWz2NYkq9fFaSspR6kvjxUTbghAlZrabiqbgyKoYpYaXS3w== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" +"@opentelemetry/core@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.17.1.tgz#10c5e09c63aeb1836b34d80baf7113760fb19d96" + integrity sha512-I6LrZvl1FF97FQXPR0iieWQmKnGxYtMbWA1GrAXnLUR+B1Hn2m8KqQNEIlZAucyv00GBgpWkpllmULmZfG8P3g== + dependencies: + "@opentelemetry/semantic-conventions" "1.17.1" + +"@opentelemetry/exporter-trace-otlp-http@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.44.0.tgz#1dfe24b87fa3e1f5edd2109da28d489029f90171" + integrity sha512-RkorGE6wf6PF5OjMUGBnbUDyaVgmN+vL7OgClJJUTxqbE7WqgbW8dkU04O+1mcB1znXZ1Aej1uDm0pS+eW/upA== + dependencies: + "@opentelemetry/core" "1.17.1" + "@opentelemetry/otlp-exporter-base" "0.44.0" + "@opentelemetry/otlp-transformer" "0.44.0" + "@opentelemetry/resources" "1.17.1" + "@opentelemetry/sdk-trace-base" "1.17.1" + +"@opentelemetry/otlp-exporter-base@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.44.0.tgz#10563cbe3ed89d7c8d422b513b819026f00ba038" + integrity sha512-DKQqRrfVMe96aSLZiCgIesLcMLfnWH8d4bTpLB1JbU+SAQJ7nVCAfS9U36mjFCVhvNDD7gwfCNrxqFMCHq6FUw== + dependencies: + "@opentelemetry/core" "1.17.1" + +"@opentelemetry/otlp-transformer@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.44.0.tgz#4f7eb2f6e4624b2110dfb3a5dda8cfebbd80225a" + integrity sha512-1/KC+aHM1oGEsXyNy7QoxpvErxGdzt26bg9VHyNb4TDILkUFdwrnywnxPc6lXZ6h/8T8Mt718UWOKjNHC514kQ== + dependencies: + "@opentelemetry/api-logs" "0.44.0" + "@opentelemetry/core" "1.17.1" + "@opentelemetry/resources" "1.17.1" + "@opentelemetry/sdk-logs" "0.44.0" + "@opentelemetry/sdk-metrics" "1.17.1" + "@opentelemetry/sdk-trace-base" "1.17.1" + +"@opentelemetry/resources@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.17.1.tgz#932f70f58c0e03fb1d38f0cba12672fd70804d99" + integrity sha512-M2e5emqg5I7qRKqlzKx0ROkcPyF8PbcSaWEdsm72od9txP7Z/Pl8PDYOyu80xWvbHAWk5mDxOF6v3vNdifzclA== + dependencies: + "@opentelemetry/core" "1.17.1" + "@opentelemetry/semantic-conventions" "1.17.1" + +"@opentelemetry/sdk-logs@0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.44.0.tgz#a46e0a013432f266fb7ef16d703c968898ae89c5" + integrity sha512-UN3ofh9Jj54gIgrSXNRWAoaH6iPvrrjed5YAtqO9cW65U+5QPzk1Rv95vjAcY9VTrmMWvuqgEK1CYObG6Hu4OQ== + dependencies: + "@opentelemetry/core" "1.17.1" + "@opentelemetry/resources" "1.17.1" + +"@opentelemetry/sdk-metrics@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.17.1.tgz#9c4d13d845bcc82be8684050d9db7cce10f61580" + integrity sha512-eHdpsMCKhKhwznxvEfls8Wv3y4ZBWkkXlD3m7vtHIiWBqsMHspWSfie1s07mM45i/bBCf6YBMgz17FUxIXwmZA== + dependencies: + "@opentelemetry/core" "1.17.1" + "@opentelemetry/resources" "1.17.1" lodash.merge "^4.6.2" -"@opentelemetry/sdk-trace-base@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.17.0.tgz#05a21763c9efa72903c20b8930293cdde344b681" - integrity sha512-2T5HA1/1iE36Q9eg6D4zYlC4Y4GcycI1J6NsHPKZY9oWfAxWsoYnRlkPfUqyY5XVtocCo/xHpnJvGNHwzT70oQ== +"@opentelemetry/sdk-trace-base@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.17.1.tgz#8ede213df8b0c957028a869c66964e535193a4fd" + integrity sha512-pfSJJSjZj5jkCJUQZicSpzN8Iz9UKMryPWikZRGObPnJo6cUSoKkjZh6BM3j+D47G4olMBN+YZKYqkFM1L6zNA== dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" - "@opentelemetry/semantic-conventions" "1.17.0" + "@opentelemetry/core" "1.17.1" + "@opentelemetry/resources" "1.17.1" + "@opentelemetry/semantic-conventions" "1.17.1" -"@opentelemetry/semantic-conventions@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.17.0.tgz#af10baa9f05ce1e64a14065fc138b5739bfb65f6" - integrity sha512-+fguCd2d8d2qruk0H0DsCEy2CTK3t0Tugg7MhZ/UQMvmewbZLNnJ6heSYyzIZWG5IPfAXzoj4f4F/qpM7l4VBA== +"@opentelemetry/semantic-conventions@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.17.1.tgz#93d219935e967fbb9aa0592cc96b2c0ec817a56f" + integrity sha512-xbR2U+2YjauIuo42qmE8XyJK6dYeRMLJuOlUP5SO4auET4VtOHOzgkRVOq+Ik18N+Xf3YPcqJs9dZMiDddz1eQ== "@pkgjs/parseargs@^0.11.0": version "0.11.0" @@ -696,9 +696,11 @@ integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== "@types/node@*": - version "20.8.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.2.tgz#d76fb80d87d0d8abfe334fc6d292e83e5524efc4" - integrity sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w== + version "20.8.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.4.tgz#0e9ebb2ff29d5c3302fc84477d066fa7c6b441aa" + integrity sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A== + dependencies: + undici-types "~5.25.1" "@types/node@16.11.47": version "16.11.47" @@ -720,26 +722,17 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.8.tgz#805eae6e8f41bd19e88917d2ea200dc992f405d3" integrity sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ== -"@types/react-dom@17.0.17": - version "17.0.17" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1" - integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== +"@types/react-dom@17.0.21": + version "17.0.21" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.21.tgz#85d56965483ce4850f5f03f9234e54a1f47786e5" + integrity sha512-3rQEFUNUUz2MYiRwJJj6UekcW7rFLOtmK7ajQP7qJpjNdggInl3I/xM4I3Hq1yYPdCGVMgax1gZsB7BBTtayXg== dependencies: "@types/react" "^17" -"@types/react@17.0.47": - version "17.0.47" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.47.tgz#4ee71aaf4c5a9e290e03aa4d0d313c5d666b3b78" - integrity sha512-mk0BL8zBinf2ozNr3qPnlu1oyVTYq+4V7WA76RgxUAtf0Em/Wbid38KN6n4abEkvO4xMTBWmnP1FtQzgkEiJoA== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/react@^17": - version "17.0.66" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.66.tgz#4b3bfd6dd5ee37835f60d4a9325cff974b064126" - integrity sha512-azQzO1tuioq9M4vVKzzdBgG5KfLhyocYkRlJMBDcrJ7bUzyjR7QIGbZk2zH7sB5KpXRWoZJQ3CznVyhDS/swxA== +"@types/react@17.0.67", "@types/react@^17": + version "17.0.67" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.67.tgz#1c224738f203829a4692aa48e33a732c34fd014a" + integrity sha512-zE76EIJ0Y58Oy9yDX/9csb/NuKjt0Eq2YgWb/8Wxo91YmuLzzbyiRoaqJE9h8iDlsT7n35GdpoLomHlaB1kFbg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -755,10 +748,10 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== -"@types/sortablejs@1.15.2": - version "1.15.2" - resolved "https://registry.yarnpkg.com/@types/sortablejs/-/sortablejs-1.15.2.tgz#d51e5ecac00a9782aa256c1401309ce1c4031ba2" - integrity sha512-mOIv/EnPMzAZAVbuh9uGjOZ1BBdimP9Y6IPGntsvQJtko5yapSDKB7GwB3AOlF5N3bkpk4sBwQRpS3aEkiUbaA== +"@types/sortablejs@1.15.3": + version "1.15.3" + resolved "https://registry.yarnpkg.com/@types/sortablejs/-/sortablejs-1.15.3.tgz#b9c0e2740100ae94919c9f138a38600c8f8124ea" + integrity sha512-v+zh6TZP/cLeMUK0MDx1onp8e7Jk2/4iTQ7sb/n80rTAvBm14yJkpOEfJdrTCkHiF7IZbPjxGX2NRJfogRoYIg== "@types/trusted-types@^2.0.2": version "2.0.4" @@ -776,22 +769,22 @@ integrity sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ== "@types/yargs@^17.0.8": - version "17.0.26" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.26.tgz#388e5002a8b284ad7b4599ba89920a6d74d8d79a" - integrity sha512-Y3vDy2X6zw/ZCumcwLpdhM5L7jmyGpmBCTYMHDLqT2IKVMYRRLdv6ZakA+wxhra6Z/3bwhNbNl9bDGXaFU+6rw== + version "17.0.28" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.28.tgz#d106e4301fbacde3d1796ab27374dd16588ec851" + integrity sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw== dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d" - integrity sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA== +"@typescript-eslint/eslint-plugin@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz#f4024b9f63593d0c2b5bd6e4ca027e6f30934d4f" + integrity sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/type-utils" "6.7.4" - "@typescript-eslint/utils" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/scope-manager" "6.7.5" + "@typescript-eslint/type-utils" "6.7.5" + "@typescript-eslint/utils" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -799,72 +792,72 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.4.tgz#23d1dd4fe5d295c7fa2ab651f5406cd9ad0bd435" - integrity sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA== +"@typescript-eslint/parser@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.5.tgz#8d7ca3d1fbd9d5a58cc4d30b2aa797a760137886" + integrity sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw== dependencies: - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/typescript-estree" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/scope-manager" "6.7.5" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/typescript-estree" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz#a484a17aa219e96044db40813429eb7214d7b386" - integrity sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A== +"@typescript-eslint/scope-manager@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz#1cf33b991043886cd67f4f3600b8e122fc14e711" + integrity sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A== dependencies: - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" -"@typescript-eslint/type-utils@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz#847cd3b59baf948984499be3e0a12ff07373e321" - integrity sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ== +"@typescript-eslint/type-utils@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz#0a65949ec16588d8956f6d967f7d9c84ddb2d72a" + integrity sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g== dependencies: - "@typescript-eslint/typescript-estree" "6.7.4" - "@typescript-eslint/utils" "6.7.4" + "@typescript-eslint/typescript-estree" "6.7.5" + "@typescript-eslint/utils" "6.7.5" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.4.tgz#5d358484d2be986980c039de68e9f1eb62ea7897" - integrity sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA== +"@typescript-eslint/types@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.5.tgz#4571320fb9cf669de9a95d9849f922c3af809790" + integrity sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ== -"@typescript-eslint/typescript-estree@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz#f2baece09f7bb1df9296e32638b2e1130014ef1a" - integrity sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ== +"@typescript-eslint/typescript-estree@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz#4578de1a26e9f24950f029a4f00d1bfe41f15a39" + integrity sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg== dependencies: - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/visitor-keys" "6.7.5" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.4.tgz#2236f72b10e38277ee05ef06142522e1de470ff2" - integrity sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA== +"@typescript-eslint/utils@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.5.tgz#ab847b53d6b65e029314b8247c2336843dba81ab" + integrity sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/typescript-estree" "6.7.4" + "@typescript-eslint/scope-manager" "6.7.5" + "@typescript-eslint/types" "6.7.5" + "@typescript-eslint/typescript-estree" "6.7.5" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz#80dfecf820fc67574012375859085f91a4dff043" - integrity sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA== +"@typescript-eslint/visitor-keys@6.7.5": + version "6.7.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz#84c68d6ceb5b12d5246b918b84f2b79affd6c2f1" + integrity sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg== dependencies: - "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/types" "6.7.5" eslint-visitor-keys "^3.4.1" "@vscode/codicons@0.0.33": @@ -1612,9 +1605,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001546" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz#10fdad03436cfe3cc632d3af7a99a0fb497407f0" - integrity sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw== + version "1.0.30001547" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz#d4f92efc488aab3c7f92c738d3977c2a3180472b" + integrity sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA== capital-case@^1.0.4: version "1.0.4" @@ -2595,9 +2588,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.535: - version "1.4.543" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.543.tgz#51116ffc9fba1ee93514d6a40d34676aa6d7d1c4" - integrity sha512-t2ZP4AcGE0iKCCQCBx/K2426crYdxD3YU6l0uK2EO3FZH0pbC4pFz/sZm2ruZsND6hQBTcDWWlo/MLpiOdif5g== + version "1.4.548" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.548.tgz#e695d769e0e801fa6d438b63f6bc9b80372000d6" + integrity sha512-R77KD6mXv37DOyKLN/eW1rGS61N6yHOfapNSX9w+y9DdPG83l9Gkuv7qkCFZ4Ta4JPhrjgQfYbv4Y3TnM1Hi2Q== emoji-regex@^8.0.0: version "8.0.0" @@ -2966,15 +2959,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@8.50.0: - version "8.50.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2" - integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== +eslint@8.51.0: + version "8.51.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" + integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.50.0" + "@eslint/js" "8.51.0" "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -4298,9 +4291,9 @@ keytar@^7.7.0: prebuild-install "^7.0.1" keyv@^4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" - integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" @@ -4992,9 +4985,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-abi@^3.3.0: - version "3.47.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.47.0.tgz#6cbfa2916805ae25c2b7156ca640131632eb05e8" - integrity sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A== + version "3.48.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.48.0.tgz#122d132ae1ac097b0d711144560b17922de026ab" + integrity sha512-uWR/uwQyVV2iN5+Wkf1/oQxOR9YjU7gBclJLg2qK7GDvVohcnY6LaBXKV89N79EQFyN4/e43O32yQYE5QdFYTA== dependencies: semver "^7.3.5" @@ -6247,10 +6240,10 @@ sass-loader@13.3.2: dependencies: neo-async "^2.6.2" -sass@1.69.0, sass@^1.7.3: - version "1.69.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.0.tgz#5195075371c239ed556280cf2f5944d234f42679" - integrity sha512-l3bbFpfTOGgQZCLU/gvm1lbsQ5mC/WnLz3djL2v4WCJBDrWm58PO+jgngcGRNnKUh6wSsdm50YaovTqskZ0xDQ== +sass@1.69.1, sass@^1.7.3: + version "1.69.1" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.1.tgz#659b3b04452245dcf82f731684831e990ddb0c89" + integrity sha512-nc969GvTVz38oqKgYYVHM/Iq7Yl33IILy5uqaH2CWSiSUmRCvw+UR7tA3845Sp4BD5ykCUimvrT3k1EjTwpVUA== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -6536,6 +6529,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + spawn-command@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" @@ -6968,15 +6966,16 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== -ts-loader@9.4.4: - version "9.4.4" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.4.tgz#6ceaf4d58dcc6979f84125335904920884b7cee4" - integrity sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w== +ts-loader@9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.0.tgz#f0a51dda37cc4d8e43e6cb14edebbc599b0c3aa2" + integrity sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg== dependencies: chalk "^4.1.0" enhanced-resolve "^5.0.0" micromatch "^4.0.0" semver "^7.3.4" + source-map "^0.7.4" tsc-alias@1.8.8: version "1.8.8" @@ -7178,6 +7177,11 @@ underscore@^1.12.1: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== +undici-types@~5.25.1: + version "5.25.3" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" + integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== + unique-filename@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" From 1c77db5c0a797f34763936b7daad76ade19e0712 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 10 Oct 2023 16:06:29 -0400 Subject: [PATCH 0036/1012] Fixes missing `folder` prop on Repository - Fixes issue when using folder tokens in `worktrees.defaultLocation` --- src/env/node/git/localGitProvider.ts | 6 +++--- src/git/models/repository.ts | 1 - src/plus/github/githubGitProvider.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 053fc2ff36b8c..3fdf45262caa2 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -503,7 +503,7 @@ export class LocalGitProvider implements GitProvider, Disposable { this.container, this.onRepositoryChanged.bind(this), this.descriptor, - folder, + folder ?? workspace.getWorkspaceFolder(uri), uri, root, suspended ?? !window.state.focused, @@ -514,7 +514,7 @@ export class LocalGitProvider implements GitProvider, Disposable { this.container, this.onRepositoryChanged.bind(this), this.descriptor, - folder, + folder ?? workspace.getWorkspaceFolder(canonicalUri), canonicalUri, root, suspended ?? !window.state.focused, @@ -529,7 +529,7 @@ export class LocalGitProvider implements GitProvider, Disposable { this.container, this.onRepositoryChanged.bind(this), this.descriptor, - folder, + folder ?? workspace.getWorkspaceFolder(uri), uri, root, suspended ?? !window.state.focused, diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 5975f8e6f8e92..1b431ed0434d5 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -226,7 +226,6 @@ export class Repository implements Disposable { suspended: boolean, closed: boolean = false, ) { - folder = workspace.getWorkspaceFolder(uri) ?? folder; if (folder != null) { if (root) { this.name = folder.name; diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index 6832633347fa1..5c73bea6779ac 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -261,7 +261,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { this.container, this.onRepositoryChanged.bind(this), this.descriptor, - folder, + folder ?? workspace.getWorkspaceFolder(uri), uri, root, suspended ?? !window.state.focused, From fe6b26928ac77ed73f5066bf14398a205627b41e Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Tue, 10 Oct 2023 13:24:07 -0700 Subject: [PATCH 0037/1012] Fixes remote name in graph 'Open Branch on Remote' --- src/plus/webviews/graph/graphWebview.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 84a9993a7991f..7c9eb816beac5 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -2180,13 +2180,20 @@ export class GraphWebviewProvider implements WebviewProvider { private openBranchOnRemote(item?: GraphItemContext, clipboard?: boolean) { if (isGraphItemRefContext(item, 'branch')) { const { ref } = item.webviewItemValue; + let remote; + if (ref.remote) { + remote = getRemoteNameFromBranchName(ref.name); + } else if (ref.upstream != null) { + remote = getRemoteNameFromBranchName(ref.upstream.name); + } + return executeCommand(Commands.OpenOnRemote, { repoPath: ref.repoPath, resource: { type: RemoteResourceType.Branch, branch: ref.name, }, - remote: ref.upstream?.name, + remote: remote, clipboard: clipboard, }); } From b48021f1fdca08f0fd8b6cb2587cd8968d15c861 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Tue, 10 Oct 2023 14:11:56 -0700 Subject: [PATCH 0038/1012] Updates graph dependency --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 51452738ab756..ebb216213737d 100644 --- a/package.json +++ b/package.json @@ -14850,7 +14850,7 @@ "vscode:prepublish": "yarn run bundle" }, "dependencies": { - "@gitkraken/gitkraken-components": "10.1.27", + "@gitkraken/gitkraken-components": "10.1.29", "@gitkraken/shared-web-components": "0.1.1-rc.11", "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", diff --git a/yarn.lock b/yarn.lock index 6413bf22cec5c..d4cfff6a1409c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -223,10 +223,10 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== -"@gitkraken/gitkraken-components@10.1.27": - version "10.1.27" - resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.27.tgz#18a9430678d7cef6a6476f8fcab956ea26dca76e" - integrity sha512-NiQ6M7J2sfrGfB2RRaIzMuM9l67GXY5BbgNVnQJajHa3zmuPN3ImLZ92Qxn0nn/0ZsrvVDaY6ZShnPRBNnbmeA== +"@gitkraken/gitkraken-components@10.1.29": + version "10.1.29" + resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.29.tgz#4d539e1bc9c343e8167bb4165f91246953725837" + integrity sha512-cqu9Mg8X6AERpdNIe+ux9CFLglkMejgRq3E6pIDG5lyMsEmLiISYr4trrTFc0DTyGfRwmbagCbqNodXeTOU6Fw== dependencies: "@axosoft/react-virtualized" "9.22.3-gitkraken.3" classnames "2.3.2" From 3bce79a8d8097fa7c50c792a2f57251dc9abbfe7 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 10 Oct 2023 17:47:17 -0400 Subject: [PATCH 0039/1012] Splits out new `getFirstCommitSha` Aligns with eventual cloud patch changes --- src/env/node/git/localGitProvider.ts | 12 +-- src/git/gitProvider.ts | 2 +- src/git/gitProviderService.ts | 16 ++-- src/plus/github/githubGitProvider.ts | 5 -- src/telemetry/usageTracker.ts | 6 +- src/uris/deepLinks/deepLink.ts | 106 +++++++++++++------------- src/uris/deepLinks/deepLinkService.ts | 26 +++---- 7 files changed, 87 insertions(+), 86 deletions(-) diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 3fdf45262caa2..c3509b96a14d6 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -2917,6 +2917,12 @@ export class LocalGitProvider implements GitProvider, Disposable { return files[0]; } + @log() + async getFirstCommitSha(repoPath: string): Promise { + const data = await this.git.rev_list(repoPath, 'HEAD', { maxParents: 0 }); + return data?.[0]; + } + @gate() @debug() async getGitDir(repoPath: string): Promise { @@ -4442,12 +4448,6 @@ export class LocalGitProvider implements GitProvider, Disposable { return GitTreeParser.parse(data) ?? []; } - @log() - async getUniqueRepositoryId(repoPath: string): Promise { - const data = await this.git.rev_list(repoPath, 'HEAD', { maxParents: 0 }); - return data?.[0]; - } - @log({ args: { 1: false } }) async hasBranchOrTag( repoPath: string | undefined, diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 8ad2b5cf119c8..508f97606c3fd 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -308,6 +308,7 @@ export interface GitProvider extends Disposable { options?: { filters?: GitDiffFilter[] | undefined; similarityThreshold?: number | undefined }, ): Promise; getFileStatusForCommit(repoPath: string, uri: Uri, ref: string): Promise; + getFirstCommitSha?(repoPath: string): Promise; getGitDir?(repoPath: string): Promise; getLastFetchedTimestamp(repoPath: string): Promise; getLog( @@ -406,7 +407,6 @@ export interface GitProvider extends Disposable { ): Promise>; getTreeEntryForRevision(repoPath: string, path: string, ref: string): Promise; getTreeForRevision(repoPath: string, ref: string): Promise; - getUniqueRepositoryId(repoPath: string): Promise; hasBranchOrTag( repoPath: string | undefined, options?: { diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index ec811edc09766..0eb207a374bed 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -97,8 +97,6 @@ const weightedDefaultBranches = new Map([ ['development', 1], ]); -const missingRepositoryId = '-'; - export type GitProvidersChangeEvent = { readonly added: readonly GitProvider[]; readonly removed: readonly GitProvider[]; @@ -2438,12 +2436,18 @@ export class GitProviderService implements Disposable { } @log() - async getUniqueRepositoryId(repoPath: string | Uri): Promise { + async getFirstCommitSha(repoPath: string | Uri): Promise { const { provider, path } = this.getProvider(repoPath); - const id = await provider.getUniqueRepositoryId(path); - if (id != null) return id; + try { + return await provider.getFirstCommitSha?.(path); + } catch { + return undefined; + } + } - return missingRepositoryId; + @log() + getUniqueRepositoryId(repoPath: string | Uri): Promise { + return this.getFirstCommitSha(repoPath); } @log({ args: { 1: false } }) diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index 5c73bea6779ac..c057f661b1403 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -2771,11 +2771,6 @@ export class GitHubGitProvider implements GitProvider, Disposable { return []; } - async getUniqueRepositoryId(_repoPath: string): Promise { - // TODO@ramint implement this if there is a way. - return undefined; - } - @log() async hasBranchOrTag( repoPath: string | undefined, diff --git a/src/telemetry/usageTracker.ts b/src/telemetry/usageTracker.ts index 8981debf38bac..6d520e6d6a9dd 100644 --- a/src/telemetry/usageTracker.ts +++ b/src/telemetry/usageTracker.ts @@ -11,11 +11,13 @@ export interface TrackedUsage { } export type TrackedUsageFeatures = + | 'accountView' | 'branchesView' | 'commitDetailsView' | 'commitsView' | 'contributorsView' | 'fileHistoryView' + | 'focusWebview' | 'graphDetailsView' | 'graphView' | 'graphWebview' @@ -31,9 +33,7 @@ export type TrackedUsageFeatures = | 'timelineWebview' | 'timelineView' | 'welcomeWebview' - | 'workspaceView' - | 'focusWebview' - | 'accountView'; + | 'workspaceView'; export type TrackedUsageKeys = `${TrackedUsageFeatures}:shown`; export type UsageChangeEvent = { diff --git a/src/uris/deepLinks/deepLink.ts b/src/uris/deepLinks/deepLink.ts index 4b7910dbfe541..901f32b1cd1cb 100644 --- a/src/uris/deepLinks/deepLink.ts +++ b/src/uris/deepLinks/deepLink.ts @@ -62,65 +62,69 @@ export function parseDeepLinkUri(uri: Uri): DeepLink | undefined { // For example, if the uri is /link/r/{repoId}/b/{branchName}?url={remoteUrl}, // the link target id is {branchName} const [, type, prefix, mainId, target, ...rest] = uri.path.split('/'); - if (type !== 'link' || (prefix !== DeepLinkType.Repository && prefix !== DeepLinkType.Workspace)) { - return undefined; - } + if (type !== 'link') return undefined; const urlParams = new URLSearchParams(uri.query); - let remoteUrl = urlParams.get('url') ?? undefined; - if (remoteUrl != null) { - remoteUrl = decodeURIComponent(remoteUrl); - } - let repoPath = urlParams.get('path') ?? undefined; - if (repoPath != null) { - repoPath = decodeURIComponent(repoPath); - } - if (!remoteUrl && !repoPath && prefix !== DeepLinkType.Workspace) return undefined; - if (prefix === DeepLinkType.Workspace) { - return { - type: DeepLinkType.Workspace, - mainId: mainId, - }; - } + switch (prefix) { + case DeepLinkType.Repository: { + let remoteUrl = urlParams.get('url') ?? undefined; + if (remoteUrl != null) { + remoteUrl = decodeURIComponent(remoteUrl); + } + let repoPath = urlParams.get('path') ?? undefined; + if (repoPath != null) { + repoPath = decodeURIComponent(repoPath); + } + if (!remoteUrl && !repoPath) return undefined; - if (target == null) { - return { - type: DeepLinkType.Repository, - mainId: mainId, - remoteUrl: remoteUrl, - repoPath: repoPath, - }; - } + if (target == null) { + return { + type: DeepLinkType.Repository, + mainId: mainId, + remoteUrl: remoteUrl, + repoPath: repoPath, + }; + } - if (rest == null || rest.length === 0) return undefined; + if (rest == null || rest.length === 0) return undefined; - let targetId: string; - let secondaryTargetId: string | undefined; - let secondaryRemoteUrl: string | undefined; - const joined = rest.join('/'); + let targetId: string; + let secondaryTargetId: string | undefined; + let secondaryRemoteUrl: string | undefined; + const joined = rest.join('/'); - if (target === DeepLinkType.Comparison) { - const split = joined.split(/(\.\.\.|\.\.)/); - if (split.length !== 3) return undefined; - targetId = split[0]; - secondaryTargetId = split[2]; - secondaryRemoteUrl = urlParams.get('prRepoUrl') ?? undefined; - if (secondaryRemoteUrl != null) { - secondaryRemoteUrl = decodeURIComponent(secondaryRemoteUrl); + if (target === DeepLinkType.Comparison) { + const split = joined.split(/(\.\.\.|\.\.)/); + if (split.length !== 3) return undefined; + targetId = split[0]; + secondaryTargetId = split[2]; + secondaryRemoteUrl = urlParams.get('prRepoUrl') ?? undefined; + if (secondaryRemoteUrl != null) { + secondaryRemoteUrl = decodeURIComponent(secondaryRemoteUrl); + } + } else { + targetId = joined; + } + + return { + type: target as DeepLinkType, + mainId: mainId, + remoteUrl: remoteUrl, + repoPath: repoPath, + targetId: targetId, + secondaryTargetId: secondaryTargetId, + secondaryRemoteUrl: secondaryRemoteUrl, + }; } - } else { - targetId = joined; - } + case DeepLinkType.Workspace: + return { + type: DeepLinkType.Workspace, + mainId: mainId, + }; - return { - type: target as DeepLinkType, - mainId: mainId, - remoteUrl: remoteUrl, - repoPath: repoPath, - targetId: targetId, - secondaryTargetId: secondaryTargetId, - secondaryRemoteUrl: secondaryRemoteUrl, - }; + default: + return undefined; + } } export const enum DeepLinkServiceState { diff --git a/src/uris/deepLinks/deepLinkService.ts b/src/uris/deepLinks/deepLinkService.ts index 3a9cfd27155bb..cc544044cdd86 100644 --- a/src/uris/deepLinks/deepLinkService.ts +++ b/src/uris/deepLinks/deepLinkService.ts @@ -25,18 +25,18 @@ import { parseDeepLinkUri, } from './deepLink'; +const missingRepositoryId = '-'; + export class DeepLinkService implements Disposable { private readonly _disposables: Disposable[] = []; private _context: DeepLinkServiceContext; - private readonly _onDeepLinkProgressUpdated: EventEmitter; + private readonly _onDeepLinkProgressUpdated = new EventEmitter(); constructor(private readonly container: Container) { this._context = { state: DeepLinkServiceState.Idle, }; - this._onDeepLinkProgressUpdated = new EventEmitter(); - this._disposables.push( container.uri.onDidReceiveUri(async (uri: Uri) => { const link = parseDeepLinkUri(uri); @@ -426,10 +426,13 @@ export class DeepLinkService implements Disposable { return; } case DeepLinkServiceState.TypeMatch: { - if (targetType === DeepLinkType.Workspace) { - action = DeepLinkServiceAction.LinkIsWorkspaceType; - } else { - action = DeepLinkServiceAction.LinkIsRepoType; + switch (targetType) { + case DeepLinkType.Workspace: + action = DeepLinkServiceAction.LinkIsWorkspaceType; + break; + default: + action = DeepLinkServiceAction.LinkIsRepoType; + break; } break; @@ -471,7 +474,7 @@ export class DeepLinkService implements Disposable { } } - if (mainId != null && mainId !== '-') { + if (mainId != null && mainId !== missingRepositoryId) { // Repo ID can be any valid SHA in the repo, though standard practice is to use the // first commit SHA. if (await this.container.git.validateReference(repo.path, mainId)) { @@ -945,7 +948,6 @@ export class DeepLinkService implements Disposable { compareRef?: StoredNamedRef, compareWithRef?: StoredNamedRef, ): Promise { - let repoId: string | undefined; let targetType: DeepLinkType | undefined; let targetId: string | undefined; let compareWithTargetId: string | undefined; @@ -963,11 +965,7 @@ export class DeepLinkService implements Disposable { } const repoPath = typeof refOrIdOrRepoPath !== 'string' ? refOrIdOrRepoPath.repoPath : refOrIdOrRepoPath; - try { - repoId = await this.container.git.getUniqueRepositoryId(repoPath); - } catch { - repoId = '-'; - } + const repoId = (await this.container.git.getUniqueRepositoryId(repoPath)) ?? missingRepositoryId; if (typeof refOrIdOrRepoPath !== 'string') { switch (refOrIdOrRepoPath.refType) { From 0448e1ba5a4eda3001e58f58f7dceaa831e63464 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 10 Oct 2023 18:31:11 -0400 Subject: [PATCH 0040/1012] Improves apply/restore for deleted files --- src/git/actions/commit.ts | 47 ++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/git/actions/commit.ts b/src/git/actions/commit.ts index f7e124dbc124b..d464fcda9367d 100644 --- a/src/git/actions/commit.ts +++ b/src/git/actions/commit.ts @@ -1,5 +1,5 @@ import type { TextDocumentShowOptions } from 'vscode'; -import { env, Range, Uri, window } from 'vscode'; +import { env, Range, Uri, window, workspace } from 'vscode'; import type { DiffWithCommandArgs } from '../../commands/diffWith'; import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPrevious'; import type { DiffWithWorkingCommandArgs } from '../../commands/diffWithWorking'; @@ -22,31 +22,39 @@ import type { GitFile } from '../models/file'; import type { GitRevisionReference } from '../models/reference'; import { getReferenceFromRevision, isUncommitted, isUncommittedStaged } from '../models/reference'; -export async function applyChanges(file: string | GitFile, ref1: GitRevisionReference, ref2?: GitRevisionReference) { +export async function applyChanges(file: string | GitFile, rev1: GitRevisionReference, rev2?: GitRevisionReference) { let create = false; - let ref = ref1.ref; + let ref1 = rev1.ref; + let ref2 = rev2?.ref; if (typeof file !== 'string') { // If the file is `?` (untracked), then this must be a stash, so get the ^3 commit to access the untracked file if (file.status === '?') { - ref = `${ref}^3`; + ref1 = `${ref1}^3`; create = true; } else if (file.status === 'A') { create = true; + } else if (file.status === 'D') { + // If the file is deleted, check to see if it exists, if so, apply the delete, otherwise restore it from the previous commit + const uri = GitUri.fromFile(file, rev1.repoPath); + try { + await workspace.fs.stat(uri); + } catch { + create = true; + + ref2 = ref1; + ref1 = `${ref1}^`; + } } } if (create) { - const uri = GitUri.fromFile(file, ref1.repoPath); - await Container.instance.git.applyChangesToWorkingFile(uri, ref, ref2?.ref); + const uri = GitUri.fromFile(file, rev1.repoPath); + await Container.instance.git.applyChangesToWorkingFile(uri, ref1, ref2); await openFile(uri, { preserveFocus: true, preview: false }); } else { // Open the working file to ensure undo will work - await openFile(file, ref1, { preserveFocus: true, preview: false }); - await Container.instance.git.applyChangesToWorkingFile( - GitUri.fromFile(file, ref1.repoPath, ref), - ref, - ref2?.ref, - ); + await openFile(file, rev1, { preserveFocus: true, preview: false }); + await Container.instance.git.applyChangesToWorkingFile(GitUri.fromFile(file, rev1.repoPath, ref1), ref1, ref2); } } @@ -550,7 +558,20 @@ export async function restoreFile(file: string | GitFile, revision: GitRevisionR ref = revision.ref; } else { path = file.path; - ref = file.status === `?` ? `${revision.ref}^3` : file.status === 'D' ? `${revision.ref}^` : revision.ref; + if (file.status === 'D') { + // If the file is deleted, check to see if it exists, if so, restore it from the previous commit, otherwise restore it from the current commit + const uri = GitUri.fromFile(file, revision.repoPath); + try { + await workspace.fs.stat(uri); + ref = `${revision.ref}^`; + } catch { + ref = revision.ref; + } + } else if (file.status === '?') { + ref = `${revision.ref}^3`; + } else { + ref = revision.ref; + } } await Container.instance.git.checkout(revision.repoPath, ref, { path: path }); From e19b9cfaa939d9c4a38cc127b3ad3a58fd959c4a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 11 Oct 2023 12:00:51 -0400 Subject: [PATCH 0041/1012] Ensures WIP node gets selected properly --- src/plus/webviews/graph/graphWebview.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 7c9eb816beac5..e4f58fe6a2a06 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -1895,7 +1895,8 @@ export class GraphWebviewProvider implements WebviewProvider { // If we have a set of data refresh to the same set const limit = Math.max(defaultItemLimit, this._graph?.ids.size ?? defaultItemLimit); - const ref = this._selectedId == null || this._selectedId === uncommitted ? 'HEAD' : this._selectedId; + const selectedId = this._selectedId; + const ref = selectedId == null || selectedId === uncommitted ? 'HEAD' : selectedId; const columns = this.getColumns(); const columnSettings = this.getColumnSettings(columns); @@ -1928,7 +1929,9 @@ export class GraphWebviewProvider implements WebviewProvider { queueMicrotask(async () => { const data = await dataPromise; this.setGraph(data); - this.setSelectedRows(data.id); + if (selectedId !== uncommitted) { + this.setSelectedRows(data.id); + } void this.notifyDidChangeRefsVisibility(); void this.notifyDidChangeRows(true); @@ -1936,7 +1939,9 @@ export class GraphWebviewProvider implements WebviewProvider { } else { data = await dataPromise; this.setGraph(data); - this.setSelectedRows(data.id); + if (selectedId !== uncommitted) { + this.setSelectedRows(data.id); + } } const [accessResult, workingStatsResult, branchResult, lastFetchedResult] = await promises; From a70e2b930a9e10697b919b158dbf3e244a8bdd5c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 11 Oct 2023 17:18:38 -0400 Subject: [PATCH 0042/1012] Adds Working Changes tab to Commit/Graph Details - Adds stage/unstage support --- CHANGELOG.md | 2 + src/trackers/gitLineTracker.ts | 2 +- src/trackers/lineTracker.ts | 1 + .../apps/commitDetails/commitDetails.scss | 103 ++- .../apps/commitDetails/commitDetails.ts | 71 +- .../components/commit-details-app.ts | 733 ++---------------- .../components/gl-commit-details.ts | 523 +++++++++++++ .../components/gl-details-base.ts | 235 ++++++ .../components/gl-wip-details.ts | 67 ++ .../components/commit/commit-identity.ts | 9 +- .../components/list/file-change-list-item.ts | 83 +- .../shared/components/list/list-container.ts | 1 - .../apps/shared/components/list/list-item.ts | 2 + .../shared/components/status/git-status.ts | 237 ++++++ .../commitDetails/commitDetailsWebview.ts | 518 +++++++++---- src/webviews/commitDetails/protocol.ts | 80 +- src/webviews/commitDetails/registration.ts | 4 +- 17 files changed, 1727 insertions(+), 944 deletions(-) create mode 100644 src/webviews/apps/commitDetails/components/gl-commit-details.ts create mode 100644 src/webviews/apps/commitDetails/components/gl-details-base.ts create mode 100644 src/webviews/apps/commitDetails/components/gl-wip-details.ts create mode 100644 src/webviews/apps/shared/components/status/git-status.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index fd868b81cb6cf..282871f57824d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added +- Adds a _Working Changes_ tab to the _Commit Details_ and _Graph Details_ views to show your working tree changes + - Adds _Stage Changes_ and _Unstage Changes_ commands to files on the _Working Changes_ tab - Adds a _[Show|Hide] Merge Commits_ toggle to the _File History_ view — closes [#2104](https://github.com/gitkraken/vscode-gitlens/issues/2104) & [#2944](https://github.com/gitkraken/vscode-gitlens/issues/2944) - Adds a `gitlens.advanced.fileHistoryShowMergeCommits` setting to specify whether merge commits will be show in file histories - Adds deep link support for workspaces in the _GitKraken Workspaces_ view diff --git a/src/trackers/gitLineTracker.ts b/src/trackers/gitLineTracker.ts index d6fd18c7134cb..945117891bda7 100644 --- a/src/trackers/gitLineTracker.ts +++ b/src/trackers/gitLineTracker.ts @@ -31,7 +31,7 @@ export class GitLineTracker extends LineTracker { updated = await this.updateState(e.selections, e.editor); } - super.fireLinesChanged(updated ? e : { ...e, selections: undefined }); + super.fireLinesChanged(updated ? e : { ...e, selections: undefined, suspended: this.suspended }); } private _subscriptionOnlyWhenActive: Disposable | undefined; diff --git a/src/trackers/lineTracker.ts b/src/trackers/lineTracker.ts index 1490e5476580d..b797aad51fe70 100644 --- a/src/trackers/lineTracker.ts +++ b/src/trackers/lineTracker.ts @@ -13,6 +13,7 @@ export interface LinesChangeEvent { readonly reason: 'editor' | 'selection'; readonly pending?: boolean; + readonly suspended?: boolean; } export interface LineSelection { diff --git a/src/webviews/apps/commitDetails/commitDetails.scss b/src/webviews/apps/commitDetails/commitDetails.scss index 3240b960fc458..a9586370ccc07 100644 --- a/src/webviews/apps/commitDetails/commitDetails.scss +++ b/src/webviews/apps/commitDetails/commitDetails.scss @@ -5,6 +5,24 @@ --gitlens-scrollbar-gutter-width: 10px; } +.vscode-high-contrast, +.vscode-dark { + --color-background--level-05: var(--color-background--lighten-05); + --color-background--level-075: var(--color-background--lighten-075); + --color-background--level-10: var(--color-background--lighten-10); + --color-background--level-15: var(--color-background--lighten-15); + --color-background--level-30: var(--color-background--lighten-30); +} + +.vscode-high-contrast-light, +.vscode-light { + --color-background--level-05: var(--color-background--darken-05); + --color-background--level-075: var(--color-background--darken-075); + --color-background--level-10: var(--color-background--darken-10); + --color-background--level-15: var(--color-background--darken-15); + --color-background--level-30: var(--color-background--darken-30); +} + // generic resets html { font-size: 62.5%; @@ -19,6 +37,9 @@ html { } body { + --gk-badge-outline-color: var(--vscode-badge-foreground); + --gk-badge-filled-background-color: var(--vscode-badge-background); + --gk-badge-filled-color: var(--vscode-badge-foreground); font-family: var(--font-family); font-size: var(--font-size); color: var(--color-foreground); @@ -250,13 +271,6 @@ ul { margin-bottom: 1rem; } -.gl-actionbar { -} -.gl-actionbar__group { -} -.gl-action { -} - .message-block { font-size: 1.3rem; border: 1px solid var(--vscode-input-border); @@ -305,6 +319,14 @@ ul { flex: none; } + &--highlight { + margin-left: 0.25em; + padding: 0 4px 2px 4px; + border: 1px solid var(--color-background--level-15); + border-radius: 0.3rem; + font-family: var(--vscode-editor-font-family); + } + &.is-pinned { background-color: var(--color-alert-warningBackground); box-shadow: 0 0 0 0.1rem var(--color-alert-warningBorder); @@ -378,3 +400,70 @@ ul { } } } + +.wip-details { + display: flex; + padding: 0.4rem 0.8rem; + background: var(--color-alert-infoBackground); + border-left: 0.3rem solid var(--color-alert-infoBorder); + align-items: center; + justify-content: space-between; + + .wip-changes { + display: inline-flex; + align-items: baseline; + } + + .wip-branch { + display: inline-block; + padding: 0 0.3rem 0.2rem; + margin-left: 0.4rem; + // background: var(--color-background--level-05); + border: 1px solid var(--color-foreground--50); + border-radius: 0.3rem; + } + + gl-button { + padding: 0.2rem 0.8rem; + opacity: 0.8; + } +} + +.details-tab { + display: flex; + justify-content: stretch; + align-items: center; + margin-bottom: 0.4rem; + gap: 0.2rem; + + & > * { + flex: 1; + } + + &__item { + appearance: none; + padding: 0.4rem; + color: var(--color-foreground--85); + background-color: transparent; + border: none; + border-bottom: 0.2rem solid transparent; + cursor: pointer; + // background-color: #00000030; + line-height: 1.8rem; + + gk-badge { + line-height: 1.36rem; + } + + &:hover { + color: var(--color-foreground); + // background-color: var(--vscode-button-hoverBackground); + background-color: #00000020; + } + + &.is-active { + color: var(--color-foreground); + border-bottom-color: var(--vscode-button-hoverBackground); + } + } +} diff --git a/src/webviews/apps/commitDetails/commitDetails.ts b/src/webviews/apps/commitDetails/commitDetails.ts index a5c5d0922ac79..110a8470a5bf0 100644 --- a/src/webviews/apps/commitDetails/commitDetails.ts +++ b/src/webviews/apps/commitDetails/commitDetails.ts @@ -1,13 +1,14 @@ /*global*/ import type { ViewFilesLayout } from '../../../config'; import type { Serialized } from '../../../system/serialize'; -import type { CommitActionsParams, State } from '../../commitDetails/protocol'; +import type { CommitActionsParams, Mode, State } from '../../commitDetails/protocol'; import { AutolinkSettingsCommandType, CommitActionsCommandType, DidChangeNotificationType, - DidExplainCommitCommandType, - ExplainCommitCommandType, + DidChangeWipStateNotificationType, + DidExplainCommandType, + ExplainCommandType, FileActionsCommandType, NavigateCommitCommandType, OpenFileCommandType, @@ -16,8 +17,11 @@ import { OpenFileOnRemoteCommandType, PickCommitCommandType, PinCommitCommandType, - PreferencesCommandType, SearchCommitCommandType, + StageFileCommandType, + SwitchModeCommandType, + UnstageFileCommandType, + UpdatePreferencesCommandType, } from '../../commitDetails/protocol'; import type { IpcMessage } from '../../protocol'; import { ExecuteCommandType, onIpc } from '../../protocol'; @@ -44,7 +48,7 @@ import './components/commit-details-app'; export const uncommittedSha = '0000000000000000000000000000000000000000'; -export type CommitState = SomeNonNullable, 'selected'>; +export type CommitState = SomeNonNullable, 'commit'>; export class CommitDetailsApp extends App> { constructor() { super('CommitDetailsApp'); @@ -71,8 +75,16 @@ export class CommitDetailsApp extends App> { DOM.on('file-change-list-item', 'file-more-actions', e => this.onFileMoreActions(e.detail), ), + DOM.on('file-change-list-item', 'file-stage', e => + this.onStageFile(e.detail), + ), + DOM.on('file-change-list-item', 'file-unstage', e => + this.onUnstageFile(e.detail), + ), DOM.on('[data-action="commit-actions"]', 'click', e => this.onCommitActions(e)), DOM.on('[data-action="pick-commit"]', 'click', e => this.onPickCommit(e)), + DOM.on('[data-action="wip"]', 'click', e => this.onSwitchMode(e, 'wip')), + DOM.on('[data-action="details"]', 'click', e => this.onSwitchMode(e, 'commit')), DOM.on('[data-action="search-commit"]', 'click', e => this.onSearchCommit(e)), DOM.on('[data-action="autolink-settings"]', 'click', e => this.onAutolinkSettings(e)), DOM.on('[data-action="files-layout"]', 'click', e => this.onToggleFilesLayout(e)), @@ -129,6 +141,14 @@ export class CommitDetailsApp extends App> { }); break; + case DidChangeWipStateNotificationType.method: + onIpc(DidChangeWipStateNotificationType, msg, params => { + this.state = { ...this.state, ...params }; + this.setState(this.state); + this.attachState(); + }); + break; + default: super.onMessageReceived?.(e); } @@ -147,11 +167,7 @@ export class CommitDetailsApp extends App> { async onExplainCommit(_e: MouseEvent) { try { - const result = await this.sendCommandWithCompletion( - ExplainCommitCommandType, - undefined, - DidExplainCommitCommandType, - ); + const result = await this.sendCommandWithCompletion(ExplainCommandType, undefined, DidExplainCommandType); if (result.error) { this.component.explain = { error: { message: result.error.message ?? 'Error retrieving content' } }; @@ -159,7 +175,6 @@ export class CommitDetailsApp extends App> { this.component.explain = { summary: result.summary }; } else { this.component.explain = undefined; - this.component.explainBusy = false; } } catch (ex) { this.component.explain = { error: { message: 'Error retrieving content' } }; @@ -173,24 +188,19 @@ export class CommitDetailsApp extends App> { const files = { ...this.state.preferences?.files, layout: layout ?? 'auto', - compact: this.state.preferences?.files?.compact ?? true, - threshold: this.state.preferences?.files?.threshold ?? 5, - icon: this.state.preferences?.files?.icon ?? 'type', }; this.state = { ...this.state, preferences: { ...this.state.preferences, files: files } }; this.attachState(); - this.sendCommand(PreferencesCommandType, { files: files }); + this.sendCommand(UpdatePreferencesCommandType, { files: files }); } private onExpandedChange(e: WebviewPaneExpandedChangeEventDetail) { - this.state.preferences = { - ...this.state.preferences, - autolinksExpanded: e.expanded, - }; + this.state = { ...this.state, preferences: { ...this.state.preferences, autolinksExpanded: e.expanded } }; + this.attachState(); - this.sendCommand(PreferencesCommandType, { autolinksExpanded: e.expanded }); + this.sendCommand(UpdatePreferencesCommandType, { autolinksExpanded: e.expanded }); } private onNavigate(direction: 'back' | 'forward', e: Event) { @@ -208,12 +218,19 @@ export class CommitDetailsApp extends App> { this.sendCommand(AutolinkSettingsCommandType, undefined); } + private onPickCommit(_e: MouseEvent) { + this.sendCommand(PickCommitCommandType, undefined); + } + private onSearchCommit(_e: MouseEvent) { this.sendCommand(SearchCommitCommandType, undefined); } - private onPickCommit(_e: MouseEvent) { - this.sendCommand(PickCommitCommandType, undefined); + private onSwitchMode(_e: MouseEvent, mode: Mode) { + this.state = { ...this.state, mode: mode }; + this.attachState(); + + this.sendCommand(SwitchModeCommandType, { mode: mode, repoPath: this.state.commit?.repoPath }); } private onOpenFileOnRemote(e: FileChangeListItemDetail) { @@ -236,9 +253,17 @@ export class CommitDetailsApp extends App> { this.sendCommand(FileActionsCommandType, e); } + onStageFile(e: FileChangeListItemDetail): void { + this.sendCommand(StageFileCommandType, e); + } + + onUnstageFile(e: FileChangeListItemDetail): void { + this.sendCommand(UnstageFileCommandType, e); + } + private onCommitActions(e: MouseEvent) { e.preventDefault(); - if (this.state.selected === undefined) { + if (this.state.commit === undefined) { e.stopPropagation(); return; } diff --git a/src/webviews/apps/commitDetails/components/commit-details-app.ts b/src/webviews/apps/commitDetails/components/commit-details-app.ts index c32661b11adbe..545b60167e9f4 100644 --- a/src/webviews/apps/commitDetails/components/commit-details-app.ts +++ b/src/webviews/apps/commitDetails/components/commit-details-app.ts @@ -1,21 +1,16 @@ -import type { TemplateResult } from 'lit'; -import { html, LitElement, nothing } from 'lit'; +import { Badge, defineGkElement } from '@gitkraken/shared-web-components'; +import { html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { when } from 'lit/directives/when.js'; -import type { Autolink } from '../../../../annotations/autolinks'; -import type { IssueOrPullRequest } from '../../../../git/models/issue'; -import type { PullRequestShape } from '../../../../git/models/pullRequest'; -import type { HierarchicalItem } from '../../../../system/array'; -import { makeHierarchical } from '../../../../system/array'; import type { Serialized } from '../../../../system/serialize'; +import { pluralize } from '../../../../system/string'; import type { State } from '../../../commitDetails/protocol'; -import { messageHeadlineSplitterToken } from '../../../commitDetails/protocol'; +import '../../shared/components/button'; +import './gl-commit-details'; +import './gl-wip-details'; import { uncommittedSha } from '../commitDetails'; -type Files = NonNullable['files']>; -type File = Files[0]; - interface ExplainState { cancelled?: boolean; error?: { message: string }; @@ -27,22 +22,17 @@ export class GlCommitDetailsApp extends LitElement { @property({ type: Object }) state?: Serialized; - @state() - explainBusy = false; - @property({ type: Object }) explain?: ExplainState; + @state() get isUncommitted() { - return this.state?.selected?.sha === uncommittedSha; + return this.state?.commit?.sha === uncommittedSha; } + @state() get isStash() { - return this.state?.selected?.stashNumber != null; - } - - get shortSha() { - return this.state?.selected?.shortSha ?? ''; + return this.state?.commit?.stashNumber != null; } get navigation() { @@ -72,628 +62,65 @@ export class GlCommitDetailsApp extends LitElement { return actions; } - override updated(changedProperties: Map) { - if (changedProperties.has('explain')) { - this.explainBusy = false; - this.querySelector('[data-region="commit-explanation"]')?.scrollIntoView(); - } - } - - private renderEmptyContent() { - return html` -
-

Rich details for commits and stashes are shown as you navigate:

+ constructor() { + super(); - + defineGkElement(Badge); + } -

Alternatively, search for or choose a commit

+ override render() { + const wip = this.state?.wip; -

- - - -

-
- `; - } - - private renderCommitMessage() { - if (this.state?.selected == null) { - return undefined; - } - - const message = this.state.selected.message; - const index = message.indexOf(messageHeadlineSplitterToken); - return html` -
-
+ ${when( - index === -1, + this.state?.mode === 'commit', () => - html`

- ${unsafeHTML(message)} -

`, + html``, () => - html`

- ${unsafeHTML(message.substring(0, index))}
${unsafeHTML(message.substring(index + 3))} -

`, + html``, )} -
-
- `; - } - - private renderAutoLinks() { - if (this.isUncommitted) { - return undefined; - } - - const deduped = new Map< - string, - | { type: 'autolink'; value: Serialized } - | { type: 'issue'; value: Serialized } - | { type: 'pr'; value: Serialized } - >(); - - if (this.state?.selected?.autolinks != null) { - for (const autolink of this.state.selected.autolinks) { - deduped.set(autolink.id, { type: 'autolink', value: autolink }); - } - } - - if (this.state?.autolinkedIssues != null) { - for (const issue of this.state.autolinkedIssues) { - deduped.set(issue.id, { type: 'issue', value: issue }); - } - } - - if (this.state?.pullRequest != null) { - deduped.set(this.state.pullRequest.id, { type: 'pr', value: this.state.pullRequest }); - } - - const autolinks: Serialized[] = []; - const issues: Serialized[] = []; - const prs: Serialized[] = []; - - for (const item of deduped.values()) { - switch (item.type) { - case 'autolink': - autolinks.push(item.value); - break; - case 'issue': - issues.push(item.value); - break; - case 'pr': - prs.push(item.value); - break; - } - } - - return html` - - Autolinks - ${this.state?.includeRichContent || deduped.size ? `${deduped.size} found ` : ''}${this.state - ?.includeRichContent - ? '' - : '…'} - ${when( - this.state == null, - () => html` -
- -
- -
-
- -
-
- `, - () => { - if (deduped.size === 0) { - return html` -
-

-  Use - autolinks - to linkify external references, like Jira issues or Zendesk tickets, in commit - messages. -

-
- `; - } - return html` -
- ${autolinks.length - ? html` - - ` - : undefined} - ${prs.length - ? html` -
- ${prs.map( - pr => html` - -
- `, - )} - - ` - : undefined} - ${issues.length - ? html` -
- ${issues.map( - issue => html` - - `, - )} -
- ` - : undefined} -
- `; - }, - )} -
- `; - } - - private renderExplainAi() { - // TODO: add loading and response states - return html` - - Explain (AI) - - - - - -
-

Let AI assist in understanding the changes made with this commit.

-

- - - -

- ${when( - this.explain, - () => html` -
- ${when( - this.explain?.error, - () => - html`

- ${this.explain!.error!.message ?? 'Error retrieving content'} -

`, - )} - ${when( - this.explain?.summary, - () => html`

${this.explain!.summary}

`, - )} -
- `, - )} -
-
- `; - } - - private renderCommitStats() { - if (this.state?.selected?.stats?.changedFiles == null) { - return undefined; - } - - if (typeof this.state.selected.stats.changedFiles === 'number') { - return html``; - } - - const { added, deleted, changed } = this.state.selected.stats.changedFiles; - return html``; - } - - private renderFileList() { - const files = this.state!.selected!.files!; - - let items; - let classes; - - if (this.isUncommitted) { - items = []; - classes = `indentGuides-${this.state!.indentGuides}`; - - const staged = files.filter(f => f.staged); - if (staged.length) { - items.push(html`Staged Changes`); - - for (const f of staged) { - items.push(this.renderFile(f, 2, true)); - } - } - - const unstaged = files.filter(f => !f.staged); - if (unstaged.length) { - items.push(html`Unstaged Changes`); - - for (const f of unstaged) { - items.push(this.renderFile(f, 2, true)); - } - } - } else { - items = files.map(f => this.renderFile(f)); - } - - return html`${items}`; - } - - private renderFileTree() { - const files = this.state!.selected!.files!; - const compact = this.state!.preferences?.files?.compact ?? true; - - let items; - - if (this.isUncommitted) { - items = []; - - const staged = files.filter(f => f.staged); - if (staged.length) { - items.push(html`Staged Changes`); - items.push(...this.renderFileSubtree(staged, 1, compact)); - } - - const unstaged = files.filter(f => !f.staged); - if (unstaged.length) { - items.push(html`Unstaged Changes`); - items.push(...this.renderFileSubtree(unstaged, 1, compact)); - } - } else { - items = this.renderFileSubtree(files, 0, compact); - } - - return html`${items}`; - } - - private renderFileSubtree(files: Files, rootLevel: number, compact: boolean) { - const tree = makeHierarchical( - files, - n => n.path.split('/'), - (...parts: string[]) => parts.join('/'), - compact, - ); - const flatTree = flattenHeirarchy(tree); - return flatTree.map(({ level, item }) => { - if (item.name === '') return undefined; - - if (item.value == null) { - return html` - - - ${item.name} - - `; - } - - return this.renderFile(item.value, rootLevel + level, true); - }); - } - - private renderFile(file: File, level: number = 1, tree: boolean = false): TemplateResult<1> { - return html` - - `; - } - - private renderChangedFiles() { - const layout = this.state?.preferences?.files?.layout ?? 'auto'; - - let value = 'tree'; - let icon = 'list-tree'; - let label = 'View as Tree'; - let isTree = false; - if (this.state?.selected?.files != null) { - if (layout === 'auto') { - isTree = this.state.selected.files.length > (this.state.preferences?.files?.threshold ?? 5); - } else { - isTree = layout === 'tree'; - } - - switch (layout) { - case 'auto': - value = 'list'; - icon = 'gl-list-auto'; - label = 'View as List'; - break; - case 'list': - value = 'tree'; - icon = 'list-flat'; - label = 'View as Tree'; - break; - case 'tree': - value = 'auto'; - icon = 'list-tree'; - label = 'View as Auto'; - break; - } - } - - return html` - - Files changed - ${this.renderCommitStats()} - - - - -
- ${when( - this.state?.selected?.files == null, - () => html` -
- -
-
- -
-
- -
- `, - () => (isTree ? this.renderFileTree() : this.renderFileList()), - )} -
-
- `; - } - - override render() { - if (this.state?.selected == null) { - return html`
${this.renderEmptyContent()}
`; - } - - const pinLabel = this.state.pinned - ? 'Unpin this Commit\nRestores Automatic Following' - : 'Pin this Commit\nSuspends Automatic Following'; - return html` -
-
-
-
-
-
- - - ${when( - this.navigation.forward, - () => html` - - `, - )} - ${when( - this.state.navigationStack.hint, - () => html` - ${this.state!.navigationStack.hint} - `, - )} -
-
- ${when( - !this.isUncommitted, - () => html` - - - ${this.shortSha} - `, - () => html` - - `, - )} - - ${when( - !this.isUncommitted, - () => html` - - `, - )} -
-
- ${when( - this.state.selected && this.state.selected.stashNumber == null, - () => html` -
    -
  • - -
  • -
- `, - )} -
-
- ${this.renderCommitMessage()} ${this.renderAutoLinks()} ${this.renderChangedFiles()} - ${this.renderExplainAi()}
`; @@ -702,46 +129,4 @@ export class GlCommitDetailsApp extends LitElement { protected override createRenderRoot() { return this; } - - onExplainChanges(e: MouseEvent | KeyboardEvent) { - if (this.explainBusy === true || (e instanceof KeyboardEvent && e.key !== 'Enter')) { - e.preventDefault(); - e.stopPropagation(); - return; - } - - this.explainBusy = true; - } -} - -function flattenHeirarchy(item: HierarchicalItem, level = 0): { level: number; item: HierarchicalItem }[] { - const flattened: { level: number; item: HierarchicalItem }[] = []; - if (item == null) return flattened; - - flattened.push({ level: level, item: item }); - - if (item.children != null) { - const children = Array.from(item.children.values()); - children.sort((a, b) => { - if (!a.value || !b.value) { - return (a.value ? 1 : -1) - (b.value ? 1 : -1); - } - - if (a.relativePath < b.relativePath) { - return -1; - } - - if (a.relativePath > b.relativePath) { - return 1; - } - - return 0; - }); - - children.forEach(child => { - flattened.push(...flattenHeirarchy(child, level + 1)); - }); - } - - return flattened; } diff --git a/src/webviews/apps/commitDetails/components/gl-commit-details.ts b/src/webviews/apps/commitDetails/components/gl-commit-details.ts new file mode 100644 index 0000000000000..391c934c40fad --- /dev/null +++ b/src/webviews/apps/commitDetails/components/gl-commit-details.ts @@ -0,0 +1,523 @@ +import { html, nothing } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import { when } from 'lit/directives/when.js'; +import type { Autolink } from '../../../../annotations/autolinks'; +import type { IssueOrPullRequest } from '../../../../git/models/issue'; +import type { PullRequestShape } from '../../../../git/models/pullRequest'; +import type { Serialized } from '../../../../system/serialize'; +import type { State } from '../../../commitDetails/protocol'; +import { messageHeadlineSplitterToken } from '../../../commitDetails/protocol'; +import { uncommittedSha } from '../commitDetails'; +import { GlDetailsBase } from './gl-details-base'; + +interface ExplainState { + cancelled?: boolean; + error?: { message: string }; + summary?: string; +} + +@customElement('gl-commit-details') +export class GlCommitDetails extends GlDetailsBase { + @property({ type: Object }) + state?: Serialized; + + @state() + get isStash() { + return this.state?.commit?.stashNumber != null; + } + + @state() + get shortSha() { + return this.state?.commit?.shortSha ?? ''; + } + + @state() + explainBusy = false; + + @property({ type: Object }) + explain?: ExplainState; + + get navigation() { + if (this.state?.navigationStack == null) { + return { + back: false, + forward: false, + }; + } + + const actions = { + back: true, + forward: true, + }; + + if (this.state.navigationStack.count <= 1) { + actions.back = false; + actions.forward = false; + } else if (this.state.navigationStack.position === 0) { + actions.back = true; + actions.forward = false; + } else if (this.state.navigationStack.position === this.state.navigationStack.count - 1) { + actions.back = false; + actions.forward = true; + } + + return actions; + } + + override updated(changedProperties: Map) { + if (changedProperties.has('explain')) { + this.explainBusy = false; + this.querySelector('[data-region="commit-explanation"]')?.scrollIntoView(); + } + } + + private renderEmptyContent() { + return html` +
+

Rich details for commits and stashes are shown as you navigate:

+ + + +

Alternatively, show your work-in-progress, or search for or choose a commit

+ +

+ +

+

+ + + + +

+
+ `; + } + + private renderCommitMessage() { + if (this.state?.commit == null) return undefined; + + const message = this.state.commit.message; + const index = message.indexOf(messageHeadlineSplitterToken); + return html` +
+
+ ${when( + index === -1, + () => + html`

+ ${unsafeHTML(message)} +

`, + () => + html`

+ ${unsafeHTML(message.substring(0, index))}
${unsafeHTML(message.substring(index + 3))} +

`, + )} +
+
+ `; + } + + private renderAutoLinks() { + if (this.isUncommitted) return undefined; + + const deduped = new Map< + string, + | { type: 'autolink'; value: Serialized } + | { type: 'issue'; value: Serialized } + | { type: 'pr'; value: Serialized } + >(); + + if (this.state?.commit?.autolinks != null) { + for (const autolink of this.state.commit.autolinks) { + deduped.set(autolink.id, { type: 'autolink', value: autolink }); + } + } + + if (this.state?.autolinkedIssues != null) { + for (const issue of this.state.autolinkedIssues) { + deduped.set(issue.id, { type: 'issue', value: issue }); + } + } + + if (this.state?.pullRequest != null) { + deduped.set(this.state.pullRequest.id, { type: 'pr', value: this.state.pullRequest }); + } + + const autolinks: Serialized[] = []; + const issues: Serialized[] = []; + const prs: Serialized[] = []; + + for (const item of deduped.values()) { + switch (item.type) { + case 'autolink': + autolinks.push(item.value); + break; + case 'issue': + issues.push(item.value); + break; + case 'pr': + prs.push(item.value); + break; + } + } + + return html` + + Autolinks + ${this.state?.includeRichContent || deduped.size ? `${deduped.size} found ` : ''}${this.state + ?.includeRichContent + ? '' + : '…'} + ${when( + this.state == null, + () => html` +
+ +
+ +
+
+ +
+
+ `, + () => { + if (deduped.size === 0) { + return html` +
+

+  Use + autolinks + to linkify external references, like Jira issues or Zendesk tickets, in commit + messages. +

+
+ `; + } + return html` +
+ ${autolinks.length + ? html` + + ` + : undefined} + ${prs.length + ? html` +
+ ${prs.map( + pr => html` + +
+ `, + )} + + ` + : undefined} + ${issues.length + ? html` +
+ ${issues.map( + issue => html` + + `, + )} +
+ ` + : undefined} +
+ `; + }, + )} +
+ `; + } + + private renderExplainAi() { + // TODO: add loading and response states + return html` + + Explain (AI) + + + + + +
+

Let AI assist in understanding the changes made with this commit.

+

+ + + +

+ ${when( + this.explain, + () => html` +
+ ${when( + this.explain?.error, + () => + html`

+ ${this.explain!.error!.message ?? 'Error retrieving content'} +

`, + )} + ${when( + this.explain?.summary, + () => html`

${this.explain!.summary}

`, + )} +
+ `, + )} +
+
+ `; + } + + override render() { + if (this.state?.commit == null) { + return this.renderEmptyContent(); + } + + const details = this.state.commit; + + const pinLabel = this.state.pinned + ? 'Unpin this Commit\nRestores Automatic Following' + : 'Pin this Commit\nSuspends Automatic Following'; + + return html` +
+
+
+
+ + + ${when( + this.navigation.forward, + () => html` + + `, + )} + ${when( + this.state.navigationStack?.hint, + () => html` + ${this.state!.navigationStack?.hint} + `, + )} +
+
+ ${when( + !this.isUncommitted, + () => html` + + + ${this.shortSha} + `, + () => html` + + `, + )} + + ${when( + !this.isUncommitted, + () => html` + + `, + )} +
+
+ ${when( + details != null && !this.isStash, + () => html` +
    +
  • + +
  • +
+ `, + )} +
+
+ ${this.renderCommitMessage()} ${this.renderAutoLinks()} + ${this.renderChangedFiles(this.isStash ? 'stash' : 'commit', this.renderCommitStats(details?.stats))} + ${this.renderExplainAi()} + `; + } + + onExplainChanges(e: MouseEvent | KeyboardEvent) { + if (this.explainBusy === true || (e instanceof KeyboardEvent && e.key !== 'Enter')) { + e.preventDefault(); + e.stopPropagation(); + return; + } + + this.explainBusy = true; + } + + private renderCommitStats(stats?: NonNullable['commit']>['stats']) { + if (stats?.changedFiles == null) return undefined; + + if (typeof stats.changedFiles === 'number') { + return html``; + } + + const { added, deleted, changed } = stats.changedFiles; + return html``; + } +} diff --git a/src/webviews/apps/commitDetails/components/gl-details-base.ts b/src/webviews/apps/commitDetails/components/gl-details-base.ts new file mode 100644 index 0000000000000..3f566798cd2e8 --- /dev/null +++ b/src/webviews/apps/commitDetails/components/gl-details-base.ts @@ -0,0 +1,235 @@ +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { when } from 'lit/directives/when.js'; +import type { HierarchicalItem } from '../../../../system/array'; +import { makeHierarchical } from '../../../../system/array'; +import type { Preferences, State } from '../../../commitDetails/protocol'; + +type Files = Mutable['files']>>; +type File = Files[0]; +type Mode = 'commit' | 'stash' | 'wip'; + +export class GlDetailsBase extends LitElement { + @property({ type: Array }) + files?: Files; + + @property({ type: Boolean }) + isUncommitted = false; + + @property({ type: Object }) + preferences?: Preferences; + + @property({ attribute: 'empty-text' }) + emptyText? = 'No Files'; + + private renderFileList(mode: Mode, files: Files) { + let items; + let classes; + + if (this.isUncommitted) { + items = []; + classes = `indentGuides-${this.preferences?.indentGuides}`; + + const staged = files.filter(f => f.staged); + if (staged.length) { + items.push(html`Staged Changes`); + + for (const f of staged) { + items.push(this.renderFile(mode, f, 2, true)); + } + } + + const unstaged = files.filter(f => !f.staged); + if (unstaged.length) { + items.push(html`Unstaged Changes`); + + for (const f of unstaged) { + items.push(this.renderFile(mode, f, 2, true)); + } + } + } else { + items = files.map(f => this.renderFile(mode, f)); + } + + return html`${items}`; + } + + private renderFileTree(mode: Mode, files: Files) { + const compact = this.preferences?.files?.compact ?? true; + + let items; + + if (this.isUncommitted) { + items = []; + + const staged = files.filter(f => f.staged); + if (staged.length) { + items.push(html`Staged Changes`); + items.push(...this.renderFileSubtree(mode, staged, 1, compact)); + } + + const unstaged = files.filter(f => !f.staged); + if (unstaged.length) { + items.push(html`Unstaged Changes`); + items.push(...this.renderFileSubtree(mode, unstaged, 1, compact)); + } + } else { + items = this.renderFileSubtree(mode, files, 0, compact); + } + + return html`${items}`; + } + + private renderFileSubtree(mode: Mode, files: Files, rootLevel: number, compact: boolean) { + const tree = makeHierarchical( + files, + n => n.path.split('/'), + (...parts: string[]) => parts.join('/'), + compact, + ); + const flatTree = flattenHeirarchy(tree); + return flatTree.map(({ level, item }) => { + if (item.name === '') return undefined; + + if (item.value == null) { + return html` + + + ${item.name} + + `; + } + + return this.renderFile(mode, item.value, rootLevel + level, true); + }); + } + + private renderFile(mode: Mode, file: File, level: number = 1, tree: boolean = false): TemplateResult<1> { + return html` + + `; + } + + protected renderChangedFiles(mode: Mode, subtitle?: TemplateResult<1>) { + const layout = this.preferences?.files?.layout ?? 'auto'; + + let value = 'tree'; + let icon = 'list-tree'; + let label = 'View as Tree'; + let isTree = false; + if (this.preferences != null && this.files != null) { + if (layout === 'auto') { + isTree = this.files.length > (this.preferences.files?.threshold ?? 5); + } else { + isTree = layout === 'tree'; + } + + switch (layout) { + case 'auto': + value = 'list'; + icon = 'gl-list-auto'; + label = 'View as List'; + break; + case 'list': + value = 'tree'; + icon = 'list-flat'; + label = 'View as Tree'; + break; + case 'tree': + value = 'auto'; + icon = 'list-tree'; + label = 'View as Auto'; + break; + } + } + + return html` + + Files changed + ${subtitle} + + + + +
+ ${when( + this.files == null, + () => html` +
+ +
+
+ +
+
+ +
+ `, + () => + when( + this.files!.length > 0, + () => + isTree + ? this.renderFileTree(mode, this.files!) + : this.renderFileList(mode, this.files!), + () => html`

${this.emptyText}

`, + ), + )} +
+
+ `; + } + + protected override createRenderRoot() { + return this; + } +} + +function flattenHeirarchy(item: HierarchicalItem, level = 0): { level: number; item: HierarchicalItem }[] { + const flattened: { level: number; item: HierarchicalItem }[] = []; + if (item == null) return flattened; + + flattened.push({ level: level, item: item }); + + if (item.children != null) { + const children = Array.from(item.children.values()); + children.sort((a, b) => { + if (!a.value || !b.value) { + return (a.value ? 1 : -1) - (b.value ? 1 : -1); + } + + if (a.relativePath < b.relativePath) { + return -1; + } + + if (a.relativePath > b.relativePath) { + return 1; + } + + return 0; + }); + + children.forEach(child => { + flattened.push(...flattenHeirarchy(child, level + 1)); + }); + } + + return flattened; +} diff --git a/src/webviews/apps/commitDetails/components/gl-wip-details.ts b/src/webviews/apps/commitDetails/components/gl-wip-details.ts new file mode 100644 index 0000000000000..b3851d019f34f --- /dev/null +++ b/src/webviews/apps/commitDetails/components/gl-wip-details.ts @@ -0,0 +1,67 @@ +import { html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { when } from 'lit/directives/when.js'; +import { pluralize } from '../../../../system/string'; +import type { Wip } from '../../../commitDetails/protocol'; +import { GlDetailsBase } from './gl-details-base'; + +@customElement('gl-wip-details') +export class GlWipDetails extends GlDetailsBase { + @property({ type: Object }) + wip?: Wip; + + override render() { + return html` +
+
+
+
+ ${when( + this.wip?.changes == null || this.files == null, + () => 'Loading...', + () => + html`${pluralize('change', this.files!.length)} on + ${this.wip!.repositoryCount > 1 + ? `${this.wip!.changes!.repository.name}:${ + this.wip!.changes!.branchName + }` + : this.wip!.changes!.branchName}`, + )} +
+
+ + +
+
+
+
+ ${this.renderChangedFiles('wip')} + `; + } +} diff --git a/src/webviews/apps/shared/components/commit/commit-identity.ts b/src/webviews/apps/shared/components/commit/commit-identity.ts index 331e97cc56800..77da398d51df2 100644 --- a/src/webviews/apps/shared/components/commit/commit-identity.ts +++ b/src/webviews/apps/shared/components/commit/commit-identity.ts @@ -1,5 +1,6 @@ import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import { dateConverter } from '../converters/date-converter'; import '../code-icon'; import '../formatted-date'; @@ -48,8 +49,8 @@ export class CommitIdentity extends LitElement { @property() email = ''; - @property() - date = ''; + @property({ converter: dateConverter(), reflect: true }) + date: Date | undefined; @property() avatarUrl = 'https://www.gravatar.com/avatar/?s=64&d=robohash'; @@ -60,7 +61,7 @@ export class CommitIdentity extends LitElement { @property() dateFormat = 'MMMM Do, YYYY h:mma'; - @property() + @property({ type: Boolean }) committer = false; @property() @@ -76,7 +77,7 @@ export class CommitIdentity extends LitElement { ${this.name} ${this.actionLabel} - + `; } diff --git a/src/webviews/apps/shared/components/list/file-change-list-item.ts b/src/webviews/apps/shared/components/list/file-change-list-item.ts index 59a4511eca7b8..406c0bfd8ae02 100644 --- a/src/webviews/apps/shared/components/list/file-change-list-item.ts +++ b/src/webviews/apps/shared/components/list/file-change-list-item.ts @@ -3,6 +3,7 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import type { TextDocumentShowOptions } from 'vscode'; import type { ListItem, ListItemSelectedEvent } from './list-item'; import '../code-icon'; +import '../status/git-status'; // Can only import types from 'vscode' const BesideViewColumn = -2; /*ViewColumn.Beside*/ @@ -17,27 +18,6 @@ export interface FileChangeListItemDetail { // TODO: "change-list__action" should be a separate component -// TODO: use the model version -const statusTextMap: Record = { - '.': 'Unchanged', - '!': 'Ignored', - '?': 'Untracked', - A: 'Added', - D: 'Deleted', - M: 'Modified', - R: 'Renamed', - C: 'Copied', - AA: 'Conflict', - AU: 'Conflict', - UA: 'Conflict', - DD: 'Conflict', - DU: 'Conflict', - UD: 'Conflict', - UU: 'Conflict', - T: 'Modified', - U: 'Updated but Unmerged', -}; - @customElement('file-change-list-item') export class FileChangeListItem extends LitElement { static override styles = css` @@ -81,6 +61,9 @@ export class FileChangeListItem extends LitElement { @property({ type: Number }) level = 1; + @property({ type: Boolean, reflect: true }) checkable = false; + @property({ type: Boolean, reflect: true }) checked = false; + @property({ type: Boolean }) active = false; @@ -90,6 +73,9 @@ export class FileChangeListItem extends LitElement { @property({ type: Boolean }) uncommitted = false; + @property({ type: Boolean }) + readonly = false; + @property({ type: String }) icon = ''; @@ -137,11 +123,6 @@ export class FileChangeListItem extends LitElement { return !this.tree && this.pathIndex > -1 ? this.path.substring(0, this.pathIndex) : ''; } - @state() - get statusName() { - return this.status !== '' ? statusTextMap[this.status] : ''; - } - override render() { return html` - + ${this.fileName} ${this.tree ? nothing : html`${this.filePath}`} - ${this.uncommitted - ? nothing - : html` + ${this.uncommitted && !this.readonly + ? this.staged + ? html` + + + + ` + : html` + + + + ` + : !this.uncommitted + ? html` `} - `} + ` + : nothing} `; @@ -239,6 +246,20 @@ export class FileChangeListItem extends LitElement { this.dispatchEvent(event); } + onStageFile(_e: MouseEvent) { + const event = new CustomEvent('file-stage', { + detail: this.getEventDetail(), + }); + this.dispatchEvent(event); + } + + onUnstageFile(_e: MouseEvent) { + const event = new CustomEvent('file-unstage', { + detail: this.getEventDetail(), + }); + this.dispatchEvent(event); + } + private getEventDetail(showOptions?: TextDocumentShowOptions): FileChangeListItemDetail { return { path: this.path, diff --git a/src/webviews/apps/shared/components/list/list-container.ts b/src/webviews/apps/shared/components/list/list-container.ts index 0688c03dc5f02..73c3fbbc3a0fa 100644 --- a/src/webviews/apps/shared/components/list/list-container.ts +++ b/src/webviews/apps/shared/components/list/list-container.ts @@ -63,7 +63,6 @@ export class ListContainer extends LitElement { if (!e.target || !e.detail.branch) return; function getLevel(el: ListItem) { - // return el.level ?? 0; return parseInt(el.getAttribute('level') ?? '0', 10); } diff --git a/src/webviews/apps/shared/components/list/list-item.ts b/src/webviews/apps/shared/components/list/list-item.ts index 32afe778e5d57..f160017001657 100644 --- a/src/webviews/apps/shared/components/list/list-item.ts +++ b/src/webviews/apps/shared/components/list/list-item.ts @@ -77,6 +77,7 @@ export class ListItem extends LitElement { display: flex; flex-direction: row; justify-content: flex-start; + align-items: center; gap: 0.6rem; width: 100%; padding: 0; @@ -130,6 +131,7 @@ export class ListItem extends LitElement { } .text { + line-height: 1.6rem; overflow: hidden; white-space: nowrap; text-align: left; diff --git a/src/webviews/apps/shared/components/status/git-status.ts b/src/webviews/apps/shared/components/status/git-status.ts new file mode 100644 index 0000000000000..f2cbaca9cc02e --- /dev/null +++ b/src/webviews/apps/shared/components/status/git-status.ts @@ -0,0 +1,237 @@ +import type { PropertyValueMap } from 'lit'; +import { css, html, LitElement } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import type { GitFileStatus } from '../../../../../git/models/file'; + +// TODO: use the model version +const statusTextMap: Record = { + '.': 'Unchanged', + '!': 'Ignored', + '?': 'Untracked', + A: 'Added', + D: 'Deleted', + M: 'Modified', + R: 'Renamed', + C: 'Copied', + AA: 'Conflict', + AU: 'Conflict', + UA: 'Conflict', + DD: 'Conflict', + DU: 'Conflict', + UD: 'Conflict', + UU: 'Conflict', + T: 'Modified', + U: 'Updated but Unmerged', +}; + +@customElement('gl-git-status') +export class GlGitStatus extends LitElement { + static override styles = [ + css` + :host-context(.vscode-high-contrast), + :host-context(.vscode-dark) { + --gl-git-status-ignored: #969696; + --gl-git-status-untracked: #6c6c6c; + --gl-git-status-added: #388a34; + --gl-git-status-deleted: #9e121d; + --gl-git-status-modified: #1b80b2; + --gl-git-status-renamed: #c63; + --gl-git-status-copied: #692c77; + --gl-git-status-conflict: #7f4e7e; + --gl-git-status-unknown: #6c6c6c; + } + + :host-context(.vscode-high-contrast-light), + :host-context(.vscode-light) { + --gl-git-status-ignored: #969696; + --gl-git-status-untracked: #6c6c6c; + --gl-git-status-added: #388a34; + --gl-git-status-deleted: #9e121d; + --gl-git-status-modified: #1b80b2; + --gl-git-status-renamed: #c63; + --gl-git-status-copied: #692c77; + --gl-git-status-conflict: #7f4e7e; + --gl-git-status-unknown: #6c6c6c; + } + + :host { + display: inline-block; + width: 16px; + aspect-ratio: 1 / 1; + } + + svg { + display: inline-block; + vertical-align: text-bottom; + } + `, + ]; + + @property() + status?: GitFileStatus | 'T'; + + @state() + get statusName() { + if (!this.status) return ''; + return statusTextMap[this.status]; + } + + override updated(changedProperties: PropertyValueMap | Map): void { + super.updated(changedProperties); + if (changedProperties.has('status')) { + if (this.statusName) { + this.setAttribute('title', this.statusName); + } else { + this.removeAttribute('title'); + } + } + } + + renderIgnored() { + return html` + + + + `; + } + + renderUntracked() { + return html` + + + + `; + } + + renderAdded() { + return html` + + + + `; + } + + renderDeleted() { + return html` + + + + `; + } + + renderModified() { + return html` + + + + `; + } + + renderRenamed() { + return html` + + + + `; + } + + renderCopied() { + return html` + + + + `; + } + + renderConflict() { + return html` + + + + `; + } + + renderUnknown() { + return html` + + + + `; + } + + override render() { + switch (this.status) { + case '!': + return this.renderIgnored(); + case '?': + return this.renderUntracked(); + case 'A': + return this.renderAdded(); + case 'D': + return this.renderDeleted(); + case 'M': + case 'T': + case 'U': + return this.renderModified(); + case 'R': + return this.renderRenamed(); + case 'C': + return this.renderCopied(); + case 'AA': + case 'AU': + case 'UA': + case 'DD': + case 'DU': + case 'UD': + case 'UU': + return this.renderConflict(); + } + + return this.renderUnknown(); + } +} diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index e108f3ecae58e..1ba4136b2697e 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -18,8 +18,8 @@ import { import { CommitFormatter } from '../../git/formatters/commitFormatter'; import type { GitCommit } from '../../git/models/commit'; import { isCommit } from '../../git/models/commit'; -import type { GitFileChange } from '../../git/models/file'; -import { getGitFileStatusIcon } from '../../git/models/file'; +import { uncommitted } from '../../git/models/constants'; +import type { GitFileChange, GitFileChangeShape } from '../../git/models/file'; import type { IssueOrPullRequest } from '../../git/models/issue'; import { serializeIssueOrPullRequest } from '../../git/models/issue'; import type { PullRequest } from '../../git/models/pullRequest'; @@ -27,12 +27,13 @@ import { serializePullRequest } from '../../git/models/pullRequest'; import type { GitRevisionReference } from '../../git/models/reference'; import { createReference, getReferenceFromRevision, shortenRevision } from '../../git/models/reference'; import type { GitRemote } from '../../git/models/remote'; +import type { Repository } from '../../git/models/repository'; +import { RepositoryChange, RepositoryChangeComparisonMode } from '../../git/models/repository'; import type { ShowInCommitGraphCommandArgs } from '../../plus/webviews/graph/protocol'; import { pauseOnCancelOrTimeoutMapTuplePromise } from '../../system/cancellation'; import { executeCommand, executeCoreCommand, registerCommand } from '../../system/command'; import { configuration } from '../../system/configuration'; import { getContext } from '../../system/context'; -import type { DateTimeFormat } from '../../system/date'; import { debug } from '../../system/decorators/log'; import type { Deferrable } from '../../system/function'; import { debounce } from '../../system/function'; @@ -49,13 +50,25 @@ import { onIpc } from '../protocol'; import type { WebviewController, WebviewProvider } from '../webviewController'; import { updatePendingContext } from '../webviewController'; import { isSerializedState } from '../webviewsController'; -import type { CommitDetails, DidExplainCommitParams, FileActionParams, Preferences, State } from './protocol'; +import type { + CommitDetails, + DidExplainParams, + FileActionParams, + Mode, + Preferences, + State, + SwitchModeParams, + UpdateablePreferences, + Wip, + WipChange, +} from './protocol'; import { AutolinkSettingsCommandType, CommitActionsCommandType, DidChangeNotificationType, - DidExplainCommitCommandType, - ExplainCommitCommandType, + DidChangeWipStateNotificationType, + DidExplainCommandType, + ExplainCommandType, FileActionsCommandType, messageHeadlineSplitterToken, NavigateCommitCommandType, @@ -65,30 +78,32 @@ import { OpenFileOnRemoteCommandType, PickCommitCommandType, PinCommitCommandType, - PreferencesCommandType, SearchCommitCommandType, + StageFileCommandType, + SwitchModeCommandType, + UnstageFileCommandType, + UpdatePreferencesCommandType, } from './protocol'; -interface Context { - pinned: boolean; - commit: GitCommit | undefined; - preferences: Preferences | undefined; - richStateLoaded: boolean; - formattedMessage: string | undefined; - autolinkedIssues: IssueOrPullRequest[] | undefined; - pullRequest: PullRequest | undefined; +type RepositorySubscription = { repo: Repository; subscription: Disposable }; - // commits: GitCommit[] | undefined; - dateFormat: DateTimeFormat | string; - // indent: number; - indentGuides: 'none' | 'onHover' | 'always'; +interface Context { + mode: Mode; navigationStack: { count: number; position: number; hint?: string; }; - + pinned: boolean; + preferences: Preferences; visible: boolean; + + commit: GitCommit | undefined; + richStateLoaded: boolean; + formattedMessage: string | undefined; + autolinkedIssues: IssueOrPullRequest[] | undefined; + pullRequest: PullRequest | undefined; + wip: Wip | undefined; } export class CommitDetailsWebviewProvider implements WebviewProvider> { @@ -105,30 +120,34 @@ export class CommitDetailsWebviewProvider implements WebviewProvider>, - private readonly options: { mode: 'default' | 'graph' }, + private readonly options: { attachedTo: 'default' | 'graph' }, ) { this._context = { + mode: 'commit', + navigationStack: { + count: 0, + position: 0, + }, pinned: false, - commit: undefined, preferences: { - autolinksExpanded: this.container.storage.getWorkspace('views:commitDetails:autolinksExpanded'), + autolinksExpanded: this.container.storage.getWorkspace('views:commitDetails:autolinksExpanded') ?? true, avatars: configuration.get('views.commitDetails.avatars'), + dateFormat: configuration.get('defaultDateFormat') ?? 'MMMM Do, YYYY h:mma', files: configuration.get('views.commitDetails.files'), + // indent: configuration.getAny('workbench.tree.indent') ?? 8, + indentGuides: + configuration.getAny( + 'workbench.tree.renderIndentGuides', + ) ?? 'onHover', }, + visible: false, + + commit: undefined, richStateLoaded: false, formattedMessage: undefined, autolinkedIssues: undefined, pullRequest: undefined, - dateFormat: configuration.get('defaultDateFormat') ?? 'MMMM Do, YYYY h:mma', - // indent: configuration.getAny('workbench.tree.indent') ?? 8, - indentGuides: - configuration.getAny('workbench.tree.renderIndentGuides') ?? - 'onHover', - navigationStack: { - count: 0, - position: 0, - }, - visible: false, + wip: undefined, }; this._disposable = configuration.onDidChangeAny(this.onAnyConfigurationChanged, this); @@ -136,6 +155,10 @@ export class CommitDetailsWebviewProvider implements WebviewProvider>(arg)) { - const { selected } = arg.state; + const { commit: selected } = arg.state; if (selected?.repoPath != null && selected?.sha != null) { if (selected.stashNumber != null) { data = { @@ -184,11 +207,16 @@ export class CommitDetailsWebviewProvider implements WebviewProvider(e, 'workbench.tree.renderIndentGuides') + ) { + this.updatePendingContext({ + preferences: { + ...this._context.preferences, + ...this._pendingContext?.preferences, + avatars: configuration.get('views.commitDetails.avatars'), + dateFormat: configuration.get('defaultDateFormat') ?? 'MMMM Do, YYYY h:mma', + files: configuration.get('views.commitDetails.files'), + indentGuides: + configuration.getAny( + 'workbench.tree.renderIndentGuides', + ) ?? 'onHover', + }, + }); this.updateState(); } - // if (configuration.changedAny(e, 'workbench.tree.indent')) { - // this.updatePendingContext({ indent: configuration.getAny('workbench.tree.indent') ?? 8 }); - // this.updateState(); - // } - - if (configuration.changedAny(e, 'workbench.tree.renderIndentGuides')) { - this.updatePendingContext({ - indentGuides: - configuration.getAny( - 'workbench.tree.renderIndentGuides', - ) ?? 'onHover', - }); + if ( + this._context.commit != null && + configuration.changed(e, ['views.commitDetails.autolinks', 'views.commitDetails.pullRequests']) + ) { + void this.updateCommit(this._context.commit, { force: true }); this.updateState(); } } @@ -315,7 +339,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { switch (params.action) { - case 'graph': - if (this._context.commit == null) return; + case 'graph': { + let ref: GitRevisionReference | undefined; + if (this._context.mode === 'wip') { + ref = + this._context.wip?.changes != null + ? createReference(uncommitted, this._context.wip.changes.repository.path, { + refType: 'revision', + }) + : undefined; + } else { + ref = + this._context.commit != null + ? getReferenceFromRevision(this._context.commit) + : undefined; + } + if (ref == null) return; void executeCommand( - this.options.mode === 'graph' + this.options.attachedTo === 'graph' ? Commands.ShowInCommitGraphView : Commands.ShowInCommitGraph, - { - ref: getReferenceFromRevision(this._context.commit), - }, + { ref: ref }, ); break; + } case 'more': this.showCommitActions(); break; @@ -403,6 +447,9 @@ export class CommitDetailsWebviewProvider implements WebviewProvider this.showCommitSearch()); break; + case SwitchModeCommandType.method: + onIpc(SwitchModeCommandType, e, params => this.switchMode(params)); + break; case AutolinkSettingsCommandType.method: onIpc(AutolinkSettingsCommandType, e, _params => this.showAutolinkSettings()); break; @@ -412,16 +459,56 @@ export class CommitDetailsWebviewProvider implements WebviewProvider this.navigateStack(params.direction)); break; - case PreferencesCommandType.method: - onIpc(PreferencesCommandType, e, params => this.updatePreferences(params)); + case UpdatePreferencesCommandType.method: + onIpc(UpdatePreferencesCommandType, e, params => this.updatePreferences(params)); + break; + case ExplainCommandType.method: + onIpc(ExplainCommandType, e, () => this.explainCommit(e.completionId)); break; - case ExplainCommitCommandType.method: - onIpc(ExplainCommitCommandType, e, () => this.explainCommit(e.completionId)); + case StageFileCommandType.method: + onIpc(StageFileCommandType, e, params => this.stageFile(params)); + break; + case UnstageFileCommandType.method: + onIpc(UnstageFileCommandType, e, params => this.unstageFile(params)); + break; + } + } + + private onActiveEditorLinesChanged(e: LinesChangeEvent) { + if (e.pending || e.editor == null || e.suspended) return; + + if (this.mode === 'wip') { + const repo = this.container.git.getBestRepositoryOrFirst(e.editor); + void this.updateWipState(repo); + + return; + } + + const line = e.selections?.[0]?.active; + const commit = line != null ? this.container.lineTracker.getState(line)?.commit : undefined; + void this.updateCommit(commit); + } + + private _wipSubscription: RepositorySubscription | undefined; + + private get mode(): Mode { + return this._pendingContext?.mode ?? this._context.mode; + } + + private setMode(mode: Mode, repository?: Repository) { + this.updatePendingContext({ mode: mode }); + if (mode === 'commit') { + this._wipSubscription?.subscription.dispose(); + this._wipSubscription = undefined; + + this.updateState(true); + } else { + void this.updateWipState(repository ?? this.container.git.getBestRepositoryOrFirst()); } } private async explainCommit(completionId?: string) { - let params: DidExplainCommitParams; + let params: DidExplainParams; try { const summary = await this.container.ai.explainCommit(this._context.commit!, { progress: { location: { viewId: this.host.id } }, @@ -431,7 +518,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider summaryModel(commit))); - const state = serialize({ + mode: current.mode, webviewId: this.host.id, timestamp: Date.now(), + commit: details, + navigationStack: current.navigationStack, pinned: current.pinned, - includeRichContent: current.richStateLoaded, - // commits: commitChoices, preferences: current.preferences, - selected: details, + includeRichContent: current.richStateLoaded, autolinkedIssues: current.autolinkedIssues?.map(serializeIssueOrPullRequest), pullRequest: current.pullRequest != null ? serializePullRequest(current.pullRequest) : undefined, - dateFormat: current.dateFormat, - // indent: current.indent, - indentGuides: current.indentGuides, - navigationStack: current.navigationStack, + wip: current.wip, }); return state; } + @debug({ args: false }) + private async updateWipState(repository: Repository | undefined): Promise { + if (this._wipSubscription != null) { + const { repo, subscription } = this._wipSubscription; + if (repository?.path !== repo.path) { + subscription.dispose(); + this._wipSubscription = undefined; + } + } + + let wip: Wip | undefined = undefined; + + if (repository != null) { + if (this._wipSubscription == null) { + this._wipSubscription = { repo: repository, subscription: this.subscribeToRepositoryWip(repository) }; + } + + const changes = await this.getWipChange(repository); + wip = { changes: changes, repositoryCount: this.container.git.openRepositoryCount }; + + if (this._pendingContext == null) { + const success = await this.host.notify(DidChangeWipStateNotificationType, { wip: wip }); + if (success) { + this._context.wip = wip; + return; + } + } + } + + this.updatePendingContext({ wip: wip }); + this.updateState(true); + } + @debug({ args: false }) private async updateRichState(current: Context, cancellation: CancellationToken): Promise { const { commit } = current; @@ -545,7 +652,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { - // this.updatePendingContext({ commit: undefined }); - this.updatePendingContext({ commit: commit }, true); - this.updateState(); - }), - ); + let wip = this._pendingContext?.wip ?? this._context.wip; + + if (this._repositorySubscription != null) { + const { repo, subscription } = this._repositorySubscription; + if (commit?.repoPath !== repo.path) { + subscription.dispose(); + this._repositorySubscription = undefined; + wip = undefined; + } + } + + if (this._repositorySubscription == null && commit != null) { + const repo = await this.container.git.getOrOpenRepository(commit.repoPath); + if (repo != null) { + this._repositorySubscription = { repo: repo, subscription: this.subscribeToRepositoryWip(repo) }; + + if (this.mode === 'wip') { + void this.updateWipState(repo); + } else { + wip = undefined; + } } } @@ -589,6 +704,7 @@ export class CommitDetailsWebviewProvider implements WebviewProvider this.onWipChanged(repo)), + repo.onDidChange(e => { + if (e.changed(RepositoryChange.Index, RepositoryChangeComparisonMode.Any)) { + this.onWipChanged(repo); + } + }), + ); + } + + private onWipChanged(repository: Repository) { + void this.updateWipState(repository); + } + + private async getWipChange(repository: Repository): Promise { + const status = await this.container.git.getStatusForRepo(repository.path); + if (status == null) return undefined; + + const files: GitFileChangeShape[] = []; + for (const file of status.files) { + const change = { + repoPath: file.repoPath, + path: file.path, + status: file.status, + originalPath: file.originalPath, + staged: file.staged, + }; + + files.push(change); + if (file.staged && file.wip) { + files.push({ + ...change, + staged: false, + }); + } + } + + return { + repository: { + name: repository.name, + path: repository.path, + uri: repository.uri.toString(), + }, + branchName: status.branch, + files: files, + }; + } + private updatePinned(pinned: boolean, immediate?: boolean) { if (pinned === this._context.pinned) return; @@ -621,11 +787,9 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { - const icon = getGitFileStatusIcon(status); - return { - path: path, - originalPath: originalPath, - status: status, - repoPath: repoPath, - icon: { - dark: this.host - .asWebviewUri(Uri.joinPath(this.host.getRootUri(), 'images', 'dark', icon)) - .toString(), - light: this.host - .asWebviewUri(Uri.joinPath(this.host.getRootUri(), 'images', 'light', icon)) - .toString(), - }, - staged: staged, - }; - }), + files: commit.files, stats: commit.stats, autolinks: autolinks != null ? [...map(autolinks.values(), serializeAutolink)] : undefined, }; @@ -848,7 +981,17 @@ export class CommitDetailsWebviewProvider implements WebviewProvider { - const commit = await this._context.commit?.getCommitForFile(params.path, params.staged); + let commit: GitCommit | undefined; + if (this.mode === 'wip') { + const uri = this._context.wip?.changes?.repository.uri; + if (uri == null) return; + + commit = await this.container.git.getCommit(Uri.parse(uri), uncommitted); + } else { + commit = this._context.commit; + } + + commit = await commit?.getCommitForFile(params.path, params.staged); return commit != null ? [commit, commit.file!] : undefined; } @@ -856,10 +999,6 @@ export class CommitDetailsWebviewProvider implements WebviewProvider>; + +export interface WipChange { + branchName: string; + repository: { name: string; path: string; uri: string }; + files: GitFileChangeShape[]; +} + +export type Mode = 'commit' | 'wip'; + +export interface Wip { + changes: WipChange | undefined; + repositoryCount: number; } export interface State { webviewId: WebviewIds | WebviewViewIds; timestamp: number; + mode: Mode; pinned: boolean; - preferences?: Preferences; - // commits?: CommitSummary[]; - includeRichContent?: boolean; - - selected?: CommitDetails; - autolinkedIssues?: IssueOrPullRequest[]; - pullRequest?: PullRequestShape; - - dateFormat: string; - // indent: number; - indentGuides: 'none' | 'onHover' | 'always'; navigationStack: { count: number; position: number; hint?: string; }; + preferences: Preferences; + includeRichContent?: boolean; + + commit?: CommitDetails; + autolinkedIssues?: IssueOrPullRequest[]; + pullRequest?: PullRequestShape; + wip?: Wip; } export type ShowCommitDetailsViewCommandArgs = string[]; @@ -82,11 +98,21 @@ export const OpenFileOnRemoteCommandType = new IpcCommandType( export const OpenFileCompareWorkingCommandType = new IpcCommandType('commit/file/compareWorking'); export const OpenFileComparePreviousCommandType = new IpcCommandType('commit/file/comparePrevious'); +export const StageFileCommandType = new IpcCommandType('commit/file/stage'); +export const UnstageFileCommandType = new IpcCommandType('commit/file/unstage'); + export const PickCommitCommandType = new IpcCommandType('commit/pickCommit'); export const SearchCommitCommandType = new IpcCommandType('commit/searchCommit'); + +export interface SwitchModeParams { + repoPath?: string; + mode: Mode; +} +export const SwitchModeCommandType = new IpcCommandType('commit/switchMode'); + export const AutolinkSettingsCommandType = new IpcCommandType('commit/autolinkSettings'); -export const ExplainCommitCommandType = new IpcCommandType('commit/explain'); +export const ExplainCommandType = new IpcCommandType('commit/explain'); export interface PinParams { pin: boolean; @@ -98,12 +124,8 @@ export interface NavigateParams { } export const NavigateCommitCommandType = new IpcCommandType('commit/navigate'); -export interface PreferenceParams { - autolinksExpanded?: boolean; - avatars?: boolean; - files?: Config['views']['commitDetails']['files']; -} -export const PreferencesCommandType = new IpcCommandType('commit/preferences'); +export type UpdatePreferenceParams = UpdateablePreferences; +export const UpdatePreferencesCommandType = new IpcCommandType('commit/preferences/update'); // NOTIFICATIONS @@ -112,19 +134,15 @@ export interface DidChangeParams { } export const DidChangeNotificationType = new IpcNotificationType('commit/didChange', true); -export type DidChangeRichStateParams = { - formattedMessage?: string; - autolinkedIssues?: IssueOrPullRequest[]; - pullRequest?: PullRequestShape; -}; -export const DidChangeRichStateNotificationType = new IpcNotificationType( - 'commit/didChange/rich', +export type DidChangeWipStateParams = Pick, 'wip'>; +export const DidChangeWipStateNotificationType = new IpcNotificationType( + 'commit/didChange/wip', ); -export type DidExplainCommitParams = +export type DidExplainParams = | { summary: string | undefined; error?: undefined; } | { error: { message: string } }; -export const DidExplainCommitCommandType = new IpcNotificationType('commit/didExplain'); +export const DidExplainCommandType = new IpcNotificationType('commit/didExplain'); diff --git a/src/webviews/commitDetails/registration.ts b/src/webviews/commitDetails/registration.ts index b863af495dff9..39bdd000e03b9 100644 --- a/src/webviews/commitDetails/registration.ts +++ b/src/webviews/commitDetails/registration.ts @@ -19,7 +19,7 @@ export function registerCommitDetailsWebviewView(controller: WebviewsController) const { CommitDetailsWebviewProvider } = await import( /* webpackChunkName: "commitDetails" */ './commitDetailsWebview' ); - return new CommitDetailsWebviewProvider(container, host, { mode: 'default' }); + return new CommitDetailsWebviewProvider(container, host, { attachedTo: 'default' }); }, ); } @@ -41,7 +41,7 @@ export function registerGraphDetailsWebviewView(controller: WebviewsController) const { CommitDetailsWebviewProvider } = await import( /* webpackChunkName: "commitDetails" */ './commitDetailsWebview' ); - return new CommitDetailsWebviewProvider(container, host, { mode: 'graph' }); + return new CommitDetailsWebviewProvider(container, host, { attachedTo: 'graph' }); }, ); } From e03275f0b83f18df76c97f7f732e850bf95ab636 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon <67011668+axosoft-ramint@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:21:20 -0700 Subject: [PATCH 0043/1012] Trial reactivation UX (#2962) * Updates account messaging to support trial reactivation * Polishes and improved messaging --- src/commands/showView.ts | 1 + src/plus/subscription/subscriptionService.ts | 31 ++++++++++++++---- src/subscription.ts | 3 ++ src/webviews/apps/plus/account/account.scss | 2 +- src/webviews/apps/plus/account/account.ts | 1 + .../account/components/account-content.ts | 32 ++++++++++++++++--- 6 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/commands/showView.ts b/src/commands/showView.ts index 4679979d95b22..53362916243d7 100644 --- a/src/commands/showView.ts +++ b/src/commands/showView.ts @@ -15,6 +15,7 @@ export class ShowViewCommand extends Command { Commands.ShowFileHistoryView, Commands.ShowGraphView, Commands.ShowHomeView, + Commands.ShowAccountView, Commands.ShowLineHistoryView, Commands.ShowRemotesView, Commands.ShowRepositoriesView, diff --git a/src/plus/subscription/subscriptionService.ts b/src/plus/subscription/subscriptionService.ts index 759bf4d53cbeb..6ba224f5de0cf 100644 --- a/src/plus/subscription/subscriptionService.ts +++ b/src/plus/subscription/subscriptionService.ts @@ -304,6 +304,7 @@ export class SubscriptionService implements Disposable { actual: getSubscriptionPlan( SubscriptionPlanId.Free, false, + 0, undefined, this._subscription.plan?.actual?.startedOn != null ? new Date(this._subscription.plan.actual.startedOn) @@ -312,6 +313,7 @@ export class SubscriptionService implements Disposable { effective: getSubscriptionPlan( SubscriptionPlanId.Free, false, + 0, undefined, this._subscription.plan?.effective?.startedOn != null ? new Date(this._subscription.plan.actual.startedOn) @@ -462,7 +464,7 @@ export class SubscriptionService implements Disposable { ...this._subscription, plan: { ...this._subscription.plan, - effective: getSubscriptionPlan(SubscriptionPlanId.Pro, false, undefined, startedOn, expiresOn), + effective: getSubscriptionPlan(SubscriptionPlanId.Pro, false, 0, undefined, startedOn, expiresOn), }, previewTrial: previewTrial, }); @@ -632,6 +634,7 @@ export class SubscriptionService implements Disposable { actual = getSubscriptionPlan( convertLicenseTypeToPlanId(licenseType), isBundleLicenseType(licenseType), + license.reactivationCount ?? 0, license.organizationId, new Date(license.latestStartDate), new Date(license.latestEndDate), @@ -643,6 +646,7 @@ export class SubscriptionService implements Disposable { actual = getSubscriptionPlan( SubscriptionPlanId.FreePlus, false, + 0, undefined, data.user.firstGitLensCheckIn != null ? new Date(data.user.firstGitLensCheckIn) @@ -668,6 +672,7 @@ export class SubscriptionService implements Disposable { effective = getSubscriptionPlan( convertLicenseTypeToPlanId(licenseType), isBundleLicenseType(licenseType), + license.reactivationCount ?? 0, license.organizationId, new Date(license.latestStartDate), new Date(license.latestEndDate), @@ -825,8 +830,8 @@ export class SubscriptionService implements Disposable { if (subscription == null) { subscription = { plan: { - actual: getSubscriptionPlan(SubscriptionPlanId.Free, false, undefined), - effective: getSubscriptionPlan(SubscriptionPlanId.Free, false, undefined), + actual: getSubscriptionPlan(SubscriptionPlanId.Free, false, 0, undefined), + effective: getSubscriptionPlan(SubscriptionPlanId.Free, false, 0, undefined), }, account: undefined, state: SubscriptionState.Free, @@ -857,6 +862,7 @@ export class SubscriptionService implements Disposable { effective: getSubscriptionPlan( SubscriptionPlanId.Pro, false, + 0, undefined, new Date(subscription.previewTrial.startedOn), new Date(subscription.previewTrial.expiresOn), @@ -999,6 +1005,7 @@ export class SubscriptionService implements Disposable { const { account, plan: { effective }, + state, } = this._subscription; if (effective.id === SubscriptionPlanId.Free) { @@ -1023,7 +1030,7 @@ export class SubscriptionService implements Disposable { } this._statusBarSubscription.name = 'GitKraken Subscription'; - this._statusBarSubscription.command = Commands.ShowHomeView; + this._statusBarSubscription.command = Commands.ShowAccountView; if (account?.verified === false) { this._statusBarSubscription.text = `$(warning) ${effective.name} (Unverified)`; @@ -1038,12 +1045,21 @@ export class SubscriptionService implements Disposable { ); } else { const remaining = getSubscriptionTimeRemaining(this._subscription, 'days'); + const isReactivatedTrial = + state === SubscriptionState.FreePlusInTrial && effective.trialReactivationCount > 0; this._statusBarSubscription.text = `${effective.name} (Trial)`; this._statusBarSubscription.tooltip = new MarkdownString( - `You have ${pluralize('day', remaining ?? 0)} left in your free **${ - effective.name - }** trial, which gives you additional access to Pro features on privately hosted repos.\n\nClick for details`, + `${ + isReactivatedTrial + ? `[See what's new](https://help.gitkraken.com/gitlens/gitlens-release-notes-current/) with + ${pluralize('day', remaining ?? 0, { + infix: ' more ', + })} + in your **${effective.name}** trial.` + : `You have ${pluralize('day', remaining ?? 0)} remaining in your **${effective.name}** trial.` + } Once your trial ends, you'll need a paid plan to continue using ✨ features.\n\nTry our + [other developer tools](https://www.gitkraken.com/suite) also included in your trial.`, true, ); } @@ -1095,6 +1111,7 @@ interface GKLicense { readonly latestStartDate: string; readonly latestEndDate: string; readonly organizationId: string | undefined; + readonly reactivationCount?: number; } type GKLicenseType = diff --git a/src/subscription.ts b/src/subscription.ts index 3cb3732804b3f..7913d174bc5a1 100644 --- a/src/subscription.ts +++ b/src/subscription.ts @@ -30,6 +30,7 @@ export interface SubscriptionPlan { readonly id: SubscriptionPlanId; readonly name: string; readonly bundle: boolean; + readonly trialReactivationCount: number; readonly cancelled: boolean; readonly startedOn: string; readonly expiresOn?: string | undefined; @@ -112,6 +113,7 @@ export function computeSubscriptionState(subscription: Optional { $content.state = subscription.state; $content.plan = subscription.plan.effective.name; $content.days = days; + $content.trialReactivationCount = subscription.plan.effective.trialReactivationCount; } } diff --git a/src/webviews/apps/plus/account/components/account-content.ts b/src/webviews/apps/plus/account/components/account-content.ts index 5ca90b1929504..0b93d0c6066f8 100644 --- a/src/webviews/apps/plus/account/components/account-content.ts +++ b/src/webviews/apps/plus/account/components/account-content.ts @@ -85,6 +85,9 @@ export class AccountContent extends LitElement { @property() plan = ''; + @property({ type: Number }) + trialReactivationCount = 0; + get daysRemaining() { if (this.days < 1) { return '<1 day'; @@ -122,6 +125,10 @@ export class AccountContent extends LitElement { return hasAccountFromSubscriptionState(this.state); } + get isReactivatedTrial() { + return this.state === SubscriptionState.FreePlusInTrial && this.trialReactivationCount > 0; + } + private renderAccountInfo() { if (!this.hasAccount) { return nothing; @@ -192,15 +199,28 @@ export class AccountContent extends LitElement { case SubscriptionState.FreePlusInTrial: return html`

- Your have ${this.daysRemaining} remaining in your GitKraken trial. Once your trial ends, you'll - need a paid plan to continue using ✨ features. + ${this.isReactivatedTrial + ? html`See what's new + with + ${pluralize('day', this.days, { + infix: ' more ', + })} + in your GitKraken trial.` + : `You have + ${this.daysRemaining} remaining in your GitKraken trial.`} + Once your trial ends, you'll need a paid plan to continue using ✨ features.

Upgrade to Pro

- You have access to ✨ features on privately hosted repos and ☁️ features based on the Pro plan - during your trial. + You have access to ✨ features on privately hosted repos and ☁️ features based on the Pro plan. +

+

+ Try our + other developer tools also included in your trial.

`; @@ -212,6 +232,10 @@ export class AccountContent extends LitElement { >

You have access to ✨ features on privately hosted repos and ☁️ features based on your plan.

+

+ Try our + other developer tools also included in your plan. +

`; } From de7c53b91e38afbb0ed1da240d139652bb95cdcf Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Thu, 12 Oct 2023 11:38:53 -0700 Subject: [PATCH 0044/1012] Updates graph dependency --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ebb216213737d..99a0ac048e9ce 100644 --- a/package.json +++ b/package.json @@ -14850,7 +14850,7 @@ "vscode:prepublish": "yarn run bundle" }, "dependencies": { - "@gitkraken/gitkraken-components": "10.1.29", + "@gitkraken/gitkraken-components": "10.1.30", "@gitkraken/shared-web-components": "0.1.1-rc.11", "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", diff --git a/yarn.lock b/yarn.lock index d4cfff6a1409c..832f6bffd3848 100644 --- a/yarn.lock +++ b/yarn.lock @@ -223,10 +223,10 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== -"@gitkraken/gitkraken-components@10.1.29": - version "10.1.29" - resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.29.tgz#4d539e1bc9c343e8167bb4165f91246953725837" - integrity sha512-cqu9Mg8X6AERpdNIe+ux9CFLglkMejgRq3E6pIDG5lyMsEmLiISYr4trrTFc0DTyGfRwmbagCbqNodXeTOU6Fw== +"@gitkraken/gitkraken-components@10.1.30": + version "10.1.30" + resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-10.1.30.tgz#75c504736a47527e410d93be36cc38a0952568d4" + integrity sha512-A7EBIFQUCqptvQxmpt5YMfwnhl4rORAeay82Vtue8jM82jedT3xr7gKltQ1Q87QmKWvPpcgCS6pHwVVfOZrJZg== dependencies: "@axosoft/react-virtualized" "9.22.3-gitkraken.3" classnames "2.3.2" From ecbcbc45465e8182778bd69eda1f8ff8a0d11899 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Thu, 12 Oct 2023 14:18:03 -0700 Subject: [PATCH 0045/1012] Updates CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 282871f57824d..3660b59dcc16b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Fixes [#2940](https://github.com/gitkraken/vscode-gitlens/issues/2940) - Can't use Azure OpenAI model because i can't save the openai key because of the verification - Fixes [#2928](https://github.com/gitkraken/vscode-gitlens/issues/2928) - Apply Changes should create new files when needed - Fixes [#2896](https://github.com/gitkraken/vscode-gitlens/issues/2896) - Repositories view stuck in loading state +- Fixes [#2460](https://github.com/gitkraken/vscode-gitlens/issues/2460) - Gitlens Remote provider doesn't work properly in "Commit graph" view - Fixes issue with "View as [List|Tree]" toggle not working in the _Commit Details_ view - Fixes an issue with deep links sometimes failing to properly resolve when a matching repository without the remote is found - Fixes an issue in the _Commit Graph_ where commits not in the history of a merge commit were showing in the same column From c985a2e70c46a09a4c9ba7675121dbcbd309567b Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 12 Oct 2023 17:57:16 -0400 Subject: [PATCH 0046/1012] Closes #2828 allows following across all branches --- CHANGELOG.md | 1 + package.json | 15 ++++----------- src/env/node/git/git.ts | 4 ++-- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3660b59dcc16b..47a6d52291ff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Improves performance of inline blame, status bar blame, and hovers especially when working with remotes with connected integrations - Changes the _File History_ view to follow renames and filters out merge commits by default — closes [#2104](https://github.com/gitkraken/vscode-gitlens/issues/2104) & [#2944](https://github.com/gitkraken/vscode-gitlens/issues/2944) +- Changes the _File History_ view to allow following renames while showing history across all branches (which was a previous limitation of Git) — closes [#2828](https://github.com/gitkraken/vscode-gitlens/issues/2828) - Changes to use our own implementation of `fetch`, `push`, and `pull` Git operations, rather than delegating to VS Code to avoid limitations especially with GitKraken Workspaces. Please report any issues and you can revert this (for now) by setting `"gitlens.experimental.nativeGit"` to `"false"` in your settings - Relaxes PR autolink detection for Azure DevOps to use `PR ` instead of `Merged PR ` — closes [#2908](https://github.com/gitkraken/vscode-gitlens/issues/2908) - Changes wording on `Reset Stored OpenAI Key` command to `Reset Stored AI Key` to reflect support for other providers diff --git a/package.json b/package.json index 99a0ac048e9ce..6f3887e50d974 100644 --- a/package.json +++ b/package.json @@ -6557,14 +6557,12 @@ { "command": "gitlens.views.fileHistory.setRenameFollowingOn", "title": "Follow Renames", - "category": "GitLens", - "enablement": "!config.gitlens.advanced.fileHistoryShowAllBranches" + "category": "GitLens" }, { "command": "gitlens.views.fileHistory.setRenameFollowingOff", "title": "Don't Follow Renames", - "category": "GitLens", - "enablement": "!config.gitlens.advanced.fileHistoryShowAllBranches" + "category": "GitLens" }, { "command": "gitlens.views.fileHistory.setShowAllBranchesOn", @@ -10860,17 +10858,12 @@ }, { "command": "gitlens.views.fileHistory.setRenameFollowingOn", - "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && config.gitlens.advanced.fileHistoryShowAllBranches", - "group": "3_gitlens@1" - }, - { - "command": "gitlens.views.fileHistory.setRenameFollowingOn", - "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && !config.gitlens.advanced.fileHistoryShowAllBranches && !config.gitlens.advanced.fileHistoryFollowsRenames", + "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && !config.gitlens.advanced.fileHistoryFollowsRenames", "group": "3_gitlens@1" }, { "command": "gitlens.views.fileHistory.setRenameFollowingOff", - "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && !config.gitlens.advanced.fileHistoryShowAllBranches && config.gitlens.advanced.fileHistoryFollowsRenames", + "when": "view =~ /^gitlens\\.views\\.fileHistory/ && !gitlens:views:fileHistory:cursorFollowing && config.gitlens.advanced.fileHistoryFollowsRenames", "group": "3_gitlens@1" }, { diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index f772c2d13549a..e6caf421e4a08 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -1275,8 +1275,8 @@ export class Git { params.push('--first-parent'); } - // Can't allow rename detection (`--follow`) if `all` or a `startLine` is specified - if (renames && (all || startLine != null)) { + // Can't allow rename detection (`--follow`) if a `startLine` is specified + if (renames && startLine != null) { renames = false; } From 3ce034a2173c4fc73e16381b511172605b4b1684 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 13 Oct 2023 12:29:44 -0400 Subject: [PATCH 0047/1012] Improves performance of pin/snooze on Focus view --- src/plus/webviews/focus/focusWebview.ts | 192 +++++++++++++----------- 1 file changed, 105 insertions(+), 87 deletions(-) diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 71c84b1875391..e4268e58e6d80 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -2,6 +2,7 @@ import { Disposable, Uri, window } from 'vscode'; import type { GHPRPullRequest } from '../../../commands/ghpr/openOrCreateWorktree'; import { Commands } from '../../../constants'; import type { Container } from '../../../container'; +import type { FeatureAccess, RepoFeatureAccess } from '../../../features'; import { PlusFeatures } from '../../../features'; import { add as addRemote } from '../../../git/actions/remote'; import * as RepoActions from '../../../git/actions/repository'; @@ -394,13 +395,22 @@ export class FocusWebviewProvider implements WebviewProvider { if (e.etag === this._etagSubscription) return; this._etagSubscription = e.etag; - void this.notifyDidChangeState(true); + this._access = undefined; + void this.notifyDidChangeState(); + } + + private _access: FeatureAccess | RepoFeatureAccess | undefined; + private async getAccess(force?: boolean) { + if (force || this._access == null) { + this._access = await this.container.git.access(PlusFeatures.Focus); + } + return this._access; } - private async getState(deferState?: boolean): Promise { + private async getState(force?: boolean, deferState?: boolean): Promise { const webviewId = this.host.id; - const access = await this.container.git.access(PlusFeatures.Focus); + const access = await this.getAccess(force); if (access.allowed !== true) { return { webviewId: webviewId, @@ -409,7 +419,7 @@ export class FocusWebviewProvider implements WebviewProvider { }; } - const allRichRepos = await this.getRichRepos(); + const allRichRepos = await this.getRichRepos(force); const githubRepos = filterGithubRepos(allRichRepos); const connectedRepos = filterUsableRepos(githubRepos); const hasConnectedRepos = connectedRepos.length > 0; @@ -426,9 +436,9 @@ export class FocusWebviewProvider implements WebviewProvider { const repos = connectedRepos.map(r => serializeRepoWithRichRemote(r)); const statePromise = Promise.allSettled([ - this.getMyPullRequests(connectedRepos), - this.getMyIssues(connectedRepos), - this.getEnrichedItems(), + this.getMyPullRequests(connectedRepos, force), + this.getMyIssues(connectedRepos, force), + this.getEnrichedItems(force), ]); async function getStateCore() { @@ -476,11 +486,11 @@ export class FocusWebviewProvider implements WebviewProvider { } async includeBootstrap(): Promise { - return this.getState(true); + return this.getState(true, true); } private async getRichRepos(force?: boolean): Promise { - if (this._repos == null || force === true) { + if (force || this._repos == null) { const repos = []; const disposables = []; for (const repo of this.container.git.openRepositories) { @@ -509,115 +519,123 @@ export class FocusWebviewProvider implements WebviewProvider { return this._repos; } - private async onRepositoryChanged(e: RepositoryChangeEvent) { + private onRepositoryChanged(e: RepositoryChangeEvent) { if (e.changed(RepositoryChange.RemoteProviders, RepositoryChangeComparisonMode.Any)) { - await this.getRichRepos(true); - void this.notifyDidChangeState(); + void this.notifyDidChangeState(true); } } - private async getMyPullRequests(richRepos: RepoWithRichRemote[]): Promise { - const allPrs: SearchedPullRequestWithRemote[] = []; - for (const richRepo of richRepos) { - const remote = richRepo.remote; - const prs = await this.container.git.getMyPullRequests(remote); - if (prs == null) { - continue; - } - - for (const pr of prs) { - if (pr.reasons.length === 0) { + private async getMyPullRequests( + richRepos: RepoWithRichRemote[], + force?: boolean, + ): Promise { + if (force || this._pullRequests == null) { + const allPrs: SearchedPullRequestWithRemote[] = []; + for (const richRepo of richRepos) { + const remote = richRepo.remote; + const prs = await this.container.git.getMyPullRequests(remote); + if (prs == null) { continue; } - const entry: SearchedPullRequestWithRemote = { - ...pr, - repoAndRemote: richRepo, - isCurrentWorktree: false, - isCurrentBranch: false, - rank: getPrRank(pr), - }; - - const remoteBranchName = `${entry.pullRequest.refs!.head.owner}/${entry.pullRequest.refs!.head.branch}`; // TODO@eamodio really need to check for upstream url rather than name - - const worktree = await getWorktreeForBranch( - entry.repoAndRemote.repo, - entry.pullRequest.refs!.head.branch, - remoteBranchName, - ); - entry.hasWorktree = worktree != null; - entry.isCurrentWorktree = worktree?.opened === true; - - const branch = await getLocalBranchByUpstream(richRepo.repo, remoteBranchName); - if (branch) { - entry.branch = branch; - entry.hasLocalBranch = true; - entry.isCurrentBranch = branch.current; - } - allPrs.push(entry); + for (const pr of prs) { + if (pr.reasons.length === 0) { + continue; + } + const entry: SearchedPullRequestWithRemote = { + ...pr, + repoAndRemote: richRepo, + isCurrentWorktree: false, + isCurrentBranch: false, + rank: getPrRank(pr), + }; + + const remoteBranchName = `${entry.pullRequest.refs!.head.owner}/${ + entry.pullRequest.refs!.head.branch + }`; // TODO@eamodio really need to check for upstream url rather than name + + const worktree = await getWorktreeForBranch( + entry.repoAndRemote.repo, + entry.pullRequest.refs!.head.branch, + remoteBranchName, + ); + entry.hasWorktree = worktree != null; + entry.isCurrentWorktree = worktree?.opened === true; + + const branch = await getLocalBranchByUpstream(richRepo.repo, remoteBranchName); + if (branch) { + entry.branch = branch; + entry.hasLocalBranch = true; + entry.isCurrentBranch = branch.current; + } + + allPrs.push(entry); + } } - } - this._pullRequests = allPrs.sort((a, b) => { - const scoreA = a.rank; - const scoreB = b.rank; + this._pullRequests = allPrs.sort((a, b) => { + const scoreA = a.rank; + const scoreB = b.rank; - if (scoreA === scoreB) { - return a.pullRequest.date.getTime() - b.pullRequest.date.getTime(); - } - return (scoreB ?? 0) - (scoreA ?? 0); - }); + if (scoreA === scoreB) { + return a.pullRequest.date.getTime() - b.pullRequest.date.getTime(); + } + return (scoreB ?? 0) - (scoreA ?? 0); + }); + } return this._pullRequests; } - private async getMyIssues(richRepos: RepoWithRichRemote[]): Promise { - const allIssues = []; - for (const richRepo of richRepos) { - const remote = richRepo.remote; - const issues = await this.container.git.getMyIssues(remote); - if (issues == null) { - continue; - } - - for (const issue of issues) { - if (issue.reasons.length === 0) { + private async getMyIssues(richRepos: RepoWithRichRemote[], force?: boolean): Promise { + if (force || this._pullRequests == null) { + const allIssues = []; + for (const richRepo of richRepos) { + const remote = richRepo.remote; + const issues = await this.container.git.getMyIssues(remote); + if (issues == null) { continue; } - allIssues.push({ - ...issue, - repoAndRemote: richRepo, - rank: 0, // getIssueRank(issue), - }); + + for (const issue of issues) { + if (issue.reasons.length === 0) { + continue; + } + allIssues.push({ + ...issue, + repoAndRemote: richRepo, + rank: 0, // getIssueRank(issue), + }); + } } - } - // this._issues = allIssues.sort((a, b) => { - // const scoreA = a.rank; - // const scoreB = b.rank; + // this._issues = allIssues.sort((a, b) => { + // const scoreA = a.rank; + // const scoreB = b.rank; - // if (scoreA === scoreB) { - // return b.issue.updatedDate.getTime() - a.issue.updatedDate.getTime(); - // } - // return (scoreB ?? 0) - (scoreA ?? 0); - // }); + // if (scoreA === scoreB) { + // return b.issue.updatedDate.getTime() - a.issue.updatedDate.getTime(); + // } + // return (scoreB ?? 0) - (scoreA ?? 0); + // }); - this._issues = allIssues.sort((a, b) => b.issue.updatedDate.getTime() - a.issue.updatedDate.getTime()); + this._issues = allIssues.sort((a, b) => b.issue.updatedDate.getTime() - a.issue.updatedDate.getTime()); + } return this._issues; } - private async getEnrichedItems(): Promise { + private async getEnrichedItems(force?: boolean): Promise { // TODO needs cache invalidation - if (this._enrichedItems == null) { + if (force || this._enrichedItems == null) { const enrichedItems = await this.container.focus.get(); this._enrichedItems = enrichedItems; } return this._enrichedItems; } - private async notifyDidChangeState(deferState?: boolean) { - void this.host.notify(DidChangeNotificationType, { state: await this.getState(deferState) }); + private async notifyDidChangeState(force?: boolean, deferState?: boolean) { + void this.host.notify(DidChangeNotificationType, { state: await this.getState(force, deferState) }); } } From 3270cadb5423e22d8f335b9355dd9b9a08a3e8be Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 13 Oct 2023 12:42:34 -0400 Subject: [PATCH 0048/1012] Fixes log sanitizing --- src/plus/github/github.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plus/github/github.ts b/src/plus/github/github.ts index 12e1dcf20fbdf..e2aaae4f93601 100644 --- a/src/plus/github/github.ts +++ b/src/plus/github/github.ts @@ -2270,7 +2270,7 @@ export class GitHubApi implements Disposable { private _enterpriseVersions = new Map(); - @debug({ args: { 0: '' } }) + @debug({ args: { 0: p => p?.name, 1: '' } }) private async getEnterpriseVersion( provider: RichRemoteProvider | undefined, token: string, @@ -2707,7 +2707,7 @@ export class GitHubApi implements Disposable { } } - @debug({ args: { 0: '' } }) + @debug({ args: { 0: p => p.name, 1: '' } }) async searchMyIssues( provider: RichRemoteProvider, token: string, From 45ab95fe54acf08507701c700f6fb0f47041a5d7 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 13 Oct 2023 12:48:15 -0400 Subject: [PATCH 0049/1012] Adds/fixes logging --- src/plus/focus/focusService.ts | 4 ++-- src/plus/webviews/focus/focusWebview.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index ccfabd227935c..63f6c49e75698 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -99,7 +99,7 @@ export class FocusService implements Disposable { return this.get('snooze'); } - @log() + @log({ args: { 0: i => `${i.id} (${i.remote.provider.name} ${i.type})` } }) async pinItem(item: FocusItem): Promise { const scope = getLogScope(); @@ -138,7 +138,7 @@ export class FocusService implements Disposable { return this.delete(id, 'unpin'); } - @log() + @log({ args: { 0: i => `${i.id} (${i.remote.provider.name} ${i.type})` } }) async snoozeItem(item: FocusItem): Promise { const scope = getLogScope(); diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index e4268e58e6d80..50e73a5ac7d7b 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -24,6 +24,7 @@ import { getWorktreeForBranch } from '../../../git/models/worktree'; import { parseGitRemoteUrl } from '../../../git/parsers/remoteParser'; import type { RichRemoteProvider } from '../../../git/remotes/richRemoteProvider'; import { executeCommand, registerCommand } from '../../../system/command'; +import { debug } from '../../../system/decorators/log'; import { getSettledValue } from '../../../system/promise'; import type { IpcMessage } from '../../../webviews/protocol'; import { onIpc } from '../../../webviews/protocol'; @@ -129,6 +130,7 @@ export class FocusWebviewProvider implements WebviewProvider { } } + @debug({ args: false }) private async onPinIssue({ issue, pin }: PinIssueParams) { const issueWithRemote = this._issues?.find(r => r.issue.nodeId === issue.nodeId); if (issueWithRemote == null) return; @@ -159,6 +161,7 @@ export class FocusWebviewProvider implements WebviewProvider { void this.notifyDidChangeState(); } + @debug({ args: false }) private async onSnoozeIssue({ issue, snooze }: SnoozeIssueParams) { const issueWithRemote = this._issues?.find(r => r.issue.nodeId === issue.nodeId); if (issueWithRemote == null) return; @@ -189,6 +192,7 @@ export class FocusWebviewProvider implements WebviewProvider { void this.notifyDidChangeState(); } + @debug({ args: false }) private async onPinPr({ pullRequest, pin }: PinPrParams) { const prWithRemote = this._pullRequests?.find(r => r.pullRequest.nodeId === pullRequest.nodeId); if (prWithRemote == null) return; @@ -219,6 +223,7 @@ export class FocusWebviewProvider implements WebviewProvider { void this.notifyDidChangeState(); } + @debug({ args: false }) private async onSnoozePr({ pullRequest, snooze }: SnoozePrParams) { const prWithRemote = this._pullRequests?.find(r => r.pullRequest.nodeId === pullRequest.nodeId); if (prWithRemote == null) return; @@ -323,6 +328,7 @@ export class FocusWebviewProvider implements WebviewProvider { }; } + @debug({ args: false }) private async onOpenBranch({ pullRequest }: OpenBranchParams) { const prWithRemote = this.findSearchedPullRequest(pullRequest); if (prWithRemote == null) return; @@ -338,6 +344,7 @@ export class FocusWebviewProvider implements WebviewProvider { void executeCommand(Commands.ShowInCommitGraph, { ref: remoteBranch.reference }); } + @debug({ args: false }) private async onSwitchBranch({ pullRequest }: SwitchToBranchParams) { const prWithRemote = this.findSearchedPullRequest(pullRequest); if (prWithRemote == null || prWithRemote.isCurrentBranch) return; @@ -357,6 +364,7 @@ export class FocusWebviewProvider implements WebviewProvider { return RepoActions.switchTo(remoteBranch.remote.repoPath, remoteBranch.reference); } + @debug({ args: false }) private async onOpenWorktree({ pullRequest }: OpenWorktreeParams) { const searchedPullRequestWithRemote = this.findSearchedPullRequest(pullRequest); if (searchedPullRequestWithRemote?.repoAndRemote == null) { @@ -400,6 +408,7 @@ export class FocusWebviewProvider implements WebviewProvider { } private _access: FeatureAccess | RepoFeatureAccess | undefined; + @debug() private async getAccess(force?: boolean) { if (force || this._access == null) { this._access = await this.container.git.access(PlusFeatures.Focus); @@ -407,6 +416,7 @@ export class FocusWebviewProvider implements WebviewProvider { return this._access; } + @debug() private async getState(force?: boolean, deferState?: boolean): Promise { const webviewId = this.host.id; @@ -489,6 +499,7 @@ export class FocusWebviewProvider implements WebviewProvider { return this.getState(true, true); } + @debug() private async getRichRepos(force?: boolean): Promise { if (force || this._repos == null) { const repos = []; @@ -525,6 +536,7 @@ export class FocusWebviewProvider implements WebviewProvider { } } + @debug({ args: { 0: false } }) private async getMyPullRequests( richRepos: RepoWithRichRemote[], force?: boolean, @@ -587,6 +599,7 @@ export class FocusWebviewProvider implements WebviewProvider { return this._pullRequests; } + @debug({ args: { 0: false } }) private async getMyIssues(richRepos: RepoWithRichRemote[], force?: boolean): Promise { if (force || this._pullRequests == null) { const allIssues = []; @@ -625,6 +638,7 @@ export class FocusWebviewProvider implements WebviewProvider { return this._issues; } + @debug() private async getEnrichedItems(force?: boolean): Promise { // TODO needs cache invalidation if (force || this._enrichedItems == null) { From 5999a261c811d3e66f16e67b7da07b5d08a5fd00 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 13 Oct 2023 14:57:09 -0400 Subject: [PATCH 0050/1012] Optimizes git calls for focus view Adds PageableResult class helper --- src/git/models/branch.ts | 23 ++++---- src/git/models/worktree.ts | 29 ++++++---- src/plus/webviews/focus/focusWebview.ts | 72 ++++++++++++++++++------- src/system/paging.ts | 31 +++++++++++ 4 files changed, 114 insertions(+), 41 deletions(-) create mode 100644 src/system/paging.ts diff --git a/src/git/models/branch.ts b/src/git/models/branch.ts index e8e647a5d1040..a1a0f4015aeaf 100644 --- a/src/git/models/branch.ts +++ b/src/git/models/branch.ts @@ -5,6 +5,7 @@ import { formatDate, fromNow } from '../../system/date'; import { debug } from '../../system/decorators/log'; import { memoize } from '../../system/decorators/memoize'; import { getLoggableName } from '../../system/logger'; +import { PageableResult } from '../../system/paging'; import { sortCompare } from '../../system/string'; import type { PullRequest, PullRequestState } from './pullRequest'; import type { GitBranchReference, GitReference } from './reference'; @@ -291,6 +292,7 @@ export function sortBranches(branches: GitBranch[], options?: BranchSortOptions) export async function getLocalBranchByUpstream( repo: Repository, remoteBranchName: string, + branches?: PageableResult, ): Promise { let qualifiedRemoteBranchName; if (remoteBranchName.startsWith('remotes/')) { @@ -300,19 +302,16 @@ export async function getLocalBranchByUpstream( qualifiedRemoteBranchName = `remotes/${remoteBranchName}`; } - let branches; - do { - branches = await repo.getBranches(branches != null ? { paging: branches.paging } : undefined); - for (const branch of branches.values) { - if ( - !branch.remote && - branch.upstream?.name != null && - (branch.upstream.name === remoteBranchName || branch.upstream.name === qualifiedRemoteBranchName) - ) { - return branch; - } + branches ??= new PageableResult(p => repo.getBranches(p != null ? { paging: p } : undefined)); + for await (const branch of branches.values()) { + if ( + !branch.remote && + branch.upstream?.name != null && + (branch.upstream.name === remoteBranchName || branch.upstream.name === qualifiedRemoteBranchName) + ) { + return branch; } - } while (branches.paging?.more); + } return undefined; } diff --git a/src/git/models/worktree.ts b/src/git/models/worktree.ts index 4c38a1a947bd9..ad8f3f91aa7d2 100644 --- a/src/git/models/worktree.ts +++ b/src/git/models/worktree.ts @@ -2,6 +2,7 @@ import type { Uri, WorkspaceFolder } from 'vscode'; import { workspace } from 'vscode'; import { Container } from '../../container'; import { memoize } from '../../system/decorators/memoize'; +import { PageableResult } from '../../system/paging'; import { normalizePath, relative } from '../../system/path'; import type { GitBranch } from './branch'; import { shortenRevision } from './reference'; @@ -84,26 +85,34 @@ export class GitWorktree { export async function getWorktreeForBranch( repo: Repository, branchName: string, - upstreamNames?: string | string[], + upstreamNames: string | string[], + worktrees?: GitWorktree[], + branches?: PageableResult, ): Promise { if (upstreamNames != null && !Array.isArray(upstreamNames)) { upstreamNames = [upstreamNames]; } - const worktrees = await repo.getWorktrees(); + worktrees ??= await repo.getWorktrees(); for (const worktree of worktrees) { if (worktree.branch === branchName) return worktree; if (upstreamNames == null || worktree.branch == null) continue; - const branch = await repo.getBranch(worktree.branch); - if ( - branch?.upstream?.name != null && - (upstreamNames.includes(branch.upstream.name) || - (branch.upstream.name.startsWith('remotes/') && - upstreamNames.includes(branch.upstream.name.substring(8)))) - ) { - return worktree; + branches ??= new PageableResult(p => repo.getBranches(p != null ? { paging: p } : undefined)); + for await (const branch of branches.values()) { + if (branch.name === worktree.branch) { + if ( + branch.upstream?.name != null && + (upstreamNames.includes(branch.upstream.name) || + (branch.upstream.name.startsWith('remotes/') && + upstreamNames.includes(branch.upstream.name.substring(8)))) + ) { + return worktree; + } + + break; + } } } diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 50e73a5ac7d7b..4d9078d66870e 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -20,11 +20,15 @@ import { createReference } from '../../../git/models/reference'; import type { GitRemote } from '../../../git/models/remote'; import type { Repository, RepositoryChangeEvent } from '../../../git/models/repository'; import { RepositoryChange, RepositoryChangeComparisonMode } from '../../../git/models/repository'; +import type { GitWorktree } from '../../../git/models/worktree'; import { getWorktreeForBranch } from '../../../git/models/worktree'; import { parseGitRemoteUrl } from '../../../git/parsers/remoteParser'; import type { RichRemoteProvider } from '../../../git/remotes/richRemoteProvider'; import { executeCommand, registerCommand } from '../../../system/command'; import { debug } from '../../../system/decorators/log'; +import { Logger } from '../../../system/logger'; +import { getLogScope } from '../../../system/logger.scope'; +import { PageableResult } from '../../../system/paging'; import { getSettledValue } from '../../../system/promise'; import type { IpcMessage } from '../../../webviews/protocol'; import { onIpc } from '../../../webviews/protocol'; @@ -541,22 +545,30 @@ export class FocusWebviewProvider implements WebviewProvider { richRepos: RepoWithRichRemote[], force?: boolean, ): Promise { + const scope = getLogScope(); + if (force || this._pullRequests == null) { const allPrs: SearchedPullRequestWithRemote[] = []; - for (const richRepo of richRepos) { - const remote = richRepo.remote; - const prs = await this.container.git.getMyPullRequests(remote); - if (prs == null) { - continue; + + const branchesByRepo = new Map>(); + const worktreesByRepo = new Map(); + + const queries = richRepos.map(r => [r, this.container.git.getMyPullRequests(r.remote)] as const); + for (const [r, query] of queries) { + let prs; + try { + prs = await query; + } catch (ex) { + Logger.error(ex, scope, `Failed to get prs for '${r.remote.url}'`); } + if (prs == null) continue; for (const pr of prs) { - if (pr.reasons.length === 0) { - continue; - } + if (pr.reasons.length === 0) continue; + const entry: SearchedPullRequestWithRemote = { ...pr, - repoAndRemote: richRepo, + repoAndRemote: r, isCurrentWorktree: false, isCurrentBranch: false, rank: getPrRank(pr), @@ -566,15 +578,32 @@ export class FocusWebviewProvider implements WebviewProvider { entry.pullRequest.refs!.head.branch }`; // TODO@eamodio really need to check for upstream url rather than name + let branches = branchesByRepo.get(entry.repoAndRemote.repo); + if (branches == null) { + branches = new PageableResult(paging => + entry.repoAndRemote.repo.getBranches(paging != null ? { paging: paging } : undefined), + ); + branchesByRepo.set(entry.repoAndRemote.repo, branches); + } + + let worktrees = worktreesByRepo.get(entry.repoAndRemote.repo); + if (worktrees == null) { + worktrees = await entry.repoAndRemote.repo.getWorktrees(); + worktreesByRepo.set(entry.repoAndRemote.repo, worktrees); + } + const worktree = await getWorktreeForBranch( entry.repoAndRemote.repo, entry.pullRequest.refs!.head.branch, remoteBranchName, + worktrees, + branches, ); + entry.hasWorktree = worktree != null; entry.isCurrentWorktree = worktree?.opened === true; - const branch = await getLocalBranchByUpstream(richRepo.repo, remoteBranchName); + const branch = await getLocalBranchByUpstream(r.repo, remoteBranchName, branches); if (branch) { entry.branch = branch; entry.hasLocalBranch = true; @@ -601,22 +630,27 @@ export class FocusWebviewProvider implements WebviewProvider { @debug({ args: { 0: false } }) private async getMyIssues(richRepos: RepoWithRichRemote[], force?: boolean): Promise { + const scope = getLogScope(); + if (force || this._pullRequests == null) { const allIssues = []; - for (const richRepo of richRepos) { - const remote = richRepo.remote; - const issues = await this.container.git.getMyIssues(remote); - if (issues == null) { - continue; + + const queries = richRepos.map(r => [r, this.container.git.getMyIssues(r.remote)] as const); + for (const [r, query] of queries) { + let issues; + try { + issues = await query; + } catch (ex) { + Logger.error(ex, scope, `Failed to get issues for '${r.remote.url}'`); } + if (issues == null) continue; for (const issue of issues) { - if (issue.reasons.length === 0) { - continue; - } + if (issue.reasons.length === 0) continue; + allIssues.push({ ...issue, - repoAndRemote: richRepo, + repoAndRemote: r, rank: 0, // getIssueRank(issue), }); } diff --git a/src/system/paging.ts b/src/system/paging.ts new file mode 100644 index 0000000000000..c7a448c2cdbb9 --- /dev/null +++ b/src/system/paging.ts @@ -0,0 +1,31 @@ +import type { PagedResult } from '../git/gitProvider'; + +export class PageableResult { + private cached: Mutable> | undefined; + + constructor(private readonly fetch: (paging: PagedResult['paging']) => Promise>) {} + + async *values(): AsyncIterable> { + if (this.cached != null) { + for (const value of this.cached.values) { + yield value; + } + } + + let results = this.cached; + while (results == null || results.paging?.more) { + results = await this.fetch(results?.paging); + + if (this.cached == null) { + this.cached = results; + } else { + this.cached.values.push(...results.values); + this.cached.paging = results.paging; + } + + for (const value of results.values) { + yield value; + } + } + } +} From 07c9c63d07b12e6a5d85797922d270bca214c885 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 13 Oct 2023 14:57:43 -0400 Subject: [PATCH 0051/1012] Avoids refresh on initial load while discovering --- src/git/gitProviderService.ts | 30 ++++++++++++++----------- src/plus/webviews/focus/focusWebview.ts | 22 +++++++++++++++++- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 0eb207a374bed..1cfcc4b6495b4 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -142,9 +142,11 @@ export class GitProviderService implements Disposable { get onDidChangeRepositories(): Event { return this._onDidChangeRepositories.event; } + private fireRepositoriesChanged(added?: Repository[], removed?: Repository[]) { - const openSchemes = this.openRepositories.map(r => r.uri.scheme); if (this.container.telemetry.enabled) { + const openSchemes = this.openRepositories.map(r => r.uri.scheme); + this.container.telemetry.setGlobalAttributes({ 'repositories.count': openSchemes.length, 'repositories.schemes': joinUnique(openSchemes, ','), @@ -163,7 +165,7 @@ export class GitProviderService implements Disposable { this._onDidChangeRepositories.fire({ added: added ?? [], removed: removed ?? [], etag: this._etag }); if (added?.length && this.container.telemetry.enabled) { - queueMicrotask(async () => { + setTimeout(async () => { for (const repo of added) { const remoteProviders = new Set(); @@ -181,7 +183,7 @@ export class GitProviderService implements Disposable { 'repository.remoteProviders': join(remoteProviders, ','), }); } - }); + }, 0); } } @@ -541,10 +543,12 @@ export class GitProviderService implements Disposable { >('git.autoRepositoryDetection'); if (this.container.telemetry.enabled) { - queueMicrotask(() => - this.container.telemetry.sendEvent('providers/registrationComplete', { - 'config.git.autoRepositoryDetection': autoRepositoryDetection, - }), + setTimeout( + () => + this.container.telemetry.sendEvent('providers/registrationComplete', { + 'config.git.autoRepositoryDetection': autoRepositoryDetection, + }), + 0, ); } @@ -576,8 +580,8 @@ export class GitProviderService implements Disposable { private _discoveredWorkspaceFolders = new Map>(); - private _isDiscoveringRepositories: Promise | undefined; - get isDiscoveringRepositories(): Promise | undefined { + private _isDiscoveringRepositories: Promise | undefined; + get isDiscoveringRepositories(): Promise | undefined { return this._isDiscoveringRepositories; } @@ -588,7 +592,7 @@ export class GitProviderService implements Disposable { this._isDiscoveringRepositories = undefined; } - const deferred = defer(); + const deferred = defer(); this._isDiscoveringRepositories = deferred.promise; try { @@ -630,7 +634,7 @@ export class GitProviderService implements Disposable { queueMicrotask(() => this.fireRepositoriesChanged(added)); } } finally { - deferred.fulfill(); + queueMicrotask(() => deferred.fulfill(this._etag)); } } @@ -910,7 +914,7 @@ export class GitProviderService implements Disposable { if (visibility == null) { visibility = await this.visibilityCore(repoPath); if (this.container.telemetry.enabled) { - queueMicrotask(() => { + setTimeout(() => { const repo = this.getRepository(repoPath); this.container.telemetry.sendEvent('repository/visibility', { 'repository.visibility': visibility, @@ -920,7 +924,7 @@ export class GitProviderService implements Disposable { 'repository.folder.scheme': repo?.folder?.uri.scheme, 'repository.provider.id': repo?.provider.id, }); - }); + }, 0); } } return visibility; diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 4d9078d66870e..8b0ac774fb65b 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -84,7 +84,9 @@ interface SearchedIssueWithRank extends SearchedIssue { export class FocusWebviewProvider implements WebviewProvider { private _pullRequests: SearchedPullRequestWithRemote[] = []; private _issues: SearchedIssueWithRank[] = []; + private _discovering: Promise | undefined; private readonly _disposable: Disposable; + private _etag?: number; private _etagSubscription?: number; private _repositoryEventsDisposable?: Disposable; private _repos?: RepoWithRichRemote[]; @@ -96,7 +98,16 @@ export class FocusWebviewProvider implements WebviewProvider { ) { this._disposable = Disposable.from( this.container.subscription.onDidChange(this.onSubscriptionChanged, this), - this.container.git.onDidChangeRepositories(() => void this.host.refresh(true)), + this.container.git.onDidChangeRepositories(async () => { + if (this._etag !== this.container.git.etag) { + if (this._discovering != null) { + this._etag = await this._discovering; + if (this._etag === this.container.git.etag) return; + } + + void this.host.refresh(true); + } + }), ); } @@ -424,6 +435,15 @@ export class FocusWebviewProvider implements WebviewProvider { private async getState(force?: boolean, deferState?: boolean): Promise { const webviewId = this.host.id; + this._etag = this.container.git.etag; + if (this.container.git.isDiscoveringRepositories) { + this._discovering = this.container.git.isDiscoveringRepositories.then(r => { + this._discovering = undefined; + return r; + }); + this._etag = await this._discovering; + } + const access = await this.getAccess(force); if (access.allowed !== true) { return { From 3d1230e191a3c19d6ffaad56eefa4e3fe7095877 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Fri, 13 Oct 2023 18:23:03 -0400 Subject: [PATCH 0052/1012] Adds required prompts when pinning or snoozing --- src/plus/focus/focusService.ts | 118 +++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index 63f6c49e75698..2ea8518019caa 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -1,7 +1,9 @@ import type { Disposable } from 'vscode'; +import { window } from 'vscode'; import type { Container } from '../../container'; import type { GitRemote } from '../../git/models/remote'; import type { RichRemoteProvider } from '../../git/remotes/richRemoteProvider'; +import { isSubscriptionPaidPlan } from '../../subscription'; import { log } from '../../system/decorators/log'; import { Logger } from '../../system/logger'; import { getLogScope } from '../../system/logger.scope'; @@ -83,6 +85,8 @@ export class FocusService implements Disposable { const result = (await rsp.json()) as Result; return type == null ? result.data : result.data.filter(i => i.type === type); } catch (ex) { + if (ex instanceof Error && ex.message === 'Authentication required') return []; + Logger.error(ex, scope); debugger; throw ex; @@ -104,6 +108,10 @@ export class FocusService implements Disposable { const scope = getLogScope(); try { + if (!(await ensureAccount('Pinning requires an account', this.container))) { + throw new Error('Unable to pin item: account required'); + } + type Result = { data: EnrichedItemResponse }; const rq: EnrichedItemRequest = { @@ -143,6 +151,10 @@ export class FocusService implements Disposable { const scope = getLogScope(); try { + if (!(await ensurePaidPlan('Snoozing requires a trial or paid plan', this.container))) { + throw new Error('Unable to snooze item: subscription required'); + } + type Result = { data: EnrichedItemResponse }; const rq: EnrichedItemRequest = { @@ -177,3 +189,109 @@ export class FocusService implements Disposable { return this.delete(id, 'unsnooze'); } } + +async function ensurePaidPlan(title: string, container: Container): Promise { + while (true) { + const subscription = await container.subscription.getSubscription(); + if (subscription.account?.verified === false) { + const resend = { title: 'Resend Verification' }; + const cancel = { title: 'Cancel', isCloseAffordance: true }; + const result = await window.showWarningMessage( + `${title}\n\nYou must verify your email before you can continue.`, + { modal: true }, + resend, + cancel, + ); + + if (result === resend) { + if (await container.subscription.resendVerification()) { + continue; + } + } + + return false; + } + + const plan = subscription.plan.effective.id; + if (isSubscriptionPaidPlan(plan)) break; + + if (subscription.account == null) { + const signIn = { title: 'Start Free GitKraken Trial' }; + const cancel = { title: 'Cancel', isCloseAffordance: true }; + const result = await window.showWarningMessage( + `${title}\n\nTry our developer productivity and collaboration services free for 7 days.`, + { modal: true }, + signIn, + cancel, + ); + + if (result === signIn) { + if (await container.subscription.loginOrSignUp()) { + continue; + } + } + } else { + const upgrade = { title: 'Upgrade to Pro' }; + const cancel = { title: 'Cancel', isCloseAffordance: true }; + const result = await window.showWarningMessage( + `${title}\n\nContinue to use our developer productivity and collaboration services.`, + { modal: true }, + upgrade, + cancel, + ); + + if (result === upgrade) { + void container.subscription.purchase(); + } + } + + return false; + } + + return true; +} + +async function ensureAccount(title: string, container: Container): Promise { + while (true) { + const subscription = await container.subscription.getSubscription(); + if (subscription.account?.verified === false) { + const resend = { title: 'Resend Verification' }; + const cancel = { title: 'Cancel', isCloseAffordance: true }; + const result = await window.showWarningMessage( + `${title}\n\nYou must verify your email before you can continue.`, + { modal: true }, + resend, + cancel, + ); + + if (result === resend) { + if (await container.subscription.resendVerification()) { + continue; + } + } + + return false; + } + + if (subscription.account != null) break; + + const signIn = { title: 'Sign In / Sign Up' }; + const cancel = { title: 'Cancel', isCloseAffordance: true }; + const result = await window.showWarningMessage( + `${title}\n\nGain access to our developer productivity and collaboration services.`, + { modal: true }, + signIn, + cancel, + ); + + if (result === signIn) { + if (await container.subscription.loginOrSignUp()) { + continue; + } + } + + return false; + } + + return true; +} From 7db0ad0ce23f27b080bd83f9d0f0eb894f7c3cd6 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Fri, 13 Oct 2023 16:50:45 -0700 Subject: [PATCH 0053/1012] Bumps to v14.4.0 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47a6d52291ff3..269d7570e9923 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +## [14.4.0] - 2023-10-13 + ### Added - Adds a _Working Changes_ tab to the _Commit Details_ and _Graph Details_ views to show your working tree changes @@ -4964,7 +4966,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Initial release but still heavily a work in progress. -[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v14.3.0...HEAD +[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v14.4.0...HEAD +[14.4.0]: https://github.com/gitkraken/vscode-gitlens/compare/v14.3.0...gitkraken:v14.4.0 [14.3.0]: https://github.com/gitkraken/vscode-gitlens/compare/v14.2.1...gitkraken:v14.3.0 [14.2.1]: https://github.com/gitkraken/vscode-gitlens/compare/v14.2.0...gitkraken:v14.2.1 [14.2.0]: https://github.com/gitkraken/vscode-gitlens/compare/v14.1.1...gitkraken:v14.2.0 diff --git a/package.json b/package.json index 6f3887e50d974..882760f969713 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "gitlens", "displayName": "GitLens — Git supercharged", "description": "Supercharge Git within VS Code — Visualize code authorship at a glance via Git blame annotations and CodeLens, seamlessly navigate and explore Git repositories, gain valuable insights via rich visualizations and powerful comparison commands, and so much more", - "version": "14.3.0", + "version": "14.4.0", "engines": { "vscode": "^1.80.0" }, From 5b0d883d3a720512286d844c302c8a1855c82088 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 16 Oct 2023 11:46:03 -0400 Subject: [PATCH 0054/1012] Adds baseRef optional chain to isHidden --- .../apps/shared/components/list/file-change-list-item.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webviews/apps/shared/components/list/file-change-list-item.ts b/src/webviews/apps/shared/components/list/file-change-list-item.ts index 406c0bfd8ae02..f780785d1a393 100644 --- a/src/webviews/apps/shared/components/list/file-change-list-item.ts +++ b/src/webviews/apps/shared/components/list/file-change-list-item.ts @@ -105,7 +105,7 @@ export class FileChangeListItem extends LitElement { @state() get isHidden() { - return this.baseRef.isHidden ?? 'false'; + return this.baseRef?.isHidden ?? 'false'; } @state() From 2ec8e6c74bdf7e10e0f5300cb8b59edd1550176a Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 16 Oct 2023 11:46:17 -0400 Subject: [PATCH 0055/1012] Updates to lit v3 --- package.json | 4 ++-- yarn.lock | 58 ++++++++++++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index 882760f969713..34ea460a2ecc8 100644 --- a/package.json +++ b/package.json @@ -14844,7 +14844,7 @@ }, "dependencies": { "@gitkraken/gitkraken-components": "10.1.30", - "@gitkraken/shared-web-components": "0.1.1-rc.11", + "@gitkraken/shared-web-components": "0.1.1-rc.15", "@microsoft/fast-element": "1.12.0", "@microsoft/fast-react-wrapper": "0.3.19", "@octokit/graphql": "7.0.2", @@ -14858,7 +14858,7 @@ "billboard.js": "3.9.4", "https-proxy-agent": "5.0.1", "iconv-lite": "0.6.3", - "lit": "2.8.0", + "lit": "3.0.0", "node-fetch": "2.7.0", "os-browserify": "0.3.0", "path-browserify": "1.0.1", diff --git a/yarn.lock b/yarn.lock index 832f6bffd3848..3dd08feac8dad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -237,10 +237,10 @@ react-dragula "1.1.17" react-onclickoutside "^6.13.0" -"@gitkraken/shared-web-components@0.1.1-rc.11": - version "0.1.1-rc.11" - resolved "https://registry.yarnpkg.com/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.11.tgz#0d588af0a9c92a6ccf2339a341787c6d9d60227c" - integrity sha512-lslDHNgU2znzoLydkLudETHP0WlRBLdV25YgRSTcm724Elah5nFfqUdJZ8lQCKehxJBnlWtll5uTxuM+7wxVDw== +"@gitkraken/shared-web-components@0.1.1-rc.15": + version "0.1.1-rc.15" + resolved "https://registry.npmjs.org/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.15.tgz#efd520083a7f5a32fe342108f447e8c77723cfd2" + integrity sha512-BXGWoZoFzWftJC3BgEEPm/cU2qYasoGveGiG8oL8cWydl2TCkRCxddsiDswsMQaZDZIeTYLwbUPwA2PBeAAg4A== dependencies: "@floating-ui/dom" "^1.4.2" typescript "^4.9.5" @@ -352,17 +352,17 @@ methods "^1.1.2" path-to-regexp "^6.2.1" -"@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0": +"@lit-labs/ssr-dom-shim@^1.1.2-pre.0": version "1.1.2" - resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz#d693d972974a354034454ec1317eb6afd0b00312" + resolved "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz#d693d972974a354034454ec1317eb6afd0b00312" integrity sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g== -"@lit/reactive-element@^1.3.0", "@lit/reactive-element@^1.6.0": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.6.3.tgz#25b4eece2592132845d303e091bad9b04cdcfe03" - integrity sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ== +"@lit/reactive-element@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.0.tgz#da14a256ac5533873b935840f306d572bac4a2ab" + integrity sha512-wn+2+uDcs62ROBmVAwssO4x5xue/uKD3MGGZOXL2sMxReTRIT0JXKyMXeu7gh0aJ4IJNEIG/3aOnUaQvM7BMzQ== dependencies: - "@lit-labs/ssr-dom-shim" "^1.0.0" + "@lit-labs/ssr-dom-shim" "^1.1.2-pre.0" "@microsoft/fast-element@1.12.0", "@microsoft/fast-element@^1.12.0", "@microsoft/fast-element@^1.6.2", "@microsoft/fast-element@^1.9.0": version "1.12.0" @@ -4430,30 +4430,30 @@ linkify-it@^3.0.1: dependencies: uc.micro "^1.0.1" -lit-element@^3.3.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.3.tgz#10bc19702b96ef5416cf7a70177255bfb17b3209" - integrity sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA== +lit-element@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/lit-element/-/lit-element-4.0.0.tgz#8343891bc9159a5fcb7f534914b37f2c0161e036" + integrity sha512-N6+f7XgusURHl69DUZU6sTBGlIN+9Ixfs3ykkNDfgfTkDYGGOWwHAYBhDqVswnFGyWgQYR2KiSpu4J76Kccs/A== dependencies: - "@lit-labs/ssr-dom-shim" "^1.1.0" - "@lit/reactive-element" "^1.3.0" - lit-html "^2.8.0" + "@lit-labs/ssr-dom-shim" "^1.1.2-pre.0" + "@lit/reactive-element" "^2.0.0" + lit-html "^3.0.0" -lit-html@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.8.0.tgz#96456a4bb4ee717b9a7d2f94562a16509d39bffa" - integrity sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q== +lit-html@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lit-html/-/lit-html-3.0.0.tgz#77d6776ee488642c74c5575315ef81aa09d24ea9" + integrity sha512-DNJIE8dNY0dQF2Gs0sdMNUppMQT2/CvV4OVnSdg7BXAsGqkVwsE5bqQ04POfkYH5dBIuGnJYdFz5fYYyNnOxiA== dependencies: "@types/trusted-types" "^2.0.2" -lit@2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/lit/-/lit-2.8.0.tgz#4d838ae03059bf9cafa06e5c61d8acc0081e974e" - integrity sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA== +lit@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lit/-/lit-3.0.0.tgz#204bd65935892a73670471e893ee8ca55d2f9a3b" + integrity sha512-nQ0teRzU1Kdj++VdmttS2WvIen8M79wChJ6guRKIIym2M3Ansg3Adj9O6yuQh2IpjxiUXlNuS81WKlQ4iL3BmA== dependencies: - "@lit/reactive-element" "^1.6.0" - lit-element "^3.3.0" - lit-html "^2.8.0" + "@lit/reactive-element" "^2.0.0" + lit-element "^4.0.0" + lit-html "^3.0.0" loader-runner@^4.2.0: version "4.3.0" From 1dbd860f82d92b68b4b51c771754ea897fdb515e Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 16 Oct 2023 11:48:19 -0400 Subject: [PATCH 0056/1012] Updates dependencies & replaces FAST React w/ Lit --- ThirdPartyNotices.txt | 77 +++---- package.json | 12 +- src/webviews/apps/plus/graph/GraphWrapper.tsx | 6 +- .../apps/plus/graph/minimap/react.tsx | 5 +- .../components/helpers/react-wrapper.ts | 19 +- .../apps/shared/components/menu/react.tsx | 8 +- .../components/overlays/pop-menu/react.tsx | 2 +- .../apps/shared/components/overlays/react.tsx | 2 +- .../components/react/feature-gate-badge.tsx | 5 +- .../shared/components/react/feature-gate.tsx | 5 +- .../apps/shared/components/search/react.tsx | 8 +- yarn.lock | 212 +++++++++--------- 12 files changed, 187 insertions(+), 174 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index ea8988ae6e39e..dcb4137ae4bfa 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -3,8 +3,8 @@ GitLens THIRD-PARTY SOFTWARE NOTICES AND INFORMATION This project incorporates components from the projects listed below. -1. @microsoft/fast-element version 1.12.0 (https://github.com/Microsoft/fast) -2. @microsoft/fast-react-wrapper version 0.3.19 (https://github.com/Microsoft/fast) +1. @lit/react version 1.0.0 (https://github.com/lit/lit) +2. @microsoft/fast-element version 1.12.0 (https://github.com/Microsoft/fast) 3. @octokit/graphql version 7.0.2 (https://github.com/octokit/graphql.js) 4. @octokit/request version 8.1.4 (https://github.com/octokit/request.js) 5. @opentelemetry/api version 1.6.0 (https://github.com/open-telemetry/opentelemetry-js) @@ -16,7 +16,7 @@ This project incorporates components from the projects listed below. 11. billboard.js version 3.9.4 (https://github.com/naver/billboard.js) 12. https-proxy-agent version 5.0.1 (https://github.com/TooTallNate/node-https-proxy-agent) 13. iconv-lite version 0.6.3 (https://github.com/ashtuchkin/iconv-lite) -14. lit version 2.8.0 (https://github.com/lit/lit) +14. lit version 3.0.0 (https://github.com/lit/lit) 15. microsoft/vscode (https://github.com/microsoft/vscode) 16. node-fetch version 2.7.0 (https://github.com/bitinn/node-fetch) 17. os-browserify version 0.3.0 (https://github.com/CoderPuppy/os-browserify) @@ -27,6 +27,39 @@ This project incorporates components from the projects listed below. 22. sindresorhus/string-width (https://github.com/sindresorhus/string-width) 23. sortablejs version 1.15.0 (https://github.com/SortableJS/Sortable) +%% @lit/react NOTICES AND INFORMATION BEGIN HERE +========================================= +BSD 3-Clause License + +Copyright (c) 2017 Google LLC. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +========================================= +END OF @lit/react NOTICES AND INFORMATION + %% @microsoft/fast-element NOTICES AND INFORMATION BEGIN HERE ========================================= # FAST Element @@ -94,44 +127,6 @@ Looking for a quick guide on building components? Check out [our Cheat Sheet](. ========================================= END OF @microsoft/fast-element NOTICES AND INFORMATION -%% @microsoft/fast-react-wrapper NOTICES AND INFORMATION BEGIN HERE -========================================= -# FAST React Wrapper - -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![npm version](https://badge.fury.io/js/%40microsoft%2Ffast-react-wrapper.svg)](https://badge.fury.io/js/%40microsoft%2Ffast-react-wrapper) - -The `fast-react-wrapper` package contains a utility that enables automatically wrapping Web Components in a React component for ease of integration into React projects. - -## Installation - -### From NPM - -To install the `fast-react-wrapper` library, use either `npm` or `yarn` as follows: - -```shell -npm install --save @microsoft/fast-react-wrapper -``` - -```shell -yarn add @microsoft/fast-react-wrapper -``` - -Within your JavaScript or TypeScript code, you can then and use the wrapper like this: - -```ts -import React from 'react'; -import { provideReactWrapper } from '@microsoft/fast-react-wrapper'; - -const { wrap } = provideReactWrapper(React); - -const MyComponent = wrap(MyComponent); -``` - -For additional wrapper settings and more information on integrating with Design Systems, see [our integration docs](https://fast.design/docs/integrations/react). -========================================= -END OF @microsoft/fast-react-wrapper NOTICES AND INFORMATION - %% @octokit/graphql NOTICES AND INFORMATION BEGIN HERE ========================================= The MIT License diff --git a/package.json b/package.json index 34ea460a2ecc8..8d477e81162aa 100644 --- a/package.json +++ b/package.json @@ -14845,8 +14845,8 @@ "dependencies": { "@gitkraken/gitkraken-components": "10.1.30", "@gitkraken/shared-web-components": "0.1.1-rc.15", + "@lit/react": "1.0.0", "@microsoft/fast-element": "1.12.0", - "@microsoft/fast-react-wrapper": "0.3.19", "@octokit/graphql": "7.0.2", "@octokit/request": "8.1.4", "@opentelemetry/api": "1.6.0", @@ -14869,14 +14869,14 @@ "devDependencies": { "@types/mocha": "10.0.1", "@types/node": "16.11.47", - "@types/react": "17.0.67", + "@types/react": "17.0.68", "@types/react-dom": "17.0.21", "@types/sortablejs": "1.15.3", "@types/vscode": "1.80.0", "@typescript-eslint/eslint-plugin": "6.7.5", "@typescript-eslint/parser": "6.7.5", "@vscode/test-electron": "2.3.5", - "@vscode/test-web": "0.0.46", + "@vscode/test-web": "0.0.47", "@vscode/vsce": "2.21.1", "circular-dependency-plugin": "5.2.2", "clean-webpack-plugin": "4.0.0", @@ -14903,12 +14903,12 @@ "html-loader": "4.2.0", "html-webpack-plugin": "5.5.3", "image-minimizer-webpack-plugin": "3.8.3", - "license-checker-rseidelsohn": "4.2.8", + "license-checker-rseidelsohn": "4.2.10", "lz-string": "1.5.0", "mini-css-extract-plugin": "2.7.6", "mocha": "10.2.0", "prettier": "3.0.3", - "sass": "1.69.1", + "sass": "1.69.3", "sass-loader": "13.3.2", "schema-utils": "4.2.0", "sharp": "0.32.6", @@ -14917,7 +14917,7 @@ "ts-loader": "9.5.0", "tsc-alias": "1.8.8", "typescript": "5.3.0-beta", - "webpack": "5.88.2", + "webpack": "5.89.0", "webpack-bundle-analyzer": "4.9.1", "webpack-cli": "5.1.4", "webpack-node-externals": "3.0.0", diff --git a/src/webviews/apps/plus/graph/GraphWrapper.tsx b/src/webviews/apps/plus/graph/GraphWrapper.tsx index c342f2e6c2947..a45242a20b8b0 100644 --- a/src/webviews/apps/plus/graph/GraphWrapper.tsx +++ b/src/webviews/apps/plus/graph/GraphWrapper.tsx @@ -1231,8 +1231,8 @@ export function GraphWrapper({ errorMessage={searchResultsError?.error ?? ''} resultsHidden={searchResultsHidden} resultsLoaded={searchResults != null} - onChange={e => handleSearchInput(e as CustomEvent)} - onNavigate={e => handleSearchNavigation(e as CustomEvent)} + onChange={e => handleSearchInput(e)} + onNavigate={e => handleSearchNavigation(e)} onOpenInView={() => handleSearchOpenInView()} /> @@ -1369,7 +1369,7 @@ export function GraphWrapper({ markers={minimapData?.markers} searchResults={minimapSearchResults} visibleDays={visibleDays} - onSelected={e => handleOnMinimapDaySelected(e as CustomEvent)} + onSelected={e => handleOnMinimapDaySelected(e)} > )}
diff --git a/src/webviews/apps/plus/graph/minimap/react.tsx b/src/webviews/apps/plus/graph/minimap/react.tsx index 2819f0c33a417..36bfd80e6424c 100644 --- a/src/webviews/apps/plus/graph/minimap/react.tsx +++ b/src/webviews/apps/plus/graph/minimap/react.tsx @@ -1,8 +1,11 @@ +import type { EventName } from '@lit/react'; import { reactWrapper } from '../../../shared/components/helpers/react-wrapper'; +import type { GraphMinimapDaySelectedEventDetail } from './minimap'; import { GraphMinimap as graphMinimapComponent } from './minimap'; export const GraphMinimap = reactWrapper(graphMinimapComponent, { + tagName: 'graph-minimap', events: { - onSelected: 'selected', + onSelected: 'selected' as EventName>, }, }); diff --git a/src/webviews/apps/shared/components/helpers/react-wrapper.ts b/src/webviews/apps/shared/components/helpers/react-wrapper.ts index 891d14ac5cf9a..4af7e8807d4b9 100644 --- a/src/webviews/apps/shared/components/helpers/react-wrapper.ts +++ b/src/webviews/apps/shared/components/helpers/react-wrapper.ts @@ -1,6 +1,19 @@ -import { provideReactWrapper } from '@microsoft/fast-react-wrapper'; +/* eslint-disable @typescript-eslint/ban-types */ +import type { EventName, Options } from '@lit/react'; +import { createComponent } from '@lit/react'; import React from 'react'; -const { wrap } = provideReactWrapper(React); +type Constructor = new () => T; +type EventNames = Record; +type Opts = Omit, 'elementClass' | 'react'>; -export { wrap as reactWrapper }; +export function reactWrapper( + elementClass: Constructor, + options: Opts, +) { + return createComponent({ + ...options, + elementClass: elementClass, + react: React, + }); +} diff --git a/src/webviews/apps/shared/components/menu/react.tsx b/src/webviews/apps/shared/components/menu/react.tsx index e4eb39785e05e..732b4971e56f7 100644 --- a/src/webviews/apps/shared/components/menu/react.tsx +++ b/src/webviews/apps/shared/components/menu/react.tsx @@ -6,7 +6,7 @@ import { MenuList as MenuListComponent, } from './index'; -export const MenuDivider = reactWrapper(MenuDividerComponent); -export const MenuItem = reactWrapper(MenuItemComponent); -export const MenuLabel = reactWrapper(MenuLabelComponent); -export const MenuList = reactWrapper(MenuListComponent); +export const MenuDivider = reactWrapper(MenuDividerComponent, { tagName: 'menu-divider' }); +export const MenuItem = reactWrapper(MenuItemComponent, { tagName: 'menu-item' }); +export const MenuLabel = reactWrapper(MenuLabelComponent, { tagName: 'menu-label' }); +export const MenuList = reactWrapper(MenuListComponent, { tagName: 'menu-list' }); diff --git a/src/webviews/apps/shared/components/overlays/pop-menu/react.tsx b/src/webviews/apps/shared/components/overlays/pop-menu/react.tsx index 935a56f64892f..f433e9365f0fb 100644 --- a/src/webviews/apps/shared/components/overlays/pop-menu/react.tsx +++ b/src/webviews/apps/shared/components/overlays/pop-menu/react.tsx @@ -1,4 +1,4 @@ import { reactWrapper } from '../../helpers/react-wrapper'; import { PopMenu as PopMenuComponent } from './index'; -export const PopMenu = reactWrapper(PopMenuComponent); +export const PopMenu = reactWrapper(PopMenuComponent, { tagName: 'pop-menu' }); diff --git a/src/webviews/apps/shared/components/overlays/react.tsx b/src/webviews/apps/shared/components/overlays/react.tsx index 7d6fe102e3817..603bacf2eaf4b 100644 --- a/src/webviews/apps/shared/components/overlays/react.tsx +++ b/src/webviews/apps/shared/components/overlays/react.tsx @@ -1,4 +1,4 @@ import { reactWrapper } from '../helpers/react-wrapper'; import { PopOver as PopOverComponent } from './pop-over'; -export const PopOver = reactWrapper(PopOverComponent); +export const PopOver = reactWrapper(PopOverComponent, { tagName: 'pop-over' }); diff --git a/src/webviews/apps/shared/components/react/feature-gate-badge.tsx b/src/webviews/apps/shared/components/react/feature-gate-badge.tsx index 97e3807165539..1c1077f069c13 100644 --- a/src/webviews/apps/shared/components/react/feature-gate-badge.tsx +++ b/src/webviews/apps/shared/components/react/feature-gate-badge.tsx @@ -1,7 +1,4 @@ import { FeatureGateBadge as featureGateBadgeComponent } from '../feature-gate-badge'; import { reactWrapper } from '../helpers/react-wrapper'; -export const FeatureGateBadge = reactWrapper(featureGateBadgeComponent, { - name: 'gk-feature-gate-badge', - properties: ['placement', 'subscription'], -}); +export const FeatureGateBadge = reactWrapper(featureGateBadgeComponent, { tagName: 'gk-feature-gate-badge' }); diff --git a/src/webviews/apps/shared/components/react/feature-gate.tsx b/src/webviews/apps/shared/components/react/feature-gate.tsx index 2ccc1952a3482..f8cad52fea0fe 100644 --- a/src/webviews/apps/shared/components/react/feature-gate.tsx +++ b/src/webviews/apps/shared/components/react/feature-gate.tsx @@ -1,7 +1,4 @@ import { FeatureGate as featureGateComponent } from '../feature-gate'; import { reactWrapper } from '../helpers/react-wrapper'; -export const FeatureGate = reactWrapper(featureGateComponent, { - name: 'gk-feature-gate', - properties: ['state', 'visible'], -}); +export const FeatureGate = reactWrapper(featureGateComponent, { tagName: 'gk-feature-gate' }); diff --git a/src/webviews/apps/shared/components/search/react.tsx b/src/webviews/apps/shared/components/search/react.tsx index 7bf8249be78db..8e54e30cd839b 100644 --- a/src/webviews/apps/shared/components/search/react.tsx +++ b/src/webviews/apps/shared/components/search/react.tsx @@ -1,10 +1,14 @@ +import type { EventName } from '@lit/react'; +import type { SearchQuery } from '../../../../../git/search'; import { reactWrapper } from '../helpers/react-wrapper'; +import type { SearchNavigationEventDetail } from './search-box'; import { SearchBox as searchBoxComponent } from './search-box'; export const SearchBox = reactWrapper(searchBoxComponent, { + tagName: 'search-box', events: { - onChange: 'change', - onNavigate: 'navigate', + onChange: 'change' as EventName>, + onNavigate: 'navigate' as EventName>, onOpenInView: 'openinview', }, }); diff --git a/yarn.lock b/yarn.lock index 3dd08feac8dad..54504cc6a5cde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,17 +42,17 @@ js-tokens "^4.0.0" "@babel/runtime-corejs2@^7.0.0": - version "7.23.1" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.23.1.tgz#f3a25c24d455be4e0309a56e56f0d2ef1a91c567" - integrity sha512-eY39r8IIgbcDfILJqsflwMImjccvK3QdgBRKo5v6lDPd5SiAsyfl3SJuAYWJ5hgbz7kfQmZ9ueirnhq0e9176Q== + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.23.2.tgz#a482c6e233fb2efa6456ce299da1b440b87260ed" + integrity sha512-lTwRWGcAUBANnxD0A4c5/wKQ0eLhgdAy9kdY2rzTmmliumBQ8u8awykMnaQAnZR3PC47jLRjGoj+hozZqy9Bww== dependencies: core-js "^2.6.12" regenerator-runtime "^0.14.0" "@babel/runtime@^7.1.2", "@babel/runtime@^7.21.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": - version "7.23.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" - integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g== + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" + integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== dependencies: regenerator-runtime "^0.14.0" @@ -239,7 +239,7 @@ "@gitkraken/shared-web-components@0.1.1-rc.15": version "0.1.1-rc.15" - resolved "https://registry.npmjs.org/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.15.tgz#efd520083a7f5a32fe342108f447e8c77723cfd2" + resolved "https://registry.yarnpkg.com/@gitkraken/shared-web-components/-/shared-web-components-0.1.1-rc.15.tgz#efd520083a7f5a32fe342108f447e8c77723cfd2" integrity sha512-BXGWoZoFzWftJC3BgEEPm/cU2qYasoGveGiG8oL8cWydl2TCkRCxddsiDswsMQaZDZIeTYLwbUPwA2PBeAAg4A== dependencies: "@floating-ui/dom" "^1.4.2" @@ -343,10 +343,11 @@ vary "^1.1.2" "@koa/router@^12.0.0": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@koa/router/-/router-12.0.0.tgz#2ae7937093fd392761c0e5833c368379d4a35737" - integrity sha512-cnnxeKHXlt7XARJptflGURdJaO+ITpNkOHmQu7NHmCoRinPbyvFzce/EG/E8Zy81yQ1W9MoSdtklc3nyaDReUw== + version "12.0.1" + resolved "https://registry.yarnpkg.com/@koa/router/-/router-12.0.1.tgz#1a66f92a630c02832cf5bbf0db06c9e53e423468" + integrity sha512-ribfPYfHb+Uw3b27Eiw6NPqjhIhTpVFzEWLwyc/1Xp+DCdwRRyIlAUODX+9bPARF6aQtUu1+/PHzdNvRzcs/+Q== dependencies: + debug "^4.3.4" http-errors "^2.0.0" koa-compose "^4.1.0" methods "^1.1.2" @@ -354,12 +355,17 @@ "@lit-labs/ssr-dom-shim@^1.1.2-pre.0": version "1.1.2" - resolved "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz#d693d972974a354034454ec1317eb6afd0b00312" + resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz#d693d972974a354034454ec1317eb6afd0b00312" integrity sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g== +"@lit/react@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@lit/react/-/react-1.0.0.tgz#1f5fc9b8d88cf6e7152653c7d67aa40456c095e6" + integrity sha512-uTuU6vpxtZvCWxcu3GNosckP2JpFWZpMKjhwQ42Bzu/OU9kjStJspA04o7RadecQfx0YiFIImX3qek15BXhaWQ== + "@lit/reactive-element@^2.0.0": version "2.0.0" - resolved "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.0.tgz#da14a256ac5533873b935840f306d572bac4a2ab" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.0.0.tgz#da14a256ac5533873b935840f306d572bac4a2ab" integrity sha512-wn+2+uDcs62ROBmVAwssO4x5xue/uKD3MGGZOXL2sMxReTRIT0JXKyMXeu7gh0aJ4IJNEIG/3aOnUaQvM7BMzQ== dependencies: "@lit-labs/ssr-dom-shim" "^1.1.2-pre.0" @@ -369,24 +375,16 @@ resolved "https://registry.yarnpkg.com/@microsoft/fast-element/-/fast-element-1.12.0.tgz#aabfc75518c3a9000710cce5f66dfc677de8c254" integrity sha512-gQutuDHPKNxUEcQ4pypZT4Wmrbapus+P9s3bR/SEOLsMbNqNoXigGImITygI5zhb+aA5rzflM6O8YWkmRbGkPA== -"@microsoft/fast-foundation@^2.38.0", "@microsoft/fast-foundation@^2.41.1", "@microsoft/fast-foundation@^2.49.1": - version "2.49.1" - resolved "https://registry.yarnpkg.com/@microsoft/fast-foundation/-/fast-foundation-2.49.1.tgz#f9cd36491d4d0080e694eaf0aece5672cdf7075a" - integrity sha512-dSajlZeX+lkqjg4108XbIIhVLECgJTCG32bE8P6rNgo8XCPHVJBDiBejrF34lv5pO9Z2uGORZjeip/N0fPib+g== +"@microsoft/fast-foundation@^2.38.0", "@microsoft/fast-foundation@^2.41.1": + version "2.49.2" + resolved "https://registry.yarnpkg.com/@microsoft/fast-foundation/-/fast-foundation-2.49.2.tgz#f310843038cd4b1dd6f64da1ac3ddba2a71b7a5e" + integrity sha512-xA7WP/Td33SW0zkpHRH5LUDxyLOPnPQQXieRxc080uLWxoGXhVxo6Rz7b6qwiL+e2IadNCm7X7KcrgsUhJwvBg== dependencies: "@microsoft/fast-element" "^1.12.0" "@microsoft/fast-web-utilities" "^5.4.1" tabbable "^5.2.0" tslib "^1.13.0" -"@microsoft/fast-react-wrapper@0.3.19": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.3.19.tgz#c1fda6d3c157bd9e28455c146068f668932d808e" - integrity sha512-Pe7z+3H2JYVFbz+CERAu/cf/6KkWboktfiP/Z/ZM0toPKiEaHUNycT+0sPZBWljOWxJiiGDX6+Dp6bw3GXCOvg== - dependencies: - "@microsoft/fast-element" "^1.12.0" - "@microsoft/fast-foundation" "^2.49.1" - "@microsoft/fast-react-wrapper@^0.1.18": version "0.1.48" resolved "https://registry.yarnpkg.com/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz#aa89c0dfb703c2f71619c536de2342e28b40b8c9" @@ -574,11 +572,11 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@playwright/browser-chromium@^1.38.1": - version "1.38.1" - resolved "https://registry.yarnpkg.com/@playwright/browser-chromium/-/browser-chromium-1.38.1.tgz#daf0ed3f7a8f9ad6ca731c73be3682b7cce8d5ff" - integrity sha512-HRhcBGtk1XaGAQjOben/04PNHxWAY3DBHT97egraR5lx5SQSLOREIiYu/j7WlvQBz4QJP+XL2JsvoxFBJfXmAw== + version "1.39.0" + resolved "https://registry.yarnpkg.com/@playwright/browser-chromium/-/browser-chromium-1.39.0.tgz#549ea67a4734e8a17d5d3fdeabcdcf1e02cffd84" + integrity sha512-s1WPO0qOE7PIZcdcJEd4CHQgXf9rOwy00Den8DsXTI26n/Eqa2HzFSbLRE1Eh2nIJZFSGyKLbopHR0HkT8ClZw== dependencies: - playwright-core "1.38.1" + playwright-core "1.39.0" "@polka/url@^1.0.0-next.20": version "1.0.0-next.23" @@ -626,9 +624,9 @@ "@types/estree" "*" "@types/eslint@*": - version "8.44.3" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.3.tgz#96614fae4875ea6328f56de38666f582d911d962" - integrity sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g== + version "8.44.4" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.4.tgz#28eaff82e1ca0a96554ec5bb0188f10ae1a74c2f" + integrity sha512-lOzjyfY/D9QR4hY9oblZ76B90MYTB3RrQ4z2vBIJKj9ROCRqdkYl2gSUx1x1a4IWPjKJZLL4Aw1Zfay7eMnmnA== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -696,9 +694,9 @@ integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== "@types/node@*": - version "20.8.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.4.tgz#0e9ebb2ff29d5c3302fc84477d066fa7c6b441aa" - integrity sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A== + version "20.8.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.6.tgz#0dbd4ebcc82ad0128df05d0e6f57e05359ee47fa" + integrity sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ== dependencies: undici-types "~5.25.1" @@ -729,10 +727,10 @@ dependencies: "@types/react" "^17" -"@types/react@17.0.67", "@types/react@^17": - version "17.0.67" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.67.tgz#1c224738f203829a4692aa48e33a732c34fd014a" - integrity sha512-zE76EIJ0Y58Oy9yDX/9csb/NuKjt0Eq2YgWb/8Wxo91YmuLzzbyiRoaqJE9h8iDlsT7n35GdpoLomHlaB1kFbg== +"@types/react@17.0.68", "@types/react@^17": + version "17.0.68" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.68.tgz#99b17f567e258f5e7be855a281ac67b49a34f9f2" + integrity sha512-y8heXejd/Gi43S28GOqIFmr6BzhLa3anMlPojRu4rHh3MtRrrpB+BtLEcqP3XPO1urXByzBdkOLU7sodYWnpkA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -875,10 +873,10 @@ jszip "^3.10.1" semver "^7.5.2" -"@vscode/test-web@0.0.46": - version "0.0.46" - resolved "https://registry.yarnpkg.com/@vscode/test-web/-/test-web-0.0.46.tgz#ad42bcaa5fbbf7929dcc629db6285fd7580753ad" - integrity sha512-s5rKDtCvIWN6kJpjXzBoWpLvftjH3m2r2MQNGUGsdY1+mOJ06lbbHeJn+g30+p0ec4Vh7PpBZGECflrRW+oH4Q== +"@vscode/test-web@0.0.47": + version "0.0.47" + resolved "https://registry.yarnpkg.com/@vscode/test-web/-/test-web-0.0.47.tgz#329abf815529c915e2acf6df8f87ffdaf682e33b" + integrity sha512-p1ym6+h30ecTLCrOcAlD7k3tq/AMVWzZjolbU3jcP0QJV0JSj9hp/Pnmfkrw8s2Xo5ywdbABSFSlNPUpZoicOA== dependencies: "@koa/cors" "^4.0.0" "@koa/router" "^12.0.0" @@ -1083,11 +1081,16 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -abbrev@1, abbrev@^1.0.0: +abbrev@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + accepts@^1.3.5: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -1605,9 +1608,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001547" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz#d4f92efc488aab3c7f92c738d3977c2a3180472b" - integrity sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA== + version "1.0.30001549" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz#7d1a3dce7ea78c06ed72c32c2743ea364b3615aa" + integrity sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA== capital-case@^1.0.4: version "1.0.4" @@ -2383,9 +2386,9 @@ deepmerge@^4.2.2: integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== define-data-property@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.0.tgz#0db13540704e1d8d479a0656cf781267531b9451" - integrity sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g== + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== dependencies: get-intrinsic "^1.2.1" gopd "^1.0.1" @@ -2588,9 +2591,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.535: - version "1.4.548" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.548.tgz#e695d769e0e801fa6d438b63f6bc9b80372000d6" - integrity sha512-R77KD6mXv37DOyKLN/eW1rGS61N6yHOfapNSX9w+y9DdPG83l9Gkuv7qkCFZ4Ta4JPhrjgQfYbv4Y3TnM1Hi2Q== + version "1.4.554" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz#04e09c2ee31dc0f1546174033809b54cc372740b" + integrity sha512-Q0umzPJjfBrrj8unkONTgbKQXzXRrH7sVV7D9ea2yBV3Oaogz991yhbpfvo2LMNkJItmruXTEzVpP9cp7vaIiQ== emoji-regex@^8.0.0: version "8.0.0" @@ -3236,9 +3239,9 @@ fork-ts-checker-webpack-plugin@6.5.3: tapable "^1.0.0" fraction.js@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d" - integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg== + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== fresh@~0.5.2: version "0.5.2" @@ -3295,9 +3298,9 @@ fsevents@~2.3.2: integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== function.prototype.name@^1.1.6: version "1.1.6" @@ -4389,16 +4392,16 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -license-checker-rseidelsohn@4.2.8: - version "4.2.8" - resolved "https://registry.yarnpkg.com/license-checker-rseidelsohn/-/license-checker-rseidelsohn-4.2.8.tgz#dba4ef59100df8e2fe1f99c3e12473b6f8d56525" - integrity sha512-WVnHC3iJff79mAp+IfAgiBwHXF2Oey/7/XugjTHRcTcufZMSpwky9a+1wyOOOe+0Z3Qo5XK1pVRfLAoOHLOGqA== +license-checker-rseidelsohn@4.2.10: + version "4.2.10" + resolved "https://registry.yarnpkg.com/license-checker-rseidelsohn/-/license-checker-rseidelsohn-4.2.10.tgz#2f08cdf5dd6abae8248359466e04b399294565a1" + integrity sha512-phvcph9WTQ/Kb209kqwLxVA6CV8BAeUnFMIo+I+wBlp74El4ngbMwq49qSqqPYC5bfj49EWBXqwjvTFswGE2Fg== dependencies: chalk "4.1.2" debug "^4.3.4" lodash.clonedeep "^4.5.0" mkdirp "^1.0.4" - nopt "^5.0.0" + nopt "^7.2.0" read-installed-packages "^2.0.1" semver "^7.3.5" spdx-correct "^3.1.1" @@ -4432,7 +4435,7 @@ linkify-it@^3.0.1: lit-element@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/lit-element/-/lit-element-4.0.0.tgz#8343891bc9159a5fcb7f534914b37f2c0161e036" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-4.0.0.tgz#8343891bc9159a5fcb7f534914b37f2c0161e036" integrity sha512-N6+f7XgusURHl69DUZU6sTBGlIN+9Ixfs3ykkNDfgfTkDYGGOWwHAYBhDqVswnFGyWgQYR2KiSpu4J76Kccs/A== dependencies: "@lit-labs/ssr-dom-shim" "^1.1.2-pre.0" @@ -4441,14 +4444,14 @@ lit-element@^4.0.0: lit-html@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lit-html/-/lit-html-3.0.0.tgz#77d6776ee488642c74c5575315ef81aa09d24ea9" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-3.0.0.tgz#77d6776ee488642c74c5575315ef81aa09d24ea9" integrity sha512-DNJIE8dNY0dQF2Gs0sdMNUppMQT2/CvV4OVnSdg7BXAsGqkVwsE5bqQ04POfkYH5dBIuGnJYdFz5fYYyNnOxiA== dependencies: "@types/trusted-types" "^2.0.2" lit@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lit/-/lit-3.0.0.tgz#204bd65935892a73670471e893ee8ca55d2f9a3b" + resolved "https://registry.yarnpkg.com/lit/-/lit-3.0.0.tgz#204bd65935892a73670471e893ee8ca55d2f9a3b" integrity sha512-nQ0teRzU1Kdj++VdmttS2WvIen8M79wChJ6guRKIIym2M3Ansg3Adj9O6yuQh2IpjxiUXlNuS81WKlQ4iL3BmA== dependencies: "@lit/reactive-element" "^2.0.0" @@ -4985,9 +4988,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-abi@^3.3.0: - version "3.48.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.48.0.tgz#122d132ae1ac097b0d711144560b17922de026ab" - integrity sha512-uWR/uwQyVV2iN5+Wkf1/oQxOR9YjU7gBclJLg2qK7GDvVohcnY6LaBXKV89N79EQFyN4/e43O32yQYE5QdFYTA== + version "3.50.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.50.0.tgz#bbee6943c8812d20e241539854d7b8003404d917" + integrity sha512-2Gxu7Eq7vnBIRfYSmqPruEllMM14FjOQFJSoqdGWthVn+tmwEXzmdPpya6cvvwf0uZA3F5N1fMFr9mijZBplFA== dependencies: semver "^7.3.5" @@ -5030,13 +5033,6 @@ node-releases@^2.0.13: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - nopt@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" @@ -5044,6 +5040,13 @@ nopt@^6.0.0: dependencies: abbrev "^1.0.0" +nopt@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== + dependencies: + abbrev "^2.0.0" + normalize-package-data@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" @@ -5102,9 +5105,9 @@ object-assign@^4.0.1, object-assign@^4.1.1: integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + version "1.13.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.0.tgz#42695d3879e1cd5bda6df5062164d80c996e23e2" + integrity sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g== object-keys@^1.1.1: version "1.1.1" @@ -5438,17 +5441,17 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -playwright-core@1.38.1: - version "1.38.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.38.1.tgz#75a3c470aa9576b7d7c4e274de3d79977448ba08" - integrity sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg== +playwright-core@1.39.0: + version "1.39.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.39.0.tgz#efeaea754af4fb170d11845b8da30b2323287c63" + integrity sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw== playwright@^1.38.1: - version "1.38.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.38.1.tgz#82ecd9bc4f4f64dbeee8a11c31793748e2528130" - integrity sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow== + version "1.39.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.39.0.tgz#184c81cd6478f8da28bcd9e60e94fcebf566e077" + integrity sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw== dependencies: - playwright-core "1.38.1" + playwright-core "1.39.0" optionalDependencies: fsevents "2.3.2" @@ -6148,9 +6151,9 @@ resolve-pkg-maps@^1.0.0: integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== resolve@^1.20.0, resolve@^1.22.4, resolve@^1.22.6, resolve@^1.3.3: - version "1.22.6" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" - integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" path-parse "^1.0.7" @@ -6240,10 +6243,10 @@ sass-loader@13.3.2: dependencies: neo-async "^2.6.2" -sass@1.69.1, sass@^1.7.3: - version "1.69.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.1.tgz#659b3b04452245dcf82f731684831e990ddb0c89" - integrity sha512-nc969GvTVz38oqKgYYVHM/Iq7Yl33IILy5uqaH2CWSiSUmRCvw+UR7tA3845Sp4BD5ykCUimvrT3k1EjTwpVUA== +sass@1.69.3, sass@^1.7.3: + version "1.69.3" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.3.tgz#f8a0c488697e6419519834a13335e7b65a609c11" + integrity sha512-X99+a2iGdXkdWn1akFPs0ZmelUzyAQfvqYc2P/MPTrJRuIRoTffGzT9W9nFqG00S+c8hXzVmgxhUuHFdrwxkhQ== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -6882,9 +6885,9 @@ terser-webpack-plugin@5.3.9, terser-webpack-plugin@^5.3.7: terser "^5.16.8" terser@^5.10.0, terser@^5.15.1, terser@^5.16.8: - version "5.21.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.21.0.tgz#d2b27e92b5e56650bc83b6defa00a110f0b124b2" - integrity sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw== + version "5.22.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.22.0.tgz#4f18103f84c5c9437aafb7a14918273310a8a49d" + integrity sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -7345,11 +7348,12 @@ webpack-cli@5.1.4: webpack-merge "^5.7.3" webpack-merge@^5.7.3: - version "5.9.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" - integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== dependencies: clone-deep "^4.0.1" + flat "^5.0.2" wildcard "^2.0.0" webpack-node-externals@3.0.0: @@ -7375,10 +7379,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.88.2: - version "5.88.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== +webpack@5.89.0: + version "5.89.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc" + integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" From e6b3c96738faddb5c1eb1a16c5226d11074965e4 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 16 Oct 2023 15:18:08 -0400 Subject: [PATCH 0057/1012] Adds `using` support & removes classes for parsers --- .../gutterBlameAnnotationProvider.ts | 2 +- .../gutterChangesAnnotationProvider.ts | 2 +- .../gutterHeatmapBlameAnnotationProvider.ts | 2 +- src/env/node/git/git.ts | 22 +- src/env/node/git/localGitProvider.ts | 90 +- src/git/models/diff.ts | 4 +- src/git/parsers/blameParser.ts | 381 ++++--- src/git/parsers/branchParser.ts | 119 ++- src/git/parsers/diffParser.ts | 34 +- src/git/parsers/logParser.ts | 979 +++++++++--------- src/git/parsers/reflogParser.ts | 219 ++-- src/git/parsers/remoteParser.ts | 121 ++- src/git/parsers/statusParser.ts | 234 ++--- src/git/parsers/tagParser.ts | 101 +- src/git/parsers/treeParser.ts | 67 +- src/git/parsers/worktreeParser.ts | 149 ++- src/system/stopwatch.ts | 66 +- src/webviews/apps/tsconfig.json | 2 +- tsconfig.base.json | 2 +- tsconfig.browser.json | 2 +- 20 files changed, 1272 insertions(+), 1326 deletions(-) diff --git a/src/annotations/gutterBlameAnnotationProvider.ts b/src/annotations/gutterBlameAnnotationProvider.ts index f1e4c06c685e2..b5496f17ca83c 100644 --- a/src/annotations/gutterBlameAnnotationProvider.ts +++ b/src/annotations/gutterBlameAnnotationProvider.ts @@ -48,7 +48,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase { const blame = await this.getBlame(); if (blame == null) return false; - const sw = maybeStopWatch(scope); + using sw = maybeStopWatch(scope); const cfg = configuration.get('blame'); diff --git a/src/annotations/gutterChangesAnnotationProvider.ts b/src/annotations/gutterChangesAnnotationProvider.ts index 6539b0b60149e..e92ed53f18409 100644 --- a/src/annotations/gutterChangesAnnotationProvider.ts +++ b/src/annotations/gutterChangesAnnotationProvider.ts @@ -156,7 +156,7 @@ export class GutterChangesAnnotationProvider extends AnnotationProviderBase(d?: T): d is T => Boolean(d)); if (!diffs?.length) return false; - const sw = maybeStopWatch(scope); + using sw = maybeStopWatch(scope); const decorationsMap = new Map< string, diff --git a/src/annotations/gutterHeatmapBlameAnnotationProvider.ts b/src/annotations/gutterHeatmapBlameAnnotationProvider.ts index 09e6881b03998..d6d9a21bf1d2d 100644 --- a/src/annotations/gutterHeatmapBlameAnnotationProvider.ts +++ b/src/annotations/gutterHeatmapBlameAnnotationProvider.ts @@ -26,7 +26,7 @@ export class GutterHeatmapBlameAnnotationProvider extends BlameAnnotationProvide const blame = await this.getBlame(); if (blame == null) return false; - const sw = maybeStopWatch(scope); + using sw = maybeStopWatch(scope); const decorationsMap = new Map< string, diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index e6caf421e4a08..8d93a4e47add1 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -24,11 +24,11 @@ import type { GitDir } from '../../../git/gitProvider'; import type { GitDiffFilter } from '../../../git/models/diff'; import { isUncommitted, isUncommittedStaged, shortenRevision } from '../../../git/models/reference'; import type { GitUser } from '../../../git/models/user'; -import { GitBranchParser } from '../../../git/parsers/branchParser'; -import { GitLogParser } from '../../../git/parsers/logParser'; -import { GitReflogParser } from '../../../git/parsers/reflogParser'; +import { parseGitBranchesDefaultFormat } from '../../../git/parsers/branchParser'; +import { parseGitLogAllFormat, parseGitLogDefaultFormat } from '../../../git/parsers/logParser'; +import { parseGitRefLogDefaultFormat } from '../../../git/parsers/reflogParser'; import { parseGitRemoteUrl } from '../../../git/parsers/remoteParser'; -import { GitTagParser } from '../../../git/parsers/tagParser'; +import { parseGitTagsDefaultFormat } from '../../../git/parsers/tagParser'; import { splitAt } from '../../../system/array'; import { configuration } from '../../../system/configuration'; import { log } from '../../../system/decorators/log'; @@ -1011,7 +1011,7 @@ export class Git { } for_each_ref__branch(repoPath: string, options: { all: boolean } = { all: false }) { - const params = ['for-each-ref', `--format=${GitBranchParser.defaultFormat}`, 'refs/heads']; + const params = ['for-each-ref', `--format=${parseGitBranchesDefaultFormat}`, 'refs/heads']; if (options.all) { params.push('refs/remotes'); } @@ -1045,7 +1045,7 @@ export class Git { }, ) { if (argsOrFormat == null) { - argsOrFormat = ['--name-status', `--format=${all ? GitLogParser.allFormat : GitLogParser.defaultFormat}`]; + argsOrFormat = ['--name-status', `--format=${all ? parseGitLogAllFormat : parseGitLogDefaultFormat}`]; } if (typeof argsOrFormat === 'string') { @@ -1242,7 +1242,7 @@ export class Git { const [file, root] = splitPath(fileName, repoPath, true); if (argsOrFormat == null) { - argsOrFormat = [`--format=${all ? GitLogParser.allFormat : GitLogParser.defaultFormat}`]; + argsOrFormat = [`--format=${all ? parseGitLogAllFormat : parseGitLogDefaultFormat}`]; } if (typeof argsOrFormat === 'string') { @@ -1438,7 +1438,7 @@ export class Git { 'show', '--stdin', '--name-status', - `--format=${GitLogParser.defaultFormat}`, + `--format=${parseGitLogDefaultFormat}`, '--use-mailmap', ); } @@ -1451,7 +1451,7 @@ export class Git { 'log', ...(options?.stdin ? ['--stdin'] : emptyArray), '--name-status', - `--format=${GitLogParser.defaultFormat}`, + `--format=${parseGitLogDefaultFormat}`, '--use-mailmap', ...search, ...(options?.ordering ? [`--${options.ordering}-order`] : emptyArray), @@ -1542,7 +1542,7 @@ export class Git { skip?: number; } = {}, ): Promise { - const params = ['log', '--walk-reflogs', `--format=${GitReflogParser.defaultFormat}`, '--date=iso8601']; + const params = ['log', '--walk-reflogs', `--format=${parseGitRefLogDefaultFormat}`, '--date=iso8601']; if (ordering) { params.push(`--${ordering}-order`); @@ -2139,7 +2139,7 @@ export class Git { } tag(repoPath: string) { - return this.git({ cwd: repoPath }, 'tag', '-l', `--format=${GitTagParser.defaultFormat}`); + return this.git({ cwd: repoPath }, 'tag', '-l', `--format=${parseGitTagsDefaultFormat}`); } worktree__add( diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index c3509b96a14d6..af4da178d8d12 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -108,9 +108,9 @@ import type { GitTreeEntry } from '../../../git/models/tree'; import type { GitUser } from '../../../git/models/user'; import { isUserMatch } from '../../../git/models/user'; import type { GitWorktree } from '../../../git/models/worktree'; -import { GitBlameParser } from '../../../git/parsers/blameParser'; -import { GitBranchParser } from '../../../git/parsers/branchParser'; -import { parseDiffNameStatusFiles, parseDiffShortStat, parseFileDiff } from '../../../git/parsers/diffParser'; +import { parseGitBlame } from '../../../git/parsers/blameParser'; +import { parseGitBranches } from '../../../git/parsers/branchParser'; +import { parseGitDiffNameStatusFiles, parseGitDiffShortStat, parseGitFileDiff } from '../../../git/parsers/diffParser'; import { createLogParserSingle, createLogParserWithFiles, @@ -119,15 +119,20 @@ import { getGraphStatsParser, getRefAndDateParser, getRefParser, - GitLogParser, LogType, + parseGitLog, + parseGitLogAllFormat, + parseGitLogDefaultFormat, + parseGitLogSimple, + parseGitLogSimpleFormat, + parseGitLogSimpleRenamed, } from '../../../git/parsers/logParser'; -import { GitReflogParser } from '../../../git/parsers/reflogParser'; -import { GitRemoteParser } from '../../../git/parsers/remoteParser'; -import { GitStatusParser } from '../../../git/parsers/statusParser'; -import { GitTagParser } from '../../../git/parsers/tagParser'; -import { GitTreeParser } from '../../../git/parsers/treeParser'; -import { GitWorktreeParser } from '../../../git/parsers/worktreeParser'; +import { parseGitRefLog } from '../../../git/parsers/reflogParser'; +import { parseGitRemotes } from '../../../git/parsers/remoteParser'; +import { parseGitStatus } from '../../../git/parsers/statusParser'; +import { parseGitTags } from '../../../git/parsers/tagParser'; +import { parseGitTree } from '../../../git/parsers/treeParser'; +import { parseGitWorktrees } from '../../../git/parsers/worktreeParser'; import { getRemoteProviderMatcher, loadRemoteProviders } from '../../../git/remotes/remoteProviders'; import type { GitSearch, GitSearchResultData, GitSearchResults, SearchQuery } from '../../../git/search'; import { getGitArgsFromSearchQuery, getSearchQueryComparisonKey } from '../../../git/search'; @@ -954,7 +959,7 @@ export class LocalGitProvider implements GitProvider, Disposable { // Now check if that commit had any renames data = await this.git.log__file(repoPath, '.', ref, { - argsOrFormat: GitLogParser.simpleFormat, + argsOrFormat: parseGitLogSimpleFormat, fileMode: 'simple', filters: ['R', 'C', 'D'], limit: 1, @@ -962,7 +967,7 @@ export class LocalGitProvider implements GitProvider, Disposable { }); if (data == null || data.length === 0) break; - const [foundRef, foundFile, foundStatus] = GitLogParser.parseSimpleRenamed(data, relativePath); + const [foundRef, foundFile, foundStatus] = parseGitLogSimpleRenamed(data, relativePath); if (foundStatus === 'D' && foundFile != null) return undefined; if (foundRef == null || foundFile == null) break; @@ -1455,7 +1460,7 @@ export class LocalGitProvider implements GitProvider, Disposable { args: configuration.get('advanced.blame.customArguments'), ignoreWhitespace: configuration.get('blame.ignoreWhitespace'), }); - const blame = GitBlameParser.parse(this.container, data, root, await this.getCurrentUser(root)); + const blame = parseGitBlame(this.container, data, root, await this.getCurrentUser(root)); return blame; } catch (ex) { // Trap and cache expected blame errors @@ -1536,7 +1541,7 @@ export class LocalGitProvider implements GitProvider, Disposable { correlationKey: `:${key}`, ignoreWhitespace: configuration.get('blame.ignoreWhitespace'), }); - const blame = GitBlameParser.parse(this.container, data, root, await this.getCurrentUser(root)); + const blame = parseGitBlame(this.container, data, root, await this.getCurrentUser(root)); return blame; } catch (ex) { // Trap and cache expected blame errors @@ -1601,7 +1606,7 @@ export class LocalGitProvider implements GitProvider, Disposable { startLine: lineToBlame, endLine: lineToBlame, }); - const blame = GitBlameParser.parse(this.container, data, root, await this.getCurrentUser(root)); + const blame = parseGitBlame(this.container, data, root, await this.getCurrentUser(root)); if (blame == null) return undefined; return { @@ -1652,7 +1657,7 @@ export class LocalGitProvider implements GitProvider, Disposable { startLine: lineToBlame, endLine: lineToBlame, }); - const blame = GitBlameParser.parse(this.container, data, root, await this.getCurrentUser(root)); + const blame = parseGitBlame(this.container, data, root, await this.getCurrentUser(root)); if (blame == null) return undefined; return { @@ -1819,7 +1824,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return current != null ? { values: [current] } : emptyPagedResult; } - return { values: GitBranchParser.parse(this.container, data, repoPath!) }; + return { values: parseGitBranches(this.container, data, repoPath!) }; } catch (ex) { this._branchesCache.delete(repoPath!); @@ -1856,7 +1861,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const data = await this.git.diff__shortstat(repoPath, ref); if (!data) return undefined; - return parseDiffShortStat(data); + return parseGitDiffShortStat(data); } @log() @@ -2752,7 +2757,7 @@ export class LocalGitProvider implements GitProvider, Disposable { similarityThreshold: configuration.get('advanced.similarityThreshold'), }); - const diff = parseFileDiff(data); + const diff = parseGitFileDiff(data); return diff; } catch (ex) { // Trap and cache expected diff errors @@ -2839,7 +2844,7 @@ export class LocalGitProvider implements GitProvider, Disposable { similarityThreshold: configuration.get('advanced.similarityThreshold'), }); - const diff = parseFileDiff(data); + const diff = parseGitFileDiff(data); return diff; } catch (ex) { // Trap and cache expected diff errors @@ -2895,7 +2900,7 @@ export class LocalGitProvider implements GitProvider, Disposable { }); if (!data) return undefined; - const files = parseDiffNameStatusFiles(data, repoPath); + const files = parseGitDiffNameStatusFiles(data, repoPath); return files == null || files.length === 0 ? undefined : files; } catch (ex) { return undefined; @@ -2911,7 +2916,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const data = await this.git.show__name_status(root, relativePath, ref); if (!data) return undefined; - const files = parseDiffNameStatusFiles(data, repoPath); + const files = parseGitDiffNameStatusFiles(data, repoPath); if (files == null || files.length === 0) return undefined; return files[0]; @@ -2986,7 +2991,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const similarityThreshold = configuration.get('advanced.similarityThreshold'); const args = [ - `--format=${options?.all ? GitLogParser.allFormat : GitLogParser.defaultFormat}`, + `--format=${options?.all ? parseGitLogAllFormat : parseGitLogDefaultFormat}`, `-M${similarityThreshold == null ? '' : `${similarityThreshold}%`}`, '-m', ]; @@ -3076,7 +3081,7 @@ export class LocalGitProvider implements GitProvider, Disposable { // ); // } - const log = GitLogParser.parse( + const log = parseGitLog( this.container, data, LogType.Log, @@ -3461,7 +3466,7 @@ export class LocalGitProvider implements GitProvider, Disposable { startLine: range == null ? undefined : range.start.line + 1, endLine: range == null ? undefined : range.end.line + 1, }); - const log = GitLogParser.parse( + const log = parseGitLog( this.container, data, // If this is the log of a folder, parse it as a normal log rather than a file log @@ -3815,7 +3820,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const relativePath = this.getRelativePath(uri, repoPath); let data = await this.git.log__file(repoPath, relativePath, ref, { - argsOrFormat: GitLogParser.simpleFormat, + argsOrFormat: parseGitLogSimpleFormat, fileMode: 'simple', filters: filters, limit: skip + 1, @@ -3825,11 +3830,11 @@ export class LocalGitProvider implements GitProvider, Disposable { }); if (data == null || data.length === 0) return undefined; - const [nextRef, file, status] = GitLogParser.parseSimple(data, skip); + const [nextRef, file, status] = parseGitLogSimple(data, skip); // If the file was deleted, check for a possible rename if (status === 'D') { data = await this.git.log__file(repoPath, '.', nextRef, { - argsOrFormat: GitLogParser.simpleFormat, + argsOrFormat: parseGitLogSimpleFormat, fileMode: 'simple', filters: ['R', 'C'], limit: 1, @@ -3840,7 +3845,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return GitUri.fromFile(file ?? relativePath, repoPath, nextRef); } - const [nextRenamedRef, renamedFile] = GitLogParser.parseSimpleRenamed(data, file ?? relativePath); + const [nextRenamedRef, renamedFile] = parseGitLogSimpleRenamed(data, file ?? relativePath); return GitUri.fromFile( renamedFile ?? file ?? relativePath, repoPath, @@ -4085,7 +4090,7 @@ export class LocalGitProvider implements GitProvider, Disposable { let data; try { data = await this.git.log__file(repoPath, relativePath, ref, { - argsOrFormat: GitLogParser.simpleFormat, + argsOrFormat: parseGitLogSimpleFormat, fileMode: 'simple', limit: skip + 2, ordering: configuration.get('advanced.commitOrdering'), @@ -4113,7 +4118,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } if (data == null || data.length === 0) return undefined; - const [previousRef, file] = GitLogParser.parseSimple(data, skip, ref); + const [previousRef, file] = parseGitLogSimple(data, skip, ref); // If the previous ref matches the ref we asked for assume we are at the end of the history if (ref != null && ref === previousRef) return undefined; @@ -4143,7 +4148,7 @@ export class LocalGitProvider implements GitProvider, Disposable { }); if (data == null) return undefined; - const reflog = GitReflogParser.parse(data, repoPath, reflogCommands, limit, limit * 100); + const reflog = parseGitRefLog(data, repoPath, reflogCommands, limit, limit * 100); if (reflog?.hasMore) { reflog.more = this.getReflogMoreFn(reflog, options); } @@ -4209,13 +4214,11 @@ export class LocalGitProvider implements GitProvider, Disposable { try { const data = await this.git.remote(repoPath!); - const remotes = GitRemoteParser.parse( + const remotes = parseGitRemotes( data, repoPath!, getRemoteProviderMatcher(this.container, providers), ); - if (remotes == null) return []; - return remotes; } catch (ex) { this._remotesCache.delete(repoPath!); @@ -4341,7 +4344,7 @@ export class LocalGitProvider implements GitProvider, Disposable { similarityThreshold: configuration.get('advanced.similarityThreshold'), }); - const status = GitStatusParser.parse(data, root, porcelainVersion); + const status = parseGitStatus(data, root, porcelainVersion); return status?.files?.[0]; } @@ -4355,7 +4358,7 @@ export class LocalGitProvider implements GitProvider, Disposable { similarityThreshold: configuration.get('advanced.similarityThreshold'), }); - const status = GitStatusParser.parse(data, root, porcelainVersion); + const status = parseGitStatus(data, root, porcelainVersion); return status?.files ?? []; } @@ -4368,7 +4371,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const data = await this.git.status(repoPath, porcelainVersion, { similarityThreshold: configuration.get('advanced.similarityThreshold'), }); - const status = GitStatusParser.parse(data, repoPath, porcelainVersion); + const status = parseGitStatus(data, repoPath, porcelainVersion); if (status?.detached) { const rebaseStatus = await this.getRebaseStatus(repoPath); @@ -4399,7 +4402,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async function load(this: LocalGitProvider): Promise> { try { const data = await this.git.tag(repoPath!); - return { values: GitTagParser.parse(data, repoPath!) ?? [] }; + return { values: parseGitTags(data, repoPath!) }; } catch (ex) { this._tagsCache.delete(repoPath!); @@ -4436,8 +4439,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const [relativePath, root] = splitPath(path, repoPath); const data = await this.git.ls_tree(root, ref, relativePath); - const trees = GitTreeParser.parse(data); - return trees?.length ? trees[0] : undefined; + return parseGitTree(data)[0]; } @log() @@ -4445,7 +4447,7 @@ export class LocalGitProvider implements GitProvider, Disposable { if (repoPath == null) return []; const data = await this.git.ls_tree(repoPath, ref); - return GitTreeParser.parse(data) ?? []; + return parseGitTree(data); } @log({ args: { 1: false } }) @@ -4811,7 +4813,7 @@ export class LocalGitProvider implements GitProvider, Disposable { shas: shas, stdin: stdin, }); - const log = GitLogParser.parse( + const log = parseGitLog( this.container, data, LogType.Log, @@ -5212,7 +5214,7 @@ export class LocalGitProvider implements GitProvider, Disposable { ); const data = await this.git.worktree__list(repoPath); - return GitWorktreeParser.parse(data, repoPath); + return parseGitWorktrees(data, repoPath); } // eslint-disable-next-line @typescript-eslint/require-await diff --git a/src/git/models/diff.ts b/src/git/models/diff.ts index 7b202d8a38ac4..fa770c8b33444 100644 --- a/src/git/models/diff.ts +++ b/src/git/models/diff.ts @@ -1,4 +1,4 @@ -import { parseDiffHunk } from '../parsers/diffParser'; +import { parseGitDiffHunk } from '../parsers/diffParser'; export interface GitDiffLine { line: string; @@ -35,7 +35,7 @@ export class GitDiffHunk { private parsedHunk: { lines: GitDiffHunkLine[]; state: 'added' | 'changed' | 'removed' } | undefined; private parseHunk() { if (this.parsedHunk == null) { - this.parsedHunk = parseDiffHunk(this); + this.parsedHunk = parseGitDiffHunk(this); } return this.parsedHunk; } diff --git a/src/git/parsers/blameParser.ts b/src/git/parsers/blameParser.ts index b673a078674ec..60d4d69193f8b 100644 --- a/src/git/parsers/blameParser.ts +++ b/src/git/parsers/blameParser.ts @@ -1,5 +1,5 @@ import type { Container } from '../../container'; -import { debug } from '../../system/decorators/log'; +import { maybeStopWatch } from '../../system/stopwatch'; import { getLines } from '../../system/string'; import type { GitBlame, GitBlameAuthor } from '../models/blame'; import type { GitCommitLine } from '../models/commit'; @@ -34,228 +34,223 @@ interface BlameEntry { summary?: string; } -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitBlameParser { - @debug({ args: false, singleLine: true }) - static parse( - container: Container, - data: string, - repoPath: string, - currentUser: GitUser | undefined, - ): GitBlame | undefined { - if (!data) return undefined; - - const authors = new Map(); - const commits = new Map(); - const lines: GitCommitLine[] = []; - - let entry: BlameEntry | undefined = undefined; - let key: string; - let line: string; - let lineParts: string[]; - - for (line of getLines(data)) { - lineParts = line.split(' '); - if (lineParts.length < 2) continue; - - [key] = lineParts; - if (entry == null) { - entry = { - sha: key, - originalLine: parseInt(lineParts[1], 10), - line: parseInt(lineParts[2], 10), - lineCount: parseInt(lineParts[3], 10), - } as unknown as BlameEntry; - - continue; - } +export function parseGitBlame( + container: Container, + data: string, + repoPath: string, + currentUser: GitUser | undefined, +): GitBlame | undefined { + using sw = maybeStopWatch(`Git.parseBlame(${repoPath})`, { log: false, logLevel: 'debug' }); + if (!data) return undefined; + + const authors = new Map(); + const commits = new Map(); + const lines: GitCommitLine[] = []; + + let entry: BlameEntry | undefined = undefined; + let key: string; + let line: string; + let lineParts: string[]; + + for (line of getLines(data)) { + lineParts = line.split(' '); + if (lineParts.length < 2) continue; + + [key] = lineParts; + if (entry == null) { + entry = { + sha: key, + originalLine: parseInt(lineParts[1], 10), + line: parseInt(lineParts[2], 10), + lineCount: parseInt(lineParts[3], 10), + } as unknown as BlameEntry; + + continue; + } - switch (key) { - case 'author': - if (entry.sha === uncommitted) { - entry.author = 'You'; - } else { - entry.author = line.slice(key.length + 1).trim(); - } - break; + switch (key) { + case 'author': + if (entry.sha === uncommitted) { + entry.author = 'You'; + } else { + entry.author = line.slice(key.length + 1).trim(); + } + break; - case 'author-mail': { - if (entry.sha === uncommitted) { - entry.authorEmail = currentUser?.email; - continue; - } + case 'author-mail': { + if (entry.sha === uncommitted) { + entry.authorEmail = currentUser?.email; + continue; + } - entry.authorEmail = line.slice(key.length + 1).trim(); - const start = entry.authorEmail.indexOf('<'); - if (start >= 0) { - const end = entry.authorEmail.indexOf('>', start); - if (end > start) { - entry.authorEmail = entry.authorEmail.substring(start + 1, end); - } else { - entry.authorEmail = entry.authorEmail.substring(start + 1); - } + entry.authorEmail = line.slice(key.length + 1).trim(); + const start = entry.authorEmail.indexOf('<'); + if (start >= 0) { + const end = entry.authorEmail.indexOf('>', start); + if (end > start) { + entry.authorEmail = entry.authorEmail.substring(start + 1, end); + } else { + entry.authorEmail = entry.authorEmail.substring(start + 1); } + } - break; + break; + } + case 'author-time': + entry.authorDate = lineParts[1]; + break; + + case 'author-tz': + entry.authorTimeZone = lineParts[1]; + break; + + case 'committer': + if (isUncommitted(entry.sha)) { + entry.committer = 'You'; + } else { + entry.committer = line.slice(key.length + 1).trim(); } - case 'author-time': - entry.authorDate = lineParts[1]; - break; + break; - case 'author-tz': - entry.authorTimeZone = lineParts[1]; - break; + case 'committer-mail': { + if (isUncommitted(entry.sha)) { + entry.committerEmail = currentUser?.email; + continue; + } - case 'committer': - if (isUncommitted(entry.sha)) { - entry.committer = 'You'; + entry.committerEmail = line.slice(key.length + 1).trim(); + const start = entry.committerEmail.indexOf('<'); + if (start >= 0) { + const end = entry.committerEmail.indexOf('>', start); + if (end > start) { + entry.committerEmail = entry.committerEmail.substring(start + 1, end); } else { - entry.committer = line.slice(key.length + 1).trim(); - } - break; - - case 'committer-mail': { - if (isUncommitted(entry.sha)) { - entry.committerEmail = currentUser?.email; - continue; + entry.committerEmail = entry.committerEmail.substring(start + 1); } - - entry.committerEmail = line.slice(key.length + 1).trim(); - const start = entry.committerEmail.indexOf('<'); - if (start >= 0) { - const end = entry.committerEmail.indexOf('>', start); - if (end > start) { - entry.committerEmail = entry.committerEmail.substring(start + 1, end); - } else { - entry.committerEmail = entry.committerEmail.substring(start + 1); - } - } - - break; } - case 'committer-time': - entry.committerDate = lineParts[1]; - break; - case 'committer-tz': - entry.committerTimeZone = lineParts[1]; - break; + break; + } + case 'committer-time': + entry.committerDate = lineParts[1]; + break; + + case 'committer-tz': + entry.committerTimeZone = lineParts[1]; + break; - case 'summary': - entry.summary = line.slice(key.length + 1).trim(); - break; + case 'summary': + entry.summary = line.slice(key.length + 1).trim(); + break; - case 'previous': - entry.previousSha = lineParts[1]; - entry.previousPath = lineParts.slice(2).join(' '); - break; + case 'previous': + entry.previousSha = lineParts[1]; + entry.previousPath = lineParts.slice(2).join(' '); + break; - case 'filename': - // Don't trim to allow spaces in the filename - entry.path = line.slice(key.length + 1); + case 'filename': + // Don't trim to allow spaces in the filename + entry.path = line.slice(key.length + 1); - // Since the filename marks the end of a commit, parse the entry and clear it for the next - GitBlameParser.parseEntry(container, entry, repoPath, commits, authors, lines, currentUser); + // Since the filename marks the end of a commit, parse the entry and clear it for the next + parseBlameEntry(container, entry, repoPath, commits, authors, lines, currentUser); - entry = undefined; - break; + entry = undefined; + break; - default: - break; - } + default: + break; } + } - for (const [, c] of commits) { - if (!c.author.name) continue; + for (const [, c] of commits) { + if (!c.author.name) continue; - const author = authors.get(c.author.name); - if (author == undefined) return undefined; + const author = authors.get(c.author.name); + if (author == undefined) return undefined; - author.lineCount += c.lines.length; - } + author.lineCount += c.lines.length; + } - const sortedAuthors = new Map([...authors.entries()].sort((a, b) => b[1].lineCount - a[1].lineCount)); + const sortedAuthors = new Map([...authors.entries()].sort((a, b) => b[1].lineCount - a[1].lineCount)); - const blame: GitBlame = { - repoPath: repoPath, - authors: sortedAuthors, - commits: commits, - lines: lines, - }; - return blame; - } + sw?.stop({ suffix: ` parsed ${lines.length} lines, ${commits.size} commits` }); - private static parseEntry( - container: Container, - entry: BlameEntry, - repoPath: string, - commits: Map, - authors: Map, - lines: GitCommitLine[], - currentUser: { name?: string; email?: string } | undefined, - ) { - let commit = commits.get(entry.sha); - if (commit == null) { - if (entry.author != null) { - if ( - currentUser != null && - // Name or e-mail is configured - (currentUser.name != null || currentUser.email != null) && - // Match on name if configured - (currentUser.name == null || currentUser.name === entry.author) && - // Match on email if configured - (currentUser.email == null || currentUser.email === entry.authorEmail) - ) { - entry.author = 'You'; - } + const blame: GitBlame = { + repoPath: repoPath, + authors: sortedAuthors, + commits: commits, + lines: lines, + }; + return blame; +} - let author = authors.get(entry.author); - if (author == null) { - author = { - name: entry.author, - lineCount: 0, - }; - authors.set(entry.author, author); - } +function parseBlameEntry( + container: Container, + entry: BlameEntry, + repoPath: string, + commits: Map, + authors: Map, + lines: GitCommitLine[], + currentUser: { name?: string; email?: string } | undefined, +) { + let commit = commits.get(entry.sha); + if (commit == null) { + if (entry.author != null) { + if ( + currentUser != null && + // Name or e-mail is configured + (currentUser.name != null || currentUser.email != null) && + // Match on name if configured + (currentUser.name == null || currentUser.name === entry.author) && + // Match on email if configured + (currentUser.email == null || currentUser.email === entry.authorEmail) + ) { + entry.author = 'You'; } - commit = new GitCommit( - container, - repoPath, - entry.sha, - new GitCommitIdentity(entry.author, entry.authorEmail, new Date((entry.authorDate as any) * 1000)), - new GitCommitIdentity( - entry.committer, - entry.committerEmail, - new Date((entry.committerDate as any) * 1000), - ), - entry.summary!, - [], - undefined, - new GitFileChange( - repoPath, - entry.path, - GitFileIndexStatus.Modified, - entry.previousPath && entry.previousPath !== entry.path ? entry.previousPath : undefined, - entry.previousSha, - ), - undefined, - [], - ); - - commits.set(entry.sha, commit); + let author = authors.get(entry.author); + if (author == null) { + author = { + name: entry.author, + lineCount: 0, + }; + authors.set(entry.author, author); + } } - for (let i = 0, len = entry.lineCount; i < len; i++) { - const line: GitCommitLine = { - sha: entry.sha, - previousSha: commit.file!.previousSha, - originalLine: entry.originalLine + i, - line: entry.line + i, - }; + commit = new GitCommit( + container, + repoPath, + entry.sha, + new GitCommitIdentity(entry.author, entry.authorEmail, new Date((entry.authorDate as any) * 1000)), + new GitCommitIdentity(entry.committer, entry.committerEmail, new Date((entry.committerDate as any) * 1000)), + entry.summary!, + [], + undefined, + new GitFileChange( + repoPath, + entry.path, + GitFileIndexStatus.Modified, + entry.previousPath && entry.previousPath !== entry.path ? entry.previousPath : undefined, + entry.previousSha, + ), + undefined, + [], + ); + + commits.set(entry.sha, commit); + } - commit.lines.push(line); - lines[line.line - 1] = line; - } + for (let i = 0, len = entry.lineCount; i < len; i++) { + const line: GitCommitLine = { + sha: entry.sha, + previousSha: commit.file!.previousSha, + originalLine: entry.originalLine + i, + line: entry.line + i, + }; + + commit.lines.push(line); + lines[line.line - 1] = line; } } diff --git a/src/git/parsers/branchParser.ts b/src/git/parsers/branchParser.ts index 96bc889c90688..ffb1199a1b9d6 100644 --- a/src/git/parsers/branchParser.ts +++ b/src/git/parsers/branchParser.ts @@ -1,5 +1,5 @@ import type { Container } from '../../container'; -import { debug } from '../../system/decorators/log'; +import { maybeStopWatch } from '../../system/stopwatch'; import { GitBranch } from '../models/branch'; const branchWithTrackingRegex = @@ -9,73 +9,72 @@ const branchWithTrackingRegex = const lb = '%3c'; // `%${'<'.charCodeAt(0).toString(16)}`; const rb = '%3e'; // `%${'>'.charCodeAt(0).toString(16)}`; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitBranchParser { - static defaultFormat = [ - `${lb}h${rb}%(HEAD)`, // HEAD indicator - `${lb}n${rb}%(refname)`, // branch name - `${lb}u${rb}%(upstream:short)`, // branch upstream - `${lb}t${rb}%(upstream:track)`, // branch upstream tracking state - `${lb}r${rb}%(objectname)`, // ref - `${lb}d${rb}%(committerdate:iso8601)`, // committer date - ].join(''); +export const parseGitBranchesDefaultFormat = [ + `${lb}h${rb}%(HEAD)`, // HEAD indicator + `${lb}n${rb}%(refname)`, // branch name + `${lb}u${rb}%(upstream:short)`, // branch upstream + `${lb}t${rb}%(upstream:track)`, // branch upstream tracking state + `${lb}r${rb}%(objectname)`, // ref + `${lb}d${rb}%(committerdate:iso8601)`, // committer date +].join(''); - @debug({ args: false, singleLine: true }) - static parse(container: Container, data: string, repoPath: string): GitBranch[] { - const branches: GitBranch[] = []; +export function parseGitBranches(container: Container, data: string, repoPath: string): GitBranch[] { + using sw = maybeStopWatch(`Git.parseBranches(${repoPath})`, { log: false, logLevel: 'debug' }); - if (!data) return branches; + const branches: GitBranch[] = []; + if (!data) return branches; - let current; - let name; - let upstream; - let ahead; - let behind; - let missing; - let ref; - let date; + let current; + let name; + let upstream; + let ahead; + let behind; + let missing; + let ref; + let date; - let remote; + let remote; - let match; - do { - match = branchWithTrackingRegex.exec(data); - if (match == null) break; + let match; + do { + match = branchWithTrackingRegex.exec(data); + if (match == null) break; - [, current, name, upstream, ahead, behind, missing, ref, date] = match; + [, current, name, upstream, ahead, behind, missing, ref, date] = match; - if (name.startsWith('refs/remotes/')) { - // Strip off refs/remotes/ - name = name.substr(13); - if (name.endsWith('/HEAD')) continue; + if (name.startsWith('refs/remotes/')) { + // Strip off refs/remotes/ + name = name.substr(13); + if (name.endsWith('/HEAD')) continue; - remote = true; - } else { - // Strip off refs/heads/ - name = name.substr(11); - remote = false; - } + remote = true; + } else { + // Strip off refs/heads/ + name = name.substr(11); + remote = false; + } - branches.push( - new GitBranch( - container, - repoPath, - name, - remote, - current.charCodeAt(0) === 42, // '*', - date ? new Date(date) : undefined, - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - ref == null || ref.length === 0 ? undefined : ` ${ref}`.substr(1), - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - upstream == null || upstream.length === 0 - ? undefined - : { name: ` ${upstream}`.substr(1), missing: Boolean(missing) }, - Number(ahead) || 0, - Number(behind) || 0, - ), - ); - } while (true); + branches.push( + new GitBranch( + container, + repoPath, + name, + remote, + current.charCodeAt(0) === 42, // '*', + date ? new Date(date) : undefined, + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + ref == null || ref.length === 0 ? undefined : ` ${ref}`.substr(1), + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + upstream == null || upstream.length === 0 + ? undefined + : { name: ` ${upstream}`.substr(1), missing: Boolean(missing) }, + Number(ahead) || 0, + Number(behind) || 0, + ), + ); + } while (true); - return branches; - } + sw?.stop({ suffix: ` parsed ${branches.length} branches` }); + + return branches; } diff --git a/src/git/parsers/diffParser.ts b/src/git/parsers/diffParser.ts index 915a3aa4d5175..12384141d1c85 100644 --- a/src/git/parsers/diffParser.ts +++ b/src/git/parsers/diffParser.ts @@ -1,5 +1,5 @@ import { maybeStopWatch } from '../../system/stopwatch'; -import { getLines, pluralize } from '../../system/string'; +import { getLines } from '../../system/string'; import type { GitDiffFile, GitDiffHunkLine, GitDiffLine, GitDiffShortStat } from '../models/diff'; import { GitDiffHunk } from '../models/diff'; import type { GitFile, GitFileStatus } from '../models/file'; @@ -7,11 +7,10 @@ import type { GitFile, GitFileStatus } from '../models/file'; const shortStatDiffRegex = /(\d+)\s+files? changed(?:,\s+(\d+)\s+insertions?\(\+\))?(?:,\s+(\d+)\s+deletions?\(-\))?/; const unifiedDiffRegex = /^@@ -([\d]+)(?:,([\d]+))? \+([\d]+)(?:,([\d]+))? @@(?:.*?)\n([\s\S]*?)(?=^@@)/gm; -export function parseFileDiff(data: string, includeContents: boolean = false): GitDiffFile | undefined { +export function parseGitFileDiff(data: string, includeContents: boolean = false): GitDiffFile | undefined { + using sw = maybeStopWatch('Git.parseFileDiff', { log: false, logLevel: 'debug' }); if (!data) return undefined; - const sw = maybeStopWatch('parseFileDiff', { log: false, logLevel: 'debug' }); - const hunks: GitDiffHunk[] = []; let previousStart; @@ -54,7 +53,7 @@ export function parseFileDiff(data: string, includeContents: boolean = false): G ); } while (true); - sw?.stop({ suffix: ` parsed ${pluralize('hunk', hunks.length)}` }); + sw?.stop({ suffix: ` parsed ${hunks.length} hunks` }); if (!hunks.length) return undefined; @@ -65,8 +64,11 @@ export function parseFileDiff(data: string, includeContents: boolean = false): G return diff; } -export function parseDiffHunk(hunk: GitDiffHunk): { lines: GitDiffHunkLine[]; state: 'added' | 'changed' | 'removed' } { - const sw = maybeStopWatch('parseDiffHunk', { log: false, logLevel: 'debug' }); +export function parseGitDiffHunk(hunk: GitDiffHunk): { + lines: GitDiffHunkLine[]; + state: 'added' | 'changed' | 'removed'; +} { + using sw = maybeStopWatch('Git.parseDiffHunk', { log: false, logLevel: 'debug' }); const currentStart = hunk.current.position.start; const previousStart = hunk.previous.position.start; @@ -140,7 +142,7 @@ export function parseDiffHunk(hunk: GitDiffHunk): { lines: GitDiffHunkLine[]; st }); } - sw?.stop({ suffix: ` parsed ${pluralize('line', hunkLines.length)}` }); + sw?.stop({ suffix: ` parsed ${hunkLines.length} hunk lines` }); return { lines: hunkLines, @@ -148,11 +150,10 @@ export function parseDiffHunk(hunk: GitDiffHunk): { lines: GitDiffHunkLine[]; st }; } -export function parseDiffNameStatusFiles(data: string, repoPath: string): GitFile[] | undefined { +export function parseGitDiffNameStatusFiles(data: string, repoPath: string): GitFile[] | undefined { + using sw = maybeStopWatch('Git.parseDiffNameStatusFiles', { log: false, logLevel: 'debug' }); if (!data) return undefined; - const sw = maybeStopWatch('parseDiffNameStatusFiles', { log: false, logLevel: 'debug' }); - const files: GitFile[] = []; let status; @@ -172,16 +173,15 @@ export function parseDiffNameStatusFiles(data: string, repoPath: string): GitFil }); } - sw?.stop({ suffix: ` parsed ${pluralize('file', files.length)}` }); + sw?.stop({ suffix: ` parsed ${files.length} files` }); return files; } -export function parseDiffShortStat(data: string): GitDiffShortStat | undefined { +export function parseGitDiffShortStat(data: string): GitDiffShortStat | undefined { + using sw = maybeStopWatch('Git.parseDiffShortStat', { log: false, logLevel: 'debug' }); if (!data) return undefined; - const sw = maybeStopWatch('parseDiffShortStat', { log: false, logLevel: 'debug' }); - const match = shortStatDiffRegex.exec(data); if (match == null) return undefined; @@ -194,9 +194,7 @@ export function parseDiffShortStat(data: string): GitDiffShortStat | undefined { }; sw?.stop({ - suffix: ` parsed ${pluralize('file', diffShortStat.changedFiles)}, +${diffShortStat.additions} -${ - diffShortStat.deletions - }`, + suffix: ` parsed ${diffShortStat.changedFiles} files, +${diffShortStat.additions} -${diffShortStat.deletions}`, }); return diffShortStat; diff --git a/src/git/parsers/logParser.ts b/src/git/parsers/logParser.ts index c47af411e93da..2a57321804bdc 100644 --- a/src/git/parsers/logParser.ts +++ b/src/git/parsers/logParser.ts @@ -1,8 +1,8 @@ import type { Range } from 'vscode'; import type { Container } from '../../container'; import { filterMap } from '../../system/array'; -import { debug } from '../../system/decorators/log'; import { normalizePath, relative } from '../../system/path'; +import { maybeStopWatch } from '../../system/stopwatch'; import { getLines } from '../../system/string'; import type { GitCommitLine, GitStashCommit } from '../models/commit'; import { GitCommit, GitCommitIdentity } from '../models/commit'; @@ -363,581 +363,548 @@ export function createLogParserWithStats>( }); } -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitLogParser { - // private static _defaultParser: ParserWithFiles<{ - // sha: string; - // author: string; - // authorEmail: string; - // authorDate: string; - // committer: string; - // committerEmail: string; - // committerDate: string; - // message: string; - // parents: string[]; - // }>; - // static get defaultParser() { - // if (this._defaultParser == null) { - // this._defaultParser = GitLogParser.createWithFiles({ - // sha: '%H', - // author: '%aN', - // authorEmail: '%aE', - // authorDate: '%at', - // committer: '%cN', - // committerEmail: '%cE', - // committerDate: '%ct', - // message: '%B', - // parents: '%P', - // }); - // } - // return this._defaultParser; - // } - - static allFormat = [ - `${lb}${sl}f${rb}`, - `${lb}r${rb}${sp}%H`, // ref - `${lb}a${rb}${sp}%aN`, // author - `${lb}e${rb}${sp}%aE`, // author email - `${lb}d${rb}${sp}%at`, // author date - `${lb}n${rb}${sp}%cN`, // committer - `${lb}m${rb}${sp}%cE`, // committer email - `${lb}c${rb}${sp}%ct`, // committer date - `${lb}p${rb}${sp}%P`, // parents - `${lb}t${rb}${sp}%D`, // tips - `${lb}s${rb}`, - '%B', // summary - `${lb}${sl}s${rb}`, - `${lb}f${rb}`, - ].join('%n'); - - static defaultFormat = [ - `${lb}${sl}f${rb}`, - `${lb}r${rb}${sp}%H`, // ref - `${lb}a${rb}${sp}%aN`, // author - `${lb}e${rb}${sp}%aE`, // author email - `${lb}d${rb}${sp}%at`, // author date - `${lb}n${rb}${sp}%cN`, // committer - `${lb}m${rb}${sp}%cE`, // committer email - `${lb}c${rb}${sp}%ct`, // committer date - `${lb}p${rb}${sp}%P`, // parents - `${lb}s${rb}`, - '%B', // summary - `${lb}${sl}s${rb}`, - `${lb}f${rb}`, - ].join('%n'); - - static simpleRefs = `${lb}r${rb}${sp}%H`; - static simpleFormat = `${lb}r${rb}${sp}%H`; - - static shortlog = '%H%x00%aN%x00%aE%x00%at'; - - @debug({ args: false }) - static parse( - container: Container, - data: string, - type: LogType, - repoPath: string | undefined, - fileName: string | undefined, - sha: string | undefined, - currentUser: GitUser | undefined, - limit: number | undefined, - reverse: boolean, - range: Range | undefined, - stashes?: Map, - hasMoreOverride?: boolean, - ): GitLog | undefined { - if (!data) return undefined; - - let relativeFileName: string | undefined; - - let entry: LogEntry = {}; - let line: string | undefined = undefined; - let token: number; - - let i = 0; - let first = true; - - const lines = getLines(`${data}`); - // Skip the first line since it will always be - let next = lines.next(); - if (next.done) return undefined; - - if (repoPath !== undefined) { - repoPath = normalizePath(repoPath); - } +export const parseGitLogAllFormat = [ + `${lb}${sl}f${rb}`, + `${lb}r${rb}${sp}%H`, // ref + `${lb}a${rb}${sp}%aN`, // author + `${lb}e${rb}${sp}%aE`, // author email + `${lb}d${rb}${sp}%at`, // author date + `${lb}n${rb}${sp}%cN`, // committer + `${lb}m${rb}${sp}%cE`, // committer email + `${lb}c${rb}${sp}%ct`, // committer date + `${lb}p${rb}${sp}%P`, // parents + `${lb}t${rb}${sp}%D`, // tips + `${lb}s${rb}`, + '%B', // summary + `${lb}${sl}s${rb}`, + `${lb}f${rb}`, +].join('%n'); +export const parseGitLogDefaultFormat = [ + `${lb}${sl}f${rb}`, + `${lb}r${rb}${sp}%H`, // ref + `${lb}a${rb}${sp}%aN`, // author + `${lb}e${rb}${sp}%aE`, // author email + `${lb}d${rb}${sp}%at`, // author date + `${lb}n${rb}${sp}%cN`, // committer + `${lb}m${rb}${sp}%cE`, // committer email + `${lb}c${rb}${sp}%ct`, // committer date + `${lb}p${rb}${sp}%P`, // parents + `${lb}s${rb}`, + '%B', // summary + `${lb}${sl}s${rb}`, + `${lb}f${rb}`, +].join('%n'); +export const parseGitLogSimpleFormat = `${lb}r${rb}${sp}%H`; + +export function parseGitLog( + container: Container, + data: string, + type: LogType, + repoPath: string | undefined, + fileName: string | undefined, + sha: string | undefined, + currentUser: GitUser | undefined, + limit: number | undefined, + reverse: boolean, + range: Range | undefined, + stashes?: Map, + hasMoreOverride?: boolean, +): GitLog | undefined { + using sw = maybeStopWatch(`Git.parseLog(${repoPath}, fileName=${fileName}, sha=${sha})`, { + log: false, + logLevel: 'debug', + }); + if (!data) return undefined; - const commits = new Map(); - let truncationCount = limit; + let relativeFileName: string | undefined; - let match; - let renamedFileName; - let renamedMatch; + let entry: LogEntry = {}; + let line: string | undefined = undefined; + let token: number; - loop: while (true) { - next = lines.next(); - if (next.done) break; + let i = 0; + let first = true; - line = next.value; + const lines = getLines(`${data}`); + // Skip the first line since it will always be + let next = lines.next(); + if (next.done) return undefined; - // Since log --reverse doesn't properly honor a max count -- enforce it here - if (reverse && limit && i >= limit) break; + if (repoPath !== undefined) { + repoPath = normalizePath(repoPath); + } - // <1-char token> data - // e.g. bd1452a2dc - token = line.charCodeAt(1); + const commits = new Map(); + let truncationCount = limit; - switch (token) { - case 114: // 'r': // ref - entry = { - sha: line.substring(4), - }; - break; + let match; + let renamedFileName; + let renamedMatch; - case 97: // 'a': // author - if (uncommitted === entry.sha) { - entry.author = 'You'; - } else { - entry.author = line.substring(4); - } - break; + loop: while (true) { + next = lines.next(); + if (next.done) break; - case 101: // 'e': // author-mail - entry.authorEmail = line.substring(4); - break; + line = next.value; - case 100: // 'd': // author-date - entry.authorDate = line.substring(4); - break; + // Since log --reverse doesn't properly honor a max count -- enforce it here + if (reverse && limit && i >= limit) break; - case 110: // 'n': // committer - entry.committer = line.substring(4); - break; + // <1-char token> data + // e.g. bd1452a2dc + token = line.charCodeAt(1); - case 109: // 'm': // committer-mail - entry.committedDate = line.substring(4); - break; + switch (token) { + case 114: // 'r': // ref + entry = { + sha: line.substring(4), + }; + break; - case 99: // 'c': // committer-date - entry.committedDate = line.substring(4); - break; + case 97: // 'a': // author + if (uncommitted === entry.sha) { + entry.author = 'You'; + } else { + entry.author = line.substring(4); + } + break; - case 112: // 'p': // parents - line = line.substring(4); - entry.parentShas = line.length !== 0 ? line.split(' ') : undefined; - break; + case 101: // 'e': // author-mail + entry.authorEmail = line.substring(4); + break; - case 116: // 't': // tips - line = line.substring(4); - entry.tips = line.length !== 0 ? line.split(', ') : undefined; - break; + case 100: // 'd': // author-date + entry.authorDate = line.substring(4); + break; - case 115: // 's': // summary - while (true) { - next = lines.next(); - if (next.done) break; + case 110: // 'n': // committer + entry.committer = line.substring(4); + break; - line = next.value; - if (line === '') break; + case 109: // 'm': // committer-mail + entry.committedDate = line.substring(4); + break; - if (entry.summary === undefined) { - entry.summary = line; - } else { - entry.summary += `\n${line}`; - } - } + case 99: // 'c': // committer-date + entry.committedDate = line.substring(4); + break; - // Remove the trailing newline - if (entry.summary != null && entry.summary.charCodeAt(entry.summary.length - 1) === 10) { - entry.summary = entry.summary.slice(0, -1); - } - break; + case 112: // 'p': // parents + line = line.substring(4); + entry.parentShas = line.length !== 0 ? line.split(' ') : undefined; + break; + + case 116: // 't': // tips + line = line.substring(4); + entry.tips = line.length !== 0 ? line.split(', ') : undefined; + break; - case 102: { - // 'f': // files - // Skip the blank line git adds before the files + case 115: // 's': // summary + while (true) { next = lines.next(); + if (next.done) break; - let hasFiles = true; - if (next.done || next.value === '') { - // If this is a merge commit and there are no files returned, skip the commit and reduce our truncationCount to ensure accurate truncation detection - if ((entry.parentShas?.length ?? 0) > 1) { - if (truncationCount) { - truncationCount--; - } + line = next.value; + if (line === '') break; - break; + if (entry.summary === undefined) { + entry.summary = line; + } else { + entry.summary += `\n${line}`; + } + } + + // Remove the trailing newline + if (entry.summary != null && entry.summary.charCodeAt(entry.summary.length - 1) === 10) { + entry.summary = entry.summary.slice(0, -1); + } + break; + + case 102: { + // 'f': // files + // Skip the blank line git adds before the files + next = lines.next(); + + let hasFiles = true; + if (next.done || next.value === '') { + // If this is a merge commit and there are no files returned, skip the commit and reduce our truncationCount to ensure accurate truncation detection + if ((entry.parentShas?.length ?? 0) > 1) { + if (truncationCount) { + truncationCount--; } - hasFiles = false; + break; } - // eslint-disable-next-line no-unmodified-loop-condition - while (hasFiles) { - next = lines.next(); - if (next.done) break; + hasFiles = false; + } - line = next.value; - if (line === '') break; + // eslint-disable-next-line no-unmodified-loop-condition + while (hasFiles) { + next = lines.next(); + if (next.done) break; - if (line.startsWith('warning:')) continue; + line = next.value; + if (line === '') break; - if (type === LogType.Log) { - match = fileStatusRegex.exec(line); - if (match != null) { - if (entry.files === undefined) { - entry.files = []; - } + if (line.startsWith('warning:')) continue; - renamedFileName = match[3]; - if (renamedFileName !== undefined) { - entry.files.push({ - status: match[1] as GitFileIndexStatus, - path: renamedFileName, - originalPath: match[2], - }); - } else { - entry.files.push({ - status: match[1] as GitFileIndexStatus, - path: match[2], - }); - } + if (type === LogType.Log) { + match = fileStatusRegex.exec(line); + if (match != null) { + if (entry.files === undefined) { + entry.files = []; } - } else { - match = diffRegex.exec(line); - if (match != null) { - [, entry.originalPath, entry.path] = match; - if (entry.path === entry.originalPath) { - entry.originalPath = undefined; - entry.status = GitFileIndexStatus.Modified; - } else { - entry.status = GitFileIndexStatus.Renamed; - } - void lines.next(); - void lines.next(); - next = lines.next(); + renamedFileName = match[3]; + if (renamedFileName !== undefined) { + entry.files.push({ + status: match[1] as GitFileIndexStatus, + path: renamedFileName, + originalPath: match[2], + }); + } else { + entry.files.push({ + status: match[1] as GitFileIndexStatus, + path: match[2], + }); + } + } + } else { + match = diffRegex.exec(line); + if (match != null) { + [, entry.originalPath, entry.path] = match; + if (entry.path === entry.originalPath) { + entry.originalPath = undefined; + entry.status = GitFileIndexStatus.Modified; + } else { + entry.status = GitFileIndexStatus.Renamed; + } - match = diffRangeRegex.exec(next.value); - if (match !== null) { - entry.line = { - sha: entry.sha!, - originalLine: parseInt(match[1], 10), - // count: parseInt(match[2], 10), - line: parseInt(match[3], 10), - // count: parseInt(match[4], 10), - }; - } + void lines.next(); + void lines.next(); + next = lines.next(); + + match = diffRangeRegex.exec(next.value); + if (match !== null) { + entry.line = { + sha: entry.sha!, + originalLine: parseInt(match[1], 10), + // count: parseInt(match[2], 10), + line: parseInt(match[3], 10), + // count: parseInt(match[4], 10), + }; + } - while (true) { - next = lines.next(); - if (next.done || next.value === '') break; - } - break; - } else { + while (true) { next = lines.next(); - match = fileStatusAndSummaryRegex.exec(`${line}\n${next.value}`); - if (match != null) { - entry.fileStats = { - additions: Number(match[1]) || 0, - deletions: Number(match[2]) || 0, - changes: 0, - }; - - switch (match[4]) { - case undefined: - entry.status = 'M' as GitFileIndexStatus; - entry.path = match[3]; - break; - case 'copy': - case 'rename': - entry.status = (match[4] === 'copy' ? 'C' : 'R') as GitFileIndexStatus; - - renamedFileName = match[3]; - renamedMatch = - fileStatusAndSummaryRenamedFilePathRegex.exec(renamedFileName); - if (renamedMatch != null) { - const [, start, from, to, end] = renamedMatch; - // If there is no new path, the path part was removed so ensure we don't end up with // - if (!to) { - entry.path = `${ - start.endsWith('/') && end.startsWith('/') - ? start.slice(0, -1) - : start - }${end}`; - } else { - entry.path = `${start}${to}${end}`; - } - - if (!from) { - entry.originalPath = `${ - start.endsWith('/') && end.startsWith('/') - ? start.slice(0, -1) - : start - }${end}`; - } else { - entry.originalPath = `${start}${from}${end}`; - } + if (next.done || next.value === '') break; + } + break; + } else { + next = lines.next(); + match = fileStatusAndSummaryRegex.exec(`${line}\n${next.value}`); + if (match != null) { + entry.fileStats = { + additions: Number(match[1]) || 0, + deletions: Number(match[2]) || 0, + changes: 0, + }; + + switch (match[4]) { + case undefined: + entry.status = 'M' as GitFileIndexStatus; + entry.path = match[3]; + break; + case 'copy': + case 'rename': + entry.status = (match[4] === 'copy' ? 'C' : 'R') as GitFileIndexStatus; + + renamedFileName = match[3]; + renamedMatch = fileStatusAndSummaryRenamedFilePathRegex.exec(renamedFileName); + if (renamedMatch != null) { + const [, start, from, to, end] = renamedMatch; + // If there is no new path, the path part was removed so ensure we don't end up with // + if (!to) { + entry.path = `${ + start.endsWith('/') && end.startsWith('/') + ? start.slice(0, -1) + : start + }${end}`; } else { - renamedMatch = - fileStatusAndSummaryRenamedFileRegex.exec(renamedFileName); - if (renamedMatch != null) { - entry.path = renamedMatch[2]; - entry.originalPath = renamedMatch[1]; - } else { - entry.path = renamedFileName; - } + entry.path = `${start}${to}${end}`; } - break; - case 'create': - entry.status = 'A' as GitFileIndexStatus; - entry.path = match[3]; - break; - case 'delete': - entry.status = 'D' as GitFileIndexStatus; - entry.path = match[3]; - break; - default: - entry.status = 'M' as GitFileIndexStatus; - entry.path = match[3]; - break; - } + if (!from) { + entry.originalPath = `${ + start.endsWith('/') && end.startsWith('/') + ? start.slice(0, -1) + : start + }${end}`; + } else { + entry.originalPath = `${start}${from}${end}`; + } + } else { + renamedMatch = fileStatusAndSummaryRenamedFileRegex.exec(renamedFileName); + if (renamedMatch != null) { + entry.path = renamedMatch[2]; + entry.originalPath = renamedMatch[1]; + } else { + entry.path = renamedFileName; + } + } + + break; + case 'create': + entry.status = 'A' as GitFileIndexStatus; + entry.path = match[3]; + break; + case 'delete': + entry.status = 'D' as GitFileIndexStatus; + entry.path = match[3]; + break; + default: + entry.status = 'M' as GitFileIndexStatus; + entry.path = match[3]; + break; } - - if (next.done || next.value === '') break; } - } - } - if (entry.files !== undefined) { - entry.path = filterMap(entry.files, f => (f.path ? f.path : undefined)).join(', '); + if (next.done || next.value === '') break; + } } + } - if (first && repoPath === undefined && type === LogType.LogFile && fileName !== undefined) { - // Try to get the repoPath from the most recent commit - repoPath = normalizePath( - fileName.replace(fileName.startsWith('/') ? `/${entry.path}` : entry.path!, ''), - ); - relativeFileName = normalizePath(relative(repoPath, fileName)); - } else { - relativeFileName = - entry.path ?? - (repoPath != null && fileName != null - ? normalizePath(relative(repoPath, fileName)) - : undefined); - } - first = false; - - const commit = commits.get(entry.sha!); - if (commit === undefined) { - i++; - if (limit && i > limit) break loop; - } else if (truncationCount) { - // Since this matches an existing commit it will be skipped, so reduce our truncationCount to ensure accurate truncation detection - truncationCount--; - } + if (entry.files !== undefined) { + entry.path = filterMap(entry.files, f => (f.path ? f.path : undefined)).join(', '); + } - GitLogParser.parseEntry( - container, - entry, - commit, - type, - repoPath, - relativeFileName, - commits, - currentUser, - stashes, + if (first && repoPath === undefined && type === LogType.LogFile && fileName !== undefined) { + // Try to get the repoPath from the most recent commit + repoPath = normalizePath( + fileName.replace(fileName.startsWith('/') ? `/${entry.path}` : entry.path!, ''), ); - - break; + relativeFileName = normalizePath(relative(repoPath, fileName)); + } else { + relativeFileName = + entry.path ?? + (repoPath != null && fileName != null + ? normalizePath(relative(repoPath, fileName)) + : undefined); } + first = false; + + const commit = commits.get(entry.sha!); + if (commit === undefined) { + i++; + if (limit && i > limit) break loop; + } else if (truncationCount) { + // Since this matches an existing commit it will be skipped, so reduce our truncationCount to ensure accurate truncation detection + truncationCount--; + } + + parseLogEntry( + container, + entry, + commit, + type, + repoPath, + relativeFileName, + commits, + currentUser, + stashes, + ); + + break; } } - - const log: GitLog = { - repoPath: repoPath!, - commits: commits, - sha: sha, - count: i, - limit: limit, - range: range, - hasMore: hasMoreOverride ?? Boolean(truncationCount && i > truncationCount && truncationCount !== 1), - }; - return log; } - private static parseEntry( - container: Container, - entry: LogEntry, - commit: GitCommit | undefined, - type: LogType, - repoPath: string | undefined, - relativeFileName: string | undefined, - commits: Map, - currentUser: GitUser | undefined, - stashes: Map | undefined, - ): void { - if (commit == null) { - if (entry.author != null) { - if (isUserMatch(currentUser, entry.author, entry.authorEmail)) { - entry.author = 'You'; - } + sw?.stop({ suffix: ` parsed ${commits.size} commits` }); + + const log: GitLog = { + repoPath: repoPath!, + commits: commits, + sha: sha, + count: i, + limit: limit, + range: range, + hasMore: hasMoreOverride ?? Boolean(truncationCount && i > truncationCount && truncationCount !== 1), + }; + return log; +} + +function parseLogEntry( + container: Container, + entry: LogEntry, + commit: GitCommit | undefined, + type: LogType, + repoPath: string | undefined, + relativeFileName: string | undefined, + commits: Map, + currentUser: GitUser | undefined, + stashes: Map | undefined, +): void { + if (commit == null) { + if (entry.author != null) { + if (isUserMatch(currentUser, entry.author, entry.authorEmail)) { + entry.author = 'You'; } + } - if (entry.committer != null) { - if (isUserMatch(currentUser, entry.committer, entry.committerEmail)) { - entry.committer = 'You'; - } + if (entry.committer != null) { + if (isUserMatch(currentUser, entry.committer, entry.committerEmail)) { + entry.committer = 'You'; } + } - const originalFileName = entry.originalPath ?? (relativeFileName !== entry.path ? entry.path : undefined); + const originalFileName = entry.originalPath ?? (relativeFileName !== entry.path ? entry.path : undefined); - const files: { file?: GitFileChange; files?: GitFileChange[] } = { - files: entry.files?.map(f => new GitFileChange(repoPath!, f.path, f.status, f.originalPath)), - }; - if (type === LogType.LogFile && relativeFileName != null) { - files.file = new GitFileChange( - repoPath!, - relativeFileName, - entry.status!, - originalFileName, - undefined, - entry.fileStats, - ); - } + const files: { file?: GitFileChange; files?: GitFileChange[] } = { + files: entry.files?.map(f => new GitFileChange(repoPath!, f.path, f.status, f.originalPath)), + }; + if (type === LogType.LogFile && relativeFileName != null) { + files.file = new GitFileChange( + repoPath!, + relativeFileName, + entry.status!, + originalFileName, + undefined, + entry.fileStats, + ); + } - const stash = stashes?.get(entry.sha!); - if (stash != null) { - commit = new GitCommit( - container, - repoPath!, - stash.sha, - stash.author, - stash.committer, - stash.summary, - stash.parents, - stash.message, - files, - undefined, - entry.line != null ? [entry.line] : [], - entry.tips, - stash.stashName, - stash.stashOnRef, - ); - commits.set(stash.sha, commit); - } else { - commit = new GitCommit( - container, - repoPath!, - entry.sha!, - - new GitCommitIdentity( - entry.author!, - entry.authorEmail, - new Date((entry.authorDate! as any) * 1000), - ), - - new GitCommitIdentity( - entry.committer!, - entry.committerEmail, - new Date((entry.committedDate! as any) * 1000), - ), - entry.summary?.split('\n', 1)[0] ?? '', - entry.parentShas ?? [], - entry.summary ?? '', - files, - undefined, - entry.line != null ? [entry.line] : [], - entry.tips, - ); - commits.set(entry.sha!, commit); - } + const stash = stashes?.get(entry.sha!); + if (stash != null) { + commit = new GitCommit( + container, + repoPath!, + stash.sha, + stash.author, + stash.committer, + stash.summary, + stash.parents, + stash.message, + files, + undefined, + entry.line != null ? [entry.line] : [], + entry.tips, + stash.stashName, + stash.stashOnRef, + ); + commits.set(stash.sha, commit); + } else { + commit = new GitCommit( + container, + repoPath!, + entry.sha!, + + new GitCommitIdentity(entry.author!, entry.authorEmail, new Date((entry.authorDate! as any) * 1000)), + + new GitCommitIdentity( + entry.committer!, + entry.committerEmail, + new Date((entry.committedDate! as any) * 1000), + ), + entry.summary?.split('\n', 1)[0] ?? '', + entry.parentShas ?? [], + entry.summary ?? '', + files, + undefined, + entry.line != null ? [entry.line] : [], + entry.tips, + ); + commits.set(entry.sha!, commit); } } +} + +export function parseGitLogSimple( + data: string, + skip: number, + skipRef?: string, +): [string | undefined, string | undefined, GitFileIndexStatus | undefined] { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + using _sw = maybeStopWatch('Git.parseLogSimple', { log: false, logLevel: 'debug' }); + + let ref; + let diffFile; + let diffRenamed; + let status; + let file; + let renamed; - @debug({ args: false }) - static parseSimple( - data: string, - skip: number, - skipRef?: string, - ): [string | undefined, string | undefined, GitFileIndexStatus | undefined] { - let ref; - let diffFile; - let diffRenamed; - let status; - let file; - let renamed; - - let match; - do { - match = logFileSimpleRegex.exec(data); - if (match == null) break; - - if (match[1] === skipRef) continue; - if (skip-- > 0) continue; - - [, ref, diffFile, diffRenamed, status, file, renamed] = match; - - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - file = ` ${diffRenamed || diffFile || renamed || file}`.substr(1); - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - status = status == null || status.length === 0 ? undefined : ` ${status}`.substr(1); - } while (skip >= 0); - - // Ensure the regex state is reset - logFileSimpleRegex.lastIndex = 0; + let match; + do { + match = logFileSimpleRegex.exec(data); + if (match == null) break; + + if (match[1] === skipRef) continue; + if (skip-- > 0) continue; + + [, ref, diffFile, diffRenamed, status, file, renamed] = match; // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - return [ - ref == null || ref.length === 0 ? undefined : ` ${ref}`.substr(1), - file, - status as GitFileIndexStatus | undefined, - ]; - } + file = ` ${diffRenamed || diffFile || renamed || file}`.substr(1); + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + status = status == null || status.length === 0 ? undefined : ` ${status}`.substr(1); + } while (skip >= 0); + + // Ensure the regex state is reset + logFileSimpleRegex.lastIndex = 0; + + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + return [ + ref == null || ref.length === 0 ? undefined : ` ${ref}`.substr(1), + file, + status as GitFileIndexStatus | undefined, + ]; +} - @debug({ args: false }) - static parseSimpleRenamed( - data: string, - originalFileName: string, - ): [string | undefined, string | undefined, GitFileIndexStatus | undefined] { - let match = logFileSimpleRenamedRegex.exec(data); - if (match == null) return [undefined, undefined, undefined]; +export function parseGitLogSimpleRenamed( + data: string, + originalFileName: string, +): [string | undefined, string | undefined, GitFileIndexStatus | undefined] { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + using _sw = maybeStopWatch('Git.parseLogSimpleRenamed', { log: false, logLevel: 'debug' }); - const [, ref, files] = match; + let match = logFileSimpleRenamedRegex.exec(data); + if (match == null) return [undefined, undefined, undefined]; - let status; - let file; - let renamed; + const [, ref, files] = match; - do { - match = logFileSimpleRenamedFilesRegex.exec(files); - if (match == null) break; + let status; + let file; + let renamed; - [, status, file, renamed] = match; + do { + match = logFileSimpleRenamedFilesRegex.exec(files); + if (match == null) break; - if (originalFileName !== file) { - status = undefined; - file = undefined; - renamed = undefined; - continue; - } + [, status, file, renamed] = match; - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - file = ` ${renamed || file}`.substr(1); - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - status = status == null || status.length === 0 ? undefined : ` ${status}`.substr(1); + if (originalFileName !== file) { + status = undefined; + file = undefined; + renamed = undefined; + continue; + } + + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + file = ` ${renamed || file}`.substr(1); + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + status = status == null || status.length === 0 ? undefined : ` ${status}`.substr(1); - break; - } while (true); + break; + } while (true); - // Ensure the regex state is reset - logFileSimpleRenamedFilesRegex.lastIndex = 0; + // Ensure the regex state is reset + logFileSimpleRenamedFilesRegex.lastIndex = 0; - return [ - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - ref == null || ref.length === 0 || file == null ? undefined : ` ${ref}`.substr(1), - file, - status as GitFileIndexStatus | undefined, - ]; - } + return [ + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + ref == null || ref.length === 0 || file == null ? undefined : ` ${ref}`.substr(1), + file, + status as GitFileIndexStatus | undefined, + ]; } diff --git a/src/git/parsers/reflogParser.ts b/src/git/parsers/reflogParser.ts index 1bbcf49792983..3f56201a3b87c 100644 --- a/src/git/parsers/reflogParser.ts +++ b/src/git/parsers/reflogParser.ts @@ -1,4 +1,4 @@ -import { debug } from '../../system/decorators/log'; +import { maybeStopWatch } from '../../system/stopwatch'; import type { GitReflog } from '../models/reflog'; import { GitReflogRecord } from '../models/reflog'; @@ -10,119 +10,118 @@ const reflogHEADRegex = /.*?\/?HEAD$/; const lb = '%x3c'; // `%x${'<'.charCodeAt(0).toString(16)}`; const rb = '%x3e'; // `%x${'>'.charCodeAt(0).toString(16)}`; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitReflogParser { - static defaultFormat = [ - `${lb}r${rb}%H`, // ref - `${lb}d${rb}%gD`, // reflog selector (with iso8601 timestamp) - `${lb}s${rb}%gs`, // reflog subject - // `${lb}n${rb}%D` // ref names - ].join(''); - - @debug({ args: false }) - static parse( - data: string, - repoPath: string, - commands: string[], - limit: number, - totalLimit: number, - ): GitReflog | undefined { - if (!data) return undefined; - - const records: GitReflogRecord[] = []; - - let sha; - let selector; - let date; - let command; - let commandArgs; - let details; - - let head; - let headDate; - let headSha; - - let count = 0; - let total = 0; - let recordDate; - let record: GitReflogRecord | undefined; - - let match; - do { - match = reflogRegex.exec(data); - if (match == null) break; - - [, sha, selector, date, command, commandArgs, details] = match; - - total++; - - if (record !== undefined) { - // If the next record has the same sha as the previous, use it if it is not pointing to just HEAD and the previous is +export const parseGitRefLogDefaultFormat = [ + `${lb}r${rb}%H`, // ref + `${lb}d${rb}%gD`, // reflog selector (with iso8601 timestamp) + `${lb}s${rb}%gs`, // reflog subject + // `${lb}n${rb}%D` // ref names +].join(''); + +export function parseGitRefLog( + data: string, + repoPath: string, + commands: string[], + limit: number, + totalLimit: number, +): GitReflog | undefined { + using sw = maybeStopWatch(`Git.parseRefLog(${repoPath})`, { log: false, logLevel: 'debug' }); + if (!data) return undefined; + + const records: GitReflogRecord[] = []; + + let sha; + let selector; + let date; + let command; + let commandArgs; + let details; + + let head; + let headDate; + let headSha; + + let count = 0; + let total = 0; + let recordDate; + let record: GitReflogRecord | undefined; + + let match; + do { + match = reflogRegex.exec(data); + if (match == null) break; + + [, sha, selector, date, command, commandArgs, details] = match; + + total++; + + if (record !== undefined) { + // If the next record has the same sha as the previous, use it if it is not pointing to just HEAD and the previous is + if ( + sha === record.sha && + (date !== recordDate || !reflogHEADRegex.test(record.selector) || reflogHEADRegex.test(selector)) + ) { + continue; + } + + if (sha !== record.sha) { if ( - sha === record.sha && - (date !== recordDate || !reflogHEADRegex.test(record.selector) || reflogHEADRegex.test(selector)) + head != null && + headDate === recordDate && + headSha == record.sha && + reflogHEADRegex.test(record.selector) ) { - continue; + record.update(sha, head); + } else { + record.update(sha); } - if (sha !== record.sha) { - if ( - head != null && - headDate === recordDate && - headSha == record.sha && - reflogHEADRegex.test(record.selector) - ) { - record.update(sha, head); - } else { - record.update(sha); - } - - records.push(record); - record = undefined; - recordDate = undefined; - - count++; - if (limit !== 0 && count >= limit) break; - } - } - - if (command === 'HEAD') { - head = selector; - headDate = date; - headSha = sha; - - continue; - } + records.push(record); + record = undefined; + recordDate = undefined; - if (commands.includes(command)) { - record = new GitReflogRecord( - repoPath, - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - ` ${sha}`.substr(1), - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - ` ${selector}`.substr(1), - new Date(date), - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - ` ${command}`.substr(1), - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - commandArgs == null || commandArgs.length === 0 ? undefined : commandArgs.substr(1), - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - details == null || details.length === 0 ? undefined : details.substr(1), - ); - recordDate = date; + count++; + if (limit !== 0 && count >= limit) break; } - } while (true); - - // Ensure the regex state is reset - reflogRegex.lastIndex = 0; - - return { - repoPath: repoPath, - records: records, - count: count, - total: total, - limit: limit, - hasMore: (limit !== 0 && count >= limit) || (totalLimit !== 0 && total >= totalLimit), - }; - } + } + + if (command === 'HEAD') { + head = selector; + headDate = date; + headSha = sha; + + continue; + } + + if (commands.includes(command)) { + record = new GitReflogRecord( + repoPath, + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + ` ${sha}`.substr(1), + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + ` ${selector}`.substr(1), + new Date(date), + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + ` ${command}`.substr(1), + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + commandArgs == null || commandArgs.length === 0 ? undefined : commandArgs.substr(1), + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + details == null || details.length === 0 ? undefined : details.substr(1), + ); + recordDate = date; + } + } while (true); + + // Ensure the regex state is reset + reflogRegex.lastIndex = 0; + + sw?.stop({ suffix: ` parsed ${records.length} records` }); + + return { + repoPath: repoPath, + records: records, + count: count, + total: total, + limit: limit, + hasMore: (limit !== 0 && count >= limit) || (totalLimit !== 0 && total >= totalLimit), + }; } diff --git a/src/git/parsers/remoteParser.ts b/src/git/parsers/remoteParser.ts index 7f0059df5d8ab..4cfef2b1530c9 100644 --- a/src/git/parsers/remoteParser.ts +++ b/src/git/parsers/remoteParser.ts @@ -1,4 +1,4 @@ -import { debug } from '../../system/decorators/log'; +import { maybeStopWatch } from '../../system/stopwatch'; import type { GitRemoteType } from '../models/remote'; import { GitRemote } from '../models/remote'; import type { getRemoteProviderMatcher } from '../remotes/remoteProviders'; @@ -7,68 +7,67 @@ const emptyStr = ''; const remoteRegex = /^(.*)\t(.*)\s\((.*)\)$/gm; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitRemoteParser { - @debug({ args: false, singleLine: true }) - static parse( - data: string, - repoPath: string, - remoteProviderMatcher: ReturnType, - ): GitRemote[] | undefined { - if (!data) return undefined; - - const remotes = new Map(); - - let name; - let url; - let type; - - let scheme; - let domain; - let path; - - let remote: GitRemote | undefined; - - let match; - do { - match = remoteRegex.exec(data); - if (match == null) break; - - [, name, url, type] = match; - - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - name = ` ${name}`.substr(1); - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - url = ` ${url}`.substr(1); - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - type = ` ${type}`.substr(1); - - [scheme, domain, path] = parseGitRemoteUrl(url); - - remote = remotes.get(name); - if (remote == null) { - remote = new GitRemote(repoPath, name, scheme, domain, path, remoteProviderMatcher(url, domain, path), [ - { url: url, type: type as GitRemoteType }, - ]); - remotes.set(name, remote); - } else { - remote.urls.push({ url: url, type: type as GitRemoteType }); - if (remote.provider != null && type !== 'push') continue; - - if (remote.provider?.hasRichIntegration()) { - remote.provider.dispose(); - } - - const provider = remoteProviderMatcher(url, domain, path); - if (provider == null) continue; - - remote = new GitRemote(repoPath, name, scheme, domain, path, provider, remote.urls); - remotes.set(name, remote); +export function parseGitRemotes( + data: string, + repoPath: string, + remoteProviderMatcher: ReturnType, +): GitRemote[] { + using sw = maybeStopWatch(`Git.parseRemotes(${repoPath})`, { log: false, logLevel: 'debug' }); + if (!data) return []; + + const remotes = new Map(); + + let name; + let url; + let type; + + let scheme; + let domain; + let path; + + let remote: GitRemote | undefined; + + let match; + do { + match = remoteRegex.exec(data); + if (match == null) break; + + [, name, url, type] = match; + + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + name = ` ${name}`.substr(1); + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + url = ` ${url}`.substr(1); + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + type = ` ${type}`.substr(1); + + [scheme, domain, path] = parseGitRemoteUrl(url); + + remote = remotes.get(name); + if (remote == null) { + remote = new GitRemote(repoPath, name, scheme, domain, path, remoteProviderMatcher(url, domain, path), [ + { url: url, type: type as GitRemoteType }, + ]); + remotes.set(name, remote); + } else { + remote.urls.push({ url: url, type: type as GitRemoteType }); + if (remote.provider != null && type !== 'push') continue; + + if (remote.provider?.hasRichIntegration()) { + remote.provider.dispose(); } - } while (true); - return [...remotes.values()]; - } + const provider = remoteProviderMatcher(url, domain, path); + if (provider == null) continue; + + remote = new GitRemote(repoPath, name, scheme, domain, path, provider, remote.urls); + remotes.set(name, remote); + } + } while (true); + + sw?.stop({ suffix: ` parsed ${remotes.size} remotes` }); + + return [...remotes.values()]; } // Test git urls diff --git a/src/git/parsers/statusParser.ts b/src/git/parsers/statusParser.ts index e295b9f5924d6..10eb8d06414a8 100644 --- a/src/git/parsers/statusParser.ts +++ b/src/git/parsers/statusParser.ts @@ -1,5 +1,5 @@ -import { debug } from '../../system/decorators/log'; import { normalizePath } from '../../system/path'; +import { maybeStopWatch } from '../../system/stopwatch'; import { GitStatus, GitStatusFile } from '../models/status'; const emptyStr = ''; @@ -7,137 +7,137 @@ const emptyStr = ''; const aheadStatusV1Regex = /(?:ahead ([0-9]+))/; const behindStatusV1Regex = /(?:behind ([0-9]+))/; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitStatusParser { - @debug({ args: false, singleLine: true }) - static parse(data: string, repoPath: string, porcelainVersion: number): GitStatus | undefined { - if (!data) return undefined; +export function parseGitStatus(data: string, repoPath: string, porcelainVersion: number): GitStatus | undefined { + using sw = maybeStopWatch(`Git.parseStatus(${repoPath}, v=${porcelainVersion})`, { + log: false, + logLevel: 'debug', + }); + if (!data) return undefined; - const lines = data.split('\n').filter((i?: T): i is T => Boolean(i)); - if (lines.length === 0) return undefined; + const lines = data.split('\n').filter((i?: T): i is T => Boolean(i)); + if (lines.length === 0) return undefined; - if (porcelainVersion < 2) return this.parseV1(lines, repoPath); + const status = porcelainVersion < 2 ? parseStatusV1(lines, repoPath) : parseStatusV2(lines, repoPath); - return this.parseV2(lines, repoPath); - } + sw?.stop({ suffix: ` parsed ${status.files.length} files` }); - @debug({ args: false, singleLine: true }) - private static parseV1(lines: string[], repoPath: string): GitStatus { - let branch: string | undefined; - const files = []; - const state = { - ahead: 0, - behind: 0, - }; - let upstream; - - let position = -1; - while (++position < lines.length) { - const line = lines[position]; - // Header - if (line.startsWith('##')) { - const lineParts = line.split(' '); - [branch, upstream] = lineParts[1].split('...'); - if (lineParts.length > 2) { - const upstreamStatus = lineParts.slice(2).join(' '); - - const aheadStatus = aheadStatusV1Regex.exec(upstreamStatus); - state.ahead = aheadStatus == null ? 0 : Number(aheadStatus[1]) || 0; - - const behindStatus = behindStatusV1Regex.exec(upstreamStatus); - state.behind = behindStatus == null ? 0 : Number(behindStatus[1]) || 0; - } + return status; +} + +function parseStatusV1(lines: string[], repoPath: string): GitStatus { + let branch: string | undefined; + const files = []; + const state = { + ahead: 0, + behind: 0, + }; + let upstream; + + let position = -1; + while (++position < lines.length) { + const line = lines[position]; + // Header + if (line.startsWith('##')) { + const lineParts = line.split(' '); + [branch, upstream] = lineParts[1].split('...'); + if (lineParts.length > 2) { + const upstreamStatus = lineParts.slice(2).join(' '); + + const aheadStatus = aheadStatusV1Regex.exec(upstreamStatus); + state.ahead = aheadStatus == null ? 0 : Number(aheadStatus[1]) || 0; + + const behindStatus = behindStatusV1Regex.exec(upstreamStatus); + state.behind = behindStatus == null ? 0 : Number(behindStatus[1]) || 0; + } + } else { + const rawStatus = line.substring(0, 2); + const fileName = line.substring(3); + if (rawStatus.startsWith('R') || rawStatus.startsWith('C')) { + const [file1, file2] = fileName.replace(/"/g, emptyStr).split('->'); + files.push(parseStatusFile(repoPath, rawStatus, file2.trim(), file1.trim())); } else { - const rawStatus = line.substring(0, 2); - const fileName = line.substring(3); - if (rawStatus.startsWith('R') || rawStatus.startsWith('C')) { - const [file1, file2] = fileName.replace(/"/g, emptyStr).split('->'); - files.push(this.parseStatusFile(repoPath, rawStatus, file2.trim(), file1.trim())); - } else { - files.push(this.parseStatusFile(repoPath, rawStatus, fileName)); - } + files.push(parseStatusFile(repoPath, rawStatus, fileName)); } } - - return new GitStatus(normalizePath(repoPath), branch ?? emptyStr, emptyStr, files, state, upstream); } - @debug({ args: false, singleLine: true }) - private static parseV2(lines: string[], repoPath: string): GitStatus { - let branch: string | undefined; - const files = []; - let sha: string | undefined; - const state = { - ahead: 0, - behind: 0, - }; - let upstream; - - let position = -1; - while (++position < lines.length) { - const line = lines[position]; - // Headers - if (line.startsWith('#')) { - const lineParts = line.split(' '); - switch (lineParts[1]) { - case 'branch.oid': - sha = lineParts[2]; - break; - case 'branch.head': - branch = lineParts[2]; - break; - case 'branch.upstream': - upstream = lineParts[2]; - break; - case 'branch.ab': - state.ahead = Number(lineParts[2].substring(1)); - state.behind = Number(lineParts[3].substring(1)); - break; - } - } else { - const lineParts = line.split(' '); - switch (lineParts[0][0]) { - case '1': // normal - files.push(this.parseStatusFile(repoPath, lineParts[1], lineParts.slice(8).join(' '))); - break; - case '2': { - // rename - const file = lineParts.slice(9).join(' ').split('\t'); - files.push(this.parseStatusFile(repoPath, lineParts[1], file[0], file[1])); - break; - } - case 'u': // unmerged - files.push(this.parseStatusFile(repoPath, lineParts[1], lineParts.slice(10).join(' '))); - break; - case '?': // untracked - files.push(this.parseStatusFile(repoPath, '??', lineParts.slice(1).join(' '))); - break; + return new GitStatus(normalizePath(repoPath), branch ?? emptyStr, emptyStr, files, state, upstream); +} + +function parseStatusV2(lines: string[], repoPath: string): GitStatus { + let branch: string | undefined; + const files = []; + let sha: string | undefined; + const state = { + ahead: 0, + behind: 0, + }; + let upstream; + + let position = -1; + while (++position < lines.length) { + const line = lines[position]; + // Headers + if (line.startsWith('#')) { + const lineParts = line.split(' '); + switch (lineParts[1]) { + case 'branch.oid': + sha = lineParts[2]; + break; + case 'branch.head': + branch = lineParts[2]; + break; + case 'branch.upstream': + upstream = lineParts[2]; + break; + case 'branch.ab': + state.ahead = Number(lineParts[2].substring(1)); + state.behind = Number(lineParts[3].substring(1)); + break; + } + } else { + const lineParts = line.split(' '); + switch (lineParts[0][0]) { + case '1': // normal + files.push(parseStatusFile(repoPath, lineParts[1], lineParts.slice(8).join(' '))); + break; + case '2': { + // rename + const file = lineParts.slice(9).join(' ').split('\t'); + files.push(parseStatusFile(repoPath, lineParts[1], file[0], file[1])); + break; } + case 'u': // unmerged + files.push(parseStatusFile(repoPath, lineParts[1], lineParts.slice(10).join(' '))); + break; + case '?': // untracked + files.push(parseStatusFile(repoPath, '??', lineParts.slice(1).join(' '))); + break; } } - - return new GitStatus(normalizePath(repoPath), branch ?? emptyStr, sha ?? emptyStr, files, state, upstream); } - static parseStatusFile( - repoPath: string, - rawStatus: string, - fileName: string, - originalFileName?: string, - ): GitStatusFile { - let x = !rawStatus.startsWith('.') ? rawStatus[0].trim() : undefined; - if (x == null || x.length === 0) { - x = undefined; - } + return new GitStatus(normalizePath(repoPath), branch ?? emptyStr, sha ?? emptyStr, files, state, upstream); +} - let y = undefined; - if (rawStatus.length > 1) { - y = rawStatus[1] !== '.' ? rawStatus[1].trim() : undefined; - if (y == null || y.length === 0) { - y = undefined; - } - } +function parseStatusFile( + repoPath: string, + rawStatus: string, + fileName: string, + originalFileName?: string, +): GitStatusFile { + let x = !rawStatus.startsWith('.') ? rawStatus[0].trim() : undefined; + if (x == null || x.length === 0) { + x = undefined; + } - return new GitStatusFile(repoPath, x, y, fileName, originalFileName); + let y = undefined; + if (rawStatus.length > 1) { + y = rawStatus[1] !== '.' ? rawStatus[1].trim() : undefined; + if (y == null || y.length === 0) { + y = undefined; + } } + + return new GitStatusFile(repoPath, x, y, fileName, originalFileName); } diff --git a/src/git/parsers/tagParser.ts b/src/git/parsers/tagParser.ts index 26a59fcc825ce..a63ce47ebda06 100644 --- a/src/git/parsers/tagParser.ts +++ b/src/git/parsers/tagParser.ts @@ -1,4 +1,4 @@ -import { debug } from '../../system/decorators/log'; +import { maybeStopWatch } from '../../system/stopwatch'; import { GitTag } from '../models/tag'; const tagRegex = /^(.+)<\*r>(.*)(.*)(.*)(.*)(.*)$/gm; @@ -7,54 +7,53 @@ const tagRegex = /^(.+)<\*r>(.*)(.*)(.*)(.*)(.*)$/gm; const lb = '%3c'; // `%${'<'.charCodeAt(0).toString(16)}`; const rb = '%3e'; // `%${'>'.charCodeAt(0).toString(16)}`; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitTagParser { - static defaultFormat = [ - `${lb}n${rb}%(refname)`, // tag name - `${lb}*r${rb}%(*objectname)`, // ref - `${lb}r${rb}%(objectname)`, // ref - `${lb}d${rb}%(creatordate:iso8601)`, // created date - `${lb}ad${rb}%(authordate:iso8601)`, // author date - `${lb}s${rb}%(subject)`, // message - ].join(''); - - @debug({ args: false, singleLine: true }) - static parse(data: string, repoPath: string): GitTag[] | undefined { - if (!data) return undefined; - - const tags: GitTag[] = []; - - let name; - let ref1; - let ref2; - let date; - let commitDate; - let message; - - let match; - do { - match = tagRegex.exec(data); - if (match == null) break; - - [, name, ref1, ref2, date, commitDate, message] = match; - - // Strip off refs/tags/ - name = name.substr(10); - - tags.push( - new GitTag( - repoPath, - name, - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - ` ${ref1 || ref2}`.substr(1), - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - ` ${message}`.substr(1), - date ? new Date(date) : undefined, - commitDate == null || commitDate.length === 0 ? undefined : new Date(commitDate), - ), - ); - } while (true); - - return tags; - } +export const parseGitTagsDefaultFormat = [ + `${lb}n${rb}%(refname)`, // tag name + `${lb}*r${rb}%(*objectname)`, // ref + `${lb}r${rb}%(objectname)`, // ref + `${lb}d${rb}%(creatordate:iso8601)`, // created date + `${lb}ad${rb}%(authordate:iso8601)`, // author date + `${lb}s${rb}%(subject)`, // message +].join(''); + +export function parseGitTags(data: string, repoPath: string): GitTag[] { + using sw = maybeStopWatch(`Git.parseTags(${repoPath})`, { log: false, logLevel: 'debug' }); + + const tags: GitTag[] = []; + if (!data) return tags; + + let name; + let ref1; + let ref2; + let date; + let commitDate; + let message; + + let match; + do { + match = tagRegex.exec(data); + if (match == null) break; + + [, name, ref1, ref2, date, commitDate, message] = match; + + // Strip off refs/tags/ + name = name.substr(10); + + tags.push( + new GitTag( + repoPath, + name, + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + ` ${ref1 || ref2}`.substr(1), + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + ` ${message}`.substr(1), + date ? new Date(date) : undefined, + commitDate == null || commitDate.length === 0 ? undefined : new Date(commitDate), + ), + ); + } while (true); + + sw?.stop({ suffix: ` parsed ${tags.length} tags` }); + + return tags; } diff --git a/src/git/parsers/treeParser.ts b/src/git/parsers/treeParser.ts index 25b4baeb60992..153680b2d0c61 100644 --- a/src/git/parsers/treeParser.ts +++ b/src/git/parsers/treeParser.ts @@ -1,40 +1,39 @@ -import { debug } from '../../system/decorators/log'; +import { maybeStopWatch } from '../../system/stopwatch'; import type { GitTreeEntry } from '../models/tree'; const emptyStr = ''; const treeRegex = /(?:.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+)/gm; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitTreeParser { - @debug({ args: false, singleLine: true }) - static parse(data: string | undefined): GitTreeEntry[] | undefined { - if (!data) return undefined; - - const trees: GitTreeEntry[] = []; - - let type; - let sha; - let size; - let filePath; - - let match; - do { - match = treeRegex.exec(data); - if (match == null) break; - - [, type, sha, size, filePath] = match; - - trees.push({ - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - commitSha: sha == null || sha.length === 0 ? emptyStr : ` ${sha}`.substr(1), - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - path: filePath == null || filePath.length === 0 ? emptyStr : ` ${filePath}`.substr(1), - size: Number(size) || 0, - // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 - type: (type == null || type.length === 0 ? emptyStr : ` ${type}`.substr(1)) as 'blob' | 'tree', - }); - } while (true); - - return trees; - } +export function parseGitTree(data: string | undefined): GitTreeEntry[] { + using sw = maybeStopWatch(`Git.parseTree`, { log: false, logLevel: 'debug' }); + + const trees: GitTreeEntry[] = []; + if (!data) return trees; + + let type; + let sha; + let size; + let filePath; + + let match; + do { + match = treeRegex.exec(data); + if (match == null) break; + + [, type, sha, size, filePath] = match; + + trees.push({ + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + commitSha: sha == null || sha.length === 0 ? emptyStr : ` ${sha}`.substr(1), + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + path: filePath == null || filePath.length === 0 ? emptyStr : ` ${filePath}`.substr(1), + size: Number(size) || 0, + // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 + type: (type == null || type.length === 0 ? emptyStr : ` ${type}`.substr(1)) as 'blob' | 'tree', + }); + } while (true); + + sw?.stop({ suffix: ` parsed ${trees.length} trees` }); + + return trees; } diff --git a/src/git/parsers/worktreeParser.ts b/src/git/parsers/worktreeParser.ts index 230037b3acd2c..816cb580568cc 100644 --- a/src/git/parsers/worktreeParser.ts +++ b/src/git/parsers/worktreeParser.ts @@ -1,6 +1,6 @@ import { Uri } from 'vscode'; -import { debug } from '../../system/decorators/log'; import { normalizePath } from '../../system/path'; +import { maybeStopWatch } from '../../system/stopwatch'; import { getLines } from '../../system/string'; import { GitWorktree } from '../models/worktree'; @@ -14,88 +14,87 @@ interface WorktreeEntry { prunable?: boolean | string; } -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class GitWorktreeParser { - @debug({ args: false, singleLine: true }) - static parse(data: string, repoPath: string): GitWorktree[] { - if (!data) return []; +export function parseGitWorktrees(data: string, repoPath: string): GitWorktree[] { + using sw = maybeStopWatch(`Git.parseWorktrees(${repoPath})`, { log: false, logLevel: 'debug' }); - if (repoPath != null) { - repoPath = normalizePath(repoPath); - } - - const worktrees: GitWorktree[] = []; + const worktrees: GitWorktree[] = []; + if (!data) return worktrees; - let entry: Partial | undefined = undefined; - let line: string; - let index: number; - let key: string; - let value: string; - let locked: string; - let prunable: string; - let main = true; // the first worktree is the main worktree + if (repoPath != null) { + repoPath = normalizePath(repoPath); + } - for (line of getLines(data)) { - index = line.indexOf(' '); - if (index === -1) { - key = line; - value = ''; - } else { - key = line.substring(0, index); - value = line.substring(index + 1); - } + let entry: Partial | undefined = undefined; + let line: string; + let index: number; + let key: string; + let value: string; + let locked: string; + let prunable: string; + let main = true; // the first worktree is the main worktree - if (key.length === 0 && entry != null) { - worktrees.push( - new GitWorktree( - main, - entry.bare ? 'bare' : entry.detached ? 'detached' : 'branch', - repoPath, - Uri.file(entry.path!), - entry.locked ?? false, - entry.prunable ?? false, - entry.sha, - entry.branch, - ), - ); + for (line of getLines(data)) { + index = line.indexOf(' '); + if (index === -1) { + key = line; + value = ''; + } else { + key = line.substring(0, index); + value = line.substring(index + 1); + } - entry = undefined; - main = false; - continue; - } + if (key.length === 0 && entry != null) { + worktrees.push( + new GitWorktree( + main, + entry.bare ? 'bare' : entry.detached ? 'detached' : 'branch', + repoPath, + Uri.file(entry.path!), + entry.locked ?? false, + entry.prunable ?? false, + entry.sha, + entry.branch, + ), + ); - if (entry == null) { - entry = {}; - } + entry = undefined; + main = false; + continue; + } - switch (key) { - case 'worktree': - entry.path = value; - break; - case 'bare': - entry.bare = true; - break; - case 'HEAD': - entry.sha = value; - break; - case 'branch': - // Strip off refs/heads/ - entry.branch = value.substr(11); - break; - case 'detached': - entry.detached = true; - break; - case 'locked': - [, locked] = value.split(' ', 2); - entry.locked = locked?.trim() || true; - break; - case 'prunable': - [, prunable] = value.split(' ', 2); - entry.prunable = prunable?.trim() || true; - break; - } + if (entry == null) { + entry = {}; } - return worktrees; + switch (key) { + case 'worktree': + entry.path = value; + break; + case 'bare': + entry.bare = true; + break; + case 'HEAD': + entry.sha = value; + break; + case 'branch': + // Strip off refs/heads/ + entry.branch = value.substr(11); + break; + case 'detached': + entry.detached = true; + break; + case 'locked': + [, locked] = value.split(' ', 2); + entry.locked = locked?.trim() || true; + break; + case 'prunable': + [, prunable] = value.split(' ', 2); + entry.prunable = prunable?.trim() || true; + break; + } } + + sw?.stop({ suffix: ` parsed ${worktrees.length} worktrees` }); + + return worktrees; } diff --git a/src/system/stopwatch.ts b/src/system/stopwatch.ts index 73c30a87e2e27..9e4351e90c99d 100644 --- a/src/system/stopwatch.ts +++ b/src/system/stopwatch.ts @@ -3,7 +3,10 @@ import type { LogProvider } from './logger'; import { defaultLogProvider } from './logger'; import type { LogLevel } from './logger.constants'; import type { LogScope } from './logger.scope'; -import { getNextLogScopeId } from './logger.scope'; +import { getNewLogScope } from './logger.scope'; + +(Symbol as any).dispose ??= Symbol('Symbol.dispose'); +(Symbol as any).asyncDispose ??= Symbol('Symbol.asyncDispose'); type StopwatchLogOptions = { message?: string; suffix?: string }; type StopwatchOptions = { @@ -13,8 +16,8 @@ type StopwatchOptions = { }; type StopwatchLogLevel = Exclude; -export class Stopwatch { - private readonly instance = `[${String(getNextLogScopeId()).padStart(5)}] `; +export class Stopwatch implements Disposable { + private readonly logScope: LogScope; private readonly logLevel: StopwatchLogLevel; private readonly logProvider: LogProvider; @@ -23,17 +26,10 @@ export class Stopwatch { return this._time; } - constructor( - private readonly scope: string | LogScope | undefined, - options?: StopwatchOptions, - ...params: any[] - ) { - let logScope; - if (typeof scope !== 'string') { - logScope = scope; - scope = ''; - this.instance = ''; - } + private _stopped = false; + + constructor(scope: string | LogScope | undefined, options?: StopwatchOptions, ...params: any[]) { + this.logScope = scope != null && typeof scope !== 'string' ? scope : getNewLogScope(scope ?? ''); let logOptions: StopwatchLogOptions | undefined; if (typeof options?.log === 'boolean') { @@ -52,57 +48,51 @@ export class Stopwatch { if (params.length) { this.logProvider.log( this.logLevel, - logScope, - `${this.instance}${scope}${logOptions.message ?? ''}${logOptions.suffix ?? ''}`, + this.logScope, + `${logOptions.message ?? ''}${logOptions.suffix ?? ''}`, ...params, ); } else { this.logProvider.log( this.logLevel, - logScope, - `${this.instance}${scope}${logOptions.message ?? ''}${logOptions.suffix ?? ''}`, + this.logScope, + `${logOptions.message ?? ''}${logOptions.suffix ?? ''}`, ); } } } + [Symbol.dispose](): void { + this.stop(); + } + elapsed(): number { const [secs, nanosecs] = hrtime(this._time); return secs * 1000 + Math.floor(nanosecs / 1000000); } log(options?: StopwatchLogOptions): void { - this.logCore(this.scope, options, false); + this.logCore(options, false); } restart(options?: StopwatchLogOptions): void { - this.logCore(this.scope, options, true); + this.logCore(options, true); this._time = hrtime(); + this._stopped = false; } stop(options?: StopwatchLogOptions): void { + if (this._stopped) return; + this.restart(options); + this._stopped = true; } - private logCore( - scope: string | LogScope | undefined, - options: StopwatchLogOptions | undefined, - logTotalElapsed: boolean, - ): void { + private logCore(options: StopwatchLogOptions | undefined, logTotalElapsed: boolean): void { if (!this.logProvider.enabled(this.logLevel)) return; - let logScope; - if (typeof scope !== 'string') { - logScope = scope; - scope = ''; - } - if (!logTotalElapsed) { - this.logProvider.log( - this.logLevel, - logScope, - `${this.instance}${scope}${options?.message ?? ''}${options?.suffix ?? ''}`, - ); + this.logProvider.log(this.logLevel, this.logScope, `${options?.message ?? ''}${options?.suffix ?? ''}`); return; } @@ -110,10 +100,10 @@ export class Stopwatch { const [secs, nanosecs] = hrtime(this._time); const ms = secs * 1000 + Math.floor(nanosecs / 1000000); - const prefix = `${this.instance}${scope}${options?.message ?? ''}`; + const prefix = options?.message ?? ''; this.logProvider.log( ms > 250 ? 'warn' : this.logLevel, - logScope, + this.logScope, `${prefix ? `${prefix} ` : ''}[${ms}ms]${options?.suffix ?? ''}`, ); } diff --git a/src/webviews/apps/tsconfig.json b/src/webviews/apps/tsconfig.json index a218684ed405a..a2c68ad8ddb06 100644 --- a/src/webviews/apps/tsconfig.json +++ b/src/webviews/apps/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../../tsconfig.base.json", "compilerOptions": { "jsx": "react", - "lib": ["dom", "dom.iterable", "es2022"], + "lib": ["dom", "dom.iterable", "es2022", "esnext.disposable"], "outDir": "../../", "paths": { "@env/*": ["src/env/browser/*"] diff --git a/tsconfig.base.json b/tsconfig.base.json index 4aeda77b862ae..4c5295e11e13b 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -6,7 +6,7 @@ "forceConsistentCasingInFileNames": true, "incremental": true, "isolatedModules": true, - "lib": ["es2022"], + "lib": ["es2022", "esnext.disposable"], "module": "esnext", "moduleResolution": "node", "noFallthroughCasesInSwitch": true, diff --git a/tsconfig.browser.json b/tsconfig.browser.json index 66a5af9bb3c0a..13a30b979c108 100644 --- a/tsconfig.browser.json +++ b/tsconfig.browser.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "lib": ["dom", "dom.iterable", "es2022"], + "lib": ["dom", "dom.iterable", "es2022", "esnext.disposable"], "paths": { "@env/*": ["src/env/browser/*"], "path": ["node_modules/path-browserify"] From 75c89e7595bf2c317652d5c54755fbdd27eec34f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 17 Oct 2023 02:59:22 -0400 Subject: [PATCH 0058/1012] Removes `radius` sensitivity as it breaks clicks Refs: https://github.com/naver/billboard.js/issues/3466 --- src/webviews/apps/plus/timeline/chart.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webviews/apps/plus/timeline/chart.ts b/src/webviews/apps/plus/timeline/chart.ts index 3f5195ed60f7d..6e23bd366f6a7 100644 --- a/src/webviews/apps/plus/timeline/chart.ts +++ b/src/webviews/apps/plus/timeline/chart.ts @@ -411,9 +411,9 @@ export class TimelineChart implements Disposable { // hide: this.compact ? [...this._authorsByIndex.values()] : undefined, padding: 10, }, - point: { - sensitivity: 'radius', - }, + // point: { + // sensitivity: 'radius', + // }, resize: { auto: false, }, From bbfb66a7e1b7c28e9b7ced8fc7e730990a073107 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 17 Oct 2023 01:09:09 -0400 Subject: [PATCH 0059/1012] Reorders props --- src/container.ts | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/container.ts b/src/container.ts index e7744880de8fb..561027f31d674 100644 --- a/src/container.ts +++ b/src/container.ts @@ -330,6 +330,11 @@ export class Container { return this._accountAuthentication; } + private readonly _accountView: WebviewViewProxy; + get accountView() { + return this._accountView; + } + private readonly _actionRunners: ActionRunners; get actionRunners() { return this._actionRunners; @@ -396,6 +401,11 @@ export class Container { return this._context.extensionMode === ExtensionMode.Development; } + private readonly _deepLinks: DeepLinkService; + get deepLinks() { + return this._deepLinks; + } + @memoize() get env(): Environment { if (this.prereleaseOrDebugging) { @@ -422,21 +432,6 @@ export class Container { return this._fileHistoryView; } - private readonly _git: GitProviderService; - get git() { - return this._git; - } - - private readonly _uri: UriService; - get uri() { - return this._uri; - } - - private readonly _deepLinks: DeepLinkService; - get deepLinks() { - return this._deepLinks; - } - private _focus: FocusService | undefined; get focus() { if (this._focus == null) { @@ -446,6 +441,11 @@ export class Container { return this._focus; } + private readonly _git: GitProviderService; + get git() { + return this._git; + } + private _github: Promise | undefined; get github() { if (this._github == null) { @@ -502,11 +502,6 @@ export class Container { return this._homeView; } - private readonly _accountView: WebviewViewProxy; - get accountView() { - return this._accountView; - } - @memoize() get id() { return this._context.extension.id; @@ -551,6 +546,14 @@ export class Container { return this._lineTracker; } + private _mode: ModeConfig | undefined; + get mode() { + if (this._mode == null) { + this._mode = configuration.get('modes')?.[configuration.get('mode.active')]; + } + return this._mode; + } + private readonly _prerelease; get prerelease() { return this._prerelease; @@ -637,6 +640,11 @@ export class Container { return this._tracker; } + private readonly _uri: UriService; + get uri() { + return this._uri; + } + private readonly _usage: UsageTracker; get usage(): UsageTracker { return this._usage; @@ -678,14 +686,6 @@ export class Container { return this._worktreesView; } - private _mode: ModeConfig | undefined; - get mode() { - if (this._mode == null) { - this._mode = configuration.get('modes')?.[configuration.get('mode.active')]; - } - return this._mode; - } - private ensureModeApplied() { const mode = this.mode; if (mode == null) { From 044887bf00452cd1efeb538861d5adf632448734 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 17 Oct 2023 01:09:54 -0400 Subject: [PATCH 0060/1012] Un-nests ifs --- src/plus/webviews/graph/graphWebview.ts | 12 +++++------- src/plus/webviews/timeline/timelineWebview.ts | 6 ++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index e4f58fe6a2a06..a6cb4eba4d606 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -753,13 +753,11 @@ export class GraphWebviewProvider implements WebviewProvider { } private onThemeChanged(theme: ColorTheme) { - if (this._theme != null) { - if ( - (isDarkTheme(theme) && isDarkTheme(this._theme)) || - (isLightTheme(theme) && isLightTheme(this._theme)) - ) { - return; - } + if ( + this._theme != null && + ((isDarkTheme(theme) && isDarkTheme(this._theme)) || (isLightTheme(theme) && isLightTheme(this._theme))) + ) { + return; } this._theme = theme; diff --git a/src/plus/webviews/timeline/timelineWebview.ts b/src/plus/webviews/timeline/timelineWebview.ts index 6ddf2467c82c1..65550cc3702b0 100644 --- a/src/plus/webviews/timeline/timelineWebview.ts +++ b/src/plus/webviews/timeline/timelineWebview.ts @@ -223,10 +223,8 @@ export class TimelineWebviewProvider implements WebviewProvider { if (e.data == null) return; let uri: Uri | undefined = e.data.uri; - if (uri != null) { - if (!this.container.git.isTrackable(uri)) { - uri = undefined; - } + if (uri != null && !this.container.git.isTrackable(uri)) { + uri = undefined; } if (!this.updatePendingUri(uri)) return; From 7f4466bce83d908877d7dd295732b0b815584129 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 17 Oct 2023 01:24:50 -0400 Subject: [PATCH 0061/1012] Improves graph restore on startup --- src/plus/webviews/graph/graphWebview.ts | 32 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index a6cb4eba4d606..1671ae66044bf 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -217,7 +217,9 @@ export class GraphWebviewProvider implements WebviewProvider { return this._selection?.[0]; } + private _discovering: Promise | undefined; private readonly _disposable: Disposable; + private _etag?: number; private _etagSubscription?: number; private _etagRepository?: number; private _firstSelection = true; @@ -261,7 +263,16 @@ export class GraphWebviewProvider implements WebviewProvider { this._disposable = Disposable.from( configuration.onDidChange(this.onConfigurationChanged, this), this.container.subscription.onDidChange(this.onSubscriptionChanged, this), - this.container.git.onDidChangeRepositories(() => void this.host.refresh(true)), + this.container.git.onDidChangeRepositories(async () => { + if (this._etag !== this.container.git.etag) { + if (this._discovering != null) { + this._etag = await this._discovering; + if (this._etag === this.container.git.etag) return; + } + + void this.host.refresh(true); + } + }), window.onDidChangeActiveColorTheme(this.onThemeChanged, this), { dispose: () => { @@ -284,6 +295,15 @@ export class GraphWebviewProvider implements WebviewProvider { ): Promise { this._firstSelection = true; + this._etag = this.container.git.etag; + if (this.container.git.isDiscoveringRepositories) { + this._discovering = this.container.git.isDiscoveringRepositories.then(r => { + this._discovering = undefined; + return r; + }); + this._etag = await this._discovering; + } + const [arg] = args; if (isRepository(arg)) { this.repository = arg; @@ -508,10 +528,10 @@ export class GraphWebviewProvider implements WebviewProvider { } onFocusChanged(focused: boolean): void { + this._showActiveSelectionDetailsDebounced?.cancel(); void this.notifyDidChangeFocus(focused); if (!focused || this.activeSelection == null || !this.container.commitDetailsView.visible) { - this._showActiveSelectionDetailsDebounced?.cancel(); return; } @@ -810,6 +830,8 @@ export class GraphWebviewProvider implements WebviewProvider { ); } } else if (e.type === 'row' && e.row) { + this._showActiveSelectionDetailsDebounced?.cancel(); + const commit = this.getRevisionReference(this.repository?.path, e.row.id, e.row.type); if (commit != null) { this.container.events.fire( @@ -1166,11 +1188,13 @@ export class GraphWebviewProvider implements WebviewProvider { undefined; private onSelectionChanged(e: UpdateSelectionParams) { + this._showActiveSelectionDetailsDebounced?.cancel(); + const item = e.selection[0]; this.setSelectedRows(item?.id); if (this._fireSelectionChangedDebounced == null) { - this._fireSelectionChangedDebounced = debounce(this.fireSelectionChanged.bind(this), 250); + this._fireSelectionChangedDebounced = debounce(this.fireSelectionChanged.bind(this), 50); } this._fireSelectionChangedDebounced(item?.id, item?.type); @@ -1900,7 +1924,7 @@ export class GraphWebviewProvider implements WebviewProvider { const columnSettings = this.getColumnSettings(columns); const dataPromise = this.container.git.getCommitsForGraph( - this.repository.path, + this.repository.uri, uri => this.host.asWebviewUri(uri), { include: { From 16692734bf24e087672244fd0451b201474c0eec Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 17 Oct 2023 01:42:20 -0400 Subject: [PATCH 0062/1012] Adds support for multi-instance webview panels - Prepares Graph, Focus, & Timeline for multi-instance support --- src/constants.ts | 1 - src/container.ts | 38 ++-- src/plus/webviews/account/accountWebview.ts | 3 +- src/plus/webviews/account/protocol.ts | 7 +- src/plus/webviews/focus/focusWebview.ts | 20 +- src/plus/webviews/focus/protocol.ts | 7 +- src/plus/webviews/focus/registration.ts | 15 +- src/plus/webviews/graph/graphWebview.ts | 21 ++- src/plus/webviews/graph/protocol.ts | 7 +- src/plus/webviews/graph/registration.ts | 25 ++- src/plus/webviews/timeline/protocol.ts | 7 +- src/plus/webviews/timeline/registration.ts | 15 +- src/plus/webviews/timeline/timelineWebview.ts | 47 ++--- src/system/webview.ts | 6 +- .../apps/commitDetails/commitDetails.html | 2 +- src/webviews/apps/home/home.html | 6 +- src/webviews/apps/plus/account/account.html | 2 +- src/webviews/apps/plus/focus/focus.html | 6 +- src/webviews/apps/plus/graph/GraphWrapper.tsx | 14 +- src/webviews/apps/plus/graph/graph.html | 2 +- src/webviews/apps/plus/timeline/timeline.html | 6 +- src/webviews/apps/rebase/rebase.html | 6 +- src/webviews/apps/settings/settings.html | 6 +- src/webviews/apps/welcome/welcome.html | 2 +- .../commitDetails/commitDetailsWebview.ts | 3 +- src/webviews/commitDetails/protocol.ts | 6 +- src/webviews/home/homeWebview.ts | 3 +- src/webviews/home/protocol.ts | 7 +- src/webviews/protocol.ts | 7 + src/webviews/rebase/protocol.ts | 6 +- src/webviews/rebase/rebaseEditor.ts | 2 + src/webviews/settings/protocol.ts | 7 +- src/webviews/settings/registration.ts | 8 +- src/webviews/settings/settingsWebview.ts | 3 +- src/webviews/webviewCommandRegistrar.ts | 19 +- src/webviews/webviewController.ts | 41 ++-- src/webviews/webviewsController.ts | 178 +++++++++++++++--- src/webviews/welcome/protocol.ts | 7 +- src/webviews/welcome/registration.ts | 2 +- src/webviews/welcome/welcomeWebview.ts | 3 +- 40 files changed, 380 insertions(+), 193 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index db3461afd9707..6d91266ac4c1e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -223,7 +223,6 @@ export const enum Commands { RefreshFocus = 'gitlens.focus.refresh', RefreshGraph = 'gitlens.graph.refresh', RefreshHover = 'gitlens.refreshHover', - RefreshTimelinePage = 'gitlens.timeline.refresh', ResetAvatarCache = 'gitlens.resetAvatarCache', ResetAIKey = 'gitlens.resetAIKey', ResetSuppressedWarnings = 'gitlens.resetSuppressedWarnings', diff --git a/src/container.ts b/src/container.ts index 561027f31d674..4a25bbd836a5e 100644 --- a/src/container.ts +++ b/src/container.ts @@ -27,14 +27,18 @@ import { ServerConnection } from './plus/gk/serverConnection'; import { IntegrationAuthenticationService } from './plus/integrationAuthentication'; import { SubscriptionService } from './plus/subscription/subscriptionService'; import { registerAccountWebviewView } from './plus/webviews/account/registration'; -import { registerFocusWebviewPanel } from './plus/webviews/focus/registration'; +import { registerFocusWebviewCommands, registerFocusWebviewPanel } from './plus/webviews/focus/registration'; import { registerGraphWebviewCommands, registerGraphWebviewPanel, registerGraphWebviewView, } from './plus/webviews/graph/registration'; import { GraphStatusBarController } from './plus/webviews/graph/statusbar'; -import { registerTimelineWebviewPanel, registerTimelineWebviewView } from './plus/webviews/timeline/registration'; +import { + registerTimelineWebviewCommands, + registerTimelineWebviewPanel, + registerTimelineWebviewView, +} from './plus/webviews/timeline/registration'; import { scheduleAddMissingCurrentWorkspaceRepos, WorkspacesService } from './plus/workspaces/workspacesService'; import { StatusBarController } from './statusbar/statusBarController'; import { executeCommand } from './system/command'; @@ -73,7 +77,7 @@ import { import { registerHomeWebviewView } from './webviews/home/registration'; import { RebaseEditorProvider } from './webviews/rebase/rebaseEditor'; import { registerSettingsWebviewCommands, registerSettingsWebviewPanel } from './webviews/settings/registration'; -import type { WebviewPanelProxy, WebviewViewProxy } from './webviews/webviewsController'; +import type { WebviewViewProxy } from './webviews/webviewsController'; import { WebviewsController } from './webviews/webviewsController'; import { registerWelcomeWebviewPanel } from './webviews/welcome/registration'; @@ -220,20 +224,29 @@ export class Container { this._disposables.push((this._codeLensController = new GitCodeLensController(this))); this._disposables.push((this._webviews = new WebviewsController(this))); - this._disposables.push(registerTimelineWebviewPanel(this._webviews)); - this._disposables.push((this._timelineView = registerTimelineWebviewView(this._webviews))); - this._disposables.push((this._graphPanel = registerGraphWebviewPanel(this._webviews))); - this._disposables.push(registerGraphWebviewCommands(this, this._graphPanel)); + const graphPanels = registerGraphWebviewPanel(this._webviews); + this._disposables.push(graphPanels); + this._disposables.push(registerGraphWebviewCommands(this, graphPanels)); this._disposables.push((this._graphView = registerGraphWebviewView(this._webviews))); this._disposables.push(new GraphStatusBarController(this)); - const settingsWebviewPanel = registerSettingsWebviewPanel(this._webviews); - this._disposables.push(settingsWebviewPanel); - this._disposables.push(registerSettingsWebviewCommands(settingsWebviewPanel)); - this._disposables.push(registerWelcomeWebviewPanel(this._webviews)); + const focusPanels = registerFocusWebviewPanel(this._webviews); + this._disposables.push(focusPanels); + this._disposables.push(registerFocusWebviewCommands(focusPanels)); + + const timelinePanels = registerTimelineWebviewPanel(this._webviews); + this._disposables.push(timelinePanels); + this._disposables.push(registerTimelineWebviewCommands(timelinePanels)); + this._disposables.push((this._timelineView = registerTimelineWebviewView(this._webviews))); + this._disposables.push((this._rebaseEditor = new RebaseEditorProvider(this))); - this._disposables.push(registerFocusWebviewPanel(this._webviews)); + + const settingsPanels = registerSettingsWebviewPanel(this._webviews); + this._disposables.push(settingsPanels); + this._disposables.push(registerSettingsWebviewCommands(settingsPanels)); + + this._disposables.push(registerWelcomeWebviewPanel(this._webviews)); this._disposables.push(new ViewFileDecorationProvider()); @@ -491,7 +504,6 @@ export class Container { return this._graphDetailsView; } - private readonly _graphPanel: WebviewPanelProxy; private readonly _graphView: WebviewViewProxy; get graphView() { return this._graphView; diff --git a/src/plus/webviews/account/accountWebview.ts b/src/plus/webviews/account/accountWebview.ts index 0abd69ffb0252..f15b08b443f7f 100644 --- a/src/plus/webviews/account/accountWebview.ts +++ b/src/plus/webviews/account/accountWebview.ts @@ -87,8 +87,7 @@ export class AccountWebviewProvider implements WebviewProvider { const subscriptionResult = await this.getSubscription(subscription); return { - webviewId: this.host.id, - timestamp: Date.now(), + ...this.host.baseWebviewState, webroot: this.host.getWebRoot(), subscription: subscriptionResult.subscription, avatar: subscriptionResult.avatar, diff --git a/src/plus/webviews/account/protocol.ts b/src/plus/webviews/account/protocol.ts index 30b27ffaa6122..75a3ae58fbc0d 100644 --- a/src/plus/webviews/account/protocol.ts +++ b/src/plus/webviews/account/protocol.ts @@ -1,11 +1,8 @@ -import type { WebviewIds, WebviewViewIds } from '../../../constants'; import type { Subscription } from '../../../subscription'; +import type { WebviewState } from '../../../webviews/protocol'; import { IpcNotificationType } from '../../../webviews/protocol'; -export interface State { - webviewId: WebviewIds | WebviewViewIds; - timestamp: number; - +export interface State extends WebviewState { webroot?: string; subscription: Subscription; avatar?: string; diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 8b0ac774fb65b..44f3f12c2ab3e 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -24,7 +24,7 @@ import type { GitWorktree } from '../../../git/models/worktree'; import { getWorktreeForBranch } from '../../../git/models/worktree'; import { parseGitRemoteUrl } from '../../../git/parsers/remoteParser'; import type { RichRemoteProvider } from '../../../git/remotes/richRemoteProvider'; -import { executeCommand, registerCommand } from '../../../system/command'; +import { executeCommand } from '../../../system/command'; import { debug } from '../../../system/decorators/log'; import { Logger } from '../../../system/logger'; import { getLogScope } from '../../../system/logger.scope'; @@ -115,10 +115,6 @@ export class FocusWebviewProvider implements WebviewProvider { this._disposable.dispose(); } - registerCommands(): Disposable[] { - return [registerCommand(Commands.RefreshFocus, () => this.host.refresh(true))]; - } - onMessageReceived(e: IpcMessage) { switch (e.method) { case OpenBranchCommandType.method: @@ -433,7 +429,7 @@ export class FocusWebviewProvider implements WebviewProvider { @debug() private async getState(force?: boolean, deferState?: boolean): Promise { - const webviewId = this.host.id; + const baseState = this.host.baseWebviewState; this._etag = this.container.git.etag; if (this.container.git.isDiscoveringRepositories) { @@ -447,8 +443,7 @@ export class FocusWebviewProvider implements WebviewProvider { const access = await this.getAccess(force); if (access.allowed !== true) { return { - webviewId: webviewId, - timestamp: Date.now(), + ...baseState, access: access, }; } @@ -460,8 +455,7 @@ export class FocusWebviewProvider implements WebviewProvider { if (!hasConnectedRepos) { return { - webviewId: webviewId, - timestamp: Date.now(), + ...baseState, access: access, repos: githubRepos.map(r => serializeRepoWithRichRemote(r)), }; @@ -478,8 +472,7 @@ export class FocusWebviewProvider implements WebviewProvider { async function getStateCore() { const [prsResult, issuesResult, enrichedItems] = await statePromise; return { - webviewId: webviewId, - timestamp: Date.now(), + ...baseState, access: access, repos: repos, pullRequests: getSettledValue(prsResult)?.map(pr => ({ @@ -508,8 +501,7 @@ export class FocusWebviewProvider implements WebviewProvider { }); return { - webviewId: webviewId, - timestamp: Date.now(), + ...baseState, access: access, repos: repos, }; diff --git a/src/plus/webviews/focus/protocol.ts b/src/plus/webviews/focus/protocol.ts index f40778ce4eb5b..33d769700e9eb 100644 --- a/src/plus/webviews/focus/protocol.ts +++ b/src/plus/webviews/focus/protocol.ts @@ -1,14 +1,11 @@ -import type { WebviewIds, WebviewViewIds } from '../../../constants'; import type { FeatureAccess } from '../../../features'; import type { IssueShape } from '../../../git/models/issue'; import type { PullRequestShape } from '../../../git/models/pullRequest'; +import type { WebviewState } from '../../../webviews/protocol'; import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol'; import type { EnrichedItem } from '../../focus/focusService'; -export interface State { - webviewId: WebviewIds | WebviewViewIds; - timestamp: number; - +export interface State extends WebviewState { access: FeatureAccess; pullRequests?: PullRequestResult[]; issues?: IssueResult[]; diff --git a/src/plus/webviews/focus/registration.ts b/src/plus/webviews/focus/registration.ts index 44f70f73c0934..da51309e27b9e 100644 --- a/src/plus/webviews/focus/registration.ts +++ b/src/plus/webviews/focus/registration.ts @@ -1,11 +1,12 @@ -import { ViewColumn } from 'vscode'; +import { Disposable, ViewColumn } from 'vscode'; import { Commands } from '../../../constants'; -import type { WebviewsController } from '../../../webviews/webviewsController'; +import { registerCommand } from '../../../system/command'; +import type { WebviewPanelsProxy, WebviewsController } from '../../../webviews/webviewsController'; import type { State } from './protocol'; export function registerFocusWebviewPanel(controller: WebviewsController) { return controller.registerWebviewPanel( - Commands.ShowFocusPage, + { id: Commands.ShowFocusPage }, { id: 'gitlens.focus', fileName: 'focus.html', @@ -26,3 +27,11 @@ export function registerFocusWebviewPanel(controller: WebviewsController) { }, ); } + +export function registerFocusWebviewCommands(panels: WebviewPanelsProxy) { + return Disposable.from( + registerCommand(`${panels.id}.refresh`, () => { + void panels.getActiveOrFirstInstance()?.refresh(true); + }), + ); +} diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 1671ae66044bf..c434563a62039 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -84,6 +84,7 @@ import { RepositoryFolderNode } from '../../../views/nodes/viewNode'; import type { IpcMessage, IpcNotificationType } from '../../../webviews/protocol'; import { onIpc } from '../../../webviews/protocol'; import type { WebviewController, WebviewProvider } from '../../../webviews/webviewController'; +import type { WebviewPanelShowCommandArgs } from '../../../webviews/webviewsController'; import { isSerializedState } from '../../../webviews/webviewsController'; import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService'; import type { @@ -363,13 +364,17 @@ export class GraphWebviewProvider implements WebviewProvider { registerCommands(): Disposable[] { return [ - registerCommand(`${this.host.id}.refresh`, () => this.host.refresh(true)), - ...(this.host.isView() ? [ + registerCommand(`${this.host.id}.refresh`, () => this.host.refresh(true)), registerCommand( `${this.host.id}.openInTab`, - () => void executeCommand(Commands.ShowGraphPage, this.repository), + () => + void executeCommand( + Commands.ShowGraphPage, + undefined, + this.repository, + ), ), ] : []), @@ -668,7 +673,7 @@ export class GraphWebviewProvider implements WebviewProvider { private showActiveSelectionDetailsCore() { const { activeSelection } = this; - if (activeSelection == null) return; + if (activeSelection == null || !this.host.active) return; this.container.events.fire( 'commit:selected', @@ -1209,6 +1214,7 @@ export class GraphWebviewProvider implements WebviewProvider { this._selection = commits; if (commits == null) return; + if (!this._firstSelection && !this.host.active) return; this.container.events.fire( 'commit:selected', @@ -1899,13 +1905,13 @@ export class GraphWebviewProvider implements WebviewProvider { private async getState(deferRows?: boolean): Promise { if (this.container.git.repositoryCount === 0) { - return { webviewId: this.host.id, timestamp: Date.now(), allowed: true, repositories: [] }; + return { ...this.host.baseWebviewState, allowed: true, repositories: [] }; } if (this.repository == null) { this.repository = this.container.git.getBestRepositoryOrFirst(); if (this.repository == null) { - return { webviewId: this.host.id, timestamp: Date.now(), allowed: true, repositories: [] }; + return { ...this.host.baseWebviewState, allowed: true, repositories: [] }; } } @@ -1990,8 +1996,7 @@ export class GraphWebviewProvider implements WebviewProvider { } return { - webviewId: this.host.id, - timestamp: Date.now(), + ...this.host.baseWebviewState, windowFocused: this.isWindowFocused, repositories: formatRepositories(this.container.git.openRepositories), selectedRepository: this.repository.path, diff --git a/src/plus/webviews/graph/protocol.ts b/src/plus/webviews/graph/protocol.ts index cfe1144dd0b03..b23b39217a044 100644 --- a/src/plus/webviews/graph/protocol.ts +++ b/src/plus/webviews/graph/protocol.ts @@ -23,7 +23,6 @@ import type { WorkDirStats, } from '@gitkraken/gitkraken-components'; import type { Config, DateStyle } from '../../../config'; -import type { WebviewIds, WebviewViewIds } from '../../../constants'; import type { RepositoryVisibility } from '../../../git/gitProvider'; import type { GitTrackingState } from '../../../git/models/branch'; import type { GitGraphRowType } from '../../../git/models/graph'; @@ -38,6 +37,7 @@ import type { GitSearchResultData, SearchQuery } from '../../../git/search'; import type { Subscription } from '../../../subscription'; import type { DateTimeFormat } from '../../../system/date'; import type { WebviewItemContext, WebviewItemGroupContext } from '../../../system/webview'; +import type { WebviewState } from '../../../webviews/protocol'; import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol'; export type { GraphRefType } from '@gitkraken/gitkraken-components'; @@ -81,10 +81,7 @@ export type GraphMinimapMarkerTypes = export const supportedRefMetadataTypes: GraphRefMetadataType[] = ['upstream', 'pullRequest', 'issue']; -export interface State { - webviewId: WebviewIds | WebviewViewIds; - timestamp: number; - +export interface State extends WebviewState { windowFocused?: boolean; repositories?: GraphRepository[]; selectedRepository?: string; diff --git a/src/plus/webviews/graph/registration.ts b/src/plus/webviews/graph/registration.ts index ebc4b9b36c8ef..a331893ec9213 100644 --- a/src/plus/webviews/graph/registration.ts +++ b/src/plus/webviews/graph/registration.ts @@ -10,12 +10,16 @@ import type { CommitFileNode } from '../../../views/nodes/commitFileNode'; import type { CommitNode } from '../../../views/nodes/commitNode'; import type { StashNode } from '../../../views/nodes/stashNode'; import type { TagNode } from '../../../views/nodes/tagNode'; -import type { WebviewPanelProxy, WebviewsController } from '../../../webviews/webviewsController'; +import type { + WebviewPanelShowCommandArgs, + WebviewPanelsProxy, + WebviewsController, +} from '../../../webviews/webviewsController'; import type { ShowInCommitGraphCommandArgs, State } from './protocol'; export function registerGraphWebviewPanel(controller: WebviewsController) { return controller.registerWebviewPanel( - Commands.ShowGraphPage, + { id: Commands.ShowGraphPage }, { id: 'gitlens.graph', fileName: 'graph.html', @@ -57,18 +61,18 @@ export function registerGraphWebviewView(controller: WebviewsController) { ); } -export function registerGraphWebviewCommands(container: Container, webview: WebviewPanelProxy) { +export function registerGraphWebviewCommands(container: Container, panels: WebviewPanelsProxy) { return Disposable.from( - registerCommand(Commands.ShowGraph, (...args: any[]) => + registerCommand(Commands.ShowGraph, (...args: unknown[]) => configuration.get('graph.layout') === 'panel' ? executeCommand(Commands.ShowGraphView, ...args) - : executeCommand(Commands.ShowGraphPage, ...args), + : executeCommand(Commands.ShowGraphPage, undefined, ...args), ), - registerCommand('gitlens.graph.switchToEditorLayout', async () => { + registerCommand(`${panels.id}.switchToEditorLayout`, async () => { await configuration.updateEffective('graph.layout', 'editor'); - queueMicrotask(() => void executeCommand(Commands.ShowGraphPage)); + queueMicrotask(() => void executeCommand(Commands.ShowGraphPage)); }), - registerCommand('gitlens.graph.switchToPanelLayout', async () => { + registerCommand(`${panels.id}.switchToPanelLayout`, async () => { await configuration.updateEffective('graph.layout', 'panel'); queueMicrotask(async () => { await executeCoreCommand('gitlens.views.graph.resetViewLocation'); @@ -107,7 +111,7 @@ export function registerGraphWebviewCommands(container: Container, webview: Webv if (configuration.get('graph.layout') === 'panel') { void container.graphView.show({ preserveFocus: preserveFocus }, args); } else { - void webview.show({ preserveFocus: preserveFocus }, args); + void panels.show({ preserveFocus: preserveFocus }, args); } }, ), @@ -127,5 +131,8 @@ export function registerGraphWebviewCommands(container: Container, webview: Webv void container.graphView.show({ preserveFocus: preserveFocus }, args); }, ), + registerCommand(`${panels.id}.refresh`, () => { + void panels.getActiveOrFirstInstance()?.refresh(true); + }), ); } diff --git a/src/plus/webviews/timeline/protocol.ts b/src/plus/webviews/timeline/protocol.ts index 4666e0690f1b9..7599e648f604b 100644 --- a/src/plus/webviews/timeline/protocol.ts +++ b/src/plus/webviews/timeline/protocol.ts @@ -1,11 +1,8 @@ -import type { WebviewIds, WebviewViewIds } from '../../../constants'; import type { FeatureAccess } from '../../../features'; +import type { WebviewState } from '../../../webviews/protocol'; import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol'; -export interface State { - webviewId: WebviewIds | WebviewViewIds; - timestamp: number; - +export interface State extends WebviewState { dataset?: Commit[]; period: Period; title?: string; diff --git a/src/plus/webviews/timeline/registration.ts b/src/plus/webviews/timeline/registration.ts index 957cb208cd7e1..8cbf01f4967fc 100644 --- a/src/plus/webviews/timeline/registration.ts +++ b/src/plus/webviews/timeline/registration.ts @@ -1,11 +1,12 @@ -import { ViewColumn } from 'vscode'; +import { Disposable, ViewColumn } from 'vscode'; import { Commands } from '../../../constants'; -import type { WebviewsController } from '../../../webviews/webviewsController'; +import { registerCommand } from '../../../system/command'; +import type { WebviewPanelsProxy, WebviewsController } from '../../../webviews/webviewsController'; import type { State } from './protocol'; export function registerTimelineWebviewPanel(controller: WebviewsController) { return controller.registerWebviewPanel( - Commands.ShowTimelinePage, + { id: Commands.ShowTimelinePage }, { id: 'gitlens.timeline', fileName: 'timeline.html', @@ -46,3 +47,11 @@ export function registerTimelineWebviewView(controller: WebviewsController) { }, ); } + +export function registerTimelineWebviewCommands(panels: WebviewPanelsProxy) { + return Disposable.from( + registerCommand(`${panels.id}.refresh`, () => { + void panels.getActiveOrFirstInstance()?.refresh(true); + }), + ); +} diff --git a/src/plus/webviews/timeline/timelineWebview.ts b/src/plus/webviews/timeline/timelineWebview.ts index 65550cc3702b0..06b964497b44c 100644 --- a/src/plus/webviews/timeline/timelineWebview.ts +++ b/src/plus/webviews/timeline/timelineWebview.ts @@ -1,5 +1,5 @@ import type { TextEditor, ViewColumn } from 'vscode'; -import { commands, Disposable, Uri, window } from 'vscode'; +import { Disposable, Uri, window } from 'vscode'; import { Commands } from '../../../constants'; import type { Container } from '../../../container'; import type { CommitSelectedEvent, FileSelectedEvent } from '../../../eventBus'; @@ -9,7 +9,7 @@ import { GitUri } from '../../../git/gitUri'; import { getChangedFilesCount } from '../../../git/models/commit'; import type { RepositoryChangeEvent } from '../../../git/models/repository'; import { RepositoryChange, RepositoryChangeComparisonMode } from '../../../git/models/repository'; -import { registerCommand } from '../../../system/command'; +import { executeCommand, registerCommand } from '../../../system/command'; import { configuration } from '../../../system/configuration'; import { createFromDateDelta } from '../../../system/date'; import { debug } from '../../../system/decorators/log'; @@ -23,6 +23,7 @@ import type { IpcMessage } from '../../../webviews/protocol'; import { onIpc } from '../../../webviews/protocol'; import type { WebviewController, WebviewProvider } from '../../../webviews/webviewController'; import { updatePendingContext } from '../../../webviews/webviewController'; +import type { WebviewPanelShowCommandArgs } from '../../../webviews/webviewsController'; import { isSerializedState } from '../../../webviews/webviewsController'; import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService'; import type { Commit, Period, State } from './protocol'; @@ -127,14 +128,24 @@ export class TimelineWebviewProvider implements WebviewProvider { } registerCommands(): Disposable[] { - if (this.host.isEditor()) { - return [registerCommand(Commands.RefreshTimelinePage, () => this.host.refresh(true))]; - } - - return [ - registerCommand(`${this.host.id}.refresh`, () => this.host.refresh(true), this), - registerCommand(`${this.host.id}.openInTab`, () => this.openInTab(), this), - ]; + return this.host.isView() + ? [ + registerCommand(`${this.host.id}.refresh`, () => this.host.refresh(true), this), + registerCommand( + `${this.host.id}.openInTab`, + () => { + if (this._context.uri == null) return; + + void executeCommand( + Commands.ShowTimelinePage, + { _type: 'WebviewPanelShowOptions' }, + this._context.uri, + ); + }, + this, + ), + ] + : []; } onVisibilityChanged(visible: boolean) { @@ -280,8 +291,7 @@ export class TimelineWebviewProvider implements WebviewProvider { if (current.uri == null || gitUri == null || repoPath == null || access.allowed === false) { const access = await this.container.git.access(PlusFeatures.Timeline, repoPath); return { - webviewId: this.host.id, - timestamp: Date.now(), + ...this.host.baseWebviewState, period: period, title: gitUri?.relativePath, sha: gitUri?.shortSha, @@ -303,8 +313,7 @@ export class TimelineWebviewProvider implements WebviewProvider { if (log == null) { return { - webviewId: this.host.id, - timestamp: Date.now(), + ...this.host.baseWebviewState, dataset: [], period: period, title: gitUri.relativePath, @@ -362,8 +371,7 @@ export class TimelineWebviewProvider implements WebviewProvider { dataset.sort((a, b) => b.sort - a.sort); return { - webviewId: this.host.id, - timestamp: Date.now(), + ...this.host.baseWebviewState, dataset: dataset, period: period, title: gitUri.relativePath, @@ -441,13 +449,6 @@ export class TimelineWebviewProvider implements WebviewProvider { if (!this.host.isView()) return task(); return window.withProgress({ location: { viewId: this.host.id } }, task); } - - private openInTab() { - const uri = this._context.uri; - if (uri == null) return; - - void commands.executeCommand(Commands.ShowTimelinePage, uri); - } } function getPeriodDate(period: Period): Date | undefined { diff --git a/src/system/webview.ts b/src/system/webview.ts index 4848ce96968c1..6ee2a0d8fb74c 100644 --- a/src/system/webview.ts +++ b/src/system/webview.ts @@ -3,12 +3,16 @@ import type { WebviewIds, WebviewViewIds } from '../constants'; export function createWebviewCommandLink( command: `${WebviewIds | WebviewViewIds}.${string}`, webviewId: WebviewIds | WebviewViewIds, + webviewInstanceId: string | undefined, ): string { - return `command:${command}?${encodeURIComponent(JSON.stringify({ webview: webviewId } satisfies WebviewContext))}`; + return `command:${command}?${encodeURIComponent( + JSON.stringify({ webview: webviewId, webviewInstance: webviewInstanceId } satisfies WebviewContext), + )}`; } export interface WebviewContext { webview: WebviewIds | WebviewViewIds; + webviewInstance: string | undefined; } export function isWebviewContext(item: object | null | undefined): item is WebviewContext { diff --git a/src/webviews/apps/commitDetails/commitDetails.html b/src/webviews/apps/commitDetails/commitDetails.html index 80e3966233598..d6dc36ce0748f 100644 --- a/src/webviews/apps/commitDetails/commitDetails.html +++ b/src/webviews/apps/commitDetails/commitDetails.html @@ -19,7 +19,7 @@ #{endOfBody} diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index c10bf9b57da84..16ccb17cdca79 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -16,7 +16,11 @@ - +
+

✨ Requires a trial or paid plan to use this on privately hosted repos.
☁️ Requires an account and access is based on your plan, e.g. Free, Pro, etc diff --git a/src/webviews/apps/home/home.scss b/src/webviews/apps/home/home.scss index 5209dadfc16cf..e104a7e7381fa 100644 --- a/src/webviews/apps/home/home.scss +++ b/src/webviews/apps/home/home.scss @@ -373,12 +373,25 @@ gl-button { &__label { font-weight: 600; + width: 100%; + } + + &__access { + position: relative; + left: 1.5rem; + filter: grayscale(1); + opacity: 0.4; } &__item:hover &__label { text-decoration: underline; } + &__item:hover &__access { + filter: none; + opacity: 1; + } + &__title { padding: 0 2rem; } diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html index 0a0a3620fd8a1..dfe5f7213b736 100644 --- a/src/webviews/apps/welcome/welcome.html +++ b/src/webviews/apps/welcome/welcome.html @@ -530,6 +530,27 @@

Configuration

> +

Companion Tools

+

Supercharge GitLens with our other dev tools

+ +

Resources

${when( From 61b51c750e7c601dba56d343b00a13d8bf88b76c Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Wed, 8 Nov 2023 14:17:36 -0700 Subject: [PATCH 0176/1012] Fixes initial patch repo location state on cloud patch open --- src/plus/drafts/draftsService.ts | 5 ++++- src/plus/repos/repositoryIdentityService.ts | 22 ++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index cf27364ef8d07..a5edbc91da0de 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -479,7 +479,10 @@ export class DraftService implements Disposable { const [contentsResult, repositoryResult] = await Promise.allSettled([ this.getPatchContentsCore(patch.secureLink), - this.container.repositoryIdentity.getRepositoryOrIdentity(patch.gkRepositoryId), + this.container.repositoryIdentity.getRepositoryOrIdentity(patch.gkRepositoryId, { + openIfNeeded: true, + skipRefValidation: true, + }), ]); const contents = getSettledValue(contentsResult)!; diff --git a/src/plus/repos/repositoryIdentityService.ts b/src/plus/repos/repositoryIdentityService.ts index c3353329c1c5b..8ecbf72553002 100644 --- a/src/plus/repos/repositoryIdentityService.ts +++ b/src/plus/repos/repositoryIdentityService.ts @@ -25,17 +25,17 @@ export class RepositoryIdentityService implements Disposable { getRepository( id: GkRepositoryId, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise; getRepository( identity: RepositoryIdentity, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise; @log() getRepository( idOrIdentity: GkRepositoryId | RepositoryIdentity, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise { return this.locateRepository(idOrIdentity, options); } @@ -43,7 +43,7 @@ export class RepositoryIdentityService implements Disposable { @log() async getRepositoryOrIdentity( id: GkRepositoryId, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise { const identity = await this.getRepositoryIdentity(id); return (await this.locateRepository(identity, options)) ?? identity; @@ -51,20 +51,20 @@ export class RepositoryIdentityService implements Disposable { private async locateRepository( id: GkRepositoryId, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise; private async locateRepository( identity: RepositoryIdentity, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise; private async locateRepository( idOrIdentity: GkRepositoryId | RepositoryIdentity, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise; @log() private async locateRepository( idOrIdentity: GkRepositoryId | RepositoryIdentity, - options?: { openIfNeeded?: boolean; prompt?: boolean }, + options?: { openIfNeeded?: boolean; prompt?: boolean; skipRefValidation?: boolean }, ): Promise { const identity = typeof idOrIdentity === 'string' ? await this.getRepositoryIdentity(idOrIdentity) : idOrIdentity; @@ -111,7 +111,11 @@ export class RepositoryIdentityService implements Disposable { } } - if (identity.initialCommitSha != null && identity.initialCommitSha !== missingRepositoryId) { + if ( + !options?.skipRefValidation && + identity.initialCommitSha != null && + identity.initialCommitSha !== missingRepositoryId + ) { // Repo ID can be any valid SHA in the repo, though standard practice is to use the // first commit SHA. if (await this.container.git.validateReference(repo.uri, identity.initialCommitSha)) { From a507615cb0a620a903a09e0858d1edc5fd5e7f34 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 8 Nov 2023 17:33:05 -0500 Subject: [PATCH 0177/1012] Adds links to cloud patches --- package.json | 9 +++++++++ src/commands/showView.ts | 3 +++ src/constants.ts | 1 + src/webviews/apps/home/home.html | 15 +++++++++++++++ src/webviews/apps/welcome/welcome.html | 14 ++++++++++++++ 5 files changed, 42 insertions(+) diff --git a/package.json b/package.json index 441d45bef12a0..8d8b7f674b75c 100644 --- a/package.json +++ b/package.json @@ -5093,6 +5093,11 @@ "title": "Show Contributors View", "category": "GitLens" }, + { + "command": "gitlens.showDraftsView", + "title": "Show Cloud Patches View", + "category": "GitLens" + }, { "command": "gitlens.showFileHistoryView", "title": "Show File History View", @@ -8597,6 +8602,10 @@ "command": "gitlens.showContributorsView", "when": "gitlens:enabled" }, + { + "command": "gitlens.showDraftsView", + "when": "gitlens:enabled" + }, { "command": "gitlens.showFileHistoryView", "when": "gitlens:enabled" diff --git a/src/commands/showView.ts b/src/commands/showView.ts index af4f4f9efec98..be20a6276342e 100644 --- a/src/commands/showView.ts +++ b/src/commands/showView.ts @@ -13,6 +13,7 @@ export class ShowViewCommand extends Command { Commands.ShowCommitDetailsView, Commands.ShowCommitsView, Commands.ShowContributorsView, + Commands.ShowDraftsView, Commands.ShowFileHistoryView, Commands.ShowGraphView, Commands.ShowHomeView, @@ -44,6 +45,8 @@ export class ShowViewCommand extends Command { return this.container.commitsView.show(); case Commands.ShowContributorsView: return this.container.contributorsView.show(); + case Commands.ShowDraftsView: + return this.container.draftsView.show(); case Commands.ShowFileHistoryView: return this.container.fileHistoryView.show(); case Commands.ShowHomeView: diff --git a/src/constants.ts b/src/constants.ts index 360f5506bc16a..815947cdd478c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -242,6 +242,7 @@ export const enum Commands { ShowCommitsInView = 'gitlens.showCommitsInView', ShowCommitsView = 'gitlens.showCommitsView', ShowContributorsView = 'gitlens.showContributorsView', + ShowDraftsView = 'gitlens.showDraftsView', ShowFileHistoryView = 'gitlens.showFileHistoryView', ShowFocusPage = 'gitlens.showFocusPage', ShowGraph = 'gitlens.showGraph', diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index c00e9796a0447..96bf7f036888f 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -214,6 +214,21 @@ >Search & Compare + Cloud Patches☁️ Side Bar Views aria-label="Show Search & Compare view" >Search & Compare + Cloud Patches ☁️ Popular views aria-label="Show Search & Compare view" >Search & Compare + Cloud Patches ☁️ Date: Wed, 8 Nov 2023 18:10:09 -0500 Subject: [PATCH 0178/1012] Hides patch links for now --- src/webviews/apps/home/home.html | 1 + src/webviews/apps/welcome/welcome.html | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index 96bf7f036888f..af67b4826b424 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -220,6 +220,7 @@ title="Show Cloud Patches view" aria-label="Show Cloud Patches view" data-requires="repo" + hidden >Cloud PatchesSide Bar Views data-requires="repo" title="Show Cloud Patches view" aria-label="Show Cloud Patches view" + hidden >Cloud Patches ☁️ Popular views data-requires="repo" title="Show Cloud Patches view" aria-label="Show Cloud Patches view" + hidden >Cloud Patches ☁️ Date: Wed, 8 Nov 2023 16:14:15 -0700 Subject: [PATCH 0179/1012] Adds promo messaging --- .../apps/plus/account/components/account-content.ts | 8 ++++++++ .../plus/shared/components/feature-gate-plus-state.ts | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/webviews/apps/plus/account/components/account-content.ts b/src/webviews/apps/plus/account/components/account-content.ts index e6f7430e2adcc..03bd16f022388 100644 --- a/src/webviews/apps/plus/account/components/account-content.ts +++ b/src/webviews/apps/plus/account/components/account-content.ts @@ -187,6 +187,10 @@ export class AccountContent extends LitElement { Your GitKraken trial has ended, please upgrade to continue to use ✨ features on privately hosted repos.

+

+ Special: 50% off GitKraken's suite of dev tools
+ 1st & 2nd seats only $4/month each +

Upgrade to Pro @@ -212,6 +216,10 @@ export class AccountContent extends LitElement { ${this.daysRemaining} remaining in your GitKraken trial.`} Once your trial ends, you'll need a paid plan to continue using ✨ features.

+

+ Special: 50% off GitKraken's suite of dev tools
+ 1st & 2nd seats only $4/month each +

Upgrade to Pro diff --git a/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts b/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts index f8e1baf0b3730..2e4e5c4b30de6 100644 --- a/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts +++ b/src/webviews/apps/plus/shared/components/feature-gate-plus-state.ts @@ -99,6 +99,10 @@ export class FeatureGatePlusState extends LitElement { Your GitKraken trial has ended, please upgrade to continue to use this on privately hosted repos.

+

+ Special: 50% off GitKraken's suite of dev tools
+ 1st & 2nd seats only $4/month each +

Upgrade to Pro From ebe7dc2075dee33d103f15652b94275fbe8f566b Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Wed, 8 Nov 2023 16:51:25 -0700 Subject: [PATCH 0180/1012] Fixes incorrect messaging on patch created notification --- src/plus/webviews/patchDetails/patchDetailsWebview.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 6d2865315a085..8efd1fa6c161e 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -381,15 +381,17 @@ export class PatchDetailsWebviewProvider async function showNotification() { const view = { title: 'View Patch' }; const copy = { title: 'Copy Link' }; + let copied = false; while (true) { const result = await window.showInformationMessage( - 'Cloud Patch successfully created \u2014 link copied to the clipboard', + `Cloud Patch successfully created${copied ? '\u2014 link copied to the clipboard' : ''}`, view, copy, ); if (result === copy) { void env.clipboard.writeText(draft.deepLinkUrl); + copied = true; continue; } From 2adc234fa12ec62f2ea65eebc106e76c710e4ef4 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 8 Nov 2023 18:55:11 -0500 Subject: [PATCH 0181/1012] Fixes repo wip states when creating --- src/plus/webviews/patchDetails/patchDetailsWebview.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 8efd1fa6c161e..907e34cd44f3c 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -555,7 +555,7 @@ export class PatchDetailsWebviewProvider let allRepos = false; if (create.changes != null) { - changesetByRepo = new Map(); + changesetByRepo = this._context.create?.changes ?? new Map(); const updated = new Set(); for (const change of create.changes) { @@ -607,7 +607,7 @@ export class PatchDetailsWebviewProvider sha: uncommitted, }, this.onRepositoryWipChanged.bind(this), - false, + true, true, // TODO revisit ), ]), From 2e4b99d118b27db7565327ef20ddd42c241520de Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 8 Nov 2023 19:42:18 -0500 Subject: [PATCH 0182/1012] Ensure patches view honors its setting --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d8b7f674b75c..286b4d70f8ccd 100644 --- a/package.json +++ b/package.json @@ -15388,7 +15388,7 @@ { "id": "gitlens.views.drafts", "name": "Cloud Patches", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && config.gitlens.cloudPatches.enabled", "contextualTitle": "GL", "icon": "$(cloud)", "initialSize": 2, From 64f9feb7460d01e2d8f3d00ad00a861a04309a39 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Wed, 8 Nov 2023 18:59:23 -0700 Subject: [PATCH 0183/1012] Adds account gating for cloud patch create and apply --- src/plus/webviews/patchDetails/patchDetailsWebview.ts | 5 +++++ src/uris/deepLinks/deepLinkService.ts | 4 ++-- src/views/draftsView.ts | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 907e34cd44f3c..fba611058dd21 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -28,6 +28,7 @@ import { onIpc } from '../../../webviews/protocol'; import type { WebviewController, WebviewProvider } from '../../../webviews/webviewController'; import type { WebviewShowOptions } from '../../../webviews/webviewsController'; import { showPatchesView } from '../../drafts/actions'; +import { ensureAccount } from '../../utils'; import type { ShowInCommitGraphCommandArgs } from '../graph/protocol'; import type { ApplyPatchParams, @@ -310,6 +311,8 @@ export class PatchDetailsWebviewProvider return; } + if (!(await ensureAccount('A GitKraken account is required to apply cloud patches.', this.container))) return; + const changeset = this._context.draft.changesets?.[0]; if (changeset == null) return; @@ -347,6 +350,8 @@ export class PatchDetailsWebviewProvider } private async createDraft({ title, changesets, description }: CreatePatchParams): Promise { + if (!(await ensureAccount('A GitKraken account is required to create cloud patches.', this.container))) return; + const createChanges: CreateDraftChange[] = []; const changes = Object.entries(changesets); diff --git a/src/uris/deepLinks/deepLinkService.ts b/src/uris/deepLinks/deepLinkService.ts index c56a1f1cc5b3a..0e0fc12b0dfdd 100644 --- a/src/uris/deepLinks/deepLinkService.ts +++ b/src/uris/deepLinks/deepLinkService.ts @@ -440,7 +440,7 @@ export class DeepLinkService implements Disposable { if ( !(await ensureAccount( - `Account required to open ${deepLinkTypeToString(targetType)} link`, + `A GitKraken account is required to open ${deepLinkTypeToString(targetType)} links.`, this.container, )) ) { @@ -465,7 +465,7 @@ export class DeepLinkService implements Disposable { if ( !(await ensurePaidPlan( - `Paid plan required to open ${deepLinkTypeToString(targetType)} link`, + `A paid plan is required to open ${deepLinkTypeToString(targetType)} links.`, this.container, )) ) { diff --git a/src/views/draftsView.ts b/src/views/draftsView.ts index 10b8e65e10177..5a8c088e8f2b6 100644 --- a/src/views/draftsView.ts +++ b/src/views/draftsView.ts @@ -110,7 +110,7 @@ export class DraftsView extends ViewBase<'drafts', DraftsViewNode, RepositoriesV const confirm = { title: 'Delete' }; const cancel = { title: 'Cancel', isCloseAffordance: true }; const result = await window.showInformationMessage( - `Are you sure you want to delete draft '${node.draft.title}'?`, + `Are you sure you want to delete Cloud Patch '${node.draft.title}'?`, { modal: true }, confirm, cancel, From e6fa3e034645855fdcfb1bc54021def5a1f446b2 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 9 Nov 2023 01:06:17 -0500 Subject: [PATCH 0184/1012] Aligns language on GK account --- README.md | 4 ++-- package.json | 4 ++-- src/plus/focus/focusService.ts | 2 +- src/plus/webviews/patchDetails/patchDetailsWebview.ts | 4 ++-- src/uris/deepLinks/deepLinkService.ts | 2 +- src/webviews/apps/home/home.html | 10 +++++----- .../plus/patchDetails/components/gl-patch-create.ts | 2 +- src/webviews/apps/welcome/welcome.html | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e54748dd96e55..c64855a304bcf 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Use `Switch to Pre-Release Version` on the extension banner to live on the edge All features are free to use on all repos, **except** for features, - marked with a ✨ require a [trial or paid plan](https://www.gitkraken.com/gitlens/pricing) for use on privately hosted repos -- marked with a ☁️ require a GitKraken Account, with access level based on your [plan](https://www.gitkraken.com/gitlens/pricing), e.g. Free, Pro, etc +- marked with a ☁️ require a GitKraken account, with access level based on your [plan](https://www.gitkraken.com/gitlens/pricing), e.g. Free, Pro, etc See the [FAQ](#is-gitlens-free-to-use 'Jump to FAQ') for more details. @@ -272,7 +272,7 @@ Yes. All features are free to use on all repos, **except** for features, - marked with a ✨ require a [trial or paid plan](https://www.gitkraken.com/gitlens/pricing) for use on privately hosted repos - marked with a ☁️ require a GitKraken Account, with access level based on your [plan](https://www.gitkraken.com/gitlens/pricing), e.g. Free, Pro, etc -While GitLens offers a remarkable set of free features, a subset of features tailored for professional developers and teams, marked with a ✨, require a trial or paid plan for use on privately hosted repos — use on local or publicly hosted repos is free for everyone. Additionally some features marked with a ☁️, rely on GitKraken Dev Services which requires an account and access is based on your plan, e.g. Free, Pro, etc. +While GitLens offers a remarkable set of free features, a subset of features tailored for professional developers and teams, marked with a ✨, require a trial or paid plan for use on privately hosted repos — use on local or publicly hosted repos is free for everyone. Additionally some features marked with a ☁️, rely on GitKraken Dev Services which requires a GitKraken account and access is based on your plan, e.g. Free, Pro, etc. Preview ✨ features instantly for free for 3 days without an account, or start a free GitKraken trial to get an additional 7 days and gain access to ☁️ features to experience the full power of GitLens. diff --git a/package.json b/package.json index 286b4d70f8ccd..654a899e3677e 100644 --- a/package.json +++ b/package.json @@ -15316,7 +15316,7 @@ }, { "view": "gitlens.views.drafts", - "contents": "[Start Free Pro Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free 7-day Pro trial to use Cloud Patches, or [sign in](command:gitlens.plus.loginOrSignUp).\n☁️ Requires an account and access is based on your plan, e.g. Free, Pro, etc", + "contents": "[Start Free Pro Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free 7-day Pro trial to use Cloud Patches, or [sign in](command:gitlens.plus.loginOrSignUp).\n☁️ Requires a GitKraken account and access is based on your plan, e.g. Free, Pro, etc", "when": "!gitlens:plus" }, { @@ -15330,7 +15330,7 @@ }, { "view": "gitlens.views.workspaces", - "contents": "[Start Free GitKraken Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free 7-day GitKraken trial to use GitKraken Workspaces, or [sign in](command:gitlens.plus.loginOrSignUp).\n☁️ Requires an account and access is based on your plan, e.g. Free, Pro, etc", + "contents": "[Start Free GitKraken Trial](command:gitlens.plus.loginOrSignUp)\n\nStart a free 7-day GitKraken trial to use GitKraken Workspaces, or [sign in](command:gitlens.plus.loginOrSignUp).\n☁️ Requires a GitKraken account and access is based on your plan, e.g. Free, Pro, etc", "when": "!gitlens:plus" }, { diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/focusService.ts index 502b5d61bb193..6b1ef2b8d6425 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/focusService.ts @@ -107,7 +107,7 @@ export class FocusService implements Disposable { const scope = getLogScope(); try { - if (!(await ensureAccount('Pinning requires an account', this.container))) { + if (!(await ensureAccount('Pinning requires a GitKraken account.', this.container))) { throw new Error('Unable to pin item: account required'); } diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index fba611058dd21..18c301d771972 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -311,7 +311,7 @@ export class PatchDetailsWebviewProvider return; } - if (!(await ensureAccount('A GitKraken account is required to apply cloud patches.', this.container))) return; + if (!(await ensureAccount('Cloud Patches require a GitKraken account.', this.container))) return; const changeset = this._context.draft.changesets?.[0]; if (changeset == null) return; @@ -350,7 +350,7 @@ export class PatchDetailsWebviewProvider } private async createDraft({ title, changesets, description }: CreatePatchParams): Promise { - if (!(await ensureAccount('A GitKraken account is required to create cloud patches.', this.container))) return; + if (!(await ensureAccount('Cloud patches require a GitKraken account.', this.container))) return; const createChanges: CreateDraftChange[] = []; diff --git a/src/uris/deepLinks/deepLinkService.ts b/src/uris/deepLinks/deepLinkService.ts index 0e0fc12b0dfdd..6133961c9422b 100644 --- a/src/uris/deepLinks/deepLinkService.ts +++ b/src/uris/deepLinks/deepLinkService.ts @@ -440,7 +440,7 @@ export class DeepLinkService implements Disposable { if ( !(await ensureAccount( - `A GitKraken account is required to open ${deepLinkTypeToString(targetType)} links.`, + `Opening ${deepLinkTypeToString(targetType)} links requires a GitKraken account.`, this.container, )) ) { diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index af67b4826b424..04cca121ecd69 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -225,8 +225,8 @@ >Cloud Patches☁️
@@ -240,8 +240,8 @@ >GitKraken Workspaces☁️ @@ -385,7 +385,7 @@

✨ Requires a trial or paid plan to use this on privately hosted repos.
- ☁️ Requires an account and access is based on your plan, e.g. Free, Pro, etc + ☁️ Requires a GitKraken account and access is based on your plan, e.g. Free, Pro, etc

diff --git a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts index 39e0dfc726873..470c7b432dcb0 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts @@ -132,7 +132,7 @@ export class GlPatchCreate extends GlTreeBase { Create Cloud Patch

-
`; diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html index bf904efe9943a..d1ad0fb7f7e41 100644 --- a/src/webviews/apps/welcome/welcome.html +++ b/src/webviews/apps/welcome/welcome.html @@ -603,7 +603,7 @@

Resources

✨ Requires a trial or paid plan for use on privately hosted repos
- ☁️ Requires an account and access is based on your plan, e.g. Free, Pro, etc + ☁️ Requires a GitKraken account and access is based on your plan, e.g. Free, Pro, etc

#{endOfBody} From 2c75f68f7074479580e5da16055cd3e5e9d4d2fc Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 9 Nov 2023 10:53:23 -0500 Subject: [PATCH 0185/1012] Adds patch storage confirmation --- src/constants.ts | 1 + src/plus/utils.ts | 29 ++++++++++++++++++- .../patchDetails/patchDetailsWebview.ts | 9 ++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 815947cdd478c..9689be5339436 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -837,6 +837,7 @@ export type GlobalStorage = { // Keep the pre-release version separate from the released version preVersion: string; 'views:welcome:visible': boolean; + 'confirm:draft:storage': boolean; } & { [key in `confirm:ai:tos:${AIProviders}`]: boolean } & { [key in `provider:authentication:skip:${string}`]: boolean; }; diff --git a/src/plus/utils.ts b/src/plus/utils.ts index d210e00f76cbb..acb552c13a5c6 100644 --- a/src/plus/utils.ts +++ b/src/plus/utils.ts @@ -1,4 +1,5 @@ -import { window } from 'vscode'; +import type { MessageItem } from 'vscode'; +import { env, Uri, window } from 'vscode'; import type { Container } from '../container'; import { isSubscriptionPaidPlan } from './gk/account/subscription'; @@ -107,3 +108,29 @@ export async function ensureAccount(title: string, container: Container): Promis return true; } + +export async function confirmDraftStorage(container: Container): Promise { + if (container.storage.get('confirm:draft:storage', false)) return true; + + const accept: MessageItem = { title: 'Yes' }; + const decline: MessageItem = { title: 'No', isCloseAffordance: true }; + const moreInfo: MessageItem = { title: 'More Info' }; + const result = await window.showInformationMessage( + `Creating a Cloud Patch will store code on GitKraken's servers.\n\nDo you want to continue?`, + { modal: true }, + accept, + decline, + moreInfo, + ); + + if (result === accept) { + void container.storage.store('confirm:draft:storage', true); + return true; + } + + if (result === moreInfo) { + void env.openExternal(Uri.parse('https://help.gitkraken.com/gitlens/security')); + } + + return false; +} diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 18c301d771972..a0a224a113158 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -28,7 +28,7 @@ import { onIpc } from '../../../webviews/protocol'; import type { WebviewController, WebviewProvider } from '../../../webviews/webviewController'; import type { WebviewShowOptions } from '../../../webviews/webviewsController'; import { showPatchesView } from '../../drafts/actions'; -import { ensureAccount } from '../../utils'; +import { confirmDraftStorage, ensureAccount } from '../../utils'; import type { ShowInCommitGraphCommandArgs } from '../graph/protocol'; import type { ApplyPatchParams, @@ -311,7 +311,12 @@ export class PatchDetailsWebviewProvider return; } - if (!(await ensureAccount('Cloud Patches require a GitKraken account.', this.container))) return; + if ( + !(await ensureAccount('Cloud Patches require a GitKraken account.', this.container)) || + !(await confirmDraftStorage(this.container)) + ) { + return; + } const changeset = this._context.draft.changesets?.[0]; if (changeset == null) return; From 86b37bebe6348706261e663472211c0abc2f0a18 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 9 Nov 2023 12:17:02 -0500 Subject: [PATCH 0186/1012] Updates patch storage confirmation --- src/plus/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plus/utils.ts b/src/plus/utils.ts index acb552c13a5c6..c1e1aa14316af 100644 --- a/src/plus/utils.ts +++ b/src/plus/utils.ts @@ -116,7 +116,7 @@ export async function confirmDraftStorage(container: Container): Promise Date: Thu, 9 Nov 2023 11:34:42 -0700 Subject: [PATCH 0187/1012] Fixes content type on patch upload --- src/plus/drafts/draftsService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index a5edbc91da0de..465e1f1211a0e 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -116,7 +116,7 @@ export class DraftService implements Disposable { await this.connection.fetchRaw(url, { method: method, headers: { - 'Content-Type': 'plain/text', + 'Content-Type': 'text/plain', Host: headers?.['Host']?.['0'] ?? '', }, body: contents, From 213ca034dc23d148d503cbdb9dafe4be67b6fbad Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Thu, 9 Nov 2023 14:32:31 -0700 Subject: [PATCH 0188/1012] Opens cloud patch on row select (hides icon for now) --- package.json | 5 ----- src/views/nodes/draftNode.ts | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 654a899e3677e..fb1073426a648 100644 --- a/package.json +++ b/package.json @@ -11997,11 +11997,6 @@ "when": "viewItem == gitlens:message:signin", "group": "inline@1" }, - { - "command": "gitlens.views.drafts.open", - "when": "viewItem =~ /gitlens:draft\\b/ && gitlens:plus", - "group": "inline@1" - }, { "command": "gitlens.views.drafts.open", "when": "viewItem =~ /gitlens:draft\\b/ && gitlens:plus", diff --git a/src/views/nodes/draftNode.ts b/src/views/nodes/draftNode.ts index 8d769fff38f69..d4fe06e64e2d4 100644 --- a/src/views/nodes/draftNode.ts +++ b/src/views/nodes/draftNode.ts @@ -55,6 +55,11 @@ export class DraftNode extends ViewNode<'draft', DraftsView> { }`, ); item.description = fromNow(this.draft.updatedAt); + item.command = { + title: 'Show Patch', + command: this.view.getQualifiedCommand('open'), + arguments: [this], + }; return item; } } From 30fa83020763e71ff89bb749a6214ae5cda5bbc0 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 9 Nov 2023 15:01:46 -0500 Subject: [PATCH 0189/1012] Applies patch to branch --- .../patchDetails/patchDetailsWebview.ts | 37 ++++++++++++-- src/plus/webviews/patchDetails/protocol.ts | 1 + src/quickpicks/branchPicker.ts | 51 +++++++++++++++++++ .../components/gl-draft-details.ts | 20 +++++++- .../apps/plus/patchDetails/patchDetails.scss | 4 ++ .../apps/plus/patchDetails/patchDetails.ts | 6 ++- .../apps/shared/components/webview-pane.ts | 2 +- 7 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 src/quickpicks/branchPicker.ts diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index a0a224a113158..678d14ceeaf83 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -1,7 +1,7 @@ import type { ConfigurationChangeEvent } from 'vscode'; import { Disposable, env, Uri, window } from 'vscode'; import type { CoreConfiguration } from '../../../constants'; -import { Commands } from '../../../constants'; +import { Commands, GlyphChars } from '../../../constants'; import type { Container } from '../../../container'; import { openChanges, openChangesWithWorking, openFile } from '../../../git/actions/commit'; import type { RepositoriesChangeEvent } from '../../../git/gitProviderService'; @@ -13,6 +13,7 @@ import { createReference } from '../../../git/models/reference'; import { isRepository } from '../../../git/models/repository'; import type { CreateDraftChange, Draft, DraftPatch, DraftPatchFileChange, LocalDraft } from '../../../gk/models/drafts'; import type { GkRepositoryId } from '../../../gk/models/repositoryIdentities'; +import { showBranchPicker } from '../../../quickpicks/branchPicker'; import { executeCommand, registerCommand } from '../../../system/command'; import { configuration } from '../../../system/configuration'; import { setContext } from '../../../system/context'; @@ -321,6 +322,8 @@ export class PatchDetailsWebviewProvider const changeset = this._context.draft.changesets?.[0]; if (changeset == null) return; + // TODO: should be overridable with targetRef + const shouldPickBranch = params.target === 'branch'; for (const patch of changeset.patches) { if (!params.selected.includes(patch.id)) continue; @@ -335,9 +338,35 @@ export class PatchDetailsWebviewProvider continue; } - void this.container.git.applyPatchCommit(commit.repoPath, commit.ref, { - branchName: patch.baseBranchName, - }); + let options: + | { + branchName?: string; + createBranchIfNeeded?: boolean; + createWorktreePath?: string; + } + | undefined = undefined; + + if (shouldPickBranch) { + const repo = commit.getRepository(); + const branch = await showBranchPicker( + `Choose a Branch ${GlyphChars.Dot} ${repo?.name}`, + 'Choose a branch to apply the Cloud Patch to', + repo, + ); + + if (branch == null) { + void window.showErrorMessage( + `Unable apply patch to '${patch.repository!.name}': No branch selected`, + ); + continue; + } + options = { + branchName: branch.ref, + createBranchIfNeeded: true, + }; + } + + void this.container.git.applyPatchCommit(commit.repoPath, commit.ref, options); } catch (ex) { void window.showErrorMessage(`Unable apply patch to '${patch.baseRef}': ${ex.message}`); } diff --git a/src/plus/webviews/patchDetails/protocol.ts b/src/plus/webviews/patchDetails/protocol.ts index 5d586a8904716..ffc43d46fadaa 100644 --- a/src/plus/webviews/patchDetails/protocol.ts +++ b/src/plus/webviews/patchDetails/protocol.ts @@ -168,6 +168,7 @@ export type ShowCommitDetailsViewCommandArgs = string[]; export interface ApplyPatchParams { details: DraftDetails; targetRef?: string; // a branch name. default to HEAD if not supplied + target: 'current' | 'branch' | 'worktree'; selected: PatchDetails['id'][]; } export const ApplyPatchCommandType = new IpcCommandType('patch/apply'); diff --git a/src/quickpicks/branchPicker.ts b/src/quickpicks/branchPicker.ts new file mode 100644 index 0000000000000..a31a73c46e37d --- /dev/null +++ b/src/quickpicks/branchPicker.ts @@ -0,0 +1,51 @@ +import type { Disposable } from 'vscode'; +import { window } from 'vscode'; +import { getBranches } from '../commands/quickCommand.steps'; +import type { Repository } from '../git/models/repository'; +import { getQuickPickIgnoreFocusOut } from '../system/utils'; +import type { BranchQuickPickItem } from './items/gitCommands'; + +export async function showBranchPicker( + title: string | undefined, + placeholder?: string, + repository?: Repository, +): Promise { + if (repository == null) { + return undefined; + } + + const items: BranchQuickPickItem[] = await getBranches(repository, {}); + if (items.length === 0) return undefined; + + const quickpick = window.createQuickPick(); + quickpick.ignoreFocusOut = getQuickPickIgnoreFocusOut(); + + const disposables: Disposable[] = []; + + try { + const pick = await new Promise(resolve => { + disposables.push( + quickpick.onDidHide(() => resolve(undefined)), + quickpick.onDidAccept(() => { + if (quickpick.activeItems.length !== 0) { + resolve(quickpick.activeItems[0]); + } + }), + ); + + quickpick.title = title; + quickpick.placeholder = placeholder; + quickpick.matchOnDescription = true; + quickpick.matchOnDetail = true; + quickpick.items = items; + + quickpick.show(); + }); + if (pick == null) return undefined; + + return pick; + } finally { + quickpick.dispose(); + disposables.forEach(d => void d.dispose()); + } +} diff --git a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts index 8db0d2deed4aa..0e57c3c569f6a 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts @@ -345,7 +345,20 @@ export class GlDraftDetails extends GlTreeBase {

- Apply Cloud Patch + Apply Patch + + + + Apply to new branch + + +

@@ -577,7 +590,10 @@ export class GlDraftDetails extends GlTreeBase { } onSelectApplyOption(e: CustomEvent<{ target: MenuItem }>) { - if (this.canSubmit === false) return; + if (this.canSubmit === false) { + this.validityMessage = 'Please select changes to apply'; + return; + } const target = e.detail?.target; if (target?.dataset?.value != null) { diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.scss b/src/webviews/apps/plus/patchDetails/patchDetails.scss index bd10a381ad36e..27a07ae0bbf2e 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.scss +++ b/src/webviews/apps/plus/patchDetails/patchDetails.scss @@ -160,5 +160,9 @@ gl-patch-create { &__group-fixed { flex: none; + + webview-pane::part(content) { + overflow: visible; + } } } diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.ts b/src/webviews/apps/plus/patchDetails/patchDetails.ts index b909ac587104b..f3a9a682199f8 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.ts +++ b/src/webviews/apps/plus/patchDetails/patchDetails.ts @@ -264,7 +264,11 @@ export class PatchDetailsApp extends App> { private onApplyPatch(e: ApplyPatchDetail) { console.log('onApplyPatch', e); if (e.selectedPatches == null || e.selectedPatches.length === 0) return; - this.sendCommand(ApplyPatchCommandType, { details: e.draft, selected: e.selectedPatches }); + this.sendCommand(ApplyPatchCommandType, { + details: e.draft, + target: e.target ?? 'current', + selected: e.selectedPatches, + }); } private onChangePatchBase(e: ChangePatchBaseDetail) { diff --git a/src/webviews/apps/shared/components/webview-pane.ts b/src/webviews/apps/shared/components/webview-pane.ts index c13a22ef11d1a..4f78bee61d4d2 100644 --- a/src/webviews/apps/shared/components/webview-pane.ts +++ b/src/webviews/apps/shared/components/webview-pane.ts @@ -140,7 +140,7 @@ export class WebviewPane extends LitElement { -
+
`; From 31732b1e960d19c8ef54c9af5a21f52605273c86 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 9 Nov 2023 17:31:11 -0500 Subject: [PATCH 0190/1012] Adds create new branch option for applying patch Co-authored-by: Ramin Tadayon --- .../patchDetails/patchDetailsWebview.ts | 12 ++- src/quickpicks/branchPicker.ts | 101 +++++++++++++++++- .../components/gl-draft-details.ts | 2 +- 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 678d14ceeaf83..6e5b73f41f3ec 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -13,7 +13,7 @@ import { createReference } from '../../../git/models/reference'; import { isRepository } from '../../../git/models/repository'; import type { CreateDraftChange, Draft, DraftPatch, DraftPatchFileChange, LocalDraft } from '../../../gk/models/drafts'; import type { GkRepositoryId } from '../../../gk/models/repositoryIdentities'; -import { showBranchPicker } from '../../../quickpicks/branchPicker'; +import { showNewOrSelectBranchPicker } from '../../../quickpicks/branchPicker'; import { executeCommand, registerCommand } from '../../../system/command'; import { configuration } from '../../../system/configuration'; import { setContext } from '../../../system/context'; @@ -348,9 +348,9 @@ export class PatchDetailsWebviewProvider if (shouldPickBranch) { const repo = commit.getRepository(); - const branch = await showBranchPicker( + const branch = await showNewOrSelectBranchPicker( `Choose a Branch ${GlyphChars.Dot} ${repo?.name}`, - 'Choose a branch to apply the Cloud Patch to', + // 'Choose a branch to apply the Cloud Patch to', repo, ); @@ -360,9 +360,11 @@ export class PatchDetailsWebviewProvider ); continue; } + + const isString = typeof branch === 'string'; options = { - branchName: branch.ref, - createBranchIfNeeded: true, + branchName: isString ? branch : branch.ref, + createBranchIfNeeded: isString, }; } diff --git a/src/quickpicks/branchPicker.ts b/src/quickpicks/branchPicker.ts index a31a73c46e37d..b098dc2c985ff 100644 --- a/src/quickpicks/branchPicker.ts +++ b/src/quickpicks/branchPicker.ts @@ -1,4 +1,4 @@ -import type { Disposable } from 'vscode'; +import type { Disposable, QuickPickItem } from 'vscode'; import { window } from 'vscode'; import { getBranches } from '../commands/quickCommand.steps'; import type { Repository } from '../git/models/repository'; @@ -49,3 +49,102 @@ export async function showBranchPicker( disposables.forEach(d => void d.dispose()); } } + +export async function showNewBranchPicker( + title: string | undefined, + placeholder?: string, + _repository?: Repository, +): Promise { + const input = window.createInputBox(); + input.ignoreFocusOut = true; + + const disposables: Disposable[] = []; + + let newBranchName: string | undefined; + try { + newBranchName = await new Promise(resolve => { + disposables.push( + input.onDidHide(() => resolve(undefined)), + input.onDidAccept(() => { + const value = input.value.trim(); + if (value == null) { + input.validationMessage = 'Please enter a valid branch name'; + return; + } + + resolve(value); + }), + ); + + input.title = title; + input.placeholder = placeholder; + input.prompt = 'Enter a name for the new branch'; + + input.show(); + }); + } finally { + input.dispose(); + disposables.forEach(d => void d.dispose()); + } + + return newBranchName; +} + +export async function showNewOrSelectBranchPicker( + title: string | undefined, + repository?: Repository, +): Promise { + if (repository == null) { + return undefined; + } + + // TODO: needs updating + const createNewBranch = { + label: 'Create new branch', + description: + 'Creates a branch to apply the Cloud Patch to. (Typing an existing branch name will use that branch.)', + }; + const selectExistingBranch = { + label: 'Select existing branch', + description: 'Selects an existing branch to apply the Cloud Patch to.', + }; + + const items: QuickPickItem[] = [createNewBranch, selectExistingBranch]; + + const quickpick = window.createQuickPick(); + quickpick.ignoreFocusOut = getQuickPickIgnoreFocusOut(); + + const disposables: Disposable[] = []; + + try { + const pick = await new Promise(resolve => { + disposables.push( + quickpick.onDidHide(() => resolve(undefined)), + quickpick.onDidAccept(() => { + if (quickpick.activeItems.length !== 0) { + resolve(quickpick.activeItems[0]); + } + }), + ); + + quickpick.title = title; + quickpick.placeholder = 'Select a branch option'; + quickpick.matchOnDescription = true; + quickpick.matchOnDetail = true; + quickpick.items = items; + + quickpick.show(); + }); + + if (pick === createNewBranch) { + return showNewBranchPicker(title, 'Enter a name for the new branch', repository); + } else if (pick === selectExistingBranch) { + return showBranchPicker(title, 'Select an existing branch', repository); + } + + return undefined; + } finally { + quickpick.dispose(); + disposables.forEach(d => void d.dispose()); + } +} diff --git a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts index 0e57c3c569f6a..57c88aebb0d35 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts @@ -355,7 +355,7 @@ export class GlDraftDetails extends GlTreeBase { > - Apply to new branch + Apply to a Branch From be6b6b1c77ffbae63d48dfd3900c06d4adc0266e Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Thu, 9 Nov 2023 17:32:17 -0700 Subject: [PATCH 0191/1012] Fixes files not showing when viewing patch after creation --- src/plus/drafts/draftsService.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index 465e1f1211a0e..907dd2e110726 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -112,6 +112,9 @@ export class DraftService implements Disposable { throw new Error(`No contents found for ${patch.baseCommitSha}`); } + const diffFiles = await this.container.git.getDiffFiles(repository.path, contents); + const files = diffFiles?.files.map(f => ({ ...f, gkRepositoryId: patch.gitRepositoryId })) ?? []; + // Upload patch to returned S3 url await this.connection.fetchRaw(url, { method: method, @@ -137,6 +140,7 @@ export class DraftService implements Disposable { secureLink: undefined!, // patch.secureDownloadData, contents: contents, + files: files, repository: repository, }); } From 2346ada9f64f60d3ed315b2196431b95850b472e Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 9 Nov 2023 22:15:56 -0500 Subject: [PATCH 0192/1012] Adds cloud patch icons --- CONTRIBUTING.md | 2 +- images/icons/cloud-patch-share.svg | 1 + images/icons/cloud-patch.svg | 1 + images/icons/template/mapping.json | 4 +++- package.json | 14 ++++++++++++++ src/webviews/apps/shared/components/code-icon.ts | 6 ++++++ src/webviews/apps/shared/glicons.scss | 8 +++++++- 7 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 images/icons/cloud-patch-share.svg create mode 100644 images/icons/cloud-patch.svg diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 414177efff84d..711072b05a2f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -207,7 +207,7 @@ The Publish Insiders workflow is no longer available and was replaced with the p To add new icons to the GL Icons font follow the steps below: - Add new SVG icons to the `images/icons` folder -- Update the `images/icons/mappings.json` file with entries for the new icons (append to the end of the file) +- Update the `images/icons/template/mapping.json` file with entries for the new icons (append to the end of the file) - Optimize and build the icons by running the following from a terminal: ``` diff --git a/images/icons/cloud-patch-share.svg b/images/icons/cloud-patch-share.svg new file mode 100644 index 0000000000000..46dbb3f551f25 --- /dev/null +++ b/images/icons/cloud-patch-share.svg @@ -0,0 +1 @@ + diff --git a/images/icons/cloud-patch.svg b/images/icons/cloud-patch.svg new file mode 100644 index 0000000000000..f2dfe4c072f98 --- /dev/null +++ b/images/icons/cloud-patch.svg @@ -0,0 +1 @@ + diff --git a/images/icons/template/mapping.json b/images/icons/template/mapping.json index a1ce4f9e85dea..33b5d5b08e7c1 100644 --- a/images/icons/template/mapping.json +++ b/images/icons/template/mapping.json @@ -39,5 +39,7 @@ "gitlens-inspect": 61732, "workspaces-view": 61733, "confirm-checked": 61734, - "confirm-unchecked": 61735 + "confirm-unchecked": 61735, + "cloud-patch": 61736, + "cloud-patch-share": 61737 } \ No newline at end of file diff --git a/package.json b/package.json index fb1073426a648..7efaac3f607bb 100644 --- a/package.json +++ b/package.json @@ -8522,6 +8522,20 @@ "fontPath": "dist/glicons.woff2", "fontCharacter": "\\f127" } + }, + "gitlens-cloud-patch": { + "description": "cloud-patch icon", + "default": { + "fontPath": "dist/glicons.woff2", + "fontCharacter": "\\f128" + } + }, + "gitlens-cloud-patch-share": { + "description": "cloud-patch-share icon", + "default": { + "fontPath": "dist/glicons.woff2", + "fontCharacter": "\\f129" + } } }, "menus": { diff --git a/src/webviews/apps/shared/components/code-icon.ts b/src/webviews/apps/shared/components/code-icon.ts index d0a21685755cc..796c4844166f7 100644 --- a/src/webviews/apps/shared/components/code-icon.ts +++ b/src/webviews/apps/shared/components/code-icon.ts @@ -1690,6 +1690,12 @@ export class CodeIcon extends LitElement { :host([icon='gl-workspaces-view']):before { content: '\\f125'; } + :host([icon='gl-cloud-patch']):before { + content: '\\f128'; + } + :host([icon='gl-cloud-patch-share']):before { + content: '\\f129'; + } @keyframes codicon-spin { 100% { diff --git a/src/webviews/apps/shared/glicons.scss b/src/webviews/apps/shared/glicons.scss index ebdf90a0d1929..3051ce6c30100 100644 --- a/src/webviews/apps/shared/glicons.scss +++ b/src/webviews/apps/shared/glicons.scss @@ -6,7 +6,7 @@ Must be placed at the end of body in the HTML file of any webview that needs it @font-face { font-family: 'glicons'; font-display: block; - src: url("#{root}/dist/glicons.woff2?30855d21cb614f41edfd373458624529") format("woff2"); + src: url("#{root}/dist/glicons.woff2?2cb9f62ddac44d3fc393ade4471fe802") format("woff2"); } */ @@ -182,3 +182,9 @@ Must be placed at the end of body in the HTML file of any webview that needs it .glicon-confirm-unchecked:before { content: '\f127'; } +.glicon-cloud-patch:before { + content: '\f128'; +} +.glicon-cloud-patch-share:before { + content: '\f129'; +} From 9b0126d0da28591a55ce8b304f1e1ca62d160b93 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 9 Nov 2023 22:17:11 -0500 Subject: [PATCH 0193/1012] Implements cloud patch icons --- package.json | 2 +- .../components/gl-commit-details.ts | 2 ++ .../components/gl-details-base.ts | 27 ++++++++++++------- .../components/gl-wip-details.ts | 4 ++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 7efaac3f607bb..32d923b6c9b27 100644 --- a/package.json +++ b/package.json @@ -15391,7 +15391,7 @@ "name": "Patch", "when": "!gitlens:untrusted && config.gitlens.cloudPatches.enabled && gitlens:views:patchDetails:mode", "contextualTitle": "GL", - "icon": "$(gitlens-commit-view)", + "icon": "$(gitlens-cloud-patch)", "initialSize": 24 }, { diff --git a/src/webviews/apps/commitDetails/components/gl-commit-details.ts b/src/webviews/apps/commitDetails/components/gl-commit-details.ts index 525fb31a044b7..c3fcb00c4e508 100644 --- a/src/webviews/apps/commitDetails/components/gl-commit-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-commit-details.ts @@ -19,6 +19,8 @@ interface ExplainState { @customElement('gl-commit-details') export class GlCommitDetails extends GlDetailsBase { + override readonly tab = 'commit'; + @property({ type: Object }) state?: Serialized; diff --git a/src/webviews/apps/commitDetails/components/gl-details-base.ts b/src/webviews/apps/commitDetails/components/gl-details-base.ts index aa47868979622..2cee5cafe01ea 100644 --- a/src/webviews/apps/commitDetails/components/gl-details-base.ts +++ b/src/webviews/apps/commitDetails/components/gl-details-base.ts @@ -12,6 +12,8 @@ type File = Files[0]; type Mode = 'commit' | 'stash' | 'wip'; export class GlDetailsBase extends LitElement { + readonly tab: 'wip' | 'commit' = 'commit'; + @property({ type: Array }) files?: Files; @@ -30,16 +32,21 @@ export class GlDetailsBase extends LitElement { return html` ${label} - + ${when( + this.tab === 'wip', + () => + html` `, + )} `; } diff --git a/src/webviews/apps/commitDetails/components/gl-wip-details.ts b/src/webviews/apps/commitDetails/components/gl-wip-details.ts index f8843630cf104..d2d3bba62b75d 100644 --- a/src/webviews/apps/commitDetails/components/gl-wip-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-wip-details.ts @@ -7,6 +7,8 @@ import { GlDetailsBase } from './gl-details-base'; @customElement('gl-wip-details') export class GlWipDetails extends GlDetailsBase { + override readonly tab = 'wip'; + @property({ type: Object }) wip?: Wip; @@ -46,7 +48,7 @@ export class GlWipDetails extends GlDetailsBase { aria-label="Share as Cloud Patch" title="Share as Cloud Patch" > - + Share Date: Fri, 10 Nov 2023 09:22:07 -0700 Subject: [PATCH 0194/1012] Adds basic welcome section for cloud patches (#3009) --- src/webviews/apps/welcome/welcome.html | 44 ++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html index d1ad0fb7f7e41..96d12966ee8d9 100644 --- a/src/webviews/apps/welcome/welcome.html +++ b/src/webviews/apps/welcome/welcome.html @@ -287,6 +287,50 @@

+

+ Cloud Patches + ☁️ + Preview +

+

+ The + Cloud Patches preview feature + allows you to easily share changes with other developers by creating a Cloud Patch from your WIP, + commit or stash and sharing the generated link with your teammates. +

+ +

+ Cloud Patches are + securely stored by GitKraken, and anyone with access to the link and a GitKraken account can view the code for now. More + permissions and controls are coming soon. +

+ +

+ For additional information about Cloud Patches, visit our + help center. +

+

Date: Fri, 10 Nov 2023 11:42:53 -0500 Subject: [PATCH 0195/1012] Updates patch icons on home and welcome --- src/webviews/apps/home/home.html | 2 +- src/webviews/apps/welcome/welcome.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index 04cca121ecd69..25505325f25ea 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -221,7 +221,7 @@ aria-label="Show Cloud Patches view" data-requires="repo" hidden - >Cloud PatchesSide Bar Views

title="Show Cloud Patches view" aria-label="Show Cloud Patches view" hidden - >Cloud Patches ☁️Cloud Patches ☁️ Popular views title="Show Cloud Patches view" aria-label="Show Cloud Patches view" hidden - >Cloud Patches ☁️Cloud Patches ☁️ Date: Fri, 10 Nov 2023 12:25:49 -0500 Subject: [PATCH 0196/1012] Updates error handling on explain AI for patches --- src/plus/webviews/patchDetails/patchDetailsWebview.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 6e5b73f41f3ec..b6c47c6bee6dc 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -463,14 +463,21 @@ export class PatchDetailsWebviewProvider try { // TODO@eamodio HACK -- only works for the first patch const patch = await this.getDraftPatch(this._context.draft); - if (patch == null) return; + if (patch == null) { + throw new Error('Unable to find patch'); + } const commit = await this.getOrCreateCommitForPatch(patch.gkRepositoryId); - if (commit == null) return; + if (commit == null) { + throw new Error('Unable to find commit'); + } const summary = await this.container.ai.explainCommit(commit, { progress: { location: { viewId: this.host.id } }, }); + if (summary == null) { + throw new Error('Error retrieving content'); + } params = { summary: summary }; } catch (ex) { debugger; From 772aaaaa7d8d8b9ac23fbcc4d3adb4aa5c5a8bc2 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Fri, 10 Nov 2023 11:48:54 -0700 Subject: [PATCH 0197/1012] Fixes input ordering when generating diff for cloud patch from commit --- src/plus/drafts/draftsService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index 907dd2e110726..44296f8bf31bc 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -217,7 +217,7 @@ export class DraftService implements Disposable { ? this.container.git.getBranch(change.repository.uri).then(b => (b != null ? [b.name] : undefined)) : this.container.git.getCommitBranches(change.repository.uri, change.revision.sha), change.contents == null - ? this.container.git.getDiff(change.repository.path, change.revision.sha, change.revision.baseSha) + ? this.container.git.getDiff(change.repository.path, change.revision.baseSha, change.revision.sha) : undefined, this.container.git.getFirstCommitSha(change.repository.uri), this.container.git.getBestRemoteWithProvider(change.repository.uri), From 2818e6e8ede2accfed1677e3aaabac378628c9af Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Fri, 10 Nov 2023 15:34:47 -0500 Subject: [PATCH 0198/1012] Fixes resuming RepositoryWipChangeset --- src/plus/webviews/patchDetails/repositoryChangeset.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plus/webviews/patchDetails/repositoryChangeset.ts b/src/plus/webviews/patchDetails/repositoryChangeset.ts index 19af2cc696918..8358d70ec69fe 100644 --- a/src/plus/webviews/patchDetails/repositoryChangeset.ts +++ b/src/plus/webviews/patchDetails/repositoryChangeset.ts @@ -133,6 +133,7 @@ export class RepositoryWipChangeset implements RepositoryChangeset { } resume() { + this._files = undefined; if (this._expanded) { this.subscribe(); } From 71410e4fc178e63ab90339b72b8caa5a5789318f Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Fri, 10 Nov 2023 14:26:13 -0700 Subject: [PATCH 0199/1012] Fixes getting diff for WIP changes when creating Cloud Patches --- src/plus/drafts/draftsService.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index 44296f8bf31bc..e5004048bdfb5 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -1,5 +1,6 @@ import type { Disposable } from 'vscode'; import type { Container } from '../../container'; +import { uncommitted, uncommittedStaged } from '../../git/models/constants'; import { isSha, isUncommitted } from '../../git/models/reference'; import { isRepository } from '../../git/models/repository'; import type { GitUser } from '../../git/models/user'; @@ -212,12 +213,17 @@ export class DraftService implements Disposable { private async getCreateDraftPatchRequestFromChange( change: CreateDraftChange, ): Promise { + const isWIP = change.revision.sha === uncommitted || change.revision.sha === uncommittedStaged; const [branchNamesResult, diffResult, firstShaResult, remoteResult, userResult] = await Promise.allSettled([ isUncommitted(change.revision.sha) ? this.container.git.getBranch(change.repository.uri).then(b => (b != null ? [b.name] : undefined)) : this.container.git.getCommitBranches(change.repository.uri, change.revision.sha), change.contents == null - ? this.container.git.getDiff(change.repository.path, change.revision.baseSha, change.revision.sha) + ? this.container.git.getDiff( + change.repository.path, + isWIP ? change.revision.sha : change.revision.baseSha, + isWIP ? change.revision.baseSha : change.revision.sha, + ) : undefined, this.container.git.getFirstCommitSha(change.repository.uri), this.container.git.getBestRemoteWithProvider(change.repository.uri), From f4d58edc506ae4c258b47a079e98dbb49b62f84e Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Fri, 10 Nov 2023 14:27:01 -0700 Subject: [PATCH 0200/1012] Fixes Share as Cloud Patch being broken in the graph --- package.json | 11 ++++++++++- src/plus/webviews/graph/graphWebview.ts | 13 +++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 32d923b6c9b27..89cb4bb4d9557 100644 --- a/package.json +++ b/package.json @@ -8228,6 +8228,11 @@ "title": "Hide Tag Markers", "category": "GitLens" }, + { + "command": "gitlens.graph.shareAsCloudPatch", + "title": "Share as Cloud Patch...", + "category": "GitLens" + }, { "command": "gitlens.timeline.refresh", "title": "Refresh", @@ -10752,6 +10757,10 @@ "command": "gitlens.graph.scrollMarkerTagOff", "when": "false" }, + { + "command": "gitlens.graph.shareAsCloudPatch", + "when": "false" + }, { "command": "gitlens.enableDebugLogging", "when": "config.gitlens.outputLevel != debug" @@ -13986,7 +13995,7 @@ "group": "1_a_gitlens@1" }, { - "command": "gitlens.shareAsCloudPatch", + "command": "gitlens.graph.shareAsCloudPatch", "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && config.gitlens.cloudPatches.enabled && webviewItem =~ /gitlens:(commit|stash)\\b/", "group": "1_a_gitlens@1" }, diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index d2535634a3708..33358e352b024 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -8,6 +8,7 @@ import type { CopyMessageToClipboardCommandArgs } from '../../../commands/copyMe import type { CopyShaToClipboardCommandArgs } from '../../../commands/copyShaToClipboard'; import type { OpenOnRemoteCommandArgs } from '../../../commands/openOnRemote'; import type { OpenPullRequestOnRemoteCommandArgs } from '../../../commands/openPullRequestOnRemote'; +import type { CreatePatchCommandArgs } from '../../../commands/patches'; import type { ShowCommitsInViewCommandArgs } from '../../../commands/showCommitsInView'; import type { Config, GraphMinimapMarkersAdditionalTypes, GraphScrollMarkersAdditionalTypes } from '../../../config'; import type { StoredGraphFilters, StoredGraphIncludeOnlyRef, StoredGraphRefType } from '../../../constants'; @@ -530,6 +531,7 @@ export class GraphWebviewProvider implements WebviewProvider(Commands.CreateCloudPatch, { + ref1: ref.ref, + repoPath: ref.repoPath, + }); + } + @debug() private resetCommit(item?: GraphItemContext) { const ref = this.getGraphItemRef(item, 'revision'); From ebf6babe2e6b7e5554d4d8bab573c5733bacad40 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Fri, 10 Nov 2023 17:25:24 -0500 Subject: [PATCH 0201/1012] Updates CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a40dc5d6d3c21..e72b56ccc2ba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added +- Adds a preview of [Cloud Patches](https://www.gitkraken.com/solutions/cloud-patches), an all-new ☁️ feature — engage in early collaboration long before the pull request: + + - Share your work with others by creating a Cloud Patch from Working Changes, Commits, Stashes or Comparisons + - View Cloud Patches from URLs shared to you and apply them to your working tree or to a new or existing branch + - Manage your Cloud Patches from the new _Cloud Patches_ view in the GitLens side bar + - Adds support to open multiple instances of the _Commit Graph_, _Focus_, and _Visual File History_ in the editor area - Adds a _Split Commit Graph_ command to the _Commit Graph_ tab context menu - Adds a `gitlens.graph.allowMultiple` setting to specify whether to allow opening multiple instances of the _Commit Graph_ in the editor area From d437f940bc8d21d7eb6ed4d7ce822c81e75f0146 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Fri, 10 Nov 2023 16:03:34 -0700 Subject: [PATCH 0202/1012] Fixes error when creating a cloud patch from a stash --- src/plus/drafts/draftsService.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index e5004048bdfb5..3cd14f4c757af 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -1,6 +1,5 @@ import type { Disposable } from 'vscode'; import type { Container } from '../../container'; -import { uncommitted, uncommittedStaged } from '../../git/models/constants'; import { isSha, isUncommitted } from '../../git/models/reference'; import { isRepository } from '../../git/models/repository'; import type { GitUser } from '../../git/models/user'; @@ -213,9 +212,10 @@ export class DraftService implements Disposable { private async getCreateDraftPatchRequestFromChange( change: CreateDraftChange, ): Promise { - const isWIP = change.revision.sha === uncommitted || change.revision.sha === uncommittedStaged; + const isWIP = isUncommitted(change.revision.sha); + const [branchNamesResult, diffResult, firstShaResult, remoteResult, userResult] = await Promise.allSettled([ - isUncommitted(change.revision.sha) + isWIP ? this.container.git.getBranch(change.repository.uri).then(b => (b != null ? [b.name] : undefined)) : this.container.git.getCommitBranches(change.repository.uri, change.revision.sha), change.contents == null @@ -267,7 +267,11 @@ export class DraftService implements Disposable { const user = getSettledValue(userResult); - const branchNames = getSettledValue(branchNamesResult); + // We need to get the branch name from the baseSha if the change is a stash. + let branchNames = getSettledValue(branchNamesResult); + if (!isWIP && !branchNames?.length) { + branchNames = await this.container.git.getCommitBranches(change.repository.uri, change.revision.baseSha); + } const branchName = branchNames?.[0] ?? ''; let baseSha = change.revision.baseSha; From 5cff36df9a40a4591dab508b8681a0b49cf2e6da Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 10 Nov 2023 15:59:54 -0500 Subject: [PATCH 0203/1012] Adds new icon to patches view --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 89cb4bb4d9557..2f544fd98e7de 100644 --- a/package.json +++ b/package.json @@ -15296,7 +15296,7 @@ { "id": "gitlensPatch", "title": "Patch", - "icon": "$(cloud)" + "icon": "$(gitlens-cloud-patch)" } ], "panel": [ @@ -15408,7 +15408,7 @@ "name": "Cloud Patches", "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && config.gitlens.cloudPatches.enabled", "contextualTitle": "GL", - "icon": "$(cloud)", + "icon": "$(gitlens-cloud-patch)", "initialSize": 2, "visibility": "visible" }, From 1f55c494b20e98d9d12501b8cb8d60435b2d7768 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 11 Nov 2023 00:48:35 -0500 Subject: [PATCH 0204/1012] Updates dependencies --- ThirdPartyNotices.txt | 10 +- package.json | 22 +- yarn.lock | 484 +++++++++++++++++++++--------------------- 3 files changed, 259 insertions(+), 257 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 6a39ffb6d7426..b9d77c83a9f39 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -6,14 +6,14 @@ This project incorporates components from the projects listed below. 1. @lit/react version 1.0.1 (https://github.com/lit/lit) 2. @microsoft/fast-element version 1.12.0 (https://github.com/Microsoft/fast) 3. @octokit/graphql version 7.0.2 (https://github.com/octokit/graphql.js) -4. @octokit/request version 8.1.4 (https://github.com/octokit/request.js) -5. @opentelemetry/api version 1.6.0 (https://github.com/open-telemetry/opentelemetry-js) -6. @opentelemetry/exporter-trace-otlp-http version 0.43.0 (https://github.com/open-telemetry/opentelemetry-js) -7. @opentelemetry/sdk-trace-base version 1.17.0 (https://github.com/open-telemetry/opentelemetry-js) +4. @octokit/request version 8.1.5 (https://github.com/octokit/request.js) +5. @opentelemetry/api version 1.7.0 (https://github.com/open-telemetry/opentelemetry-js) +6. @opentelemetry/exporter-trace-otlp-http version 0.45.1 (https://github.com/open-telemetry/opentelemetry-js) +7. @opentelemetry/sdk-trace-base version 1.18.1 (https://github.com/open-telemetry/opentelemetry-js) 8. @vscode/codicons version 0.0.35 (https://github.com/microsoft/vscode-codicons) 9. @vscode/webview-ui-toolkit version 1.2.2 (https://github.com/microsoft/vscode-webview-ui-toolkit) 10. ansi-regex version 6.0.1 (https://github.com/chalk/ansi-regex) -11. billboard.js version 3.10.2 (https://github.com/naver/billboard.js) +11. billboard.js version 3.10.3 (https://github.com/naver/billboard.js) 12. https-proxy-agent version 5.0.1 (https://github.com/TooTallNate/node-https-proxy-agent) 13. iconv-lite version 0.6.3 (https://github.com/ashtuchkin/iconv-lite) 14. lit version 3.0.2 (https://github.com/lit/lit) diff --git a/package.json b/package.json index 2f544fd98e7de..b96e2f9bd473f 100644 --- a/package.json +++ b/package.json @@ -15739,14 +15739,14 @@ "@lit/react": "1.0.1", "@microsoft/fast-element": "1.12.0", "@octokit/graphql": "7.0.2", - "@octokit/request": "8.1.4", - "@opentelemetry/api": "1.6.0", - "@opentelemetry/exporter-trace-otlp-http": "0.43.0", - "@opentelemetry/sdk-trace-base": "1.17.0", + "@octokit/request": "8.1.5", + "@opentelemetry/api": "1.7.0", + "@opentelemetry/exporter-trace-otlp-http": "0.45.1", + "@opentelemetry/sdk-trace-base": "1.18.1", "@vscode/codicons": "0.0.35", "@vscode/webview-ui-toolkit": "1.2.2", "ansi-regex": "6.0.1", - "billboard.js": "3.10.2", + "billboard.js": "3.10.3", "https-proxy-agent": "5.0.1", "iconv-lite": "0.6.3", "lit": "3.0.2", @@ -15759,14 +15759,14 @@ }, "devDependencies": { "@twbs/fantasticon": "2.7.1", - "@types/mocha": "10.0.1", + "@types/mocha": "10.0.4", "@types/node": "16.11.47", - "@types/react": "17.0.69", + "@types/react": "17.0.70", "@types/react-dom": "17.0.21", - "@types/sortablejs": "1.15.4", + "@types/sortablejs": "1.15.5", "@types/vscode": "1.81.0", - "@typescript-eslint/eslint-plugin": "6.9.1", - "@typescript-eslint/parser": "6.9.1", + "@typescript-eslint/eslint-plugin": "6.10.0", + "@typescript-eslint/parser": "6.10.0", "@vscode/test-electron": "2.3.6", "@vscode/test-web": "0.0.48", "@vscode/vsce": "2.22.0", @@ -15803,7 +15803,7 @@ "sass-loader": "13.3.2", "schema-utils": "4.2.0", "sharp": "0.32.6", - "svgo": "3.0.2", + "svgo": "3.0.3", "terser-webpack-plugin": "5.3.9", "ts-loader": "9.5.0", "tsc-alias": "1.8.8", diff --git a/yarn.lock b/yarn.lock index 6994229dc7ab1..7d5abad2a59d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -381,9 +381,9 @@ integrity sha512-gQutuDHPKNxUEcQ4pypZT4Wmrbapus+P9s3bR/SEOLsMbNqNoXigGImITygI5zhb+aA5rzflM6O8YWkmRbGkPA== "@microsoft/fast-foundation@^2.38.0", "@microsoft/fast-foundation@^2.41.1": - version "2.49.3" - resolved "https://registry.yarnpkg.com/@microsoft/fast-foundation/-/fast-foundation-2.49.3.tgz#caf2f6ed20985a9ca892cd14d6c75b2d5899f229" - integrity sha512-9+XSYOuZeEbmZEdH5ze+pj+Y/Yqyeb37mQ95eGcz1Mvz2ALdDwcmx3K5ahBWAEYasoTeyIPXB7ZSjR9TJlMi2w== + version "2.49.4" + resolved "https://registry.yarnpkg.com/@microsoft/fast-foundation/-/fast-foundation-2.49.4.tgz#322150cd6f0bed89d6d2238a700e6b9db94ac694" + integrity sha512-5I2tSPo6bnOfVAIX7XzX+LhilahwvD7h+yzl3jW0t5IYmMX9Lci9VUVyx5f8hHdb1O9a8Y9Atb7Asw7yFO/u+w== dependencies: "@microsoft/fast-element" "^1.12.0" "@microsoft/fast-web-utilities" "^5.4.1" @@ -481,10 +481,10 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@8.1.4", "@octokit/request@^8.0.1": - version "8.1.4" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.1.4.tgz#12dfaebdb2ea375eaabb41d39d45182531ac2857" - integrity sha512-M0aaFfpGPEKrg7XoA/gwgRvc9MSXHRO2Ioki1qrPDbl1e9YhjIwVoHE7HIKmv/m3idzldj//xBujcFNqGX6ENA== +"@octokit/request@8.1.5", "@octokit/request@^8.0.1": + version "8.1.5" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.1.5.tgz#902ae9565117a1dc410d10b5dbc44c4d27a89b71" + integrity sha512-zVKbNbX1xUluD9ZR4/tPs1yuYrK9xeh5fGZUXA6u04XGsTvomg0YO8/ZUC0FqAd49hAOEMFPAVUTh+2lBhOhLA== dependencies: "@octokit/endpoint" "^9.0.0" "@octokit/request-error" "^5.0.0" @@ -493,99 +493,99 @@ universal-user-agent "^6.0.0" "@octokit/types@^12.0.0": - version "12.1.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.1.1.tgz#376726d8435625b3a1b6fcd8cd3e1b03ade939dc" - integrity sha512-qnJTldJ1NyGT5MTsCg/Zi+y2IFHZ1Jo5+njNCjJ9FcainV7LjuHgmB697kA0g4MjZeDAJsM3B45iqCVsCLVFZg== + version "12.2.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.2.0.tgz#c21044ec70c5e2222043bcbe7fe2c3448a13df31" + integrity sha512-ZkdHqHJdifVndN7Pha10+qrgAjy3AcG//Vmjr/o5UFuTiYCcMhqDj39Yr9VM9zJ/42KO2xAYhV7cvLnLI9Kvwg== dependencies: "@octokit/openapi-types" "^19.0.2" -"@opentelemetry/api-logs@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.43.0.tgz#472dacbf91488ad6f6b9de39a6f5038b450bdbc6" - integrity sha512-0CXMOYPXgAdLM2OzVkiUfAL6QQwWVhnMfUXCqLsITY42FZ9TxAhZIHkoc4mfVxvPuXsBnRYGR8UQZX86p87z4A== +"@opentelemetry/api-logs@0.45.1": + version "0.45.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.45.1.tgz#9e4f2c652dcce798c5627939b22304c2b5ce19c5" + integrity sha512-zVGq/k70l+kB/Wuv3O/zhptP2hvDhEbhDu9EtHde1iWZJf3FedeYS/nWVcMBkkyPAjS/JKNk86WN4CBQLGUuOw== dependencies: "@opentelemetry/api" "^1.0.0" -"@opentelemetry/api@1.6.0", "@opentelemetry/api@^1.0.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.6.0.tgz#de2c6823203d6f319511898bb5de7e70f5267e19" - integrity sha512-OWlrQAnWn9577PhVgqjUvMr1pg57Bc4jv0iL4w0PRuOSRvq67rvHW9Ie/dZVMvCzhSCB+UxhcY/PmCmFj33Q+g== - -"@opentelemetry/core@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.17.0.tgz#6a72425f5f953dc68b4c7c66d947c018173d30d2" - integrity sha512-tfnl3h+UefCgx1aeN2xtrmr6BmdWGKXypk0pflQR0urFS40aE88trnkOMc2HTJZbMrqEEl4HsaBeFhwLVXsrJg== - dependencies: - "@opentelemetry/semantic-conventions" "1.17.0" - -"@opentelemetry/exporter-trace-otlp-http@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.43.0.tgz#4d0a3587a1d372d19c883d9a4720f6eeb7dc9671" - integrity sha512-X6RGl4RTWC13EBrFstAbTh4vKqVqf6afpvFcud9qYhvl2A53OZ5RTAQP+9MrAMhthiKQaftNsEDdB2/0Sq+Xkw== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/otlp-exporter-base" "0.43.0" - "@opentelemetry/otlp-transformer" "0.43.0" - "@opentelemetry/resources" "1.17.0" - "@opentelemetry/sdk-trace-base" "1.17.0" - -"@opentelemetry/otlp-exporter-base@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.43.0.tgz#3ac36e959897050ceba8838bb2af7145a9e73d2c" - integrity sha512-LXNtRFVuPRXB9q0qdvrLikQ3NtT9Jmv255Idryz3RJPhOh/Fa03sBASQoj3D55OH3xazmA90KFHfhJ/d8D8y4A== - dependencies: - "@opentelemetry/core" "1.17.0" - -"@opentelemetry/otlp-transformer@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.43.0.tgz#d4b12ba52d5193a35840d9e1a5e646c4e7e06a5b" - integrity sha512-KXYmgzWdVBOD5NvPmGW1nEMJjyQ8gK3N8r6pi4HvmEhTp0v4T13qDSax4q0HfsqmbPJR355oqQSJUnu1dHNutw== - dependencies: - "@opentelemetry/api-logs" "0.43.0" - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" - "@opentelemetry/sdk-logs" "0.43.0" - "@opentelemetry/sdk-metrics" "1.17.0" - "@opentelemetry/sdk-trace-base" "1.17.0" - -"@opentelemetry/resources@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.17.0.tgz#ee29144cfd7d194c69698c8153dbadec7fe6819f" - integrity sha512-+u0ciVnj8lhuL/qGRBPeVYvk7fL+H/vOddfvmOeJaA1KC+5/3UED1c9KoZQlRsNT5Kw1FaK8LkY2NVLYfOVZQw== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/semantic-conventions" "1.17.0" - -"@opentelemetry/sdk-logs@0.43.0": - version "0.43.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.43.0.tgz#ad40803f0e8893d1839af3a32756d5f46f0f7bbe" - integrity sha512-JyJ2BBRKm37Mc4cSEhFmsMl5ASQn1dkGhEWzAAMSlhPtLRTv5PfvJwhR+Mboaic/eDLAlciwsgijq8IFlf6IgQ== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" - -"@opentelemetry/sdk-metrics@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.17.0.tgz#e51d39e0bb749780d17f9b1df12f0490438dec1a" - integrity sha512-HlWM27yGmYuwCoVRe3yg2PqKnIsq0kEF0HQgvkeDWz2NYkq9fFaSspR6kvjxUTbghAlZrabiqbgyKoYpYaXS3w== - dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" +"@opentelemetry/api@1.7.0", "@opentelemetry/api@^1.0.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.7.0.tgz#b139c81999c23e3c8d3c0a7234480e945920fc40" + integrity sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw== + +"@opentelemetry/core@1.18.1": + version "1.18.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.18.1.tgz#d2e45f6bd6be4f00d20d18d4f1b230ec33805ae9" + integrity sha512-kvnUqezHMhsQvdsnhnqTNfAJs3ox/isB0SVrM1dhVFw7SsB7TstuVa6fgWnN2GdPyilIFLUvvbTZoVRmx6eiRg== + dependencies: + "@opentelemetry/semantic-conventions" "1.18.1" + +"@opentelemetry/exporter-trace-otlp-http@0.45.1": + version "0.45.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.45.1.tgz#2265181bd4787dc6660bdac33d658490a883283a" + integrity sha512-a6CGqSG66n5R1mghzLMzyzn3iGap1b0v+0PjKFjfYuwLtpHQBxh2PHxItu+m2mXSwnM4R0GJlk9oUW5sQkCE0w== + dependencies: + "@opentelemetry/core" "1.18.1" + "@opentelemetry/otlp-exporter-base" "0.45.1" + "@opentelemetry/otlp-transformer" "0.45.1" + "@opentelemetry/resources" "1.18.1" + "@opentelemetry/sdk-trace-base" "1.18.1" + +"@opentelemetry/otlp-exporter-base@0.45.1": + version "0.45.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.45.1.tgz#7170ec200152f89d74b2cf82fcf21fd32deebf03" + integrity sha512-Jvd6x8EwWGKEPWF4tkP4LpTPXiIkkafMNMvMJUfJd5DyNAftL1vAz+48jmi3URL2LMPkGryrvWPz8Tdu917gQw== + dependencies: + "@opentelemetry/core" "1.18.1" + +"@opentelemetry/otlp-transformer@0.45.1": + version "0.45.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.45.1.tgz#8f6590b93f177510983bea3055e5a3f3d30faad2" + integrity sha512-FhIHgfC0b0XtoBrS5ISfva939yWffNl47ypXR8I7Ru+dunlySpmf2TLocKHYLHGcWiuoeSNO5O4dZCmSKOtpXw== + dependencies: + "@opentelemetry/api-logs" "0.45.1" + "@opentelemetry/core" "1.18.1" + "@opentelemetry/resources" "1.18.1" + "@opentelemetry/sdk-logs" "0.45.1" + "@opentelemetry/sdk-metrics" "1.18.1" + "@opentelemetry/sdk-trace-base" "1.18.1" + +"@opentelemetry/resources@1.18.1": + version "1.18.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.18.1.tgz#e27bdc4715bccc8cd4a72d4aca3995ad0a496fe7" + integrity sha512-JjbcQLYMttXcIabflLRuaw5oof5gToYV9fuXbcsoOeQ0BlbwUn6DAZi++PNsSz2jjPeASfDls10iaO/8BRIPRA== + dependencies: + "@opentelemetry/core" "1.18.1" + "@opentelemetry/semantic-conventions" "1.18.1" + +"@opentelemetry/sdk-logs@0.45.1": + version "0.45.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.45.1.tgz#d59a99147ab15eb36757932517dfc9a10e1645e9" + integrity sha512-z0RRgW4LeKEKnhXS4F/HnqB6+7gsy63YK47F4XAJYHs4s1KKg8XnQ2RkbuL31i/a9nXkylttYtvsT50CGr487g== + dependencies: + "@opentelemetry/core" "1.18.1" + "@opentelemetry/resources" "1.18.1" + +"@opentelemetry/sdk-metrics@1.18.1": + version "1.18.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.18.1.tgz#1dd334744a1e5d2eec27e9e9765c73cd2f43aef3" + integrity sha512-TEFgeNFhdULBYiCoHbz31Y4PDsfjjxRp8Wmdp6ybLQZPqMNEb+dRq+XN8Xw3ivIgTaf9gYsomgV5ensX99RuEQ== + dependencies: + "@opentelemetry/core" "1.18.1" + "@opentelemetry/resources" "1.18.1" lodash.merge "^4.6.2" -"@opentelemetry/sdk-trace-base@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.17.0.tgz#05a21763c9efa72903c20b8930293cdde344b681" - integrity sha512-2T5HA1/1iE36Q9eg6D4zYlC4Y4GcycI1J6NsHPKZY9oWfAxWsoYnRlkPfUqyY5XVtocCo/xHpnJvGNHwzT70oQ== +"@opentelemetry/sdk-trace-base@1.18.1": + version "1.18.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.18.1.tgz#256605d90b202002d5672305c66dbcf377132379" + integrity sha512-tRHfDxN5dO+nop78EWJpzZwHsN1ewrZRVVwo03VJa3JQZxToRDH29/+MB24+yoa+IArerdr7INFJiX/iN4gjqg== dependencies: - "@opentelemetry/core" "1.17.0" - "@opentelemetry/resources" "1.17.0" - "@opentelemetry/semantic-conventions" "1.17.0" + "@opentelemetry/core" "1.18.1" + "@opentelemetry/resources" "1.18.1" + "@opentelemetry/semantic-conventions" "1.18.1" -"@opentelemetry/semantic-conventions@1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.17.0.tgz#af10baa9f05ce1e64a14065fc138b5739bfb65f6" - integrity sha512-+fguCd2d8d2qruk0H0DsCEy2CTK3t0Tugg7MhZ/UQMvmewbZLNnJ6heSYyzIZWG5IPfAXzoj4f4F/qpM7l4VBA== +"@opentelemetry/semantic-conventions@1.18.1": + version "1.18.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.18.1.tgz#8e47caf57a84b1dcc1722b2025693348cdf443b4" + integrity sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA== "@pkgjs/parseargs@^0.11.0": version "0.11.0" @@ -642,38 +642,38 @@ ttf2woff "^3.0.0" ttf2woff2 "^5.0.0" -"@types/d3-selection@*", "@types/d3-selection@^3.0.8": - version "3.0.8" - resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.8.tgz#9423511db3ed00a55aad4217ac8d546db5d8e5f5" - integrity sha512-pxCZUfQyedq/DIlPXIR5wE1mIH37omOdx1yxRudL3KZ4AC+156jMjOv1z5RVlGq62f8WX2kyO0hTVgEx627QFg== +"@types/d3-selection@*", "@types/d3-selection@^3.0.9": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.10.tgz#98cdcf986d0986de6912b5892e7c015a95ca27fe" + integrity sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg== -"@types/d3-transition@^3.0.6": - version "3.0.6" - resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.6.tgz#141684ef8046f4dc5da2d5b015c497513eba541c" - integrity sha512-K0To23B5UxNwFtKORnS5JoNYvw/DnknU5MzhHIS9czJ/lTqFFDeU6w9lArOdoTl0cZFNdNrMJSFCbRCEHccH2w== +"@types/d3-transition@^3.0.7": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.8.tgz#677707f5eed5b24c66a1918cde05963021351a8f" + integrity sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ== dependencies: "@types/d3-selection" "*" "@types/eslint-scope@^3.7.3": - version "3.7.6" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.6.tgz#585578b368ed170e67de8aae7b93f54a1b2fdc26" - integrity sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ== + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== dependencies: "@types/eslint" "*" "@types/estree" "*" "@types/eslint@*": - version "8.44.6" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.6.tgz#60e564551966dd255f4c01c459f0b4fb87068603" - integrity sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw== + version "8.44.7" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.7.tgz#430b3cc96db70c81f405e6a08aebdb13869198f5" + integrity sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" "@types/estree@*", "@types/estree@^1.0.0": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.4.tgz#d9748f5742171b26218516cf1828b8eafaf8a9fa" - integrity sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw== + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== "@types/glob@^7.1.1": version "7.2.0" @@ -689,28 +689,28 @@ integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#fdfdd69fa16d530047d9963635bd77c71a08c068" - integrity sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ== + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.2.tgz#394798d5f727402eb5ec99eb9618ffcd2b7645a1" - integrity sha512-8toY6FgdltSdONav1XtUHl4LN1yTmLza+EuDazb/fEmRNCwjyqNVIQWs2IfC74IqjHkREs/nQ2FWq5kZU9IC0w== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.3.tgz#0313e2608e6d6955d195f55361ddeebd4b74c6e7" - integrity sha512-1nESsePMBlf0RPRffLZi5ujYh7IH1BWL4y9pr+Bn3cJBdxz+RTP8bUFljLz9HvzhhOSWKdyBZ4DIivdL6rvgZg== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" "@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.14" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.14.tgz#74a97a5573980802f32c8e47b663530ab3b6b7d1" - integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw== + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/json5@^0.0.29": version "0.0.29" @@ -723,19 +723,19 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/minimist@^1.2.2": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.4.tgz#81f886786411c45bba3f33e781ab48bd56bfca2e" - integrity sha512-Kfe/D3hxHTusnPNRbycJE1N77WHDsdS4AjUYIzlDzhDrS47NrwuL3YW4VITxwR7KCVpzwgy4Rbj829KSSQmwXQ== + version "1.2.5" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e" + integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag== -"@types/mocha@10.0.1": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b" - integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== +"@types/mocha@10.0.4": + version "10.0.4" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.4.tgz#b5331955ebca216604691fd4fcd2dbdc2bd559a4" + integrity sha512-xKU7bUjiFTIttpWaIZ9qvgg+22O1nmbA+HRxdlR+u6TWsGfmFdXrheJoK4fFxrHNVIOBDvDNKZG+LYBpMHpX3w== "@types/node@*": - version "20.8.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.10.tgz#a5448b895c753ae929c26ce85cab557c6d4a365e" - integrity sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w== + version "20.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298" + integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw== dependencies: undici-types "~5.26.4" @@ -745,19 +745,19 @@ integrity sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g== "@types/normalize-package-data@^2.4.0": - version "2.4.3" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz#291c243e4b94dbfbc0c0ee26b7666f1d5c030e2c" - integrity sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg== + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" + integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== "@types/parse-json@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.1.tgz#27f7559836ad796cea31acb63163b203756a5b4e" - integrity sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng== + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" + integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== "@types/prop-types@*": - version "15.7.9" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d" - integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g== + version "15.7.10" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.10.tgz#892afc9332c4d62a5ea7e897fe48ed2085bbb08a" + integrity sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A== "@types/react-dom@17.0.21": version "17.0.21" @@ -766,34 +766,34 @@ dependencies: "@types/react" "^17" -"@types/react@17.0.69", "@types/react@^17": - version "17.0.69" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.69.tgz#245a0cf2f5b0fb1d645691d3083e3c7d4409b98f" - integrity sha512-klEeru//GhiQvXUBayz0Q4l3rKHWsBR/EUOhOeow6hK2jV7MlO44+8yEk6+OtPeOlRfnpUnrLXzGK+iGph5aeg== +"@types/react@17.0.70", "@types/react@^17": + version "17.0.70" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.70.tgz#35301a9cb94ba1a65dc306b7ce169a2c4fda1986" + integrity sha512-yqYMK49/cnqw+T8R9/C+RNjRddYmPDGI5lKHi3bOYceQCBAh8X2ngSbZP0gnVeyvHr0T7wEgIIGKT1usNol08w== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" "@types/scheduler@*": - version "0.16.5" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.5.tgz#4751153abbf8d6199babb345a52e1eb4167d64af" - integrity sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw== + version "0.16.6" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.6.tgz#eb26db6780c513de59bee0b869ef289ad3068711" + integrity sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA== "@types/semver@^7.5.0": - version "7.5.4" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" - integrity sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ== + version "7.5.5" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.5.tgz#deed5ab7019756c9c90ea86139106b0346223f35" + integrity sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg== -"@types/sortablejs@1.15.4": - version "1.15.4" - resolved "https://registry.yarnpkg.com/@types/sortablejs/-/sortablejs-1.15.4.tgz#9ccaa84a64205defcbb78df63176a3722121ccd7" - integrity sha512-7oL7CcPSfoyoNx3Ba1+79ykJzpEKVhHUyfAiN5eT/FoeDXOR3eBDLXf9ndDNuxaExmjpI+zVi2dMMuaoXUOzNA== +"@types/sortablejs@1.15.5": + version "1.15.5" + resolved "https://registry.yarnpkg.com/@types/sortablejs/-/sortablejs-1.15.5.tgz#c59e51765bc53c920192de0d0202f75b7ce4cb3f" + integrity sha512-qqqbEFbB1EZt08I1Ok2BA3Sx0zlI8oizdIguMsajk4Yo/iHgXhCb3GM6N09JOJqT9xIMYM9LTFy8vit3RNY71Q== "@types/trusted-types@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.5.tgz#5cac7e7df3275bb95f79594f192d97da3b4fd5fe" - integrity sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA== + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.6.tgz#d12451beaeb9c3838f12024580dc500b7e88b0ad" + integrity sha512-HYtNooPvUY9WAVRBr4u+4Qa9fYD1ze2IUlAD3HoA6oehn1taGwBx3Oa52U4mTslTS+GAExKpaFu39Y5xUEwfjg== "@types/vscode@1.81.0": version "1.81.0" @@ -801,27 +801,27 @@ integrity sha512-YIaCwpT+O2E7WOMq0eCgBEABE++SX3Yl/O02GoMIF2DO3qAtvw7m6BXFYsxnc6XyzwZgh6/s/UG78LSSombl2w== "@types/yargs-parser@*": - version "21.0.2" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.2.tgz#7bd04c5da378496ef1695a1008bf8f71847a8b8b" - integrity sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw== + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": - version "17.0.29" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.29.tgz#06aabc72497b798c643c812a8b561537fea760cf" - integrity sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA== + version "17.0.31" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.31.tgz#8fd0089803fd55d8a285895a18b88cb71a99683c" + integrity sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg== dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz#d8ce497dc0ed42066e195c8ecc40d45c7b1254f4" - integrity sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg== +"@typescript-eslint/eslint-plugin@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz#cfe2bd34e26d2289212946b96ab19dcad64b661a" + integrity sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.9.1" - "@typescript-eslint/type-utils" "6.9.1" - "@typescript-eslint/utils" "6.9.1" - "@typescript-eslint/visitor-keys" "6.9.1" + "@typescript-eslint/scope-manager" "6.10.0" + "@typescript-eslint/type-utils" "6.10.0" + "@typescript-eslint/utils" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -829,72 +829,72 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.9.1.tgz#4f685f672f8b9580beb38d5fb99d52fc3e34f7a3" - integrity sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg== +"@typescript-eslint/parser@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.10.0.tgz#578af79ae7273193b0b6b61a742a2bc8e02f875a" + integrity sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog== dependencies: - "@typescript-eslint/scope-manager" "6.9.1" - "@typescript-eslint/types" "6.9.1" - "@typescript-eslint/typescript-estree" "6.9.1" - "@typescript-eslint/visitor-keys" "6.9.1" + "@typescript-eslint/scope-manager" "6.10.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/typescript-estree" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz#e96afeb9a68ad1cd816dba233351f61e13956b75" - integrity sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg== +"@typescript-eslint/scope-manager@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz#b0276118b13d16f72809e3cecc86a72c93708540" + integrity sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg== dependencies: - "@typescript-eslint/types" "6.9.1" - "@typescript-eslint/visitor-keys" "6.9.1" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" -"@typescript-eslint/type-utils@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz#efd5db20ed35a74d3c7d8fba51b830ecba09ce32" - integrity sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg== +"@typescript-eslint/type-utils@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz#1007faede067c78bdbcef2e8abb31437e163e2e1" + integrity sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg== dependencies: - "@typescript-eslint/typescript-estree" "6.9.1" - "@typescript-eslint/utils" "6.9.1" + "@typescript-eslint/typescript-estree" "6.10.0" + "@typescript-eslint/utils" "6.10.0" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.9.1.tgz#a6cfc20db0fcedcb2f397ea728ef583e0ee72459" - integrity sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ== +"@typescript-eslint/types@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367" + integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg== -"@typescript-eslint/typescript-estree@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz#8c77910a49a04f0607ba94d78772da07dab275ad" - integrity sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw== +"@typescript-eslint/typescript-estree@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz#667381eed6f723a1a8ad7590a31f312e31e07697" + integrity sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg== dependencies: - "@typescript-eslint/types" "6.9.1" - "@typescript-eslint/visitor-keys" "6.9.1" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.9.1.tgz#763da41281ef0d16974517b5f0d02d85897a1c1e" - integrity sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA== +"@typescript-eslint/utils@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.10.0.tgz#4d76062d94413c30e402c9b0df8c14aef8d77336" + integrity sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.9.1" - "@typescript-eslint/types" "6.9.1" - "@typescript-eslint/typescript-estree" "6.9.1" + "@typescript-eslint/scope-manager" "6.10.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/typescript-estree" "6.10.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz#6753a9225a0ba00459b15d6456b9c2780b66707d" - integrity sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw== +"@typescript-eslint/visitor-keys@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz#b9eaf855a1ac7e95633ae1073af43d451e8f84e3" + integrity sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg== dependencies: - "@typescript-eslint/types" "6.9.1" + "@typescript-eslint/types" "6.10.0" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -1456,13 +1456,13 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -billboard.js@3.10.2: - version "3.10.2" - resolved "https://registry.yarnpkg.com/billboard.js/-/billboard.js-3.10.2.tgz#86e7472d0bf12594b7bd092e49d6ae7fec6b67eb" - integrity sha512-iBOGlc0P3VaupNKZ9JM/quxBqlSjudw+p+XG7skMn3xuPSpsMFD49wHeYOVOxASGGo+SvBn8T5lkFdRbQOYsow== +billboard.js@3.10.3: + version "3.10.3" + resolved "https://registry.yarnpkg.com/billboard.js/-/billboard.js-3.10.3.tgz#e328d59f7f4cf495bbbfd43d4da1d798e63643bd" + integrity sha512-GtexPEGbN4gkcxKL6/9iU2VK5YBaUUdJ1wcG7eJEtihJMx/LWrAxqKCd2H0Kfrypc557yhs14SFsfhr9xD1BWA== dependencies: - "@types/d3-selection" "^3.0.8" - "@types/d3-transition" "^3.0.6" + "@types/d3-selection" "^3.0.9" + "@types/d3-transition" "^3.0.7" d3-axis "^3.0.0" d3-brush "^3.0.0" d3-drag "^3.0.0" @@ -2169,7 +2169,7 @@ cssnano@^6.0.1: cssnano-preset-default "^6.0.1" lilconfig "^2.1.0" -csso@^5.0.5: +csso@5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" integrity sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ== @@ -2616,9 +2616,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.535: - version "1.4.576" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz#0c6940fdc0d60f7e34bd742b29d8fa847c9294d1" - integrity sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA== + version "1.4.581" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz#23b684c67bf56d4284e95598c05a5d266653b6d8" + integrity sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw== emoji-regex@^8.0.0: version "8.0.0" @@ -2745,9 +2745,9 @@ es-abstract@^1.22.1: which-typed-array "^1.1.13" es-module-lexer@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.1.tgz#c1b0dd5ada807a3b3155315911f364dc4e909db1" - integrity sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q== + version "1.4.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.0.tgz#285182e7f8f536ff5f4c57f2309836ef851474d8" + integrity sha512-lcCr3v3OLezdfFyx9r5NRYHOUTQNnFEQ9E87Mx8Kc+iqyJNkO7MJoB4GQRTlIMw9kLLTwGw0OAkm4BQQud/d9g== es-set-tostringtag@^2.0.1: version "2.0.2" @@ -3064,9 +3064,9 @@ fast-fifo@^1.1.0, fast-fifo@^1.2.0: integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== fast-glob@^3.2.11, fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -4537,9 +4537,11 @@ lru-cache@^7.5.1, lru-cache@^7.7.1: integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== "lru-cache@^9.1.1 || ^10.0.0": - version "10.0.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" - integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== + version "10.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.2.tgz#34504678cc3266b09b8dfd6fab4e1515258271b7" + integrity sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg== + dependencies: + semver "^7.3.5" lz-string@1.5.0: version "1.5.0" @@ -4891,9 +4893,9 @@ nanoid@3.3.3: integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== napi-build-utils@^1.0.1: version "1.0.2" @@ -6555,9 +6557,9 @@ stream-shift@^1.0.0: integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== streamx@^2.15.0: - version "2.15.2" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.2.tgz#680eacebdc9c43ede7362c2e6695b34dd413c741" - integrity sha512-b62pAV/aeMjUoRN2C/9F0n+G8AfcJjNC0zw/ZmOHeFsIe4m4GzjVW9m6VHXVjk536NbdU9JRwKMJRfkc+zUFTg== + version "2.15.4" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.4.tgz#497b8102d076ae12b43c456e0bb16940d1ba0999" + integrity sha512-uSXKl88bibiUCQ1eMpItRljCzDENcDx18rsfDmV79r0e/ThfrAwxG4Y2FarQZ2G4/21xcOKmFFd1Hue+ZIDwHw== dependencies: fast-fifo "^1.1.0" queue-tick "^1.0.1" @@ -6718,16 +6720,16 @@ svgicons2svgfont@^12.0.0: sax "^1.2.4" svg-pathdata "^6.0.3" -svgo@3.0.2, svgo@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a" - integrity sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ== +svgo@3.0.3, svgo@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.3.tgz#8cdfece6d4a0dc1dc116766d806daf817c1798b8" + integrity sha512-X4UZvLhOglD5Xrp834HzGHf8RKUW0Ahigg/08yRO1no9t2NxffOkMiQ0WmaMIbaGlVTlSst2zWANsdhz5ybXgA== dependencies: "@trysound/sax" "0.2.0" commander "^7.2.0" css-select "^5.1.0" css-tree "^2.2.1" - csso "^5.0.5" + csso "5.0.5" picocolors "^1.0.0" svgpath@^2.1.5: From 4476ba83a9543892ee8f8272c19c9768a363e648 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 11 Nov 2023 16:16:39 -0500 Subject: [PATCH 0205/1012] Renames to decoration and fixes alignment --- .../patchDetails/components/gl-tree-base.ts | 2 +- .../apps/shared/components/tree/base.ts | 12 ++++----- .../shared/components/tree/tree-generator.ts | 26 +++++++++---------- .../apps/shared/components/tree/tree-item.ts | 6 ++--- .../apps/shared/components/tree/tree.css.ts | 8 +++++- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts b/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts index ca9a5ee5d0291..92b14c52da9af 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts @@ -208,7 +208,7 @@ export class GlTreeBase extends GlElement extends TreeItemBase { label: string; @@ -55,7 +55,7 @@ interface TreeModelBase extends TreeItemBase { description?: string; context?: Context; actions?: TreeItemAction[]; - decorators?: TreeItemDecorator[]; + decorations?: TreeItemDecoration[]; contextData?: unknown; } diff --git a/src/webviews/apps/shared/components/tree/tree-generator.ts b/src/webviews/apps/shared/components/tree/tree-generator.ts index 493abd69837f6..e3cc2da97cd0d 100644 --- a/src/webviews/apps/shared/components/tree/tree-generator.ts +++ b/src/webviews/apps/shared/components/tree/tree-generator.ts @@ -86,25 +86,25 @@ export class GlTreeGenerator extends GlElement { }); } - private renderDecorators(model: TreeModelFlat) { - const decorators = model.decorators; - if (decorators == null || decorators.length === 0) return nothing; + private renderDecorations(model: TreeModelFlat) { + const decorations = model.decorations; + if (decorations == null || decorations.length === 0) return nothing; - return decorators.map(decorator => { - if (decorator.type === 'icon') { + return decorations.map(decoration => { + if (decoration.type === 'icon') { return html``; } - if (decorator.type === 'text') { - return html`${decorator.label}`; + if (decoration.type === 'text') { + return html`${decoration.label}`; } - // TODO: implement badge and indicator decorators + // TODO: implement badge and indicator decorations return undefined; }); @@ -132,7 +132,7 @@ export class GlTreeGenerator extends GlElement { model.description != null, () => html`${model.description}`, )} - ${this.renderActions(model)} ${this.renderDecorators(model)} + ${this.renderActions(model)} ${this.renderDecorations(model)} `; } diff --git a/src/webviews/apps/shared/components/tree/tree-item.ts b/src/webviews/apps/shared/components/tree/tree-item.ts index d648aac488c53..037be48972753 100644 --- a/src/webviews/apps/shared/components/tree/tree-item.ts +++ b/src/webviews/apps/shared/components/tree/tree-item.ts @@ -164,8 +164,8 @@ export class GlTreeItem extends GlElement { return html``; } - private renderDecorators() { - return html``; + private renderDecorations() { + return html``; } override render() { @@ -184,7 +184,7 @@ export class GlTreeItem extends GlElement { - ${this.renderActions()}${this.renderDecorators()} + ${this.renderActions()}${this.renderDecorations()} `; } diff --git a/src/webviews/apps/shared/components/tree/tree.css.ts b/src/webviews/apps/shared/components/tree/tree.css.ts index ac7ae4a72d525..0058144ecc84f 100644 --- a/src/webviews/apps/shared/components/tree/tree.css.ts +++ b/src/webviews/apps/shared/components/tree/tree.css.ts @@ -11,7 +11,8 @@ export const treeItemStyles = [ --tree-connector-size: var(--gitlens-tree-indent, 1.6rem); box-sizing: border-box; padding-left: var(--gitlens-gutter-width); - padding-right: var(--gitlens-scrollbar-gutter-width); + /* padding-right: var(--gitlens-scrollbar-gutter-width); */ + padding-right: 0.5rem; padding-top: 0.1rem; padding-bottom: 0.1rem; line-height: 2.2rem; @@ -213,5 +214,10 @@ export const treeItemStyles = [ .checkbox__input:checked + .checkbox__check { opacity: 1; } + + slot[name='decorations'] { + display: inline-block; + margin-left: 0.4rem; + } `, ]; From e052b44fad06865362e33fb8886e556c0e7e79b6 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 12 Nov 2023 00:46:47 -0500 Subject: [PATCH 0206/1012] Unifies webview panel show command args --- package.json | 84 ++++++++++++------------- src/constants.ts | 28 ++++----- src/plus/webviews/graph/graphWebview.ts | 2 +- src/plus/webviews/graph/registration.ts | 14 +---- src/webviews/apps/home/home.html | 2 +- src/webviews/apps/welcome/welcome.html | 4 +- src/webviews/settings/registration.ts | 2 +- src/webviews/webviewsController.ts | 19 +----- 8 files changed, 66 insertions(+), 89 deletions(-) diff --git a/package.json b/package.json index b96e2f9bd473f..42d73b1191639 100644 --- a/package.json +++ b/package.json @@ -5200,85 +5200,85 @@ "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#views", + "command": "gitlens.showSettingsPage!views", "title": "Open Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#autolinks", + "command": "gitlens.showSettingsPage!autolinks", "title": "Configure Autolinks", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#branches-view", + "command": "gitlens.showSettingsPage!branches-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#commits-view", + "command": "gitlens.showSettingsPage!commits-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#contributors-view", + "command": "gitlens.showSettingsPage!contributors-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#file-history-view", + "command": "gitlens.showSettingsPage!file-history-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#line-history-view", + "command": "gitlens.showSettingsPage!line-history-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#remotes-view", + "command": "gitlens.showSettingsPage!remotes-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#repositories-view", + "command": "gitlens.showSettingsPage!repositories-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#search-compare-view", + "command": "gitlens.showSettingsPage!search-compare-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#stashes-view", + "command": "gitlens.showSettingsPage!stashes-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#tags-view", + "command": "gitlens.showSettingsPage!tags-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#worktrees-view", + "command": "gitlens.showSettingsPage!worktrees-view", "title": "Open View Settings", "category": "GitLens", "icon": "$(gear)" }, { - "command": "gitlens.showSettingsPage#commit-graph", + "command": "gitlens.showSettingsPage!commit-graph", "title": "Open Commit Graph Settings", "category": "GitLens", "icon": "$(gear)" @@ -8694,55 +8694,55 @@ "when": "gitlens:enabled" }, { - "command": "gitlens.showSettingsPage#views", + "command": "gitlens.showSettingsPage!views", "when": "false" }, { - "command": "gitlens.showSettingsPage#branches-view", + "command": "gitlens.showSettingsPage!branches-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#commits-view", + "command": "gitlens.showSettingsPage!commits-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#contributors-view", + "command": "gitlens.showSettingsPage!contributors-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#file-history-view", + "command": "gitlens.showSettingsPage!file-history-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#line-history-view", + "command": "gitlens.showSettingsPage!line-history-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#remotes-view", + "command": "gitlens.showSettingsPage!remotes-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#repositories-view", + "command": "gitlens.showSettingsPage!repositories-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#search-compare-view", + "command": "gitlens.showSettingsPage!search-compare-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#stashes-view", + "command": "gitlens.showSettingsPage!stashes-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#tags-view", + "command": "gitlens.showSettingsPage!tags-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#worktrees-view", + "command": "gitlens.showSettingsPage!worktrees-view", "when": "false" }, { - "command": "gitlens.showSettingsPage#commit-graph", + "command": "gitlens.showSettingsPage!commit-graph", "when": "false" }, { @@ -11959,57 +11959,57 @@ "group": "navigation@-98" }, { - "command": "gitlens.showSettingsPage#branches-view", + "command": "gitlens.showSettingsPage!branches-view", "when": "view =~ /^gitlens\\.views\\.branches/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#commits-view", + "command": "gitlens.showSettingsPage!commits-view", "when": "view =~ /^gitlens\\.views\\.commits/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#contributors-view", + "command": "gitlens.showSettingsPage!contributors-view", "when": "view =~ /^gitlens\\.views\\.contributors/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#file-history-view", + "command": "gitlens.showSettingsPage!file-history-view", "when": "view =~ /^gitlens\\.views\\.fileHistory/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#line-history-view", + "command": "gitlens.showSettingsPage!line-history-view", "when": "view =~ /^gitlens\\.views\\.lineHistory/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#remotes-view", + "command": "gitlens.showSettingsPage!remotes-view", "when": "view =~ /^gitlens\\.views\\.remotes/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#repositories-view", + "command": "gitlens.showSettingsPage!repositories-view", "when": "view =~ /^gitlens\\.views\\.repositories/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#search-compare-view", + "command": "gitlens.showSettingsPage!search-compare-view", "when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#stashes-view", + "command": "gitlens.showSettingsPage!stashes-view", "when": "view =~ /^gitlens\\.views\\.stashes/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#tags-view", + "command": "gitlens.showSettingsPage!tags-view", "when": "view =~ /^gitlens\\.views\\.tags/", "group": "9_gitlens@1" }, { - "command": "gitlens.showSettingsPage#worktrees-view", + "command": "gitlens.showSettingsPage!worktrees-view", "when": "view =~ /^gitlens\\.views\\.worktrees/", "group": "9_gitlens@1" } @@ -12692,12 +12692,12 @@ "alt": "gitlens.copyRemoteFileUrlWithoutRange" }, { - "command": "gitlens.showSettingsPage#autolinks", + "command": "gitlens.showSettingsPage!autolinks", "when": "viewItem =~ /gitlens:autolinked:items\\b/", "group": "inline@99" }, { - "command": "gitlens.showSettingsPage#autolinks", + "command": "gitlens.showSettingsPage!autolinks", "when": "viewItem =~ /gitlens:autolinked:items\\b/", "group": "1_gitlens_actions@99" }, @@ -14531,7 +14531,7 @@ "group": "1_gitlens@1" }, { - "command": "gitlens.showSettingsPage#commit-graph", + "command": "gitlens.showSettingsPage!commit-graph", "group": "9_gitlens@1" } ], @@ -15636,7 +15636,7 @@ { "id": "gitlens.welcome.hostingServiceIntegrations", "title": "Integrate with Git hosting services", - "description": "Simplify your workflow and quickly gain insights with automatic linking of issues and pull requests across multiple Git hosting services including GitHub, GitHub Enterprise ✨, GitLab, GitLab self-managed ✨, Gitea, Gerrit, Google Source, Bitbucket, Bitbucket Server, Azure DevOps, and custom servers.\n\nAll integration provide automatic linking, while rich integrations with GitHub & GitLab offer detailed hover information for autolinks, and correlations between pull requests, branches, and commits, as well as user avatars for added context.\n\n**Define your own autolinks**\nUse autolinks to linkify external references, like Jira issues or Zendesk tickets, in commit messages.\n\n[Configure Autolinks](command:gitlens.showSettingsPage?%22autolinks%22)", + "description": "Simplify your workflow and quickly gain insights with automatic linking of issues and pull requests across multiple Git hosting services including GitHub, GitHub Enterprise ✨, GitLab, GitLab self-managed ✨, Gitea, Gerrit, Google Source, Bitbucket, Bitbucket Server, Azure DevOps, and custom servers.\n\nAll integration provide automatic linking, while rich integrations with GitHub & GitLab offer detailed hover information for autolinks, and correlations between pull requests, branches, and commits, as well as user avatars for added context.\n\n**Define your own autolinks**\nUse autolinks to linkify external references, like Jira issues or Zendesk tickets, in commit messages.\n\n[Configure Autolinks](command:gitlens.showSettingsPage!autolinks)", "media": { "markdown": "walkthroughs/welcome/integrations.md" } diff --git a/src/constants.ts b/src/constants.ts index 9689be5339436..382ff6b856a17 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -272,20 +272,20 @@ export const enum Commands { ShowRepositoriesView = 'gitlens.showRepositoriesView', ShowSearchAndCompareView = 'gitlens.showSearchAndCompareView', ShowSettingsPage = 'gitlens.showSettingsPage', - ShowSettingsPageAndJumpToBranchesView = 'gitlens.showSettingsPage#branches-view', - ShowSettingsPageAndJumpToCommitsView = 'gitlens.showSettingsPage#commits-view', - ShowSettingsPageAndJumpToContributorsView = 'gitlens.showSettingsPage#contributors-view', - ShowSettingsPageAndJumpToFileHistoryView = 'gitlens.showSettingsPage#file-history-view', - ShowSettingsPageAndJumpToLineHistoryView = 'gitlens.showSettingsPage#line-history-view', - ShowSettingsPageAndJumpToRemotesView = 'gitlens.showSettingsPage#remotes-view', - ShowSettingsPageAndJumpToRepositoriesView = 'gitlens.showSettingsPage#repositories-view', - ShowSettingsPageAndJumpToSearchAndCompareView = 'gitlens.showSettingsPage#search-compare-view', - ShowSettingsPageAndJumpToStashesView = 'gitlens.showSettingsPage#stashes-view', - ShowSettingsPageAndJumpToTagsView = 'gitlens.showSettingsPage#tags-view', - ShowSettingsPageAndJumpToWorkTreesView = 'gitlens.showSettingsPage#worktrees-view', - ShowSettingsPageAndJumpToViews = 'gitlens.showSettingsPage#views', - ShowSettingsPageAndJumpToCommitGraph = 'gitlens.showSettingsPage#commit-graph', - ShowSettingsPageAndJumpToAutolinks = 'gitlens.showSettingsPage#autolinks', + ShowSettingsPageAndJumpToBranchesView = 'gitlens.showSettingsPage!branches-view', + ShowSettingsPageAndJumpToCommitsView = 'gitlens.showSettingsPage!commits-view', + ShowSettingsPageAndJumpToContributorsView = 'gitlens.showSettingsPage!contributors-view', + ShowSettingsPageAndJumpToFileHistoryView = 'gitlens.showSettingsPage!file-history-view', + ShowSettingsPageAndJumpToLineHistoryView = 'gitlens.showSettingsPage!line-history-view', + ShowSettingsPageAndJumpToRemotesView = 'gitlens.showSettingsPage!remotes-view', + ShowSettingsPageAndJumpToRepositoriesView = 'gitlens.showSettingsPage!repositories-view', + ShowSettingsPageAndJumpToSearchAndCompareView = 'gitlens.showSettingsPage!search-compare-view', + ShowSettingsPageAndJumpToStashesView = 'gitlens.showSettingsPage!stashes-view', + ShowSettingsPageAndJumpToTagsView = 'gitlens.showSettingsPage!tags-view', + ShowSettingsPageAndJumpToWorkTreesView = 'gitlens.showSettingsPage!worktrees-view', + ShowSettingsPageAndJumpToViews = 'gitlens.showSettingsPage!views', + ShowSettingsPageAndJumpToCommitGraph = 'gitlens.showSettingsPage!commit-graph', + ShowSettingsPageAndJumpToAutolinks = 'gitlens.showSettingsPage!autolinks', ShowStashesView = 'gitlens.showStashesView', ShowTagsView = 'gitlens.showTagsView', ShowTimelinePage = 'gitlens.showTimelinePage', diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 33358e352b024..3da475945fe9e 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -395,7 +395,7 @@ export class GraphWebviewProvider implements WebviewProvider void executeCommand( Commands.ShowGraphPage, - { _type: 'WebviewPanelShowOptions' }, + undefined, this.repository, ), ), diff --git a/src/plus/webviews/graph/registration.ts b/src/plus/webviews/graph/registration.ts index 30cb1c33d1892..73c6165719d67 100644 --- a/src/plus/webviews/graph/registration.ts +++ b/src/plus/webviews/graph/registration.ts @@ -99,21 +99,11 @@ export function registerGraphWebviewCommands( return executeCommand(Commands.ShowGraphView, ...args); } - return executeCommand( - Commands.ShowGraphPage, - { _type: 'WebviewPanelShowOptions' }, - undefined, - ...args, - ); + return executeCommand(Commands.ShowGraphPage, undefined, ...args); }), registerCommand(`${panels.id}.switchToEditorLayout`, async () => { await configuration.updateEffective('graph.layout', 'editor'); - queueMicrotask( - () => - void executeCommand(Commands.ShowGraphPage, { - _type: 'WebviewPanelShowOptions', - }), - ); + queueMicrotask(() => void executeCommand(Commands.ShowGraphPage)); }), registerCommand(`${panels.id}.switchToPanelLayout`, async () => { await configuration.updateEffective('graph.layout', 'panel'); diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index 25505325f25ea..68e9d32eb14a3 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -322,7 +322,7 @@ > Integrations Use autolinks to linkify external references, like Jira issues or Zendesk tickets, in commit messages.

- Configure Autolinks @@ -583,7 +583,7 @@

Configuration

>GitLens Settings
Autolinks Settings(panels: WebviewPanelsProxy { // The show and jump commands are structured to have a # separating the base command from the anchor let anchor: string | undefined; - const match = /.*?#(.*)/.exec(c); + const match = /.*?!(.*)/.exec(c); if (match != null) { [, anchor] = match; } diff --git a/src/webviews/webviewsController.ts b/src/webviews/webviewsController.ts index 00a7a17b8997f..53431834c5165 100644 --- a/src/webviews/webviewsController.ts +++ b/src/webviews/webviewsController.ts @@ -357,13 +357,8 @@ export class WebviewsController implements Disposable { }), registerCommand( command.id, - (...args: unknown[]) => { - if (hasWebviewPanelShowOptions(args)) { - const [{ _type, ...opts }, ...rest] = args; - return show({ ...command.options, ...opts }, ...(rest as ShowingArgs)); - } - - return show({ ...command.options }, ...(args as ShowingArgs)); + (opts: WebviewPanelShowOptions | undefined, ...args: unknown[]) => { + return show({ ...command.options, ...opts }, ...(args as ShowingArgs)); }, this, ), @@ -415,10 +410,7 @@ interface WebviewPanelsShowOptions extends WebviewPanelShowOptions { preserveInstance?: string | boolean; } -export type WebviewPanelShowCommandArgs = [ - WebviewPanelsShowOptions & { _type: 'WebviewPanelShowOptions' }, - ...args: unknown[], -]; +export type WebviewPanelShowCommandArgs = [WebviewPanelsShowOptions | undefined, ...args: unknown[]]; export interface WebviewViewShowOptions { column?: never; @@ -518,8 +510,3 @@ function getBestController(o: unknown): o is { state: Partial } { return o != null && typeof o === 'object' && 'state' in o && o.state != null && typeof o.state === 'object'; } - -function hasWebviewPanelShowOptions(args: unknown[]): args is WebviewPanelShowCommandArgs { - const [arg] = args; - return arg != null && typeof arg === 'object' && '_type' in arg && arg._type === 'WebviewPanelShowOptions'; -} From 167aec2804549f5a9f7f6490838350fd53bfbf8a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 12 Nov 2023 01:14:04 -0500 Subject: [PATCH 0207/1012] Updates feature usage type to avoid duplication Fixes worktrees and workspaces view usage key --- src/telemetry/usageTracker.ts | 29 ++++------------------------- src/views/workspacesView.ts | 2 +- src/views/worktreesView.ts | 2 +- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/telemetry/usageTracker.ts b/src/telemetry/usageTracker.ts index 1fdc0c1b43315..bdba5680be30c 100644 --- a/src/telemetry/usageTracker.ts +++ b/src/telemetry/usageTracker.ts @@ -1,5 +1,6 @@ import type { Disposable, Event } from 'vscode'; import { EventEmitter } from 'vscode'; +import type { CustomEditorTypes, TreeViewTypes, WebviewTypes, WebviewViewTypes } from '../constants'; import type { Container } from '../container'; import { updateRecordValue } from '../system/object'; import type { Storage } from '../system/storage'; @@ -11,31 +12,9 @@ export interface TrackedUsage { } export type TrackedUsageFeatures = - | 'accountView' - | 'branchesView' - | 'commitDetailsView' - | 'commitsView' - | 'contributorsView' - | 'draftsView' - | 'fileHistoryView' - | 'focusWebview' - | 'graphDetailsView' - | 'graphView' - | 'graphWebview' - | 'homeView' - | 'lineHistoryView' - | 'patchDetailsView' - | 'rebaseEditor' - | 'remotesView' - | 'repositoriesView' - | 'stashesView' - | 'settingsWebview' - | 'searchAndCompareView' - | 'tagsView' - | 'timelineWebview' - | 'timelineView' - | 'welcomeWebview' - | 'workspaceView'; + | `${WebviewTypes}Webview` + | `${TreeViewTypes | WebviewViewTypes}View` + | `${CustomEditorTypes}Editor`; export type TrackedUsageKeys = `${TrackedUsageFeatures}:shown`; export type UsageChangeEvent = { diff --git a/src/views/workspacesView.ts b/src/views/workspacesView.ts index a4d72e5e1f872..5e064e46c6339 100644 --- a/src/views/workspacesView.ts +++ b/src/views/workspacesView.ts @@ -83,7 +83,7 @@ export class WorkspacesView extends ViewBase<'workspaces', WorkspacesViewNode, W private _disposable: Disposable | undefined; constructor(container: Container) { - super(container, 'workspaces', 'Workspaces', 'workspaceView'); + super(container, 'workspaces', 'Workspaces', 'workspacesView'); this.description = `PREVIEW\u00a0\u00a0☁️`; this.disposables.push(container.workspaces.onDidResetWorkspaces(() => void this.refresh(true))); diff --git a/src/views/worktreesView.ts b/src/views/worktreesView.ts index 5f82c3016333d..be3e56ecd3734 100644 --- a/src/views/worktreesView.ts +++ b/src/views/worktreesView.ts @@ -97,7 +97,7 @@ export class WorktreesView extends ViewBase<'worktrees', WorktreesViewNode, Work protected readonly configKey = 'worktrees'; constructor(container: Container) { - super(container, 'worktrees', 'Worktrees', 'workspaceView'); + super(container, 'worktrees', 'Worktrees', 'worktreesView'); this.disposables.push( window.registerFileDecorationProvider({ From 96d1e9300bceac30e54a301451fa44743fdf44fd Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 12 Nov 2023 01:14:29 -0500 Subject: [PATCH 0208/1012] Adds experimental editor layout for Cloud Patches --- package.json | 24 ++++++++++++ src/config.ts | 3 ++ src/constants.ts | 3 +- src/container.ts | 7 +++- .../patchDetails/patchDetailsWebview.ts | 36 ++++++++++++++--- .../webviews/patchDetails/registration.ts | 39 ++++++++++++++++++- 6 files changed, 104 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 42d73b1191639..ae6f34e7f2eec 100644 --- a/package.json +++ b/package.json @@ -2695,6 +2695,21 @@ "markdownDescription": "Specifies whether to enable the preview of _Cloud Patches_, which allow you to easily and securely share code with your teammates or other developers", "scope": "window", "order": 10 + }, + "gitlens.cloudPatches.experimental.layout": { + "type": "string", + "default": "view", + "enum": [ + "editor", + "view" + ], + "enumDescriptions": [ + "Prefer showing Cloud Patches in the editor area", + "Prefer showing Cloud Patches in a view" + ], + "markdownDescription": "Specifies the preferred layout of for _Cloud Patches_", + "scope": "window", + "order": 11 } } }, @@ -5048,6 +5063,11 @@ "title": "Get Started", "category": "GitLens" }, + { + "command": "gitlens.showPatchDetailsPage", + "title": "Show Patch Details", + "category": "GitLens" + }, { "command": "gitlens.createPatch", "title": "Create Patch...", @@ -8581,6 +8601,10 @@ "command": "gitlens.plus.refreshRepositoryAccess", "when": "gitlens:enabled" }, + { + "command": "gitlens.showPatchDetailsPage", + "when": "gitlens:enabled && config.gitlens.cloudPatches.enabled" + }, { "command": "gitlens.createPatch", "when": "false && gitlens:enabled" diff --git a/src/config.ts b/src/config.ts index 801ba14aeb4fb..3199a489ec7b9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -43,6 +43,9 @@ export interface Config { }; readonly cloudPatches: { readonly enabled: boolean; + readonly experimental: { + readonly layout: 'editor' | 'view'; + }; }; readonly codeLens: CodeLensConfig; readonly currentLine: { diff --git a/src/constants.ts b/src/constants.ts index 382ff6b856a17..f476489466459 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -258,6 +258,7 @@ export const enum Commands { ShowLineCommitInView = 'gitlens.showLineCommitInView', ShowLineHistoryView = 'gitlens.showLineHistoryView', OpenOnlyChangedFiles = 'gitlens.openOnlyChangedFiles', + ShowPatchDetailsPage = 'gitlens.showPatchDetailsPage', ShowQuickBranchHistory = 'gitlens.showQuickBranchHistory', ShowQuickCommit = 'gitlens.showQuickCommitDetails', ShowQuickCommitFile = 'gitlens.showQuickCommitFileDetails', @@ -470,7 +471,7 @@ export type TreeViewTypes = | 'worktrees'; export type TreeViewIds = `gitlens.views.${TreeViewTypes}`; -export type WebviewTypes = 'graph' | 'settings' | 'timeline' | 'welcome' | 'focus'; +export type WebviewTypes = 'focus' | 'graph' | 'patchDetails' | 'settings' | 'timeline' | 'welcome'; export type WebviewIds = `gitlens.${WebviewTypes}`; export type WebviewViewTypes = diff --git a/src/container.ts b/src/container.ts index 3ffb9e95b7e3d..2dd04b0dd8783 100644 --- a/src/container.ts +++ b/src/container.ts @@ -38,7 +38,10 @@ import { } from './plus/webviews/graph/registration'; import { GraphStatusBarController } from './plus/webviews/graph/statusbar'; import type { PatchDetailsWebviewShowingArgs } from './plus/webviews/patchDetails/registration'; -import { registerPatchDetailsWebviewView } from './plus/webviews/patchDetails/registration'; +import { + registerPatchDetailsWebviewPanel, + registerPatchDetailsWebviewView, +} from './plus/webviews/patchDetails/registration'; import type { TimelineWebviewShowingArgs } from './plus/webviews/timeline/registration'; import { registerTimelineWebviewCommands, @@ -260,6 +263,8 @@ export class Container { this._disposables.push((this._repositoriesView = new RepositoriesView(this))); this._disposables.push((this._commitDetailsView = registerCommitDetailsWebviewView(this._webviews))); + const patchDetailsPanels = registerPatchDetailsWebviewPanel(this._webviews); + this._disposables.push(patchDetailsPanels); this._disposables.push((this._patchDetailsView = registerPatchDetailsWebviewView(this._webviews))); this._disposables.push((this._graphDetailsView = registerGraphDetailsWebviewView(this._webviews))); this._disposables.push((this._commitsView = new CommitsView(this))); diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index b6c47c6bee6dc..9c1856cbff5bc 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -115,6 +115,27 @@ export class PatchDetailsWebviewProvider this._disposable.dispose(); } + canReuseInstance(...args: PatchDetailsWebviewShowingArgs): boolean | undefined { + const [arg] = args; + if (arg?.mode === 'view' && arg.draft != null) { + switch (arg.draft.draftType) { + case 'cloud': + return ( + this._context.draft?.draftType === arg.draft.draftType && + this._context.draft.id === arg.draft.id + ); + + case 'local': + return ( + this._context.draft?.draftType === arg.draft.draftType && + this._context.draft.patch.contents === arg.draft.patch?.contents + ); + } + } + + return false; + } + async onShowing( _loading: boolean, options: WebviewShowOptions, @@ -142,10 +163,12 @@ export class PatchDetailsWebviewProvider } registerCommands(): Disposable[] { - return [ - registerCommand(`${this.host.id}.refresh`, () => this.host.refresh(true)), - registerCommand(`${this.host.id}.close`, () => this.closeView()), - ]; + return this.host.isView() + ? [ + registerCommand(`${this.host.id}.refresh`, () => this.host.refresh(true)), + registerCommand(`${this.host.id}.close`, () => this.closeView()), + ] + : []; } onMessageReceived(e: IpcMessage) { @@ -293,7 +316,10 @@ export class PatchDetailsWebviewProvider private setMode(mode: Mode, silent?: boolean) { this._context.mode = mode; this.setHostTitle(mode); - void setContext('gitlens:views:patchDetails:mode', mode); + void setContext( + 'gitlens:views:patchDetails:mode', + configuration.get('cloudPatches.experimental.layout') === 'editor' ? undefined : mode, + ); if (!silent) { this.updateState(true); } diff --git a/src/plus/webviews/patchDetails/registration.ts b/src/plus/webviews/patchDetails/registration.ts index d6cfaa59abbed..a7c0397b89f6a 100644 --- a/src/plus/webviews/patchDetails/registration.ts +++ b/src/plus/webviews/patchDetails/registration.ts @@ -1,8 +1,12 @@ +import { ViewColumn } from 'vscode'; +import { Commands } from '../../../constants'; import type { DraftSelectedEvent } from '../../../eventBus'; import type { Repository } from '../../../git/models/repository'; +import { executeCommand } from '../../../system/command'; +import { configuration } from '../../../system/configuration'; import { setContext } from '../../../system/context'; import type { Serialized } from '../../../system/serialize'; -import type { WebviewsController } from '../../../webviews/webviewsController'; +import type { WebviewPanelShowCommandArgs, WebviewsController } from '../../../webviews/webviewsController'; import type { Change, State } from './protocol'; interface CreateDraftFromChanges { @@ -54,6 +58,12 @@ export function registerPatchDetailsWebviewView(controller: WebviewsController) return new PatchDetailsWebviewProvider(container, host); }, async (...args) => { + if (configuration.get('cloudPatches.experimental.layout') === 'editor') { + await setContext('gitlens:views:patchDetails:mode', undefined); + void executeCommand(Commands.ShowPatchDetailsPage, undefined, ...args); + return; + } + const arg = args[0]; if (arg == null) return; @@ -61,3 +71,30 @@ export function registerPatchDetailsWebviewView(controller: WebviewsController) }, ); } + +export function registerPatchDetailsWebviewPanel(controller: WebviewsController) { + return controller.registerWebviewPanel, PatchDetailsWebviewShowingArgs>( + { id: Commands.ShowPatchDetailsPage, options: { preserveInstance: true } }, + { + id: 'gitlens.patchDetails', + fileName: 'patchDetails.html', + iconPath: 'images/gitlens-icon.png', + title: 'Patch', + contextKeyPrefix: `gitlens:webview:patchDetails`, + trackingFeature: 'patchDetailsWebview', + plusFeature: true, + column: ViewColumn.Active, + webviewHostOptions: { + retainContextWhenHidden: false, + enableFindWidget: false, + }, + allowMultipleInstances: true, + }, + async (container, host) => { + const { PatchDetailsWebviewProvider } = await import( + /* webpackChunkName: "patchDetails" */ './patchDetailsWebview' + ); + return new PatchDetailsWebviewProvider(container, host); + }, + ); +} From 685340b13c07435e30a6fa6a8ca8e6be687da12c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 00:26:44 -0500 Subject: [PATCH 0209/1012] Changes `getDiff` to use to/from args for clarity Changes `PatchRevisionRange` to use to/from args for clarity Changes `openChanges`/`openAllChanges` to use lhs/rhs args for clarity Ensures comparisons -> patch works properly --- src/commands/patches.ts | 240 ++++++------------ src/env/node/git/localGitProvider.ts | 36 +-- src/git/actions/commit.ts | 77 +++--- src/git/gitProvider.ts | 4 +- src/git/gitProviderService.ts | 6 +- src/git/models/diff.ts | 3 +- src/git/models/patch.ts | 10 +- src/plus/drafts/draftsService.ts | 25 +- src/plus/webviews/graph/graphWebview.ts | 2 +- .../patchDetails/patchDetailsWebview.ts | 40 ++- src/plus/webviews/patchDetails/protocol.ts | 20 +- .../webviews/patchDetails/registration.ts | 21 +- src/views/viewCommands.ts | 4 +- .../commitDetails/commitDetailsWebview.ts | 5 +- 14 files changed, 193 insertions(+), 300 deletions(-) diff --git a/src/commands/patches.ts b/src/commands/patches.ts index 376c7a5a0e11e..e34cddbd24690 100644 --- a/src/commands/patches.ts +++ b/src/commands/patches.ts @@ -2,12 +2,11 @@ import type { TextEditor } from 'vscode'; import { window, workspace } from 'vscode'; import { Commands } from '../constants'; import type { Container } from '../container'; -import type { PatchRevisionRange } from '../git/models/patch'; -import { shortenRevision } from '../git/models/reference'; +import { isSha, shortenRevision } from '../git/models/reference'; import type { Repository } from '../git/models/repository'; import type { Draft, LocalDraft } from '../gk/models/drafts'; import { showPatchesView } from '../plus/drafts/actions'; -import type { Change } from '../plus/webviews/patchDetails/protocol'; +import type { Change, CreateDraft } from '../plus/webviews/patchDetails/protocol'; import { getRepositoryOrShowPicker } from '../quickpicks/repositoryPicker'; import { command } from '../system/command'; import type { CommandContext } from './base'; @@ -19,8 +18,8 @@ import { } from './base'; export interface CreatePatchCommandArgs { - ref1?: string; - ref2?: string; + to?: string; + from?: string; repoPath?: string; } @@ -36,13 +35,13 @@ export class CreatePatchCommand extends Command { if (isCommandContextViewNodeHasCommit(context)) { args = { repoPath: context.node.commit.repoPath, - ref1: context.node.commit.ref, + to: context.node.commit.ref, }; } else if (isCommandContextViewNodeHasComparison(context)) { args = { repoPath: context.node.uri.fsPath, - ref1: context.node.compareWithRef.ref, - ref2: context.node.compareRef.ref, + to: context.node.compareRef.ref, + from: context.node.compareWithRef.ref, }; } } @@ -59,22 +58,11 @@ export class CreatePatchCommand extends Command { repo = this.container.git.getRepository(args.repoPath); } if (repo == null) return undefined; - if (args?.ref1 == null) return; + if (args?.to == null) return; - const diff = await getDiffContents(this.container, repo, args); + const diff = await this.container.git.getDiff(repo.uri, args.to ?? 'HEAD', args.from); if (diff == null) return; - // let repo; - // if (args?.repoPath == null) { - // repo = await getRepositoryOrShowPicker('Create Patch'); - // } else { - // repo = this.container.git.getRepository(args.repoPath); - // } - // if (repo == null) return; - - // const diff = await this.container.git.getDiff(repo.uri, args?.ref1 ?? 'HEAD', args?.ref2); - // if (diff == null) return; - const d = await workspace.openTextDocument({ content: diff.contents, language: 'diff' }); await window.showTextDocument(d); @@ -88,101 +76,6 @@ export class CreatePatchCommand extends Command { } } -async function getDiffContents( - container: Container, - repository: Repository, - args: CreatePatchCommandArgs, -): Promise<{ contents: string; revision: PatchRevisionRange } | undefined> { - const sha = args.ref1 ?? 'HEAD'; - - const diff = await container.git.getDiff(repository.uri, sha, args.ref2); - if (diff == null) return undefined; - - return { - contents: diff.contents, - revision: { - baseSha: args.ref2 ?? `${sha}^`, - sha: sha, - }, - }; -} - -interface CreateLocalChange { - title?: string; - description?: string; - changes: Change[]; -} - -async function createLocalChange( - container: Container, - repository: Repository, - args: CreatePatchCommandArgs, -): Promise { - if (args.ref1 == null) return undefined; - - const sha = args.ref1 ?? 'HEAD'; - // const [branchName] = await container.git.getCommitBranches(repository.uri, sha); - - const change: Change = { - type: 'revision', - repository: { - name: repository.name, - path: repository.path, - uri: repository.uri.toString(), - }, - files: undefined!, - revision: { - sha: sha, - baseSha: args.ref2 ?? `${sha}^`, - // branchName: branchName ?? 'HEAD', - }, - }; - - const create: CreateLocalChange = { changes: [change] }; - - const commit = await container.git.getCommit(repository.uri, sha); - if (commit == null) return undefined; - - const message = commit.message!.trim(); - const index = message.indexOf('\n'); - if (index < 0) { - create.title = message; - } else { - create.title = message.substring(0, index); - create.description = message.substring(index + 1); - } - - if (args.ref2 == null) { - change.files = commit.files != null ? [...commit.files] : []; - } else { - const diff = await getDiffContents(container, repository, args); - if (diff == null) return undefined; - - const result = await container.git.getDiffFiles(repository.uri, diff.contents); - if (result?.files == null) return; - - create.title = `Comparing ${shortenRevision(args.ref2)} with ${shortenRevision(args.ref1)}`; - - change.files = result.files; - } - - // const change: Change = { - // type: 'commit', - // repository: { - // name: repository.name, - // path: repository.path, - // uri: repository.uri.toString(), - // }, - // files: result.files, - // range: { - // ...range, - // branchName: branchName ?? 'HEAD', - // }, - // }; - - return create; -} - @command() export class CreateCloudPatchCommand extends Command { constructor(private readonly container: Container) { @@ -195,13 +88,13 @@ export class CreateCloudPatchCommand extends Command { if (isCommandContextViewNodeHasCommit(context)) { args = { repoPath: context.node.commit.repoPath, - ref1: context.node.commit.ref, + to: context.node.commit.ref, }; } else if (isCommandContextViewNodeHasComparison(context)) { args = { repoPath: context.node.uri.fsPath, - ref1: context.node.compareWithRef.ref, - ref2: context.node.compareRef.ref, + to: context.node.compareRef.ref, + from: context.node.compareWithRef.ref, }; } } @@ -220,7 +113,7 @@ export class CreateCloudPatchCommand extends Command { return showPatchesView({ mode: 'create' }); } - const create = await createLocalChange(this.container, repo, args); + const create = await createDraft(this.container, repo, args); if (create == null) { return showPatchesView({ mode: 'create', create: { repositories: [repo] } }); } @@ -366,60 +259,83 @@ export class OpenCloudPatchCommand extends Command { async execute(args?: OpenCloudPatchCommandArgs) { if (args?.id == null && args?.draft == null) { - void window.showErrorMessage('Cannot open cloud patch: no patch or patch id provided'); + void window.showErrorMessage('Cannot open Cloud Patch; no patch or patch id provided'); return; } const draft = args?.draft ?? (await this.container.drafts.getDraft(args?.id)); if (draft == null) { - void window.showErrorMessage(`Cannot open cloud patch: patch ${args.id} not found`); + void window.showErrorMessage(`Cannot open Cloud Patch; patch '${args.id}' not found`); return; } - // let patch: DraftPatch | undefined; - // if (args?.patchId) { - // patch = await this.container.drafts.getPatch(args.patchId); - // } else { - // const patches = draft.changesets?.[0]?.patches; - - // if (patches == null || patches.length === 0) { - // void window.showErrorMessage(`Cannot open cloud patch: no patch found under id ${args.patchId}`); - // return; - // } - - // patch = patches[0]; - - // if (patch.repo == null && patch.repoData != null) { - // const repo = await this.container.git.findMatchingRepository({ - // firstSha: patch.repoData.initialCommitSha, - // remoteUrl: patch.repoData.remote?.url, - // }); - // if (repo != null) { - // patch.repo = repo; - // } - // } + void showPatchesView({ mode: 'view', draft: draft }); + } +} - // if (patch.repo == null) { - // void window.showErrorMessage(`Cannot open cloud patch: no repository found for patch ${args.patchId}`); - // return; - // } +async function createDraft( + container: Container, + repository: Repository, + args: CreatePatchCommandArgs, +): Promise { + if (args.to == null) return undefined; - // // Opens the patch repository if it's not already open - // void this.container.git.getOrOpenRepository(patch.repo.uri); + const to = args.to ?? 'HEAD'; - // const patchContents = await this.container.drafts.getPatchContents(patch.id); - // if (patchContents == null) { - // void window.showErrorMessage(`Cannot open cloud patch: patch not found of contents empty`); - // return; - // } - // patch.contents = patchContents; - // } + const change: Change = { + type: 'revision', + repository: { + name: repository.name, + path: repository.path, + uri: repository.uri.toString(), + }, + files: undefined!, + revision: { to: to, from: args.from ?? `${to}^` }, + }; - // if (patch == null) { - // void window.showErrorMessage(`Cannot open cloud patch: patch not found`); - // return; - // } + const create: CreateDraft = { changes: [change] }; - void showPatchesView({ mode: 'view', draft: draft }); + const commit = await container.git.getCommit(repository.uri, to); + if (commit == null) return undefined; + + const message = commit.message!.trim(); + const index = message.indexOf('\n'); + if (index < 0) { + create.title = message; + } else { + create.title = message.substring(0, index); + create.description = message.substring(index + 1); } + + if (args.from == null) { + if (commit.files == null) return; + + change.files = [...commit.files]; + } else { + const diff = await container.git.getDiff(repository.uri, to, args.from); + if (diff == null) return; + + const result = await container.git.getDiffFiles(repository.uri, diff.contents); + if (result?.files == null) return; + + change.files = result.files; + + create.title = `Comparing ${shortenRevision(args.to)} with ${shortenRevision(args.from)}`; + + if (!isSha(args.to)) { + const commit = await container.git.getCommit(repository.uri, args.to); + if (commit != null) { + change.revision.to = commit.sha; + } + } + + if (!isSha(args.from)) { + const commit = await container.git.getCommit(repository.uri, args.from); + if (commit != null) { + change.revision.from = commit.sha; + } + } + } + + return create; } diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 1acc0fd717c12..29a69127f5f09 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -2955,38 +2955,38 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async getDiff( repoPath: string, - ref1: string, - ref2?: string, + to: string, + from?: string, options?: { context?: number }, ): Promise { const scope = getLogScope(); const params = [`-U${options?.context ?? 3}`]; - if (ref1 === uncommitted) { - if (ref2 != null) { - params.push(ref2); + if (to === uncommitted) { + if (from != null) { + params.push(from); } else { // Get only unstaged changes - ref2 = 'HEAD'; + from = 'HEAD'; } - } else if (ref1 === uncommittedStaged) { + } else if (to === uncommittedStaged) { params.push('--staged'); - if (ref2 != null) { - params.push(ref2); + if (from != null) { + params.push(from); } else { // Get only staged changes - ref2 = 'HEAD'; + from = 'HEAD'; } - } else if (ref2 == null) { - if (ref1 === '' || ref1.toUpperCase() === 'HEAD') { - ref2 = 'HEAD'; - params.push(ref2); + } else if (from == null) { + if (to === '' || to.toUpperCase() === 'HEAD') { + from = 'HEAD'; + params.push(from); } else { - ref2 = ref1; - params.push(`${ref1}^`, ref2); + from = `${to}^`; + params.push(from, to); } } else { - params.push(ref1, ref2); + params.push(from, to); } let data; @@ -2998,7 +2998,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return undefined; } - const diff: GitDiff = { baseSha: ref2, contents: data }; + const diff: GitDiff = { contents: data, from: from, to: to }; return diff; } diff --git a/src/git/actions/commit.ts b/src/git/actions/commit.ts index c87545af76519..600f9be778b1f 100644 --- a/src/git/actions/commit.ts +++ b/src/git/actions/commit.ts @@ -22,6 +22,9 @@ import type { GitFile } from '../models/file'; import type { GitRevisionReference } from '../models/reference'; import { getReferenceFromRevision, isUncommitted, isUncommittedStaged } from '../models/reference'; +type Ref = { repoPath: string; ref: string }; +type RefRange = { repoPath: string; rhs: string; lhs: string }; + export async function applyChanges(file: string | GitFile, rev1: GitRevisionReference, rev2?: GitRevisionReference) { let create = false; let ref1 = rev1.ref; @@ -58,11 +61,11 @@ export async function applyChanges(file: string | GitFile, rev1: GitRevisionRefe } } -export async function copyIdToClipboard(ref: { repoPath: string; ref: string } | GitCommit) { +export async function copyIdToClipboard(ref: Ref | GitCommit) { await env.clipboard.writeText(ref.ref); } -export async function copyMessageToClipboard(ref: { repoPath: string; ref: string } | GitCommit): Promise { +export async function copyMessageToClipboard(ref: Ref | GitCommit): Promise { let commit; if (isCommit(ref)) { commit = ref; @@ -81,16 +84,16 @@ export async function copyMessageToClipboard(ref: { repoPath: string; ref: strin export async function openAllChanges(commit: GitCommit, options?: TextDocumentShowOptions): Promise; export async function openAllChanges( files: GitFile[], - refs: { repoPath: string; ref1: string; ref2: string }, + refs: RefRange, options?: TextDocumentShowOptions, ): Promise; export async function openAllChanges( commitOrFiles: GitCommit | GitFile[], - refsOrOptions: { repoPath: string; ref1: string; ref2: string } | TextDocumentShowOptions | undefined, + refsOrOptions: RefRange | TextDocumentShowOptions | undefined, options?: TextDocumentShowOptions, ) { let files; - let refs; + let refs: RefRange | undefined; if (isCommit(commitOrFiles)) { if (commitOrFiles.files == null) { await commitOrFiles.ensureFullDetails(); @@ -99,15 +102,15 @@ export async function openAllChanges( files = commitOrFiles.files ?? []; refs = { repoPath: commitOrFiles.repoPath, + rhs: commitOrFiles.sha, // Don't need to worry about verifying the previous sha, as the DiffWith command will - ref1: commitOrFiles.unresolvedPreviousSha, - ref2: commitOrFiles.sha, + lhs: commitOrFiles.unresolvedPreviousSha, }; options = refsOrOptions as TextDocumentShowOptions | undefined; } else { files = commitOrFiles; - refs = refsOrOptions as { repoPath: string; ref1: string; ref2: string }; + refs = refsOrOptions as RefRange; } if (files.length > 10) { @@ -127,14 +130,8 @@ export async function openAllChanges( } export async function openAllChangesWithDiffTool(commit: GitCommit): Promise; -export async function openAllChangesWithDiffTool( - files: GitFile[], - ref: { repoPath: string; ref: string }, -): Promise; -export async function openAllChangesWithDiffTool( - commitOrFiles: GitCommit | GitFile[], - ref?: { repoPath: string; ref: string }, -) { +export async function openAllChangesWithDiffTool(files: GitFile[], ref: Ref): Promise; +export async function openAllChangesWithDiffTool(commitOrFiles: GitCommit | GitFile[], ref?: Ref) { let files; if (isCommit(commitOrFiles)) { if (commitOrFiles.files == null) { @@ -167,12 +164,12 @@ export async function openAllChangesWithDiffTool( export async function openAllChangesWithWorking(commit: GitCommit, options?: TextDocumentShowOptions): Promise; export async function openAllChangesWithWorking( files: GitFile[], - ref: { repoPath: string; ref: string }, + ref: Ref, options?: TextDocumentShowOptions, ): Promise; export async function openAllChangesWithWorking( commitOrFiles: GitCommit | GitFile[], - refOrOptions: { repoPath: string; ref: string } | TextDocumentShowOptions | undefined, + refOrOptions: Ref | TextDocumentShowOptions | undefined, options?: TextDocumentShowOptions, ) { let files; @@ -191,7 +188,7 @@ export async function openAllChangesWithWorking( options = refOrOptions as TextDocumentShowOptions | undefined; } else { files = commitOrFiles; - ref = refOrOptions as { repoPath: string; ref: string }; + ref = refOrOptions as Ref; } if (files.length > 10) { @@ -217,17 +214,17 @@ export async function openChanges( ): Promise; export async function openChanges( file: GitFile, - refs: { repoPath: string; ref1: string; ref2: string }, + refs: RefRange, options?: TextDocumentShowOptions & { lhsTitle?: string; rhsTitle?: string }, ): Promise; export async function openChanges( file: GitFile, - commitOrRefs: GitCommit | { repoPath: string; ref1: string; ref2: string }, + commitOrRefs: GitCommit | RefRange, options?: TextDocumentShowOptions & { lhsTitle?: string; rhsTitle?: string }, ): Promise; export async function openChanges( file: string | GitFile, - commitOrRefs: GitCommit | { repoPath: string; ref1: string; ref2: string }, + commitOrRefs: GitCommit | RefRange, options?: TextDocumentShowOptions & { lhsTitle?: string; rhsTitle?: string }, ) { const isArgCommit = isCommit(commitOrRefs); @@ -253,38 +250,30 @@ export async function openChanges( return; } - const refs = isArgCommit + const refs: RefRange = isArgCommit ? { repoPath: commitOrRefs.repoPath, + rhs: commitOrRefs.sha, // Don't need to worry about verifying the previous sha, as the DiffWith command will - ref1: commitOrRefs.unresolvedPreviousSha, - ref2: commitOrRefs.sha, + lhs: commitOrRefs.unresolvedPreviousSha, } : commitOrRefs; const rhsUri = GitUri.fromFile(file, refs.repoPath); const lhsUri = - file.status === 'R' || file.status === 'C' ? GitUri.fromFile(file, refs.repoPath, refs.ref1, true) : rhsUri; + file.status === 'R' || file.status === 'C' ? GitUri.fromFile(file, refs.repoPath, refs.lhs, true) : rhsUri; void (await executeCommand(Commands.DiffWith, { repoPath: refs.repoPath, - lhs: { uri: lhsUri, sha: refs.ref1, title: options?.lhsTitle }, - rhs: { uri: rhsUri, sha: refs.ref2, title: options?.rhsTitle }, + lhs: { uri: lhsUri, sha: refs.lhs, title: options?.lhsTitle }, + rhs: { uri: rhsUri, sha: refs.rhs, title: options?.rhsTitle }, showOptions: options, })); } export function openChangesWithDiffTool(file: string | GitFile, commit: GitCommit, tool?: string): Promise; -export function openChangesWithDiffTool( - file: GitFile, - ref: { repoPath: string; ref: string }, - tool?: string, -): Promise; -export async function openChangesWithDiffTool( - file: string | GitFile, - commitOrRef: GitCommit | { repoPath: string; ref: string }, - tool?: string, -) { +export function openChangesWithDiffTool(file: GitFile, ref: Ref, tool?: string): Promise; +export async function openChangesWithDiffTool(file: string | GitFile, commitOrRef: GitCommit | Ref, tool?: string) { if (typeof file === 'string') { if (!isCommit(commitOrRef)) throw new Error('Invalid arguments'); @@ -313,12 +302,12 @@ export async function openChangesWithWorking( ): Promise; export async function openChangesWithWorking( file: GitFile, - ref: { repoPath: string; ref: string }, + ref: Ref, options?: TextDocumentShowOptions & { lhsTitle?: string }, ): Promise; export async function openChangesWithWorking( file: string | GitFile, - commitOrRef: GitCommit | { repoPath: string; ref: string }, + commitOrRef: GitCommit | Ref, options?: TextDocumentShowOptions & { lhsTitle?: string }, ) { if (typeof file === 'string') { @@ -360,15 +349,11 @@ export async function openDirectoryCompare( return Container.instance.git.openDirectoryCompare(repoPath, ref, ref2, tool); } -export async function openDirectoryCompareWithPrevious( - ref: { repoPath: string; ref: string } | GitCommit, -): Promise { +export async function openDirectoryCompareWithPrevious(ref: Ref | GitCommit): Promise { return openDirectoryCompare(ref.repoPath, ref.ref, `${ref.ref}^`); } -export async function openDirectoryCompareWithWorking( - ref: { repoPath: string; ref: string } | GitCommit, -): Promise { +export async function openDirectoryCompareWithWorking(ref: Ref | GitCommit): Promise { return openDirectoryCompare(ref.repoPath, ref.ref, undefined); } diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 8a428a829a22b..3bae8ef8f9037 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -285,8 +285,8 @@ export interface GitProvider extends Disposable { getDefaultBranchName(repoPath: string | undefined, remote?: string): Promise; getDiff?( repoPath: string | Uri, - ref1: string, - ref2?: string, + to: string, + from?: string, options?: { context?: number }, ): Promise; getDiffFiles?(repoPath: string | Uri, contents: string): Promise; diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index e7d77d1119fb3..f065cba3e95a0 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -1834,12 +1834,12 @@ export class GitProviderService implements Disposable { @log() async getDiff( repoPath: string | Uri, - ref1: string, - ref2?: string, + to: string, + from?: string, options?: { context?: number }, ): Promise { const { provider, path } = this.getProvider(repoPath); - return provider.getDiff?.(path, ref1, ref2, options); + return provider.getDiff?.(path, to, from, options); } @log({ args: { 1: false } }) diff --git a/src/git/models/diff.ts b/src/git/models/diff.ts index f2c6011d6f43c..afe146d4e801e 100644 --- a/src/git/models/diff.ts +++ b/src/git/models/diff.ts @@ -1,8 +1,9 @@ import type { GitFileChange } from './file'; export interface GitDiff { - readonly baseSha: string; readonly contents: string; + readonly from: string; + readonly to: string; } export interface GitDiffHunkLine { diff --git a/src/git/models/patch.ts b/src/git/models/patch.ts index 8fc15b21d554b..ad9319f8ad036 100644 --- a/src/git/models/patch.ts +++ b/src/git/models/patch.ts @@ -4,13 +4,13 @@ import type { GitDiffFiles } from './diff'; import type { Repository } from './repository'; /** - * For a single commit `sha` is the commit SHA and `baseSha` is its parent `^` - * For a commit range `sha` is the tip SHA and `baseSha` is the base SHA - * For a WIP `sha` is the "uncommitted" SHA and `baseSha` is the current HEAD SHA + * For a single commit `to` is the commit SHA and `from` is its parent `^` + * For a commit range `to` is the tip SHA and `from` is the base SHA + * For a WIP `to` is the "uncommitted" SHA and `from` is the current HEAD SHA */ export interface PatchRevisionRange { - baseSha: string; - sha: string; + from: string; + to: string; } export interface GitPatch { diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index 3cd14f4c757af..87fc9b81fc15a 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -212,18 +212,20 @@ export class DraftService implements Disposable { private async getCreateDraftPatchRequestFromChange( change: CreateDraftChange, ): Promise { - const isWIP = isUncommitted(change.revision.sha); + const isWIP = isUncommitted(change.revision.to); const [branchNamesResult, diffResult, firstShaResult, remoteResult, userResult] = await Promise.allSettled([ isWIP ? this.container.git.getBranch(change.repository.uri).then(b => (b != null ? [b.name] : undefined)) - : this.container.git.getCommitBranches(change.repository.uri, change.revision.sha), + : this.container.git + .getCommitBranches(change.repository.uri, change.revision.to) + .then(branches => + branches.length + ? branches + : this.container.git.getCommitBranches(change.repository.uri, change.revision.from), + ), change.contents == null - ? this.container.git.getDiff( - change.repository.path, - isWIP ? change.revision.sha : change.revision.baseSha, - isWIP ? change.revision.baseSha : change.revision.sha, - ) + ? this.container.git.getDiff(change.repository.path, change.revision.to, change.revision.from) : undefined, this.container.git.getFirstCommitSha(change.repository.uri), this.container.git.getBestRemoteWithProvider(change.repository.uri), @@ -263,18 +265,15 @@ export class DraftService implements Disposable { const diff = getSettledValue(diffResult); const contents = change.contents ?? diff?.contents; - if (contents == null) throw new Error(`Unable to diff ${change.revision.baseSha} and ${change.revision.sha}`); + if (contents == null) throw new Error(`Unable to diff ${change.revision.from} and ${change.revision.to}`); const user = getSettledValue(userResult); // We need to get the branch name from the baseSha if the change is a stash. - let branchNames = getSettledValue(branchNamesResult); - if (!isWIP && !branchNames?.length) { - branchNames = await this.container.git.getCommitBranches(change.repository.uri, change.revision.baseSha); - } + const branchNames = getSettledValue(branchNamesResult); const branchName = branchNames?.[0] ?? ''; - let baseSha = change.revision.baseSha; + let baseSha = change.revision.from; if (!isSha(baseSha)) { const commit = await this.container.git.getCommit(change.repository.uri, baseSha); if (commit != null) { diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 3da475945fe9e..cc0db2ba048b5 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -2443,7 +2443,7 @@ export class GraphWebviewProvider implements WebviewProvider(Commands.CreateCloudPatch, { - ref1: ref.ref, + to: ref.ref, repoPath: ref.repoPath, }); } diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 9c1856cbff5bc..a0f09b2d84cc6 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -34,6 +34,7 @@ import type { ShowInCommitGraphCommandArgs } from '../graph/protocol'; import type { ApplyPatchParams, Change, + CreateDraft, CreatePatchParams, DidExplainParams, DraftPatchCheckedParams, @@ -67,7 +68,7 @@ import { UpdateCreatePatchRepositoryCheckedStateCommandType, UpdatePreferencesCommandType, } from './protocol'; -import type { CreateDraft, PatchDetailsWebviewShowingArgs } from './registration'; +import type { PatchDetailsWebviewShowingArgs } from './registration'; import type { RepositoryChangeset } from './repositoryChangeset'; import { RepositoryRefChangeset, RepositoryWipChangeset } from './repositoryChangeset'; @@ -289,7 +290,7 @@ export class PatchDetailsWebviewProvider new RepositoryWipChangeset( this.container, repo, - { baseSha: 'HEAD', sha: uncommitted }, + { to: uncommitted, from: 'HEAD' }, this.onRepositoryWipChanged.bind(this), false, true, @@ -427,7 +428,7 @@ export class PatchDetailsWebviewProvider let { revision, repository } = repoChangeset; if (change.type === 'wip' && change.checked === 'staged') { - revision = { ...revision, sha: uncommittedStaged }; + revision = { ...revision, to: uncommittedStaged }; } createChanges.push({ @@ -676,10 +677,7 @@ export class PatchDetailsWebviewProvider new RepositoryWipChangeset( this.container, r, - { - baseSha: 'HEAD', - sha: uncommitted, - }, + { to: uncommitted, from: 'HEAD' }, this.onRepositoryWipChanged.bind(this), true, true, // TODO revisit @@ -934,17 +932,19 @@ export class PatchDetailsWebviewProvider if (change == null) return [undefined]; if (change.type === 'revision') { - const commit = await this.container.git.getCommit(file.repoPath, change.revision.sha ?? uncommitted); + const commit = await this.container.git.getCommit(file.repoPath, change.revision.to ?? uncommitted); if ( - change.revision.sha === change.revision.baseSha || - change.revision.sha === change.revision.baseSha.substring(0, change.revision.baseSha.length - 1) + change.revision.to === change.revision.from || + (change.revision.from.length === change.revision.to.length + 1 && + change.revision.from.endsWith('^') && + change.revision.from.startsWith(change.revision.to)) ) { return [commit]; } return [commit, change.revision]; } else if (change.type === 'wip') { - return [await this.container.git.getCommit(file.repoPath, change.revision.sha ?? uncommitted)]; + return [await this.container.git.getCommit(file.repoPath, change.revision.to ?? uncommitted)]; } return [undefined]; @@ -1010,7 +1010,7 @@ export class PatchDetailsWebviewProvider void openChanges( file, revision != null - ? { repoPath: commit.repoPath, ref1: revision.sha ?? uncommitted, ref2: revision.baseSha } + ? { repoPath: commit.repoPath, rhs: revision.to ?? uncommitted, lhs: revision.from } : commit, { preserveFocus: true, @@ -1028,15 +1028,11 @@ export class PatchDetailsWebviewProvider const [commit, file, revision] = result; - void openChangesWithWorking( - file, - revision != null ? { repoPath: commit.repoPath, ref: revision.baseSha } : commit, - { - preserveFocus: true, - preview: true, - ...params.showOptions, - lhsTitle: this.mode === 'view' ? `${basename(file.path)} (Patch)` : undefined, - }, - ); + void openChangesWithWorking(file, revision != null ? { repoPath: commit.repoPath, ref: revision.to } : commit, { + preserveFocus: true, + preview: true, + ...params.showOptions, + lhsTitle: this.mode === 'view' ? `${basename(file.path)} (Patch)` : undefined, + }); } } diff --git a/src/plus/webviews/patchDetails/protocol.ts b/src/plus/webviews/patchDetails/protocol.ts index ffc43d46fadaa..8af139561e8ee 100644 --- a/src/plus/webviews/patchDetails/protocol.ts +++ b/src/plus/webviews/patchDetails/protocol.ts @@ -3,7 +3,8 @@ import type { Config } from '../../../config'; import type { WebviewIds, WebviewViewIds } from '../../../constants'; import type { GitFileChangeShape } from '../../../git/models/file'; import type { PatchRevisionRange } from '../../../git/models/patch'; -import type { DraftPatch, DraftPatchFileChange } from '../../../gk/models/drafts'; +import type { Repository } from '../../../git/models/repository'; +import type { Draft, DraftPatch, DraftPatchFileChange, LocalDraft } from '../../../gk/models/drafts'; import type { GkRepositoryId } from '../../../gk/models/repositoryIdentities'; import type { DateTimeFormat } from '../../../system/date'; import type { Serialized } from '../../../system/serialize'; @@ -19,6 +20,23 @@ export type PatchDetails = Serialized< } >; +interface CreateDraftFromChanges { + title?: string; + description?: string; + changes: Change[]; + repositories?: never; +} + +interface CreateDraftFromRepositories { + title?: string; + description?: string; + changes?: never; + repositories: Repository[] | undefined; +} + +export type CreateDraft = CreateDraftFromChanges | CreateDraftFromRepositories; +export type ViewDraft = LocalDraft | Draft; + interface LocalDraftDetails { draftType: 'local'; diff --git a/src/plus/webviews/patchDetails/registration.ts b/src/plus/webviews/patchDetails/registration.ts index a7c0397b89f6a..9e5d466ce7c11 100644 --- a/src/plus/webviews/patchDetails/registration.ts +++ b/src/plus/webviews/patchDetails/registration.ts @@ -1,30 +1,11 @@ import { ViewColumn } from 'vscode'; import { Commands } from '../../../constants'; -import type { DraftSelectedEvent } from '../../../eventBus'; -import type { Repository } from '../../../git/models/repository'; import { executeCommand } from '../../../system/command'; import { configuration } from '../../../system/configuration'; import { setContext } from '../../../system/context'; import type { Serialized } from '../../../system/serialize'; import type { WebviewPanelShowCommandArgs, WebviewsController } from '../../../webviews/webviewsController'; -import type { Change, State } from './protocol'; - -interface CreateDraftFromChanges { - title?: string; - description?: string; - changes: Change[]; - repositories?: never; -} - -interface CreateDraftFromRepositories { - title?: string; - description?: string; - changes?: never; - repositories: Repository[] | undefined; -} - -export type CreateDraft = CreateDraftFromChanges | CreateDraftFromRepositories; -export type ViewDraft = DraftSelectedEvent['data']['draft']; +import type { CreateDraft, State, ViewDraft } from './protocol'; export type ShowCreateDraft = { mode: 'create'; diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts index 5cd3818827372..2eaaa9a5f926e 100644 --- a/src/views/viewCommands.ts +++ b/src/views/viewCommands.ts @@ -1067,8 +1067,8 @@ export class ViewCommands { diff, { repoPath: node.repoPath, - ref1: node.ref1, - ref2: node.ref2, + lhs: node.ref1, + rhs: node.ref2, }, options, ); diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index b46de1b7ee2c3..69d31ea602fc3 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -504,10 +504,7 @@ export class CommitDetailsWebviewProvider uri: e.changes.repository.uri, }, files: e.changes.files, - revision: { - baseSha: 'HEAD', - sha: uncommitted, - }, + revision: { to: uncommitted, from: 'HEAD' }, checked: e.checked, }; From 74c6db49426d8fa9c11837213e4333c68b44ec49 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 00:47:03 -0500 Subject: [PATCH 0210/1012] Removes dead code --- src/commands/patches.ts | 85 ---------------------- src/plus/webviews/patchDetails/protocol.ts | 56 -------------- 2 files changed, 141 deletions(-) diff --git a/src/commands/patches.ts b/src/commands/patches.ts index e34cddbd24690..bf0fe73028515 100644 --- a/src/commands/patches.ts +++ b/src/commands/patches.ts @@ -118,92 +118,7 @@ export class CreateCloudPatchCommand extends Command { return showPatchesView({ mode: 'create', create: { repositories: [repo] } }); } return showPatchesView({ mode: 'create', create: create }); - - // let changes: Change[] | undefined; - // if (args?.repoPath != null) { - // const repo = this.container.git.getRepository(args.repoPath); - // if (repo == null) return; - - // const diff = await this.container.git.getDiff(repo.uri, args.ref1 ?? 'HEAD', args.ref2); - // if (diff == null) return; - - // const result = await this.container.git.getDiffFiles(args.repoPath, diff.contents); - // if (result?.files == null) return; - - // const branch = await repo.getBranch(); - - // changes = [ - // { - // type: 'commit', - // repository: { - // name: repo.name, - // path: repo.path, - // uri: repo.uri.toString(true), - // }, - // files: result.files, - // range: { - // baseSha: args.ref2 ?? `${args.ref1 ?? 'HEAD'}^`, - // branchName: branch?.name ?? 'HEAD', - // sha: args.ref1 ?? 'HEAD', - // }, - // }, - // ]; - // } - - // let repo; - // if (args?.repoPath == null) { - // repo = await getRepositoryOrShowPicker('Create Cloud Patch'); - // } else { - // repo = this.container.git.getRepository(args.repoPath); - // } - // if (repo == null) return; - - // const diff = await this.container.git.getDiff(repo.uri, args?.ref1 ?? 'HEAD', args?.ref2); - // if (diff == null) return; - - // const d = await workspace.openTextDocument({ content: diff.contents, language: 'diff' }); - // await window.showTextDocument(d); - - // // ask the user for a title - - // const title = await window.showInputBox({ - // title: 'Create Cloud Patch', - // prompt: 'Enter a title for the patch', - // validateInput: value => (value == null || value.length === 0 ? 'A title is required' : undefined), - // }); - // if (title == null) return; - - // // ask the user for an optional description - // const description = await window.showInputBox({ - // title: 'Create Cloud Patch', - // prompt: 'Enter an optional description for the patch', - // }); - - // const patch = await this.container.drafts.createDraft( - // 'patch', - // title, - // { - // contents: diff.contents, - // baseSha: diff.baseSha, - // repository: repo, - // }, - // { description: description }, - // ); - // void this.showPatchNotification(patch); } - - // private async showPatchNotification(patch: Draft | undefined) { - // if (patch == null) return; - - // await env.clipboard.writeText(patch.deepLinkUrl); - - // const copy = { title: 'Copy Link' }; - // const result = await window.showInformationMessage(`Created cloud patch ${patch.id}`, copy); - - // if (result === copy) { - // await env.clipboard.writeText(patch.deepLinkUrl); - // } - // } } @command() diff --git a/src/plus/webviews/patchDetails/protocol.ts b/src/plus/webviews/patchDetails/protocol.ts index 8af139561e8ee..32aeb7cfbd80a 100644 --- a/src/plus/webviews/patchDetails/protocol.ts +++ b/src/plus/webviews/patchDetails/protocol.ts @@ -49,15 +49,6 @@ interface LocalDraftDetails { description?: string; patches?: PatchDetails[]; - - // files?: GitFileChangeShape[]; - // stats?: GitCommitStats; - - // repoPath?: string; - // repoName?: string; - - // baseRef?: string; - // commit?: string; } interface CloudDraftDetails { @@ -77,33 +68,10 @@ interface CloudDraftDetails { description?: string; patches?: PatchDetails[]; - - // commit?: string; - - // files?: GitFileChangeShape[]; - // stats?: GitCommitStats; - - // repoPath: string; - // repoName?: string; - // baseRef?: string; } export type DraftDetails = LocalDraftDetails | CloudDraftDetails; -// export interface RangeRef { -// baseSha: string; -// sha: string | undefined; -// branchName: string; -// // shortSha: string; -// // summary: string; -// // message: string; -// // author: GitCommitIdentityShape & { avatar: string | undefined }; -// // committer: GitCommitIdentityShape & { avatar: string | undefined }; -// // parents: string[]; -// // repoPath: string; -// // stashNumber?: string; -// } - export interface Preferences { avatars: boolean; dateFormat: DateTimeFormat | string; @@ -139,30 +107,6 @@ export interface RevisionChange { export type Change = WipChange | RevisionChange; -// export interface RepoCommitChange { -// type: 'commit'; - -// repoName: string; -// repoUri: string; -// change: Change; - -// checked: boolean; -// expanded: boolean; -// } - -// export interface RepoWipChange { -// type: 'wip'; - -// repoName: string; -// repoUri: string; -// change: Change | undefined; - -// checked: boolean | 'staged'; -// expanded: boolean; -// } - -// export type RepoChangeSet = RepoCommitChange | RepoWipChange; - export interface State { webviewId: WebviewIds | WebviewViewIds; timestamp: number; From 7efde55afe02e093290f112a15d5c77637e6d6fe Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 13 Nov 2023 11:12:48 -0500 Subject: [PATCH 0211/1012] Fixes menu colors --- .../apps/plus/patchDetails/patchDetails.scss | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.scss b/src/webviews/apps/plus/patchDetails/patchDetails.scss index 27a07ae0bbf2e..c40778544840a 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.scss +++ b/src/webviews/apps/plus/patchDetails/patchDetails.scss @@ -1,5 +1,27 @@ @use '../../shared/styles/details-base'; +body { + --gk-menu-border-color: var(--vscode-menu-border); + --gk-menu-background-color: var(--vscode-menu-background); + --gk-menu-item-background-color-hover: var(--vscode-menu-selectionBackground); + --gk-menu-item-background-color-active: var(--vscode-menu-background); + --gk-focus-border-color: var(--focus-color); + --gk-tooltip-padding: 0.4rem 0.8rem; + --gk-divider-color: var(--color-background--level-05); +} + +gk-menu { + color: var(--vscode-menu-foreground); +} + +gk-menu-item { + color: var(--vscode-menu-foreground); + + &:hover { + color: var(--vscode-menu-selectionForeground); + } +} + .message-block__text strong:not(:only-child) { display: inline-block; margin-bottom: 0.52rem; From e8668ef8679b54d2e2b0e3afe9274afd7ddb80d3 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 11:43:04 -0500 Subject: [PATCH 0212/1012] Adds cloud patches to home & welcome --- src/webviews/apps/home/home.html | 37 +++++++++++----------- src/webviews/apps/home/home.scss | 25 +++++++++++++++ src/webviews/apps/welcome/welcome.html | 44 ++++++++++++-------------- 3 files changed, 65 insertions(+), 41 deletions(-) diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index 68e9d32eb14a3..90d40f25dff92 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -169,7 +169,7 @@ class="nav-list__access" title="Requires a trial or paid plan to use this on privately hosted repos" aria-label="Requires a trial or paid plan to use this on privately hosted repos" - >✨PreviewPopular views >✨ + Cloud PatchesNew!Preview ☁️ Popular views >Search & Compare - Popular views class="nav-list__access" title="Requires a GitKraken account and access is based on your plan, e.g. Free, Pro, etc" aria-label="Requires a GitKraken account and access is based on your plan, e.g. Free, Pro, etc" - >☁️Preview ☁️ Side Bar Views aria-label="Show Branches view" >Branches + Cloud Patches ☁️ Side Bar Views aria-label="Show Search & Compare view" >Search & Compare - Popular views aria-label="Show Visual File History view" >Visual File History ✨ - Stashes - Search & Compare Popular views aria-label="Show GitKraken Workspaces view" >GitKraken Workspaces ☁️ + Stashes + Search & Compare Date: Mon, 13 Nov 2023 12:17:10 -0500 Subject: [PATCH 0213/1012] Adds file icon to files in patches file list --- src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts b/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts index 92b14c52da9af..9882692b16912 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-tree-base.ts @@ -203,7 +203,7 @@ export class GlTreeBase extends GlElement Date: Mon, 13 Nov 2023 13:12:37 -0500 Subject: [PATCH 0214/1012] Hides patch actions for now --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ae6f34e7f2eec..9f208a435fd18 100644 --- a/package.json +++ b/package.json @@ -2707,7 +2707,7 @@ "Prefer showing Cloud Patches in the editor area", "Prefer showing Cloud Patches in a view" ], - "markdownDescription": "Specifies the preferred layout of for _Cloud Patches_", + "markdownDescription": "Specifies the preferred layout of for _Cloud Patches_ (experimental)", "scope": "window", "order": 11 } @@ -8623,7 +8623,7 @@ }, { "command": "gitlens.openPatch", - "when": "gitlens:enabled" + "when": "false && gitlens:enabled" }, { "command": "gitlens.timeline.refresh", @@ -10881,7 +10881,7 @@ "editor/title": [ { "command": "gitlens.openPatch", - "when": "editorLangId == diff" + "when": "false && editorLangId == diff" }, { "command": "gitlens.diffWithWorking", From 334865b3f14c3f474232285f8df36fde9469336e Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 14:05:45 -0500 Subject: [PATCH 0215/1012] Adds vscode style border radius on input --- src/webviews/apps/shared/styles/details-base.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webviews/apps/shared/styles/details-base.scss b/src/webviews/apps/shared/styles/details-base.scss index f3afb8b7a1631..ea6cde7b28584 100644 --- a/src/webviews/apps/shared/styles/details-base.scss +++ b/src/webviews/apps/shared/styles/details-base.scss @@ -279,6 +279,7 @@ ul { border: 1px solid var(--vscode-input-border); background: var(--vscode-input-background); padding: 0.5rem; + border-radius: 2px; &__text { margin: 0; From 4131f384061936a4e7227f8a2b2677e6f87b742f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 14:07:04 -0500 Subject: [PATCH 0216/1012] Adds feedback to link copying --- .../apps/plus/patchDetails/components/gl-draft-details.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts index 57c88aebb0d35..b54a711861e28 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts @@ -86,6 +86,9 @@ export class GlDraftDetails extends GlTreeBase { @state() validityMessage?: string; + @state() + private _copiedLink: boolean = false; + get canSubmit() { return this.selectedPatches.length > 0; // return this.state.draft?.repoPath != null && this.state.draft?.baseRef != null; @@ -423,7 +426,7 @@ export class GlDraftDetails extends GlTreeBase { this.state?.draft?.draftType === 'cloud', () => html` - + Copy Link `, @@ -625,6 +628,8 @@ export class GlDraftDetails extends GlTreeBase { onCopyCloudLink() { this.fireEvent('gl-patch-details-copy-cloud-link', { draft: this.state.draft! }); + this._copiedLink = true; + setTimeout(() => (this._copiedLink = false), 1000); } onShareLocalPatch() { From 62a21ad0f6432ba02e2748de0ea47acee37ea51b Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 14:21:21 -0500 Subject: [PATCH 0217/1012] Splits title from message --- src/commands/patches.ts | 2 +- .../components/gl-draft-details.ts | 43 ++++--------------- .../apps/plus/patchDetails/patchDetails.scss | 6 +++ 3 files changed, 16 insertions(+), 35 deletions(-) diff --git a/src/commands/patches.ts b/src/commands/patches.ts index bf0fe73028515..a0607d688837f 100644 --- a/src/commands/patches.ts +++ b/src/commands/patches.ts @@ -219,7 +219,7 @@ async function createDraft( create.title = message; } else { create.title = message.substring(0, index); - create.description = message.substring(index + 1); + create.description = message.substring(index + 1).trim(); } if (args.from == null) { diff --git a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts index b54a711861e28..c8a8c5101c7f9 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts @@ -144,26 +144,18 @@ export class GlDraftDetails extends GlTreeBase { } private renderPatchMessage() { - if (this.state?.draft?.title == null) { - return undefined; - } + if (this.state?.draft?.title == null) return undefined; + let description = this.state.draft.draftType === 'cloud' ? this.state.draft.description : undefined; + if (description == null) return undefined; + + description = description.trim(); - const title = this.state.draft.title; - const description = this.state.draft.draftType === 'cloud' ? this.state.draft.description : undefined; return html`
- ${when( - description == null, - () => - html`

- ${unsafeHTML(title)} -

`, - () => - html`

- ${unsafeHTML(title)}
${unsafeHTML(description)} -

`, - )} +

+ ${unsafeHTML(description)} +

`; @@ -443,24 +435,7 @@ export class GlDraftDetails extends GlTreeBase { )}
- ${when( - this.state.draft?.draftType === 'cloud' && this.state.draft?.author.name != null, - () => html` -
    -
  • - -
  • -
- `, - )} +

${this.state.draft?.title}

${this.renderPatchMessage()} diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.scss b/src/webviews/apps/plus/patchDetails/patchDetails.scss index c40778544840a..2ec33c4f6fbbd 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.scss +++ b/src/webviews/apps/plus/patchDetails/patchDetails.scss @@ -22,6 +22,12 @@ gk-menu-item { } } +.title { + font-size: 1.8rem; + font-weight: 600; + margin: 0; +} + .message-block__text strong:not(:only-child) { display: inline-block; margin-bottom: 0.52rem; From 0f6ebcef97fce4d6b25277fb50927971306c5059 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 14:25:41 -0500 Subject: [PATCH 0218/1012] Enables cloud patches by default --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9f208a435fd18..b4c8372f26336 100644 --- a/package.json +++ b/package.json @@ -2691,7 +2691,7 @@ "properties": { "gitlens.cloudPatches.enabled": { "type": "boolean", - "default": false, + "default": true, "markdownDescription": "Specifies whether to enable the preview of _Cloud Patches_, which allow you to easily and securely share code with your teammates or other developers", "scope": "window", "order": 10 From 9e4dbb3f67db7e38aa858d36a284314767773346 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 13 Nov 2023 15:28:54 -0500 Subject: [PATCH 0219/1012] Fixes patches panes --- .../components/gl-draft-details.ts | 110 +++++++++--------- .../components/gl-patch-create.ts | 11 +- .../apps/plus/patchDetails/patchDetails.scss | 27 ++++- 3 files changed, 78 insertions(+), 70 deletions(-) diff --git a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts index c8a8c5101c7f9..dbb9d0748e5d2 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-draft-details.ts @@ -151,12 +151,10 @@ export class GlDraftDetails extends GlTreeBase { description = description.trim(); return html` -
-
-

- ${unsafeHTML(description)} -

-
+
+

+ ${unsafeHTML(description)} +

`; } @@ -335,29 +333,26 @@ export class GlDraftDetails extends GlTreeBase { //
${getActions()}
//
return html` - - Apply -
-

- - Apply Patch - - - - Apply to a Branch - - - - -

-
-
+
+

+ + Apply Patch + + + + Apply to a Branch + + + + +

+
`; } @@ -409,36 +404,39 @@ export class GlDraftDetails extends GlTreeBase { return html`
-
-
-
-
-
- ${when( - this.state?.draft?.draftType === 'cloud', - () => html` - - - Copy Link - `, - () => html` - Share - `, - )} -
+
+
+
+
+ ${when( + this.state?.draft?.draftType === 'cloud', + () => html` + + + Copy Link + `, + () => html` + Share + `, + )}
-

${this.state.draft?.title}

+ ${when( + this.state.draft?.title != null, + () => html` +

${this.state.draft?.title}

+ ${this.renderPatchMessage()} + `, + )}
- ${this.renderPatchMessage()}
${this.renderChangedFiles()}
diff --git a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts index 470c7b432dcb0..f094cb1fc2c6e 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts @@ -108,7 +108,7 @@ export class GlPatchCreate extends GlTreeBase { renderForm() { return html` -
+
${when( this.state?.create?.creationError != null, () => @@ -150,19 +150,14 @@ export class GlPatchCreate extends GlTreeBase { return html`
${this.renderChangedFiles()}
-
- Create PatchPREVIEW ☁️${this.renderForm()} -
+
${this.renderForm()}
`; } private renderChangedFiles() { return html` - + Changes to Include ${this.renderLayoutAction(this.fileLayout)} diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.scss b/src/webviews/apps/plus/patchDetails/patchDetails.scss index 2ec33c4f6fbbd..625bcc1512733 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.scss +++ b/src/webviews/apps/plus/patchDetails/patchDetails.scss @@ -23,9 +23,9 @@ gk-menu-item { } .title { - font-size: 1.8rem; + font-size: 1.6rem; font-weight: 600; - margin: 0; + margin: 0.2rem 0 0.8rem; } .message-block__text strong:not(:only-child) { @@ -76,10 +76,16 @@ gk-menu-item { } } -textarea.message-input__control { - resize: vertical; - min-height: 4rem; - max-height: 40rem; +.section--action { + border-top: 1px solid var(--vscode-sideBarSectionHeader-border); + padding: { + top: 1.5rem; + bottom: 1.5rem; + } + + > :first-child { + padding-top: 0; + } } .message-input { @@ -112,6 +118,12 @@ textarea.message-input__control { } } +textarea.message-input__control { + resize: vertical; + min-height: 4rem; + max-height: 40rem; +} + .h { &-spacing { margin-bottom: 1.5rem; @@ -120,6 +132,9 @@ textarea.message-input__control { margin: 0.8rem 0 0.4rem; opacity: 0.8; } + &-no-border { + --vscode-sideBarSectionHeader-border: transparent; + } } .alert { From 5ca04749b294855763eef7acc1244ec631619209 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 16:37:13 -0500 Subject: [PATCH 0220/1012] Moves patch view into its own sidebar --- package.json | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index b4c8372f26336..fda78d8225baa 100644 --- a/package.json +++ b/package.json @@ -6824,7 +6824,7 @@ }, { "command": "gitlens.views.patchDetails.close", - "title": "Close Patch View", + "title": "Close Patch", "category": "GitLens", "icon": "$(close)" }, @@ -15319,7 +15319,7 @@ }, { "id": "gitlensPatch", - "title": "Patch", + "title": "GitLens Patch", "icon": "$(gitlens-cloud-patch)" } ], @@ -15411,22 +15411,12 @@ { "type": "webview", "id": "gitlens.views.home", - "-when": "!gitlens:views:patchDetails:mode || !config.gitlens.cloudPatches.enabled", "name": "Home", "contextualTitle": "GL", "icon": "$(gitlens-gitlens)", "initialSize": 6, "visibility": "visible" }, - { - "type": "webview", - "id": "gitlens.views.patchDetails", - "name": "Patch", - "when": "!gitlens:untrusted && config.gitlens.cloudPatches.enabled && gitlens:views:patchDetails:mode", - "contextualTitle": "GL", - "icon": "$(gitlens-cloud-patch)", - "initialSize": 24 - }, { "id": "gitlens.views.drafts", "name": "Cloud Patches", @@ -15526,6 +15516,17 @@ "visibility": "visible" } ], + "gitlensPatch": [ + { + "type": "webview", + "id": "gitlens.views.patchDetails", + "name": "Patch", + "when": "!gitlens:untrusted && config.gitlens.cloudPatches.enabled && gitlens:views:patchDetails:mode", + "contextualTitle": "GitLens", + "icon": "$(gitlens-cloud-patch)", + "initialSize": 24 + } + ], "scm": [ { "id": "gitlens.views.repositories", From 422bafda355fa17fe3f3820827ab4abdaaa29eaf Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 16:38:21 -0500 Subject: [PATCH 0221/1012] Updates messaging for Cloud patches security --- src/plus/utils.ts | 48 +++++++++++-------- .../patchDetails/patchDetailsWebview.ts | 14 +++--- .../components/gl-patch-create.ts | 8 +++- .../apps/plus/patchDetails/patchDetails.scss | 2 +- 4 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/plus/utils.ts b/src/plus/utils.ts index c1e1aa14316af..97fc09f9d815a 100644 --- a/src/plus/utils.ts +++ b/src/plus/utils.ts @@ -112,25 +112,35 @@ export async function ensureAccount(title: string, container: Container): Promis export async function confirmDraftStorage(container: Container): Promise { if (container.storage.get('confirm:draft:storage', false)) return true; - const accept: MessageItem = { title: 'Yes' }; - const decline: MessageItem = { title: 'No', isCloseAffordance: true }; - const moreInfo: MessageItem = { title: 'More Info' }; - const result = await window.showInformationMessage( - `Cloud Patches are securely stored by GitKraken.\n\nDo you want to continue?`, - { modal: true }, - accept, - decline, - moreInfo, - ); - - if (result === accept) { - void container.storage.store('confirm:draft:storage', true); - return true; - } + while (true) { + const accept: MessageItem = { title: 'Continue' }; + const decline: MessageItem = { title: 'Cancel', isCloseAffordance: true }; + const moreInfo: MessageItem = { title: 'Learn More' }; + const security: MessageItem = { title: 'Security' }; + const result = await window.showInformationMessage( + `Cloud Patches are securely stored by GitKraken and can be accessed by anyone with the link and a GitKraken account.`, + { modal: true }, + accept, + moreInfo, + security, + decline, + ); - if (result === moreInfo) { - void env.openExternal(Uri.parse('https://help.gitkraken.com/gitlens/security')); - } + if (result === accept) { + void container.storage.store('confirm:draft:storage', true); + return true; + } - return false; + if (result === security) { + void env.openExternal(Uri.parse('https://help.gitkraken.com/gitlens/security')); + continue; + } + + if (result === moreInfo) { + void env.openExternal(Uri.parse('https://www.gitkraken.com/solutions/cloud-patches')); + continue; + } + + return false; + } } diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index a0f09b2d84cc6..970fb8008def1 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -339,13 +339,6 @@ export class PatchDetailsWebviewProvider return; } - if ( - !(await ensureAccount('Cloud Patches require a GitKraken account.', this.container)) || - !(await confirmDraftStorage(this.container)) - ) { - return; - } - const changeset = this._context.draft.changesets?.[0]; if (changeset == null) return; @@ -413,7 +406,12 @@ export class PatchDetailsWebviewProvider } private async createDraft({ title, changesets, description }: CreatePatchParams): Promise { - if (!(await ensureAccount('Cloud patches require a GitKraken account.', this.container))) return; + if ( + !(await ensureAccount('Cloud Patches require a GitKraken account.', this.container)) || + !(await confirmDraftStorage(this.container)) + ) { + return; + } const createChanges: CreateDraftChange[] = []; diff --git a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts index f094cb1fc2c6e..65c7a52087fe1 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts @@ -132,8 +132,12 @@ export class GlPatchCreate extends GlTreeBase { Create Cloud Patch

- + +

Cloud Patches are securely stored by GitKraken. +

`; } diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.scss b/src/webviews/apps/plus/patchDetails/patchDetails.scss index 625bcc1512733..f1f30c1d99cde 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.scss +++ b/src/webviews/apps/plus/patchDetails/patchDetails.scss @@ -130,7 +130,7 @@ textarea.message-input__control { } &-deemphasize { margin: 0.8rem 0 0.4rem; - opacity: 0.8; + opacity: 0.7; } &-no-border { --vscode-sideBarSectionHeader-border: transparent; From 50a31faa052d86f132305c8fd893a48c8c787b1d Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 16:38:40 -0500 Subject: [PATCH 0222/1012] Adds/handles title limit on cloud patches --- src/plus/drafts/draftsService.ts | 5 +++++ .../apps/plus/patchDetails/components/gl-patch-create.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index 87fc9b81fc15a..c7d52de5c7db3 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -82,6 +82,11 @@ export class DraftService implements Disposable { } satisfies CreateDraftRequest), }); + if (!createDraftRsp.ok) { + const json = (await createDraftRsp.json()) as { error?: { message?: string } } | undefined; + throw new Error(json?.error?.message ?? createDraftRsp.statusText); + } + const createDraft = ((await createDraftRsp.json()) as DraftResult).data; const draftId = createDraft.id; diff --git a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts index 65c7a52087fe1..fac85180d82a3 100644 --- a/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts +++ b/src/webviews/apps/plus/patchDetails/components/gl-patch-create.ts @@ -118,12 +118,12 @@ export class GlPatchCreate extends GlTreeBase {
`, )}
-
-
From c283474a5f8e188d54ab0f6b856f886dc73439e0 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 13 Nov 2023 16:38:56 -0500 Subject: [PATCH 0223/1012] Updates welcome messaging for cloud patches --- src/webviews/apps/welcome/welcome.html | 89 +++++++++++++------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html index f61daf9140e4b..dbbaeda7a38a1 100644 --- a/src/webviews/apps/welcome/welcome.html +++ b/src/webviews/apps/welcome/welcome.html @@ -249,6 +249,51 @@

Side Bar Views

Features which need a repository are currently unavailable

+

+ Cloud Patches + ☁️ + Preview +

+

+ The + Cloud Patches + preview allows you to easily share changes with other developers by creating a Cloud Patch from your + WIP, commit or stash and sharing the generated link with your teammates. +

+ +

+ Cloud Patches are + securely stored + by GitKraken, and anyone with access to the link and a GitKraken account can view the code for now. + More permissions and controls are coming soon. +

+ +

+ For additional information about Cloud Patches, visit our + help center. +

+

-

- Cloud Patches - ☁️ - Preview -

-

- The - Cloud Patches preview feature - allows you to easily share changes with other developers by creating a Cloud Patch from your WIP, - commit or stash and sharing the generated link with your teammates. -

- -

- Cloud Patches are - securely stored by GitKraken, and anyone with access to the link and a GitKraken account can view the code for now. More - permissions and controls are coming soon. -

- -

- For additional information about Cloud Patches, visit our - help center. -

-

Date: Mon, 13 Nov 2023 16:41:46 -0500 Subject: [PATCH 0224/1012] Updates changelog --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e72b56ccc2ba8..4617c498e9c87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added -- Adds a preview of [Cloud Patches](https://www.gitkraken.com/solutions/cloud-patches), an all-new ☁️ feature — engage in early collaboration long before the pull request: - +- Adds a preview of [Cloud Patches](https://www.gitkraken.com/solutions/cloud-patches), an all-new ☁️ feature — engage in early collaboration before the pull request: - Share your work with others by creating a Cloud Patch from Working Changes, Commits, Stashes or Comparisons - View Cloud Patches from URLs shared to you and apply them to your working tree or to a new or existing branch - Manage your Cloud Patches from the new _Cloud Patches_ view in the GitLens side bar - - Adds support to open multiple instances of the _Commit Graph_, _Focus_, and _Visual File History_ in the editor area - Adds a _Split Commit Graph_ command to the _Commit Graph_ tab context menu - Adds a `gitlens.graph.allowMultiple` setting to specify whether to allow opening multiple instances of the _Commit Graph_ in the editor area From 5d54debab99ba963eeec6c559b09e0deea68003d Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Mon, 13 Nov 2023 14:47:53 -0700 Subject: [PATCH 0225/1012] Updates CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4617c498e9c87..b8bffcbc7ac4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Share your work with others by creating a Cloud Patch from Working Changes, Commits, Stashes or Comparisons - View Cloud Patches from URLs shared to you and apply them to your working tree or to a new or existing branch - Manage your Cloud Patches from the new _Cloud Patches_ view in the GitLens side bar + - Adds a _Share as Cloud Patch..._ command to the command palette and to the _Share_ submenu in applicable GitLens views + - Adds a `gitlens.cloudPatches.enabled` setting to specificy whether to enable Cloud Patches (defaults to `true`) - Adds support to open multiple instances of the _Commit Graph_, _Focus_, and _Visual File History_ in the editor area - Adds a _Split Commit Graph_ command to the _Commit Graph_ tab context menu - Adds a `gitlens.graph.allowMultiple` setting to specify whether to allow opening multiple instances of the _Commit Graph_ in the editor area From 90fd1e258d24a784dd23e54a2279d31962fa35c0 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Mon, 13 Nov 2023 16:53:59 -0700 Subject: [PATCH 0226/1012] Updates CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8bffcbc7ac4e..0cda75d39b1b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Adds a stateful authors picker to make it much easier to search for commits by specific authors - Adds a file and folder picker to make it much easier to search for commits containing specific files or in specific folders - Adds ability to sort repositories in the views and quick pick menus — closes [#2836](https://github.com/gitkraken/vscode-gitlens/issues/2836) thanks to [PR #2991](https://github.com/gitkraken/vscode-gitlens/pull/2991) - - Adds a `gitlens.sortRepositoriesBy` setting to specify how repositories are sorted in quick pick menus and viewsby Aidos Kanapyanov ([@aidoskanapyanov](https://github.com/aidoskanapyanov)) + - Adds a `gitlens.sortRepositoriesBy` setting to specify how repositories are sorted in quick pick menus and views by Aidos Kanapyanov ([@aidoskanapyanov](https://github.com/aidoskanapyanov)) - Adds a _[Show|Hide] Merge Commits_ toggle to the Commits\_ view — closes [#1399](https://github.com/gitkraken/vscode-gitlens/issues/1399) thanks to [PR #1540](https://github.com/gitkraken/vscode-gitlens/pull/1540) by Shashank Shastri ([@Shashank-Shastri](https://github.com/Shashank-Shastri)) - Adds a _Filter Commits by Author..._ commands to the _Commits_ view and comparisons context menus to filter commits in the _Commits_ view by specific authors - Adds ability to publish to a remote branch to a specific commit using the _Push to Commit_ command From 5ae55676b8e52de841cfb17b24e7adf3c5d7c7cb Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Mon, 13 Nov 2023 17:22:29 -0700 Subject: [PATCH 0227/1012] Bumps to v14.5.0 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cda75d39b1b0..982aa290b3c16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +## [14.5.0] - 2023-11-13 + ### Added - Adds a preview of [Cloud Patches](https://www.gitkraken.com/solutions/cloud-patches), an all-new ☁️ feature — engage in early collaboration before the pull request: @@ -5030,7 +5032,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Initial release but still heavily a work in progress. -[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v14.4.0...HEAD +[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/v14.5.0...HEAD +[14.5.0]: https://github.com/gitkraken/vscode-gitlens/compare/v14.4.0...gitkraken:v14.5.0 [14.4.0]: https://github.com/gitkraken/vscode-gitlens/compare/v14.3.0...gitkraken:v14.4.0 [14.3.0]: https://github.com/gitkraken/vscode-gitlens/compare/v14.2.1...gitkraken:v14.3.0 [14.2.1]: https://github.com/gitkraken/vscode-gitlens/compare/v14.2.0...gitkraken:v14.2.1 diff --git a/package.json b/package.json index fda78d8225baa..0f3bcb1f22ede 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "gitlens", "displayName": "GitLens — Git supercharged", "description": "Supercharge Git within VS Code — Visualize code authorship at a glance via Git blame annotations and CodeLens, seamlessly navigate and explore Git repositories, gain valuable insights via rich visualizations and powerful comparison commands, and so much more", - "version": "14.4.0", + "version": "14.5.0", "engines": { "vscode": "^1.81.0" }, From 9c04fc12f851a0be699db75ffbdd17a6b49548ea Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 14 Nov 2023 15:10:44 -0500 Subject: [PATCH 0228/1012] Adds open folder to worktree error notification --- src/commands/git/worktree.ts | 29 +++++++++++++++++--------- src/git/actions/repository.ts | 5 ----- src/git/actions/worktree.ts | 5 ----- src/system/utils.ts | 38 +++++++++++++++++++---------------- src/views/viewCommands.ts | 6 +++--- 5 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/commands/git/worktree.ts b/src/commands/git/worktree.ts index 24f8f72963ea0..0777352e18fe0 100644 --- a/src/commands/git/worktree.ts +++ b/src/commands/git/worktree.ts @@ -1,9 +1,9 @@ import type { MessageItem } from 'vscode'; -import { QuickInputButtons, Uri, window, workspace } from 'vscode'; +import { env, QuickInputButtons, Uri, window, workspace } from 'vscode'; import type { Config } from '../../config'; import type { Container } from '../../container'; import { PlusFeatures } from '../../features'; -import { convertOpenFlagsToLocation, reveal, revealInFileExplorer } from '../../git/actions/worktree'; +import { convertOpenFlagsToLocation, reveal } from '../../git/actions/worktree'; import { WorktreeCreateError, WorktreeCreateErrorReason, @@ -23,7 +23,7 @@ import { createFlagsQuickPickItem } from '../../quickpicks/items/flags'; import { configuration } from '../../system/configuration'; import { basename, isDescendant } from '../../system/path'; import { pluralize, truncateLeft } from '../../system/string'; -import { openWorkspace } from '../../system/utils'; +import { openWorkspace, revealInFileExplorer } from '../../system/utils'; import type { ViewsWithRepositoryFolders } from '../../views/viewBase'; import type { AsyncStepResultGenerator, @@ -469,12 +469,21 @@ export class WorktreeGitCommand extends QuickCommand { continue; } } else if (WorktreeCreateError.is(ex, WorktreeCreateErrorReason.AlreadyExists)) { - void window.showErrorMessage( - `Unable to create a new worktree in '${GitWorktree.getFriendlyPath( - uri, - )}' because the folder already exists and is not empty.`, - 'OK', - ); + const confirm: MessageItem = { title: 'OK' }; + const openFolder: MessageItem = { title: 'Open Folder' }; + void window + .showErrorMessage( + `Unable to create a new worktree in '${GitWorktree.getFriendlyPath( + uri, + )}' because the folder already exists and is not empty.`, + confirm, + openFolder, + ) + .then(result => { + if (result === openFolder) { + void env.openExternal(uri); + } + }); } else { void showGenericErrorMessage( `Unable to create a new worktree in '${GitWorktree.getFriendlyPath(uri)}.`, @@ -835,7 +844,7 @@ export class WorktreeGitCommand extends QuickCommand { if (worktree == null) break; if (state.flags.includes('--reveal-explorer')) { - void revealInFileExplorer(worktree); + void revealInFileExplorer(worktree.uri); } else { openWorkspace(worktree.uri, { location: convertOpenFlagsToLocation(state.flags) }); } diff --git a/src/git/actions/repository.ts b/src/git/actions/repository.ts index 3eec04ae16650..680b7cbf6659c 100644 --- a/src/git/actions/repository.ts +++ b/src/git/actions/repository.ts @@ -1,6 +1,5 @@ import type { ResetGitCommandArgs } from '../../commands/git/reset'; import { Container } from '../../container'; -import { executeCoreCommand } from '../../system/command'; import type { ViewsWithRepositoryFolders } from '../../views/viewBase'; import { executeGitCommand } from '../actions'; import type { GitBranchReference, GitReference, GitRevisionReference } from '../models/reference'; @@ -83,7 +82,3 @@ export async function reveal( } return node; } - -export async function revealInFileExplorer(repo: Repository) { - void (await executeCoreCommand('revealFileInOS', repo.uri)); -} diff --git a/src/git/actions/worktree.ts b/src/git/actions/worktree.ts index a30ed3ee0f629..febb6caac80c8 100644 --- a/src/git/actions/worktree.ts +++ b/src/git/actions/worktree.ts @@ -2,7 +2,6 @@ import type { Uri } from 'vscode'; import type { WorktreeGitCommandArgs } from '../../commands/git/worktree'; import { Container } from '../../container'; import { ensure } from '../../system/array'; -import { executeCoreCommand } from '../../system/command'; import type { OpenWorkspaceLocation } from '../../system/utils'; import { executeGitCommand } from '../actions'; import type { GitReference } from '../models/reference'; @@ -65,10 +64,6 @@ export async function reveal( return node; } -export async function revealInFileExplorer(worktree: GitWorktree) { - void (await executeCoreCommand('revealFileInOS', worktree.uri)); -} - type OpenFlagsArray = Extract>, { subcommand: 'open' }>['flags']; export function convertLocationToOpenFlags(location: OpenWorkspaceLocation | undefined): OpenFlagsArray | undefined { diff --git a/src/system/utils.ts b/src/system/utils.ts index b24069e286ab3..19ec57a1a2ba3 100644 --- a/src/system/utils.ts +++ b/src/system/utils.ts @@ -58,6 +58,25 @@ export function findOrOpenEditors(uris: Uri[]): void { } } +export function getEditorCommand() { + let editor; + switch (env.appName) { + case 'Visual Studio Code - Insiders': + editor = 'code-insiders --wait --reuse-window'; + break; + case 'Visual Studio Code - Exploration': + editor = 'code-exploration --wait --reuse-window'; + break; + case 'VSCodium': + editor = 'codium --wait --reuse-window'; + break; + default: + editor = 'code --wait --reuse-window'; + break; + } + return editor; +} + export function getEditorIfActive(document: TextDocument): TextEditor | undefined { const editor = window.activeTextEditor; return editor != null && editor.document === document ? editor : undefined; @@ -180,23 +199,8 @@ export function openWorkspace( }); } -export function getEditorCommand() { - let editor; - switch (env.appName) { - case 'Visual Studio Code - Insiders': - editor = 'code-insiders --wait --reuse-window'; - break; - case 'Visual Studio Code - Exploration': - editor = 'code-exploration --wait --reuse-window'; - break; - case 'VSCodium': - editor = 'codium --wait --reuse-window'; - break; - default: - editor = 'code --wait --reuse-window'; - break; - } - return editor; +export async function revealInFileExplorer(uri: Uri) { + void (await executeCoreCommand('revealFileInOS', uri)); } export function supportedInVSCodeVersion(feature: 'input-prompt-links') { diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts index 2eaaa9a5f926e..962c5132c5067 100644 --- a/src/views/viewCommands.ts +++ b/src/views/viewCommands.ts @@ -36,7 +36,7 @@ import { setContext } from '../system/context'; import { log } from '../system/decorators/log'; import { sequentialize } from '../system/function'; import type { OpenWorkspaceLocation } from '../system/utils'; -import { openWorkspace } from '../system/utils'; +import { openWorkspace, revealInFileExplorer } from '../system/utils'; import { RepositoryFolderNode } from './nodes/abstract/repositoryFolderNode'; import { canEditNode, @@ -781,14 +781,14 @@ export class ViewCommands { private revealRepositoryInExplorer(node: RepositoryNode) { if (!(node instanceof RepositoryNode)) return undefined; - return RepoActions.revealInFileExplorer(node.repo); + return revealInFileExplorer(node.repo.uri); } @log() private revealWorktreeInExplorer(node: WorktreeNode) { if (!(node instanceof WorktreeNode)) return undefined; - return WorktreeActions.revealInFileExplorer(node.worktree); + return revealInFileExplorer(node.worktree.uri); } @log() From b58d654f89c1f2c409b316937c260bc54c73a577 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 10:11:44 -0500 Subject: [PATCH 0229/1012] Updates dependencies --- package.json | 8 +-- yarn.lock | 200 +++++++++++++++++++++++---------------------------- 2 files changed, 92 insertions(+), 116 deletions(-) diff --git a/package.json b/package.json index 0f3bcb1f22ede..d54b1036b7dd0 100644 --- a/package.json +++ b/package.json @@ -15790,8 +15790,8 @@ "@types/react-dom": "17.0.21", "@types/sortablejs": "1.15.5", "@types/vscode": "1.81.0", - "@typescript-eslint/eslint-plugin": "6.10.0", - "@typescript-eslint/parser": "6.10.0", + "@typescript-eslint/eslint-plugin": "6.11.0", + "@typescript-eslint/parser": "6.11.0", "@vscode/test-electron": "2.3.6", "@vscode/test-web": "0.0.48", "@vscode/vsce": "2.22.0", @@ -15823,7 +15823,7 @@ "lz-string": "1.5.0", "mini-css-extract-plugin": "2.7.6", "mocha": "10.2.0", - "prettier": "3.0.3", + "prettier": "3.1.0", "sass": "1.69.5", "sass-loader": "13.3.2", "schema-utils": "4.2.0", @@ -15834,7 +15834,7 @@ "tsc-alias": "1.8.8", "typescript": "5.3.1-rc", "webpack": "5.89.0", - "webpack-bundle-analyzer": "4.9.1", + "webpack-bundle-analyzer": "4.10.0", "webpack-cli": "5.1.4", "webpack-node-externals": "3.0.0", "webpack-require-from": "1.8.6" diff --git a/yarn.lock b/yarn.lock index 7d5abad2a59d1..a9deb5cfa7fde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -493,9 +493,9 @@ universal-user-agent "^6.0.0" "@octokit/types@^12.0.0": - version "12.2.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.2.0.tgz#c21044ec70c5e2222043bcbe7fe2c3448a13df31" - integrity sha512-ZkdHqHJdifVndN7Pha10+qrgAjy3AcG//Vmjr/o5UFuTiYCcMhqDj39Yr9VM9zJ/42KO2xAYhV7cvLnLI9Kvwg== + version "12.3.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.3.0.tgz#e3f8bc53f65ef551e19cc1a0fea15adadec17d2d" + integrity sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ== dependencies: "@octokit/openapi-types" "^19.0.2" @@ -812,16 +812,16 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz#cfe2bd34e26d2289212946b96ab19dcad64b661a" - integrity sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg== +"@typescript-eslint/eslint-plugin@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz#52aae65174ff526576351f9ccd41cea01001463f" + integrity sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.10.0" - "@typescript-eslint/type-utils" "6.10.0" - "@typescript-eslint/utils" "6.10.0" - "@typescript-eslint/visitor-keys" "6.10.0" + "@typescript-eslint/scope-manager" "6.11.0" + "@typescript-eslint/type-utils" "6.11.0" + "@typescript-eslint/utils" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -829,72 +829,72 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.10.0.tgz#578af79ae7273193b0b6b61a742a2bc8e02f875a" - integrity sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog== +"@typescript-eslint/parser@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.11.0.tgz#9640d9595d905f3be4f278bf515130e6129b202e" + integrity sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ== dependencies: - "@typescript-eslint/scope-manager" "6.10.0" - "@typescript-eslint/types" "6.10.0" - "@typescript-eslint/typescript-estree" "6.10.0" - "@typescript-eslint/visitor-keys" "6.10.0" + "@typescript-eslint/scope-manager" "6.11.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/typescript-estree" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz#b0276118b13d16f72809e3cecc86a72c93708540" - integrity sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg== +"@typescript-eslint/scope-manager@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz#621f603537c89f4d105733d949aa4d55eee5cea8" + integrity sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A== dependencies: - "@typescript-eslint/types" "6.10.0" - "@typescript-eslint/visitor-keys" "6.10.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" -"@typescript-eslint/type-utils@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz#1007faede067c78bdbcef2e8abb31437e163e2e1" - integrity sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg== +"@typescript-eslint/type-utils@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz#d0b8b1ab6c26b974dbf91de1ebc5b11fea24e0d1" + integrity sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA== dependencies: - "@typescript-eslint/typescript-estree" "6.10.0" - "@typescript-eslint/utils" "6.10.0" + "@typescript-eslint/typescript-estree" "6.11.0" + "@typescript-eslint/utils" "6.11.0" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367" - integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg== +"@typescript-eslint/types@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.11.0.tgz#8ad3aa000cbf4bdc4dcceed96e9b577f15e0bf53" + integrity sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA== -"@typescript-eslint/typescript-estree@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz#667381eed6f723a1a8ad7590a31f312e31e07697" - integrity sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg== +"@typescript-eslint/typescript-estree@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz#7b52c12a623bf7f8ec7f8a79901b9f98eb5c7990" + integrity sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ== dependencies: - "@typescript-eslint/types" "6.10.0" - "@typescript-eslint/visitor-keys" "6.10.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.10.0.tgz#4d76062d94413c30e402c9b0df8c14aef8d77336" - integrity sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg== +"@typescript-eslint/utils@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.11.0.tgz#11374f59ef4cea50857b1303477c08aafa2ca604" + integrity sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.10.0" - "@typescript-eslint/types" "6.10.0" - "@typescript-eslint/typescript-estree" "6.10.0" + "@typescript-eslint/scope-manager" "6.11.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/typescript-estree" "6.11.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz#b9eaf855a1ac7e95633ae1073af43d451e8f84e3" - integrity sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg== +"@typescript-eslint/visitor-keys@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz#d991538788923f92ec40d44389e7075b359f3458" + integrity sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ== dependencies: - "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/types" "6.11.0" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -1652,9 +1652,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001561" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" - integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== + version "1.0.30001562" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001562.tgz#9d16c5fd7e9c592c4cd5e304bc0f75b0008b2759" + integrity sha512-kfte3Hym//51EdX4239i+Rmp20EsLIYGdPkERegTgU19hQWCRhsRFGKHTliUlsry53tv17K7n077Kqa0WJU4ng== capital-case@^1.0.4: version "1.0.4" @@ -2339,6 +2339,11 @@ date-fns@^2.30.0: dependencies: "@babel/runtime" "^7.21.0" +debounce@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + debug@2.6.9, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -2616,9 +2621,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.535: - version "1.4.581" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz#23b684c67bf56d4284e95598c05a5d266653b6d8" - integrity sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw== + version "1.4.583" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.583.tgz#7b0ac4f36388da4b5485788adb92cd7dd0abffc4" + integrity sha512-93y1gcONABZ7uqYe/JWDVQP/Pj/sQSunF0HVAPdlg/pfBnOyBMLlQUxWvkqcljJg1+W6cjvPuYD+r1Th9Tn8mA== emoji-regex@^8.0.0: version "8.0.0" @@ -2745,9 +2750,9 @@ es-abstract@^1.22.1: which-typed-array "^1.1.13" es-module-lexer@^1.2.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.0.tgz#285182e7f8f536ff5f4c57f2309836ef851474d8" - integrity sha512-lcCr3v3OLezdfFyx9r5NRYHOUTQNnFEQ9E87Mx8Kc+iqyJNkO7MJoB4GQRTlIMw9kLLTwGw0OAkm4BQQud/d9g== + version "1.4.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5" + integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w== es-set-tostringtag@^2.0.1: version "2.0.2" @@ -3151,9 +3156,9 @@ find-up@^4.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.1.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" - integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" keyv "^4.5.3" @@ -3580,6 +3585,11 @@ hosted-git-info@^6.0.0: dependencies: lru-cache "^7.5.1" +html-escaper@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + html-loader@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-4.2.0.tgz#20f69f9ec69244860c250ae6ee0046c8c5c4d348" @@ -4452,26 +4462,6 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - -lodash.escape@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" - integrity sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw== - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== - -lodash.invokemap@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz#1748cda5d8b0ef8369c4eb3ec54c21feba1f2d62" - integrity sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w== - lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -4482,21 +4472,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.pullall@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.pullall/-/lodash.pullall-4.2.0.tgz#9d98b8518b7c965b0fae4099bd9fb7df8bbf38ba" - integrity sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg== - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash.uniqby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" - integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww== - lodash@^4.17.10, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -5696,10 +5676,10 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" - integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== +prettier@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" + integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== pretty-error@^4.0.0: version "4.0.0" @@ -6557,9 +6537,9 @@ stream-shift@^1.0.0: integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== streamx@^2.15.0: - version "2.15.4" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.4.tgz#497b8102d076ae12b43c456e0bb16940d1ba0999" - integrity sha512-uSXKl88bibiUCQ1eMpItRljCzDENcDx18rsfDmV79r0e/ThfrAwxG4Y2FarQZ2G4/21xcOKmFFd1Hue+ZIDwHw== + version "2.15.5" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.5.tgz#87bcef4dc7f0b883f9359671203344a4e004c7f1" + integrity sha512-9thPGMkKC2GctCzyCUjME3yR03x2xNo0GPKGkRw2UMYN+gqWa9uqpyNWhmsNCutU5zHmkUum0LsCRQTXUgUCAg== dependencies: fast-fifo "^1.1.0" queue-tick "^1.0.1" @@ -7209,24 +7189,20 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -webpack-bundle-analyzer@4.9.1: - version "4.9.1" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.1.tgz#d00bbf3f17500c10985084f22f1a2bf45cb2f09d" - integrity sha512-jnd6EoYrf9yMxCyYDPj8eutJvtjQNp8PHmni/e/ulydHBWhT5J3menXt3HEkScsu9YqMAcG4CfFjs3rj5pVU1w== +webpack-bundle-analyzer@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.0.tgz#eecb0ade9bd1944d3d2e38262ec9793da6f13e69" + integrity sha512-j+apH0Cs+FY8IOIwxLbkgEJnbQgEPEG8uqLVnRb9tAoGbyKNxQA1u9wNDrTQHK3PinO4Pckew7AE7pnX/RS3wA== dependencies: "@discoveryjs/json-ext" "0.5.7" acorn "^8.0.4" acorn-walk "^8.0.0" commander "^7.2.0" + debounce "^1.2.1" escape-string-regexp "^4.0.0" gzip-size "^6.0.0" + html-escaper "^2.0.2" is-plain-object "^5.0.0" - lodash.debounce "^4.0.8" - lodash.escape "^4.0.1" - lodash.flatten "^4.4.0" - lodash.invokemap "^4.6.0" - lodash.pullall "^4.2.0" - lodash.uniqby "^4.7.0" opener "^1.5.2" picocolors "^1.0.0" sirv "^2.0.3" From fd23c90ed6140442db7fe3a5b58ac014c279c369 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 12:08:18 -0500 Subject: [PATCH 0230/1012] Closes #3005 adds GPT-4 Turbo & latest Anthropic models --- CHANGELOG.md | 8 +++ package.json | 36 ++++++------- src/ai/anthropicProvider.ts | 86 ++++++++++++++++++++---------- src/ai/openaiProvider.ts | 92 ++++++++++++++++++++++----------- src/quickpicks/aiModelPicker.ts | 22 +++----- 5 files changed, 152 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 982aa290b3c16..cc148d942ba81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Added + +- Adds support for OpenAI's GPT-4 Turbo and latest Anthropic models for GitLens' experimental AI features — closes [#3005](https://github.com/gitkraken/vscode-gitlens/issues/3005) + +### Changed + +- Refines AI prompts to provide better commit message generation and explanation results + ## [14.5.0] - 2023-11-13 ### Added diff --git a/package.json b/package.json index d54b1036b7dd0..308bc0aaeaf80 100644 --- a/package.json +++ b/package.json @@ -3175,7 +3175,7 @@ }, "gitlens.experimental.generateCommitMessagePrompt": { "type": "string", - "default": "Commit messages must have a short description that is less than 50 chars followed by a newline and a more detailed description.\n- Write concisely using an informal tone and avoid specific names from the code", + "default": "Now, please generate a commit message. Ensure that it includes a precise and informative subject line that succinctly summarizes the crux of the changes in under 50 characters. If necessary, follow with an explanatory body providing insight into the nature of the changes, the reasoning behind them, and any significant consequences or considerations arising from them. Conclude with any relevant issue references at the end of the message.", "markdownDescription": "Specifies the prompt to use to tell OpenAI how to structure or format the generated commit message", "scope": "window", "order": 2 @@ -3202,19 +3202,23 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", "gpt-4", "gpt-4-0613", "gpt-4-32k", - "gpt-4-32k-0613" + "gpt-4-32k-0613", + "gpt-4-1106-preview" ], "enumDescriptions": [ - "GPT 3.5 Turbo", - "GPT 3.5 Turbo 16k", - "GPT 3.5 Turbo (June 13)", - "GPT 4", - "GPT 4 (June 13)", - "GPT 4 32k", - "GPT 4 32k (June 13)" + "GPT-3.5 Turbo", + "GPT-3.5 Turbo 16k", + "GPT-3.5 Turbo (June 13)", + "GPT-3.5 Turbo (Nov 6)", + "GPT-4", + "GPT-4 (June 13)", + "GPT-4 32k", + "GPT-4 32k (June 13)", + "GPT-4 Turbo (Nov 6)" ], "markdownDescription": "Specifies the OpenAI model to use for GitLens' experimental AI features", "scope": "window", @@ -3232,20 +3236,14 @@ }, "gitlens.ai.experimental.anthropic.model": { "type": "string", - "default": "claude-v1", + "default": "claude-instant-1", "enum": [ - "claude-v1", - "claude-v1-100k", - "claude-instant-v1", - "claude-instant-v1-100k", + "claude-instant-1", "claude-2" ], "enumDescriptions": [ - "Claude v1", - "Claude v1 100k", - "Claude Instant v1", - "Claude Instant v1 100k", - "Claude 2" + "Claude Instant", + "Claude" ], "markdownDescription": "Specifies the Anthropic model to use for GitLens' experimental AI features", "scope": "window", diff --git a/src/ai/anthropicProvider.ts b/src/ai/anthropicProvider.ts index f5eeac82c73e3..da9970c239549 100644 --- a/src/ai/anthropicProvider.ts +++ b/src/ai/anthropicProvider.ts @@ -12,7 +12,7 @@ export class AnthropicProvider implements AIProvider { readonly name = 'Anthropic'; private get model(): AnthropicModels { - return configuration.get('ai.experimental.anthropic.model') || 'claude-v1'; + return configuration.get('ai.experimental.anthropic.model') || 'claude-instant-1'; } constructor(private readonly container: Container) {} @@ -24,7 +24,7 @@ export class AnthropicProvider implements AIProvider { if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model); + const maxCodeCharacters = getMaxCharacters(model, 1600); const code = diff.substring(0, maxCodeCharacters); if (diff.length > maxCodeCharacters) { @@ -38,15 +38,29 @@ export class AnthropicProvider implements AIProvider { customPrompt += '.'; } - let prompt = - "\n\nHuman: You are an AI programming assistant tasked with writing a meaningful commit message by summarizing code changes.\n- Follow the user's instructions carefully & to the letter!\n- Don't repeat yourself or make anything up!\n- Minimize any other prose."; - prompt += `\n${customPrompt}\n- Avoid phrases like "this commit", "this change", etc.`; - prompt += '\n\nAssistant: OK'; - if (options?.context) { - prompt += `\n\nHuman: Use "${options.context}" to help craft the commit message.\n\nAssistant: OK`; - } - prompt += `\n\nHuman: Write a meaningful commit message for the following code changes:\n\n${code}`; - prompt += '\n\nAssistant:'; + const prompt = `\n\nHuman: You are an advanced AI programming assistant tasked with summarizing code changes into a concise and meaningful commit message. Compose a commit message that: +- Strictly synthesizes meaningful information from the provided code diff +- Utilizes any additional user-provided context to comprehend the rationale behind the code changes +- Is clear and brief, with an informal yet professional tone, and without superfluous descriptions +- Avoids unnecessary phrases such as "this commit", "this change", and the like +- Avoids direct mention of specific code identifiers, names, or file names, unless they are crucial for understanding the purpose of the changes +- Most importantly emphasizes the 'why' of the change, its benefits, or the problem it addresses rather than only the 'what' that changed + +Follow the user's instructions carefully, don't repeat yourself, don't include the code in the output, or make anything up! + +Human: Here is the code diff to use to generate the commit message: + +${code} + +${ + options?.context + ? `Human: Here is additional context which should be taken into account when generating the commit message:\n\n${options.context}` + : '' +} + +Human: ${customPrompt} + +Assistant:`; const request: AnthropicCompletionRequest = { model: model, @@ -80,7 +94,7 @@ export class AnthropicProvider implements AIProvider { if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model); + const maxCodeCharacters = getMaxCharacters(model, 2400); const code = diff.substring(0, maxCodeCharacters); if (diff.length > maxCodeCharacters) { @@ -89,12 +103,24 @@ export class AnthropicProvider implements AIProvider { ); } - let prompt = - "\n\nHuman: You are an AI programming assistant tasked with providing an easy to understand but detailed explanation of a commit by summarizing the code changes while also using the commit message as additional context and framing.\nDon't make anything up!"; - prompt += `\nUse the following user-provided commit message, which should provide some explanation to why these changes where made, when attempting to generate the rich explanation:\n\n${message}`; - prompt += '\n\nAssistant: OK'; - prompt += `\n\nHuman: Explain the following code changes:\n\n${code}`; - prompt += '\n\nAssistant:'; + const prompt = `\n\nHuman: You are an advanced AI programming assistant tasked with summarizing code changes into an explanation that is both easy to understand and meaningful. Construct an explanation that: + - Concisely synthesizes meaningful information from the provided code diff + - Incorporates any additional context provided by the user to understand the rationale behind the code changes + - Places the emphasis on the 'why' of the change, clarifying its benefits or addressing the problem that necessitated the change, beyond just detailing the 'what' has changed + + Do not make any assumptions or invent details that are not supported by the code diff or the user-provided context. + +Human: Here is additional context provided by the author of the changes, which should provide some explanation to why these changes where made. Please strongly consider this information when generating your explanation: + +${message} + +Human: Now, kindly explain the following code diff in a way that would be clear to someone reviewing or trying to understand these changes: + +${code} + +Human: Remember to frame your explanation in a way that is suitable for a reviewer to quickly grasp the essence of the changes, the issues they resolve, and their implications on the codebase. + +Assistant:`; const request: AnthropicCompletionRequest = { model: model, @@ -200,18 +226,22 @@ async function getApiKey(storage: Storage): Promise { return apiKey; } -function getMaxCharacters(model: AnthropicModels): number { - if (model === 'claude-2' || model === 'claude-v1-100k' || model === 'claude-instant-v1-100k') { - return 135000; +function getMaxCharacters(model: AnthropicModels, outputLength: number): number { + let tokens; + switch (model) { + case 'claude-2': // 100,000 tokens + case 'claude-instant-1': + tokens = 100000; + break; + default: // 4,096 tokens + tokens = 4096; + break; } - return 12000; + + return tokens * 4 - outputLength / 4; } -export type AnthropicModels = - | 'claude-v1' - | 'claude-v1-100k' - | 'claude-instant-v1' - | 'claude-instant-v1-100k' - | 'claude-2'; + +export type AnthropicModels = 'claude-instant-1' | 'claude-2'; interface AnthropicCompletionRequest { model: string; diff --git a/src/ai/openaiProvider.ts b/src/ai/openaiProvider.ts index ed57215ad6651..aa652a777bdfe 100644 --- a/src/ai/openaiProvider.ts +++ b/src/ai/openaiProvider.ts @@ -28,7 +28,7 @@ export class OpenAIProvider implements AIProvider { if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model); + const maxCodeCharacters = getMaxCharacters(model, 1600); const code = diff.substring(0, maxCodeCharacters); if (diff.length > maxCodeCharacters) { @@ -47,27 +47,35 @@ export class OpenAIProvider implements AIProvider { messages: [ { role: 'system', - content: - "You are an AI programming assistant tasked with writing a meaningful commit message by summarizing code changes.\n\n- Follow the user's instructions carefully & to the letter!\n- Don't repeat yourself or make anything up!\n- Minimize any other prose.", + content: `You are an advanced AI programming assistant tasked with summarizing code changes into a concise and meaningful commit message. Compose a commit message that: +- Strictly synthesizes meaningful information from the provided code diff +- Utilizes any additional user-provided context to comprehend the rationale behind the code changes +- Is clear and brief, with an informal yet professional tone, and without superfluous descriptions +- Avoids unnecessary phrases such as "this commit", "this change", and the like +- Avoids direct mention of specific code identifiers, names, or file names, unless they are crucial for understanding the purpose of the changes +- Most importantly emphasizes the 'why' of the change, its benefits, or the problem it addresses rather than only the 'what' that changed + +Follow the user's instructions carefully, don't repeat yourself, don't include the code in the output, or make anything up!`, + }, + { + role: 'user', + content: `Here is the code diff to use to generate the commit message:\n\n${code}`, }, + ...(options?.context + ? [ + { + role: 'user' as const, + content: `Here is additional context which should be taken into account when generating the commit message:\n\n${options.context}`, + }, + ] + : []), { role: 'user', - content: `${customPrompt}\n- Avoid phrases like "this commit", "this change", etc.`, + content: customPrompt, }, ], }; - if (options?.context) { - request.messages.push({ - role: 'user', - content: `Use "${options.context}" to help craft the commit message.`, - }); - } - request.messages.push({ - role: 'user', - content: `Write a meaningful commit message for the following code changes:\n\n${code}`, - }); - const rsp = await this.fetch(apiKey, request); if (!rsp.ok) { debugger; @@ -89,7 +97,7 @@ export class OpenAIProvider implements AIProvider { if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model); + const maxCodeCharacters = getMaxCharacters(model, 2400); const code = diff.substring(0, maxCodeCharacters); if (diff.length > maxCodeCharacters) { @@ -103,20 +111,25 @@ export class OpenAIProvider implements AIProvider { messages: [ { role: 'system', - content: - "You are an AI programming assistant tasked with providing an easy to understand but detailed explanation of a commit by summarizing the code changes while also using the commit message as additional context and framing.\n\n- Don't make anything up!", + content: `You are an advanced AI programming assistant tasked with summarizing code changes into an explanation that is both easy to understand and meaningful. Construct an explanation that: +- Concisely synthesizes meaningful information from the provided code diff +- Incorporates any additional context provided by the user to understand the rationale behind the code changes +- Places the emphasis on the 'why' of the change, clarifying its benefits or addressing the problem that necessitated the change, beyond just detailing the 'what' has changed + +Do not make any assumptions or invent details that are not supported by the code diff or the user-provided context.`, }, { role: 'user', - content: `Use the following user-provided commit message, which should provide some explanation to why these changes where made, when attempting to generate the rich explanation:\n\n${message}`, + content: `Here is additional context provided by the author of the changes, which should provide some explanation to why these changes where made. Please strongly consider this information when generating your explanation:\n\n${message}`, }, { - role: 'assistant', - content: 'OK', + role: 'user', + content: `Now, kindly explain the following code diff in a way that would be clear to someone reviewing or trying to understand these changes:\n\n${code}`, }, { role: 'user', - content: `Explain the following code changes:\n\n${code}`, + content: + 'Remember to frame your explanation in a way that is suitable for a reviewer to quickly grasp the essence of the changes, the issues they resolve, and their implications on the codebase.', }, ], }; @@ -220,26 +233,45 @@ async function getApiKey(storage: Storage): Promise { return openaiApiKey; } -function getMaxCharacters(model: OpenAIModels): number { +function getMaxCharacters(model: OpenAIModels, outputLength: number): number { + let tokens; switch (model) { - case 'gpt-4-32k': + case 'gpt-4-1106-preview': // 128,000 tokens (4,096 max output tokens) + tokens = 128000; + break; + case 'gpt-4-32k': // 32,768 tokens case 'gpt-4-32k-0613': - return 43000; - case 'gpt-3.5-turbo-16k': - return 21000; - default: - return 12000; + tokens = 32768; + break; + case 'gpt-4': // 8,192 tokens + case 'gpt-4-0613': + tokens = 8192; + break; + case 'gpt-3.5-turbo-1106': // 16,385 tokens (4,096 max output tokens) + tokens = 16385; + break; + case 'gpt-3.5-turbo-16k': // 16,385 tokens; Will point to gpt-3.5-turbo-1106 starting Dec 11, 2023 + tokens = 16385; + break; + case 'gpt-3.5-turbo': // Will point to gpt-3.5-turbo-1106 starting Dec 11, 2023 + default: // 4,096 tokens + tokens = 4096; + break; } + + return tokens * 4 - outputLength / 4; } export type OpenAIModels = + | 'gpt-3.5-turbo-1106' | 'gpt-3.5-turbo' | 'gpt-3.5-turbo-16k' | 'gpt-3.5-turbo-0613' | 'gpt-4' | 'gpt-4-0613' | 'gpt-4-32k' - | 'gpt-4-32k-0613'; + | 'gpt-4-32k-0613' + | 'gpt-4-1106-preview'; interface OpenAIChatCompletionRequest { model: OpenAIModels; diff --git a/src/quickpicks/aiModelPicker.ts b/src/quickpicks/aiModelPicker.ts index 0109e61a87f14..260268381286e 100644 --- a/src/quickpicks/aiModelPicker.ts +++ b/src/quickpicks/aiModelPicker.ts @@ -14,28 +14,20 @@ export async function showAIModelPicker(): Promise Date: Wed, 15 Nov 2023 12:08:52 -0500 Subject: [PATCH 0231/1012] Adds border radius to AI explain box --- src/webviews/apps/shared/styles/details-base.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webviews/apps/shared/styles/details-base.scss b/src/webviews/apps/shared/styles/details-base.scss index ea6cde7b28584..e08611e099996 100644 --- a/src/webviews/apps/shared/styles/details-base.scss +++ b/src/webviews/apps/shared/styles/details-base.scss @@ -381,6 +381,7 @@ ul { background: var(--vscode-input-background); margin-top: 1rem; padding: 0.5rem; + border-radius: 2px; &.has-error { border-left-color: var(--color-alert-errorBorder); From 0ca7b41aa8152269763c4bc8557a564af355446d Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 12:09:31 -0500 Subject: [PATCH 0232/1012] Updates for latest vscode settings changes --- .vscode/settings.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5a748806bc17f..4367562dcbdc1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,7 @@ { "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, - "eslint.packageManager": "yarn", "files.associations": { ".eslintrc*.json": "jsonc" }, From fbccf2428fd671378202de43ff99deff66168a13 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 12:13:41 -0500 Subject: [PATCH 0233/1012] =?UTF-8?q?=F0=9F=92=84prettiers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .prettierrc | 4 -- src/annotations/blameAnnotationProvider.ts | 8 +-- .../gutterChangesAnnotationProvider.ts | 4 +- src/commands/git/push.ts | 16 ++--- src/commands/quickCommand.ts | 16 ++--- src/errors.ts | 4 +- src/extension.ts | 4 +- src/plus/github/github.ts | 32 ++++----- src/plus/github/githubGitProvider.ts | 8 +-- src/plus/gk/checkin.ts | 4 +- src/quickpicks/referencePicker.ts | 8 +-- src/system/configuration.ts | 4 +- src/system/serialize.ts | 20 +++--- src/views/nodes/abstract/viewNode.ts | 68 +++++++++---------- src/views/nodes/autolinkedItemNode.ts | 12 ++-- src/views/nodes/branchNode.ts | 14 ++-- src/views/nodes/commitNode.ts | 8 +-- src/views/nodes/fileHistoryNode.ts | 12 ++-- src/views/nodes/fileRevisionAsCommitNode.ts | 4 +- src/views/nodes/remoteNode.ts | 14 ++-- src/views/nodes/resultsCommitsNode.ts | 4 +- src/views/nodes/resultsFilesNode.ts | 4 +- src/views/nodes/worktreeNode.ts | 12 ++-- src/views/viewCommands.ts | 8 +-- .../focus/components/gk-pull-request-row.ts | 8 +-- src/webviews/apps/plus/timeline/chart.ts | 4 +- .../components/list/file-change-list-item.ts | 68 +++++++++---------- src/webviews/webviewController.ts | 4 +- 28 files changed, 190 insertions(+), 186 deletions(-) diff --git a/.prettierrc b/.prettierrc index 5a24bc35e38c2..df7b60158484f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -14,10 +14,6 @@ { "files": "*.md", "options": { "tabWidth": 2 } - }, - { - "files": "*.svg", - "options": { "parser": "html" } } ] } diff --git a/src/annotations/blameAnnotationProvider.ts b/src/annotations/blameAnnotationProvider.ts index 3c8b47de9dd83..de6bf5f368b63 100644 --- a/src/annotations/blameAnnotationProvider.ts +++ b/src/annotations/blameAnnotationProvider.ts @@ -107,10 +107,10 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase Array.isArray(lookupTable) ? lookupTable : unified - ? lookupTable.hot.concat(lookupTable.cold) - : date.getTime() < coldThresholdTimestamp - ? lookupTable.cold - : lookupTable.hot; + ? lookupTable.hot.concat(lookupTable.cold) + : date.getTime() < coldThresholdTimestamp + ? lookupTable.cold + : lookupTable.hot; const computeRelativeAge = (date: Date, lookup: number[]) => { const time = date.getTime(); diff --git a/src/annotations/gutterChangesAnnotationProvider.ts b/src/annotations/gutterChangesAnnotationProvider.ts index 742315766e46b..5ce792727cbf6 100644 --- a/src/annotations/gutterChangesAnnotationProvider.ts +++ b/src/annotations/gutterChangesAnnotationProvider.ts @@ -211,8 +211,8 @@ export class GutterChangesAnnotationProvider extends AnnotationProviderBase { useForceIfIncludes ? ' (with lease and if includes)' : useForceWithLease - ? ' (with lease)' - : '' + ? ' (with lease)' + : '' }`, description: `--force${ useForceWithLease @@ -254,8 +254,8 @@ export class PushGitCommand extends QuickCommand { useForceIfIncludes ? ' (with lease and if includes)' : useForceWithLease - ? ' (with lease)' - : '' + ? ' (with lease)' + : '' } ${branch?.state.ahead ? ` ${pluralize('commit', branch.state.ahead)}` : ''}${ branch.getRemoteName() ? ` to ${branch.getRemoteName()}` : '' }${ @@ -406,8 +406,8 @@ export class PushGitCommand extends QuickCommand { useForceIfIncludes ? ' (with lease and if includes)' : useForceWithLease - ? ' (with lease)' - : '' + ? ' (with lease)' + : '' }`, description: `--force${ useForceWithLease @@ -418,8 +418,8 @@ export class PushGitCommand extends QuickCommand { useForceIfIncludes ? ' (with lease and if includes)' : useForceWithLease - ? ' (with lease)' - : '' + ? ' (with lease)' + : '' } ${pushDetails}${ status != null && status.state.behind > 0 ? `, overwriting ${pluralize('commit', status.state.behind)}${ diff --git a/src/commands/quickCommand.ts b/src/commands/quickCommand.ts index d4c6bd3d072e3..91a3714aead5d 100644 --- a/src/commands/quickCommand.ts +++ b/src/commands/quickCommand.ts @@ -88,10 +88,10 @@ export type StepGenerator = export type StepItemType = T extends CustomStep ? U : T extends QuickPickStep - ? U[] - : T extends QuickInputStep - ? string - : never; + ? U[] + : T extends QuickInputStep + ? string + : never; export type StepNavigationKeys = Exclude; export const StepResultBreak = Symbol('BreakStep'); export type StepResult = typeof StepResultBreak | T; @@ -112,10 +112,10 @@ export type AsyncStepResultGenerator = AsyncGenerator< export type StepSelection = T extends CustomStep ? U | Directive : T extends QuickPickStep - ? U[] | Directive - : T extends QuickInputStep - ? string | Directive - : never; + ? U[] | Directive + : T extends QuickInputStep + ? string | Directive + : never; export type PartialStepState = Partial & { counter: number; confirm?: boolean; startingStep?: number }; export type StepState> = T & { counter: number; confirm?: boolean; startingStep?: number }; diff --git a/src/errors.ts b/src/errors.ts index 173b4cf8a0d87..143ec67ddee8b 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -192,8 +192,8 @@ export class ProviderNotFoundError extends Error { pathOrUri == null ? String(pathOrUri) : typeof pathOrUri === 'string' - ? pathOrUri - : pathOrUri.toString(true) + ? pathOrUri + : pathOrUri.toString(true) }'`, ); diff --git a/src/extension.ts b/src/extension.ts index c6553c663facc..d40e64cc91cd3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -273,8 +273,8 @@ function registerBuiltInActionRunners(container: Container): void { compare: ctx.branch.isRemote ? getBranchNameWithoutRemote(ctx.branch.name) : ctx.branch.upstream - ? getBranchNameWithoutRemote(ctx.branch.upstream) - : ctx.branch.name, + ? getBranchNameWithoutRemote(ctx.branch.upstream) + : ctx.branch.name, remote: ctx.remote?.name ?? '', repoPath: ctx.repoPath, })); diff --git a/src/plus/github/github.ts b/src/plus/github/github.ts index e2aaae4f93601..38f70a2f3b162 100644 --- a/src/plus/github/github.ts +++ b/src/plus/github/github.ts @@ -298,14 +298,14 @@ export class GitHubApi implements Disposable { !author.avatarUrl || isGitHubDotCom(options) ? author.avatarUrl ?? undefined : author.email && options?.baseUrl != null - ? await this.createEnterpriseAvatarUrl( - provider, - token, - options.baseUrl, - author.email, - options.avatarSize, - ) - : undefined, + ? await this.createEnterpriseAvatarUrl( + provider, + token, + options.baseUrl, + author.email, + options.avatarSize, + ) + : undefined, }; } catch (ex) { if (ex instanceof ProviderRequestNotFoundError) return undefined; @@ -385,14 +385,14 @@ export class GitHubApi implements Disposable { !author.avatarUrl || isGitHubDotCom(options) ? author.avatarUrl ?? undefined : author.email && options?.baseUrl != null - ? await this.createEnterpriseAvatarUrl( - provider, - token, - options.baseUrl, - author.email, - options.avatarSize, - ) - : undefined, + ? await this.createEnterpriseAvatarUrl( + provider, + token, + options.baseUrl, + author.email, + options.avatarSize, + ) + : undefined, }; } catch (ex) { if (ex instanceof ProviderRequestNotFoundError) return undefined; diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index 5ee14666b6460..3cc75f3d82c26 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -2924,8 +2924,8 @@ export class GitHubGitProvider implements GitProvider, Disposable { options?.ordering === 'date' ? 'committer-date' : options?.ordering === 'author-date' - ? 'author-date' - : undefined, + ? 'author-date' + : undefined, }); if (result == null) return undefined; @@ -3116,8 +3116,8 @@ export class GitHubGitProvider implements GitProvider, Disposable { options?.ordering === 'date' ? 'committer-date' : options?.ordering === 'author-date' - ? 'author-date' - : undefined, + ? 'author-date' + : undefined, }); if (result == null || options?.cancellation?.isCancellationRequested) { diff --git a/src/plus/gk/checkin.ts b/src/plus/gk/checkin.ts index 9a5b4d60ec3b5..73d281416ce6e 100644 --- a/src/plus/gk/checkin.ts +++ b/src/plus/gk/checkin.ts @@ -90,8 +90,8 @@ export function getSubscriptionFromCheckIn(data: GKCheckInResponse): Partial> = P extends `${infer Key}.${infer Re : never : never : P extends keyof T - ? T[P] - : never; + ? T[P] + : never; export type ConfigPath = Path; export type ConfigPathValue

= PathValue; diff --git a/src/system/serialize.ts b/src/system/serialize.ts index 151cbf1c70523..7cec955a496c5 100644 --- a/src/system/serialize.ts +++ b/src/system/serialize.ts @@ -3,16 +3,16 @@ import type { Branded } from './brand'; export type Serialized = T extends Function ? never : T extends Date - ? number - : T extends Branded - ? U - : T extends any[] - ? Serialized[] - : T extends object - ? { - [K in keyof T]: T[K] extends Date ? number : Serialized; - } - : T; + ? number + : T extends Branded + ? U + : T extends any[] + ? Serialized[] + : T extends object + ? { + [K in keyof T]: T[K] extends Date ? number : Serialized; + } + : T; export function serialize(obj: T): Serialized; export function serialize(obj: T | undefined): Serialized | undefined; diff --git a/src/views/nodes/abstract/viewNode.ts b/src/views/nodes/abstract/viewNode.ts index 3a4d74e880708..7d366d217044e 100644 --- a/src/views/nodes/abstract/viewNode.ts +++ b/src/views/nodes/abstract/viewNode.ts @@ -370,40 +370,40 @@ type TreeViewNodesByType = { [T in TreeViewNodeTypes]: T extends 'branch' ? BranchNode : T extends 'commit' - ? CommitNode - : T extends 'commit-file' - ? CommitFileNode - : T extends 'compare-branch' - ? CompareBranchNode - : T extends 'compare-results' - ? CompareResultsNode - : T extends 'conflict-file' - ? MergeConflictFileNode - : T extends 'file-commit' - ? FileRevisionAsCommitNode - : T extends 'folder' - ? FolderNode - : T extends 'line-history-tracker' - ? LineHistoryTrackerNode - : T extends 'repository' - ? RepositoryNode - : T extends 'repo-folder' - ? RepositoryFolderNode - : T extends 'results-commits' - ? ResultsCommitsNode - : T extends 'results-file' - ? ResultsFileNode - : T extends 'stash' - ? StashNode - : T extends 'stash-file' - ? StashFileNode - : T extends 'status-file' - ? StatusFileNode - : T extends 'tag' - ? TagNode - : T extends 'uncommitted-file' - ? UncommittedFileNode - : ViewNode; + ? CommitNode + : T extends 'commit-file' + ? CommitFileNode + : T extends 'compare-branch' + ? CompareBranchNode + : T extends 'compare-results' + ? CompareResultsNode + : T extends 'conflict-file' + ? MergeConflictFileNode + : T extends 'file-commit' + ? FileRevisionAsCommitNode + : T extends 'folder' + ? FolderNode + : T extends 'line-history-tracker' + ? LineHistoryTrackerNode + : T extends 'repository' + ? RepositoryNode + : T extends 'repo-folder' + ? RepositoryFolderNode + : T extends 'results-commits' + ? ResultsCommitsNode + : T extends 'results-file' + ? ResultsFileNode + : T extends 'stash' + ? StashNode + : T extends 'stash-file' + ? StashFileNode + : T extends 'status-file' + ? StatusFileNode + : T extends 'tag' + ? TagNode + : T extends 'uncommitted-file' + ? UncommittedFileNode + : ViewNode; }; export function isViewNode(node: unknown): node is ViewNode; diff --git a/src/views/nodes/autolinkedItemNode.ts b/src/views/nodes/autolinkedItemNode.ts index 6a8be012e0a8a..4783556433440 100644 --- a/src/views/nodes/autolinkedItemNode.ts +++ b/src/views/nodes/autolinkedItemNode.ts @@ -56,10 +56,10 @@ export class AutolinkedItemNode extends ViewNode<'autolink', ViewsWithCommits> { pending ? 'loading~spin' : autolink.type == null - ? 'link' - : autolink.type === 'pullrequest' - ? 'git-pull-request' - : 'issues', + ? 'link' + : autolink.type === 'pullrequest' + ? 'git-pull-request' + : 'issues', ); item.contextValue = ContextValues.AutolinkedItem; item.tooltip = new MarkdownString( @@ -70,8 +70,8 @@ export class AutolinkedItemNode extends ViewNode<'autolink', ViewsWithCommits> { autolink.type == null ? 'Autolinked' : autolink.type === 'pullrequest' - ? 'Autolinked Pull Request' - : 'Autolinked Issue' + ? 'Autolinked Pull Request' + : 'Autolinked Issue' } ${autolink.prefix}${autolink.id}` } \\\n[${autolink.url}](${autolink.url}${autolink.title != null ? ` "${autolink.title}"` : ''})`, ); diff --git a/src/views/nodes/branchNode.ts b/src/views/nodes/branchNode.ts index f32a1b9641c9c..56b690e8f547b 100644 --- a/src/views/nodes/branchNode.ts +++ b/src/views/nodes/branchNode.ts @@ -500,11 +500,15 @@ export class BranchNode pendingPullRequest != null ? new ThemeIcon('loading~spin') : this.options.showAsCommits - ? new ThemeIcon('git-commit', color) - : { - dark: this.view.container.context.asAbsolutePath(`images/dark/icon-branch${iconSuffix}.svg`), - light: this.view.container.context.asAbsolutePath(`images/light/icon-branch${iconSuffix}.svg`), - }; + ? new ThemeIcon('git-commit', color) + : { + dark: this.view.container.context.asAbsolutePath( + `images/dark/icon-branch${iconSuffix}.svg`, + ), + light: this.view.container.context.asAbsolutePath( + `images/light/icon-branch${iconSuffix}.svg`, + ), + }; item.tooltip = tooltip; item.resourceUri = Uri.parse( `gitlens-view://branch/status/${await this.branch.getStatus()}${ diff --git a/src/views/nodes/commitNode.ts b/src/views/nodes/commitNode.ts index 95d27f909486f..70b35b55b70ef 100644 --- a/src/views/nodes/commitNode.ts +++ b/src/views/nodes/commitNode.ts @@ -188,10 +188,10 @@ export class CommitNode extends ViewRefNode<'commit', ViewsWithCommits | FileHis pendingPullRequest != null ? new ThemeIcon('loading~spin') : this.unpublished - ? new ThemeIcon('arrow-up', new ThemeColor('gitlens.unpublishedCommitIconColor' satisfies Colors)) - : this.view.config.avatars - ? await this.commit.getAvatarUri({ defaultStyle: configuration.get('defaultGravatarsStyle') }) - : undefined; + ? new ThemeIcon('arrow-up', new ThemeColor('gitlens.unpublishedCommitIconColor' satisfies Colors)) + : this.view.config.avatars + ? await this.commit.getAvatarUri({ defaultStyle: configuration.get('defaultGravatarsStyle') }) + : undefined; // item.tooltip = this.tooltip; return item; diff --git a/src/views/nodes/fileHistoryNode.ts b/src/views/nodes/fileHistoryNode.ts index a0b2147b18445..3df1d11931e35 100644 --- a/src/views/nodes/fileHistoryNode.ts +++ b/src/views/nodes/fileHistoryNode.ts @@ -129,12 +129,12 @@ export class FileHistoryNode }, ) : c.file != null - ? new FileRevisionAsCommitNode(this.view, this, c.file, c, { - branch: this.branch, - getBranchAndTagTips: getBranchAndTagTips, - unpublished: unpublishedCommits?.has(c.ref), - }) - : undefined, + ? new FileRevisionAsCommitNode(this.view, this, c.file, c, { + branch: this.branch, + getBranchAndTagTips: getBranchAndTagTips, + unpublished: unpublishedCommits?.has(c.ref), + }) + : undefined, ), this, ), diff --git a/src/views/nodes/fileRevisionAsCommitNode.ts b/src/views/nodes/fileRevisionAsCommitNode.ts index 96afcdd9db922..c5bcecb86bb55 100644 --- a/src/views/nodes/fileRevisionAsCommitNode.ts +++ b/src/views/nodes/fileRevisionAsCommitNode.ts @@ -139,8 +139,8 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode< return this.commit.file?.hasConflicts ? `${ContextValues.File}+conflicted` : this.commit.isUncommittedStaged - ? `${ContextValues.File}+staged` - : `${ContextValues.File}+unstaged`; + ? `${ContextValues.File}+staged` + : `${ContextValues.File}+unstaged`; } override getCommand(): Command | undefined { diff --git a/src/views/nodes/remoteNode.ts b/src/views/nodes/remoteNode.ts index f3c4aadf71665..4eeec86a91831 100644 --- a/src/views/nodes/remoteNode.ts +++ b/src/views/nodes/remoteNode.ts @@ -92,11 +92,15 @@ export class RemoteNode extends ViewNode<'remote', ViewsWithRemotes> { provider.avatarUri != null && this.view.config.avatars ? provider.avatarUri : provider.icon === 'remote' - ? new ThemeIcon('cloud') - : { - dark: this.view.container.context.asAbsolutePath(`images/dark/icon-${provider.icon}.svg`), - light: this.view.container.context.asAbsolutePath(`images/light/icon-${provider.icon}.svg`), - }; + ? new ThemeIcon('cloud') + : { + dark: this.view.container.context.asAbsolutePath( + `images/dark/icon-${provider.icon}.svg`, + ), + light: this.view.container.context.asAbsolutePath( + `images/light/icon-${provider.icon}.svg`, + ), + }; if (provider.hasRichIntegration()) { const connected = provider.maybeConnected ?? (await provider.isConnected()); diff --git a/src/views/nodes/resultsCommitsNode.ts b/src/views/nodes/resultsCommitsNode.ts index ba866a46729df..3b349013076c2 100644 --- a/src/views/nodes/resultsCommitsNode.ts +++ b/src/views/nodes/resultsCommitsNode.ts @@ -156,8 +156,8 @@ export class ResultsCommitsNode { diff --git a/src/views/nodes/resultsFilesNode.ts b/src/views/nodes/resultsFilesNode.ts index 309e34f88d416..627516faf2e7e 100644 --- a/src/views/nodes/resultsFilesNode.ts +++ b/src/views/nodes/resultsFilesNode.ts @@ -156,8 +156,8 @@ export class ResultsFilesNode extends ViewNode<'results-files', ViewsWithCommits files == null || files.length === 0 ? TreeItemCollapsibleState.None : this._options.expand - ? TreeItemCollapsibleState.Expanded - : TreeItemCollapsibleState.Collapsed; + ? TreeItemCollapsibleState.Expanded + : TreeItemCollapsibleState.Collapsed; } } catch (ex) { if (ex instanceof PromiseCancelledError) { diff --git a/src/views/nodes/worktreeNode.ts b/src/views/nodes/worktreeNode.ts index 99459f9ffbc43..85a15fcd70bb5 100644 --- a/src/views/nodes/worktreeNode.ts +++ b/src/views/nodes/worktreeNode.ts @@ -202,8 +202,8 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit this.worktree.main ? `_Main${this.worktree.opened ? ', Active_' : '_'}` : this.worktree.opened - ? '_Active_' - : '' + ? '_Active_' + : '' } ` : ''; @@ -367,14 +367,14 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit pendingPullRequest != null ? new ThemeIcon('loading~spin') : this.worktree.opened - ? new ThemeIcon('check') - : icon; + ? new ThemeIcon('check') + : icon; item.tooltip = tooltip; item.resourceUri = missing ? Uri.parse('gitlens-view://worktree/missing') : hasChanges - ? Uri.parse('gitlens-view://worktree/changes') - : undefined; + ? Uri.parse('gitlens-view://worktree/changes') + : undefined; return item; } diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts index 962c5132c5067..91ec0067446b0 100644 --- a/src/views/viewCommands.ts +++ b/src/views/viewCommands.ts @@ -417,8 +417,8 @@ export class ViewCommands { node instanceof ViewRefNode || node instanceof ViewRefFileNode ? node?.ref : node instanceof BranchTrackingStatusNode - ? node.branch - : undefined; + ? node.branch + : undefined; if (from == null) { const branch = await this.container.git.getBranch( node?.repoPath ?? this.container.git.getBestRepository()?.uri, @@ -467,8 +467,8 @@ export class ViewCommands { node instanceof ViewRefNode || node instanceof ViewRefFileNode ? node?.ref : node instanceof BranchTrackingStatusNode - ? node.branch - : undefined; + ? node.branch + : undefined; if (from == null) { const branch = await this.container.git.getBranch( node?.repoPath ?? this.container.git.getBestRepository()?.uri, diff --git a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts index 39c6ac57590b9..61a39f23d49d4 100644 --- a/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts +++ b/src/webviews/apps/plus/focus/components/gk-pull-request-row.ts @@ -264,8 +264,8 @@ export class GkPullRequestRow extends LitElement { aria-label="${this.isCurrentBranch ? 'Already on this branch' : this.hasWorktree - ? 'This branch has a worktree' - : 'Switch to Branch...'}" + ? 'This branch has a worktree' + : 'Switch to Branch...'}" @click="${this.onSwitchBranchClick}" > @@ -273,8 +273,8 @@ export class GkPullRequestRow extends LitElement { >${this.isCurrentBranch ? 'Already on this branch' : this.hasWorktree - ? 'This branch has a worktree' - : 'Switch to Branch...'} diff --git a/src/webviews/apps/plus/timeline/chart.ts b/src/webviews/apps/plus/timeline/chart.ts index 3f5195ed60f7d..2589b736134b0 100644 --- a/src/webviews/apps/plus/timeline/chart.ts +++ b/src/webviews/apps/plus/timeline/chart.ts @@ -339,8 +339,8 @@ export class TimelineChart implements Disposable { this.compact ? '' : typeof x === 'number' - ? x - : formatDate(x, this._shortDateFormat ?? 'short'), + ? x + : formatDate(x, this._shortDateFormat ?? 'short'), multiline: false, show: false, outer: !this.compact, diff --git a/src/webviews/apps/shared/components/list/file-change-list-item.ts b/src/webviews/apps/shared/components/list/file-change-list-item.ts index faa390ebe5e38..a246d1983acb7 100644 --- a/src/webviews/apps/shared/components/list/file-change-list-item.ts +++ b/src/webviews/apps/shared/components/list/file-change-list-item.ts @@ -169,40 +169,40 @@ export class FileChangeListItem extends LitElement { ` : !this.uncommitted - ? html` - - - - ${this.stash - ? nothing - : html` - - - - - - - `} - ` - : nothing} + ? html` + + + + ${this.stash + ? nothing + : html` + + + + + + + `} + ` + : nothing} `; diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 93789f974b6a3..d4c6702318c91 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -40,8 +40,8 @@ function nextIpcId() { type GetParentType = T extends WebviewPanelDescriptor ? WebviewPanel : T extends WebviewViewDescriptor - ? WebviewView - : never; + ? WebviewView + : never; export type WebviewShowingArgs = T | [{ state: Partial }] | []; From 216e6f62e8054ed16e04017e31a2e6449d19b2f5 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 12:14:58 -0500 Subject: [PATCH 0234/1012] Excludes fbccf24 from blames --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 58466c32b141a..28f97a2c07331 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -8,3 +8,4 @@ d790e9db047769de079f6838c3578f3a47bf5930 9c2df377d3e1842ed09eea5bb99be00edee9ca9c 444bf829156b3170c8b4b5156dcf10b06db83779 4dba4612670c0a942e3daa3e6a34a57aebe257ae +fbccf2428fd671378202de43ff99deff66168a13 From 05ad596a99e3552d87b3d8eef47182dec2532472 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 12:21:17 -0500 Subject: [PATCH 0235/1012] Adds missing webpanel activations --- package.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 308bc0aaeaf80..35b3547a8318f 100644 --- a/package.json +++ b/package.json @@ -50,10 +50,12 @@ "activationEvents": [ "onAuthenticationRequest:gitlens-gitkraken", "onFileSystem:gitlens", - "onWebviewPanel:gitlens.welcome", - "onWebviewPanel:gitlens.settings", - "onWebviewPanel:gitlens.graph", "onWebviewPanel:gitlens.focus", + "onWebviewPanel:gitlens.graph", + "onWebviewPanel:gitlens.patchDetails", + "onWebviewPanel:gitlens.settings", + "onWebviewPanel:gitlens.timeline", + "onWebviewPanel:gitlens.welcome", "onStartupFinished" ], "capabilities": { From a0a68919fee9905418f63c6c7409c68e22b8ebcd Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Wed, 15 Nov 2023 11:56:25 -0700 Subject: [PATCH 0236/1012] Fixes cloud patch deep links requiring paid plan --- src/uris/deepLinks/deepLink.ts | 4 ++-- src/uris/deepLinks/deepLinkService.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/uris/deepLinks/deepLink.ts b/src/uris/deepLinks/deepLink.ts index 5e8e7e9cbc4b8..47b08c4a7658a 100644 --- a/src/uris/deepLinks/deepLink.ts +++ b/src/uris/deepLinks/deepLink.ts @@ -15,8 +15,8 @@ export enum DeepLinkType { Workspace = 'workspace', } -export const AccountDeepLinkTypes = [DeepLinkType.Draft, DeepLinkType.Workspace]; -export const PaidDeepLinkTypes = []; +export const AccountDeepLinkTypes: DeepLinkType[] = [DeepLinkType.Draft, DeepLinkType.Workspace]; +export const PaidDeepLinkTypes: DeepLinkType[] = []; export function deepLinkTypeToString(type: DeepLinkType): string { switch (type) { diff --git a/src/uris/deepLinks/deepLinkService.ts b/src/uris/deepLinks/deepLinkService.ts index 6133961c9422b..1fff8870f9909 100644 --- a/src/uris/deepLinks/deepLinkService.ts +++ b/src/uris/deepLinks/deepLinkService.ts @@ -26,6 +26,7 @@ import { deepLinkStateTransitionTable, DeepLinkType, deepLinkTypeToString, + PaidDeepLinkTypes, parseDeepLinkUri, } from './deepLink'; @@ -458,7 +459,7 @@ export class DeepLinkService implements Disposable { message = 'No link type provided.'; break; } - if (!AccountDeepLinkTypes.includes(targetType)) { + if (!PaidDeepLinkTypes.includes(targetType)) { action = DeepLinkServiceAction.PlanCheckPassed; break; } From e6aa7c2d6ad93cccc4ddd91e4d9602568ab5ea50 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 15:11:08 -0500 Subject: [PATCH 0237/1012] Adds protection --- src/trackers/documentTracker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/trackers/documentTracker.ts b/src/trackers/documentTracker.ts index 7d1f3310a6be3..ebba25002023a 100644 --- a/src/trackers/documentTracker.ts +++ b/src/trackers/documentTracker.ts @@ -394,7 +394,9 @@ export class DocumentTracker implements Disposable { if (this._documentMap.size === 0) return; for await (const doc of this._documentMap.values()) { - const repoPath = doc.uri.repoPath!.toLocaleLowerCase(); + const repoPath = doc.uri.repoPath?.toLocaleLowerCase(); + if (repoPath == null) continue; + if (changed?.removedRepoPaths?.has(repoPath)) { void this.remove(doc.document, doc); } else if (changed == null || changed?.addedOrChangedRepoPaths?.has(repoPath)) { From a56f87c57f524095d36335dd8e5843d1bc6ddf48 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 18:26:42 -0500 Subject: [PATCH 0238/1012] Fixes wrong char --- src/commands/switchMode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/switchMode.ts b/src/commands/switchMode.ts index e19ba1f84bb26..b1dc705f1ca09 100644 --- a/src/commands/switchMode.ts +++ b/src/commands/switchMode.ts @@ -21,7 +21,7 @@ export class SwitchModeCommand extends Command { const pick = await showModePicker(); if (pick === undefined) return; - setLogScopeExit(scope, ` \u2014 mode=${pick.key ?? ''}`); + setLogScopeExit(scope, ` \u2022 mode=${pick.key ?? ''}`); const active = configuration.get('mode.active'); if (active === pick.key) return; From c9a9929fef1264961b64c07b4009917e301486f8 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 18:27:02 -0500 Subject: [PATCH 0239/1012] Increases timeout since some requests can be slow --- src/webviews/webviewController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index d4c6702318c91..040c7d177324c 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -580,7 +580,7 @@ export class WebviewController< debugger; setLogScopeExit(scope, undefined, 'TIMEDOUT'); resolve(false); - }, 5000); + }, 30000); }), ]); From be50f2b3ed41fe0c834147fdf86d8b3d5a9852d1 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 18:26:24 -0500 Subject: [PATCH 0240/1012] Adds optional binary serialization to ipc messages - Improves performance on sending lots of data to the Graph --- src/plus/webviews/graph/protocol.ts | 8 +++- src/system/logger.scope.ts | 4 +- .../apps/commitDetails/commitDetails.ts | 7 +-- src/webviews/apps/home/home.ts | 8 +--- src/webviews/apps/plus/account/account.ts | 8 +--- src/webviews/apps/plus/focus/focus.ts | 7 ++- src/webviews/apps/plus/graph/graph.tsx | 40 ++++++++--------- .../apps/plus/patchDetails/patchDetails.ts | 7 +-- src/webviews/apps/plus/timeline/timeline.ts | 8 +--- src/webviews/apps/rebase/rebase.ts | 9 ++-- src/webviews/apps/settings/settings.ts | 8 +--- src/webviews/apps/shared/appBase.ts | 45 +++++++++++++++---- src/webviews/apps/welcome/welcome.ts | 8 +--- src/webviews/protocol.ts | 2 + src/webviews/webviewController.ts | 21 +++++++-- 15 files changed, 106 insertions(+), 84 deletions(-) diff --git a/src/plus/webviews/graph/protocol.ts b/src/plus/webviews/graph/protocol.ts index a5f6cd0263f2e..e3f07b98062da 100644 --- a/src/plus/webviews/graph/protocol.ts +++ b/src/plus/webviews/graph/protocol.ts @@ -309,7 +309,7 @@ export const UpdateSelectionCommandType = new IpcCommandType('graph/didChange', true); +export const DidChangeNotificationType = new IpcNotificationType('graph/didChange', true, true); export interface DidChangeGraphConfigurationParams { config: GraphComponentConfig; @@ -387,7 +387,11 @@ export interface DidChangeRowsParams { rowsStatsLoading: boolean; selectedRows?: GraphSelectedRows; } -export const DidChangeRowsNotificationType = new IpcNotificationType('graph/rows/didChange'); +export const DidChangeRowsNotificationType = new IpcNotificationType( + 'graph/rows/didChange', + undefined, + true, +); export interface DidChangeRowsStatsParams { rowsStats: Record; diff --git a/src/system/logger.scope.ts b/src/system/logger.scope.ts index 95d746af094a9..48e55b0243e2d 100644 --- a/src/system/logger.scope.ts +++ b/src/system/logger.scope.ts @@ -18,7 +18,9 @@ export function getLogScope(): LogScope | undefined { return scopes.get(scopeCounter); } -export function getNewLogScope(prefix: string): LogScope { +export function getNewLogScope(prefix: string, scope?: LogScope | undefined): LogScope { + if (scope != null) return { scopeId: scope.scopeId, prefix: `${scope.prefix}${prefix}` }; + const scopeId = getNextLogScopeId(); return { scopeId: scopeId, diff --git a/src/webviews/apps/commitDetails/commitDetails.ts b/src/webviews/apps/commitDetails/commitDetails.ts index 40526fc1a4ea2..f8be93a08c9b7 100644 --- a/src/webviews/apps/commitDetails/commitDetails.ts +++ b/src/webviews/apps/commitDetails/commitDetails.ts @@ -105,10 +105,7 @@ export class CommitDetailsApp extends App> { return disposables; } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { // case DidChangeRichStateNotificationType.method: // onIpc(DidChangeRichStateNotificationType, msg, params => { @@ -152,7 +149,7 @@ export class CommitDetailsApp extends App> { break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); } } diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index 349b65fbf2868..e3145bc55cb65 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -38,13 +38,9 @@ export class HomeApp extends App { return disposables; } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { case DidChangeRepositoriesType.method: - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - onIpc(DidChangeRepositoriesType, msg, params => { this.state.repositories = params; this.state.timestamp = Date.now(); @@ -53,7 +49,7 @@ export class HomeApp extends App { }); break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); break; } } diff --git a/src/webviews/apps/plus/account/account.ts b/src/webviews/apps/plus/account/account.ts index 74fc3d99493ae..cecc557358586 100644 --- a/src/webviews/apps/plus/account/account.ts +++ b/src/webviews/apps/plus/account/account.ts @@ -31,13 +31,9 @@ export class AccountApp extends App { return disposables; } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { case DidChangeSubscriptionNotificationType.method: - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - onIpc(DidChangeSubscriptionNotificationType, msg, params => { this.state.subscription = params.subscription; this.state.avatar = params.avatar; @@ -48,7 +44,7 @@ export class AccountApp extends App { break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); break; } } diff --git a/src/webviews/apps/plus/focus/focus.ts b/src/webviews/apps/plus/focus/focus.ts index dbe34377a7038..6a9b2bde89589 100644 --- a/src/webviews/apps/plus/focus/focus.ts +++ b/src/webviews/apps/plus/focus/focus.ts @@ -118,10 +118,7 @@ export class FocusApp extends App { } } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { case DidChangeNotificationType.method: onIpc(DidChangeNotificationType, msg, params => { @@ -130,6 +127,8 @@ export class FocusApp extends App { this.attachState(); }); break; + default: + super.onMessageReceived?.(msg); } } } diff --git a/src/webviews/apps/plus/graph/graph.tsx b/src/webviews/apps/plus/graph/graph.tsx index 5286b96494fb6..fdee004469991 100644 --- a/src/webviews/apps/plus/graph/graph.tsx +++ b/src/webviews/apps/plus/graph/graph.tsx @@ -51,7 +51,9 @@ import { UpdateSelectionCommandType, } from '../../../../plus/webviews/graph/protocol'; import { Color, darken, getCssVariable, lighten, mix, opacity } from '../../../../system/color'; +import { debug } from '../../../../system/decorators/log'; import { debounce } from '../../../../system/function'; +import { getLogScope, setLogScopeExit } from '../../../../system/logger.scope'; import type { IpcMessage, IpcNotificationType } from '../../../protocol'; import { onIpc } from '../../../protocol'; import { App } from '../../shared/appBase'; @@ -73,7 +75,7 @@ const graphLaneThemeColors = new Map([ ]); export class GraphApp extends App { - private callback?: UpdateStateCallback; + private updateStateCallback?: UpdateStateCallback; constructor() { super('GraphApp'); @@ -93,7 +95,7 @@ export class GraphApp extends App { this.registerEvents(callback)} + subscriber={(updateState: UpdateStateCallback) => this.registerUpdateStateCallback(updateState)} onColumnsChange={debounce( settings => this.onColumnsChanged(settings), 250, @@ -139,14 +141,13 @@ export class GraphApp extends App { // } // } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); + protected override onMessageReceived(msg: IpcMessage) { + const scope = getLogScope(); switch (msg.method) { case DidChangeNotificationType.method: onIpc(DidChangeNotificationType, msg, (params, type) => { - this.setState({ ...this.state, ...params.state }, type); + this.setState({ ...this.state, ...params }, type); }); break; @@ -215,7 +216,8 @@ export class GraphApp extends App { const newRowsLength = params.rows.length; this.log( - `onMessageReceived(${msg.id}:${msg.method}): paging in ${newRowsLength} rows into existing ${previousRowsLength} rows at ${params.paging.startingCursor} (last existing row: ${lastId})`, + scope, + `paging in ${newRowsLength} rows into existing ${previousRowsLength} rows at ${params.paging.startingCursor} (last existing row: ${lastId})`, ); rows = []; @@ -223,18 +225,14 @@ export class GraphApp extends App { rows.length = previousRowsLength + newRowsLength; if (params.paging.startingCursor !== lastId) { - this.log( - `onMessageReceived(${msg.id}:${msg.method}): searching for ${params.paging.startingCursor} in existing rows`, - ); + this.log(scope, `searching for ${params.paging.startingCursor} in existing rows`); let i = 0; let row; for (row of previousRows) { rows[i++] = row; if (row.sha === params.paging.startingCursor) { - this.log( - `onMessageReceived(${msg.id}:${msg.method}): found ${params.paging.startingCursor} in existing rows`, - ); + this.log(scope, `found ${params.paging.startingCursor} in existing rows`); previousRowsLength = i; @@ -256,7 +254,7 @@ export class GraphApp extends App { rows[previousRowsLength + i] = params.rows[i]; } } else { - this.log(`onMessageReceived(${msg.id}:${msg.method}): setting to ${params.rows.length} rows`); + this.log(scope, `setting to ${params.rows.length} rows`); if (params.rows.length === 0) { rows = this.state.rows; @@ -281,6 +279,8 @@ export class GraphApp extends App { } this.state.loading = false; this.setState(this.state, type); + + setLogScopeExit(scope, ` \u2022 rows=${this.state.rows?.length ?? 0}`); }); break; @@ -339,7 +339,7 @@ export class GraphApp extends App { break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); } } @@ -474,14 +474,14 @@ export class GraphApp extends App { this.setState(this.state, 'didChangeTheme'); } + @debug({ args: false, singleLine: true }) protected override setState(state: State, type?: IpcNotificationType | InternalNotificationType) { - this.log(`setState()`); const themingChanged = this.ensureTheming(state); this.state = state; super.setState({ timestamp: state.timestamp, selectedRepository: state.selectedRepository }); - this.callback?.(this.state, type, themingChanged); + this.updateStateCallback?.(this.state, type, themingChanged); } private ensureTheming(state: State): boolean { @@ -691,11 +691,11 @@ export class GraphApp extends App { }); } - private registerEvents(callback: UpdateStateCallback): () => void { - this.callback = callback; + private registerUpdateStateCallback(updateState: UpdateStateCallback): () => void { + this.updateStateCallback = updateState; return () => { - this.callback = undefined; + this.updateStateCallback = undefined; }; } } diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.ts b/src/webviews/apps/plus/patchDetails/patchDetails.ts index f3a9a682199f8..09da58735b1dc 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.ts +++ b/src/webviews/apps/plus/patchDetails/patchDetails.ts @@ -135,10 +135,7 @@ export class PatchDetailsApp extends App> { return disposables; } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { // case DidChangeRichStateNotificationType.method: // onIpc(DidChangeRichStateNotificationType, msg, params => { @@ -222,7 +219,7 @@ export class PatchDetailsApp extends App> { break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); } } diff --git a/src/webviews/apps/plus/timeline/timeline.ts b/src/webviews/apps/plus/timeline/timeline.ts index a0978119ffd41..9c656aefddf95 100644 --- a/src/webviews/apps/plus/timeline/timeline.ts +++ b/src/webviews/apps/plus/timeline/timeline.ts @@ -48,13 +48,9 @@ export class TimelineApp extends App { return disposables; } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { case DidChangeNotificationType.method: - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - onIpc(DidChangeNotificationType, msg, params => { this.state = params.state; this.setState(this.state); @@ -63,7 +59,7 @@ export class TimelineApp extends App { break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); } } diff --git a/src/webviews/apps/rebase/rebase.ts b/src/webviews/apps/rebase/rebase.ts index 4ed4df5adde09..193d4281dccde 100644 --- a/src/webviews/apps/rebase/rebase.ts +++ b/src/webviews/apps/rebase/rebase.ts @@ -1,6 +1,7 @@ /*global document window*/ import './rebase.scss'; import Sortable from 'sortablejs'; +import type { IpcMessage } from '../../protocol'; import { onIpc } from '../../protocol'; import type { RebaseEntry, RebaseEntryAction, State } from '../../rebase/protocol'; import { @@ -318,13 +319,9 @@ class RebaseEditor extends App { }); } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data; - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { case DidChangeNotificationType.method: - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - onIpc(DidChangeNotificationType, msg, params => { this.state = params.state; this.setState(this.state); @@ -333,7 +330,7 @@ class RebaseEditor extends App { break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); } } diff --git a/src/webviews/apps/settings/settings.ts b/src/webviews/apps/settings/settings.ts index f70f186b686bb..2fae79ca789ee 100644 --- a/src/webviews/apps/settings/settings.ts +++ b/src/webviews/apps/settings/settings.ts @@ -133,11 +133,7 @@ export class SettingsApp extends App { return disposables; } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { case DidOpenAnchorNotificationType.method: { onIpc(DidOpenAnchorNotificationType, msg, params => { @@ -157,7 +153,7 @@ export class SettingsApp extends App { break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); } } diff --git a/src/webviews/apps/shared/appBase.ts b/src/webviews/apps/shared/appBase.ts index 3ee4b29f9eca5..90e8a7c5271fc 100644 --- a/src/webviews/apps/shared/appBase.ts +++ b/src/webviews/apps/shared/appBase.ts @@ -1,7 +1,11 @@ /*global window document*/ import type { CustomEditorIds, WebviewIds, WebviewViewIds } from '../../../constants'; +import { debug } from '../../../system/decorators/log'; import { debounce } from '../../../system/function'; import { Logger } from '../../../system/logger'; +import type { LogScope } from '../../../system/logger.scope'; +import { getLogScope, getNewLogScope } from '../../../system/logger.scope'; +import { maybeStopWatch } from '../../../system/stopwatch'; import type { IpcCommandType, IpcMessage, @@ -38,6 +42,8 @@ function nextIpcId() { return `webview:${ipcSequence}`; } +const textDecoder = new TextDecoder(); + export abstract class App< State extends { webviewId: CustomEditorIds | WebviewIds | WebviewViewIds; timestamp: number } = { webviewId: CustomEditorIds | WebviewIds | WebviewViewIds; @@ -77,7 +83,7 @@ export abstract class App< DEBUG ? 'debug' : 'off', ); - this.log(`ctor()`); + this.log(`${appName}()`); // this.log(`ctor(${this.state ? JSON.stringify(this.state) : ''})`); this._api = acquireVsCodeApi(); @@ -93,14 +99,14 @@ export abstract class App< disposables.push(watchThemeColors()); requestAnimationFrame(() => { - this.log(`ctor(): initializing...`); + this.log(`${appName}(): initializing...`); try { this.onInitialize?.(); this.bind(); if (this.onMessageReceived != null) { - disposables.push(DOM.on(window, 'message', this.onMessageReceived.bind(this))); + disposables.push(DOM.on(window, 'message', e => this.onMessageReceivedCore(e))); } this.sendCommand(WebviewReadyCommandType, undefined); @@ -127,9 +133,26 @@ export abstract class App< protected onInitialize?(): void; protected onBind?(): Disposable[]; protected onInitialized?(): void; - protected onMessageReceived?(e: MessageEvent): void; + protected onMessageReceived?(msg: IpcMessage): void; protected onThemeUpdated?(e: ThemeChangeEvent): void; + @debug({ args: { 0: e => `${e.data.id}, method=${e.data.method}` } }) + private onMessageReceivedCore(e: MessageEvent) { + const scope = getLogScope(); + + const msg = e.data as IpcMessage; + if (msg.packed && msg.params instanceof Uint8Array) { + const sw = maybeStopWatch(getNewLogScope(` deserializing msg=${e.data.method}`, scope), { + log: false, + logLevel: 'debug', + }); + msg.params = JSON.parse(textDecoder.decode(msg.params)); + sw?.stop(); + } + + this.onMessageReceived!(msg); + } + private _focused?: boolean; private _inputFocused?: boolean; @@ -166,8 +189,14 @@ export abstract class App< ); } - protected log(message: string, ...optionalParams: any[]) { - Logger.log(message, ...optionalParams); + protected log(message: string, ...optionalParams: any[]): void; + protected log(scope: LogScope | undefined, message: string, ...optionalParams: any[]): void; + protected log(scopeOrMessage: LogScope | string | undefined, ...optionalParams: any[]): void { + if (typeof scopeOrMessage === 'string') { + Logger.log(scopeOrMessage, ...optionalParams); + } else { + Logger.log(scopeOrMessage, optionalParams.shift(), ...optionalParams); + } } protected getState(): State | undefined { @@ -179,7 +208,7 @@ export abstract class App< params: IpcMessageParams, ): void { const id = nextIpcId(); - this.log(`sendCommand(${id}): name=${command.method}`); + this.log(`${this.appName}.sendCommand(${id}): name=${command.method}`); this.postMessage({ id: id, method: command.method, params: params }); } @@ -193,7 +222,7 @@ export abstract class App< completion: TCompletion, ): Promise> { const id = nextIpcId(); - this.log(`sendCommandWithCompletion(${id}): name=${command.method}`); + this.log(`${this.appName}.sendCommandWithCompletion(${id}): name=${command.method}`); const promise = new Promise>((resolve, reject) => { let timeout: ReturnType | undefined; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index da127c4053c74..523bbc78e97b7 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -41,13 +41,9 @@ export class WelcomeApp extends App { return disposables; } - protected override onMessageReceived(e: MessageEvent) { - const msg = e.data as IpcMessage; - + protected override onMessageReceived(msg: IpcMessage) { switch (msg.method) { case DidChangeNotificationType.method: - this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); - onIpc(DidChangeNotificationType, msg, params => { this.state = params.state; this.setState(this.state); @@ -55,7 +51,7 @@ export class WelcomeApp extends App { }); break; default: - super.onMessageReceived?.(e); + super.onMessageReceived?.(msg); break; } } diff --git a/src/webviews/protocol.ts b/src/webviews/protocol.ts index c91235e320675..178dc11f0055f 100644 --- a/src/webviews/protocol.ts +++ b/src/webviews/protocol.ts @@ -5,6 +5,7 @@ import type { ConfigPath, ConfigPathValue, Path, PathValue } from '../system/con export interface IpcMessage { id: string; method: string; + packed?: boolean; params?: unknown; completionId?: string; } @@ -14,6 +15,7 @@ abstract class IpcMessageType { constructor( public readonly method: string, public readonly reset: boolean = false, + public readonly pack: boolean = false, ) {} } export type IpcMessageParams = T extends IpcMessageType ? P : never; diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 040c7d177324c..1b89a40cf494a 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -9,8 +9,9 @@ import { setContext } from '../system/context'; import { debug, logName } from '../system/decorators/log'; import { serialize } from '../system/decorators/serialize'; import { Logger } from '../system/logger'; -import { getLogScope, setLogScopeExit } from '../system/logger.scope'; +import { getLogScope, getNewLogScope, setLogScopeExit } from '../system/logger.scope'; import { isPromise } from '../system/promise'; +import { maybeStopWatch } from '../system/stopwatch'; import type { WebviewContext } from '../system/webview'; import type { IpcMessage, @@ -25,6 +26,7 @@ import type { WebviewPanelDescriptor, WebviewShowOptions, WebviewViewDescriptor const maxSmallIntegerV8 = 2 ** 30; // Max number that can be stored in V8's smis (small integers) const utf8TextDecoder = new TextDecoder('utf8'); +const utf8TextEncoder = new TextEncoder(); let ipcSequence = 0; function nextIpcId() { @@ -385,7 +387,7 @@ export class WebviewController< } @debug['onMessageReceivedCore']>({ - args: { 0: e => (e != null ? `${e.id}: method=${e.method}` : '') }, + args: { 0: e => (e != null ? `${e.id}, method=${e.method}` : '') }, }) private onMessageReceivedCore(e: IpcMessage) { if (e == null) return; @@ -534,10 +536,23 @@ export class WebviewController< params: IpcMessageParams, completionId?: string, ): Promise { + let packed; + if (type.pack && params != null) { + const scope = getLogScope(); + + const sw = maybeStopWatch(getNewLogScope(` serializing msg=${type.method}`, scope), { + log: false, + logLevel: 'debug', + }); + packed = utf8TextEncoder.encode(JSON.stringify(params)); + sw?.stop(); + } + const msg: IpcMessage = { id: this.nextIpcId(), method: type.method, - params: params, + params: packed ?? params, + packed: packed != null, completionId: completionId, }; From 1eb9f49904c81b9915c6e7502ea999362771ef0e Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 23:14:32 -0500 Subject: [PATCH 0241/1012] Fixes #3018 escapes () in markdown command links --- CHANGELOG.md | 4 ++++ src/commands/base.ts | 3 ++- src/git/formatters/commitFormatter.ts | 3 ++- src/git/models/reference.ts | 6 +++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc148d942ba81..32092bc2aee14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Refines AI prompts to provide better commit message generation and explanation results +### Fixed + +- Fixes [#3018](https://github.com/gitkraken/vscode-gitlens/issues/3018) - Line blame overlay is broken when commit message contains a `)` + ## [14.5.0] - 2023-11-13 ### Added diff --git a/src/commands/base.ts b/src/commands/base.ts index f695b2d0021ae..b60d1aede3952 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -285,7 +285,8 @@ export abstract class Command implements Disposable { command: Commands | `${Commands.ActionPrefix}${ActionContext['type']}`, args: T, ): string { - return `command:${command}?${encodeURIComponent(JSON.stringify(args))}`; + // Since we are using the command in a markdown link, we need to escape ()'s so they don't get interpreted as markdown + return `command:${command}?${encodeURIComponent(JSON.stringify(args)).replace(/([()])/g, '\\$1')}`; } protected readonly contextParsingOptions: CommandContextParsingOptions = { expectsEditor: false }; diff --git a/src/git/formatters/commitFormatter.ts b/src/git/formatters/commitFormatter.ts index 370e228c9561d..27608fb126b32 100644 --- a/src/git/formatters/commitFormatter.ts +++ b/src/git/formatters/commitFormatter.ts @@ -438,7 +438,8 @@ export class CommitFormatter extends Formatter { if (arePlusFeaturesEnabled()) { commands += `  [$(gitlens-graph)](${Command.getMarkdownCommandArgsCore( Commands.ShowInCommitGraph, - { ref: getReferenceFromRevision(this._item) }, + // Avoid including the message here, it just bloats the command url + { ref: getReferenceFromRevision(this._item, { excludeMessage: true }) }, )} "Open in Commit Graph")`; } diff --git a/src/git/models/reference.ts b/src/git/models/reference.ts index b6cab92dd6a5b..43fa67a57a4ad 100644 --- a/src/git/models/reference.ts +++ b/src/git/models/reference.ts @@ -233,20 +233,20 @@ export function getReferenceFromBranch(branch: GitBranchReference) { }); } -export function getReferenceFromRevision(revision: GitRevisionReference) { +export function getReferenceFromRevision(revision: GitRevisionReference, options?: { excludeMessage?: boolean }) { if (revision.refType === 'stash') { return createReference(revision.ref, revision.repoPath, { refType: revision.refType, name: revision.name, number: revision.number, - message: revision.message, + message: options?.excludeMessage ? undefined : revision.message, }); } return createReference(revision.ref, revision.repoPath, { refType: revision.refType, name: revision.name, - message: revision.message, + message: options?.excludeMessage ? undefined : revision.message, }); } From 7a534db6dcb53a0131b551957a8f2c2137063c35 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 15 Nov 2023 23:15:19 -0500 Subject: [PATCH 0242/1012] Updates CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32092bc2aee14..67d10b9b68a73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed +- Improves the performance of the _Commit Graph_ when loading a large number of commits - Refines AI prompts to provide better commit message generation and explanation results ### Fixed From 7346bde3f1e84eab0645543d0ecb37b0c22e48f7 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 16 Nov 2023 00:08:53 -0500 Subject: [PATCH 0243/1012] Slims lint rules & switches to bundler module res --- .eslintrc.base.json | 42 ++++++++++++++++++------------ package.json | 1 + src/test/suite/system/trie.test.ts | 1 - src/webviews/apps/.eslintrc.json | 9 ------- tsconfig.base.json | 2 +- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/.eslintrc.base.json b/.eslintrc.base.json index 5427199841601..83577746fc704 100644 --- a/.eslintrc.base.json +++ b/.eslintrc.base.json @@ -5,7 +5,6 @@ "extends": [ "eslint:recommended", "plugin:@typescript-eslint/strict-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", "plugin:import/recommended", "plugin:import/typescript", "prettier" @@ -24,25 +23,17 @@ "root": true, "rules": { "anti-trojan-source/no-bidi": "error", - "arrow-parens": ["off"], - "brace-style": ["off", "stroustrup"], - "consistent-return": "off", - "curly": ["error", "multi-line", "consistent"], - "eol-last": "error", - "linebreak-style": ["error", "unix"], - "new-parens": "error", - "no-console": "off", "no-constant-condition": ["warn", { "checkLoops": false }], "no-constant-binary-expression": "error", "no-caller": "error", "no-debugger": "off", - "no-dupe-class-members": "off", "no-else-return": "warn", "no-empty": ["warn", { "allowEmptyCatch": true }], "no-eval": "error", "no-ex-assign": "warn", "no-extend-native": "error", "no-extra-bind": "error", + "no-extra-semi": "off", "no-floating-decimal": "error", "no-implicit-coercion": "error", "no-implied-eval": "error", @@ -50,7 +41,7 @@ "no-lone-blocks": "error", "no-lonely-if": "error", "no-loop-func": "error", - "no-multi-spaces": "error", + "no-mixed-spaces-and-tabs": "off", "no-restricted-globals": ["error", "process"], "no-restricted-imports": [ "error", @@ -98,8 +89,13 @@ "message": "Use @env/ instead" }, { - "group": ["src/**/*"], + "group": ["src/*"], "message": "Use relative paths instead" + }, + { + "group": ["react-dom"], + "importNames": ["Container"], + "message": "Use our Container instead" } ] } @@ -138,10 +134,7 @@ "prefer-rest-params": "error", "prefer-spread": "error", "prefer-template": "error", - "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }], "require-atomic-updates": "off", - "semi": ["error", "always"], - "semi-style": ["error", "last"], "sort-imports": [ "error", { @@ -153,7 +146,7 @@ ], "yoda": "error", "import/consistent-type-specifier-style": ["error", "prefer-top-level"], - "import/extensions": ["error", "never"], + "import/extensions": "off", "import/newline-after-import": "warn", "import/no-absolute-path": "error", "import/no-cycle": "off", @@ -326,7 +319,22 @@ { "files": ["src/env/node/**/*"], "rules": { - "no-restricted-imports": "off" + "no-restricted-imports": [ + "error", + { + "patterns": [ + { + "group": ["src/*"], + "message": "Use relative paths instead" + }, + { + "group": ["react-dom"], + "importNames": ["Container"], + "message": "Use our Container instead" + } + ] + } + ] } } ] diff --git a/package.json b/package.json index 35b3547a8318f..3b90398bbad12 100644 --- a/package.json +++ b/package.json @@ -15739,6 +15739,7 @@ "patch-pre": "node ./scripts/applyPreReleasePatch.js", "prep-release": "node ./scripts/prep-release.js", "pretty": "prettier --config .prettierrc --log-level warn --write .", + "pretty:check": "prettier --config .prettierrc --check .", "pub": "vsce publish --yarn", "pub-pre": "vsce publish --yarn --pre-release", "rebuild": "yarn run reset && yarn run build", diff --git a/src/test/suite/system/trie.test.ts b/src/test/suite/system/trie.test.ts index 70867e0f662da..73e95b903419f 100644 --- a/src/test/suite/system/trie.test.ts +++ b/src/test/suite/system/trie.test.ts @@ -5,7 +5,6 @@ import { isLinux } from '../../../env/node/platform'; import { normalizeRepoUri } from '../../../repositories'; import type { UriEntry } from '../../../system/trie'; import { PathEntryTrie, UriEntryTrie, UriTrie } from '../../../system/trie'; -// eslint-disable-next-line import/extensions import paths from './paths.json'; describe('PathEntryTrie Test Suite', () => { diff --git a/src/webviews/apps/.eslintrc.json b/src/webviews/apps/.eslintrc.json index b2ea94ebb0f79..db4dddde1ba60 100644 --- a/src/webviews/apps/.eslintrc.json +++ b/src/webviews/apps/.eslintrc.json @@ -3,15 +3,6 @@ "env": { "browser": true }, - "rules": { - "import/extensions": [ - "error", - "never", - { - "js": "always" - } - ] - }, "parserOptions": { "project": "src/webviews/apps/tsconfig.json" }, diff --git a/tsconfig.base.json b/tsconfig.base.json index 4c5295e11e13b..31cd77e086c98 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -8,7 +8,7 @@ "isolatedModules": true, "lib": ["es2022", "esnext.disposable"], "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "Bundler", "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, From 021dbdc719d432023a9c0ac339c2f5f702843317 Mon Sep 17 00:00:00 2001 From: Ramin Tadayon Date: Thu, 16 Nov 2023 10:13:34 -0700 Subject: [PATCH 0244/1012] Fixes provider typing in cloud workspace model --- src/plus/workspaces/models.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plus/workspaces/models.ts b/src/plus/workspaces/models.ts index 74b4391238bf4..564ec8dcc46ac 100644 --- a/src/plus/workspaces/models.ts +++ b/src/plus/workspaces/models.ts @@ -1,7 +1,6 @@ import type { Disposable } from '../../api/gitlens'; import type { Container } from '../../container'; import type { Repository } from '../../git/models/repository'; -import type { GkProviderId } from '../../gk/models/repositoryIdentities'; export type WorkspaceType = 'cloud' | 'local'; export type WorkspaceAutoAddSetting = 'disabled' | 'enabled' | 'prompt'; @@ -150,7 +149,7 @@ export interface CloudWorkspaceRepositoryDescriptor { name: string; description: string; repository_id: string; - provider: GkProviderId | null; + provider: CloudWorkspaceProviderType | null; provider_project_name: string | null; provider_organization_id: string; provider_organization_name: string | null; @@ -318,7 +317,7 @@ export interface CloudWorkspaceRepositoryData { name: string; description: string; repository_id: string; - provider: GkProviderId | null; + provider: CloudWorkspaceProviderType | null; provider_project_name: string | null; provider_organization_id: string; provider_organization_name: string | null; From 81c0a12e3a39c791278fa86a410ce0530c6d8a6d Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 16 Nov 2023 12:35:40 -0500 Subject: [PATCH 0245/1012] Fixes #2625 unescapes markdown for url --- CHANGELOG.md | 1 + src/git/remotes/github.ts | 6 ++++-- src/git/remotes/gitlab.ts | 6 ++++-- src/system/string.ts | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67d10b9b68a73..993438dc7b920 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Fixed - Fixes [#3018](https://github.com/gitkraken/vscode-gitlens/issues/3018) - Line blame overlay is broken when commit message contains a `)` +- Fixes [#2625](https://github.com/gitkraken/vscode-gitlens/issues/2625) - full issue ref has escape characters that break hover links ## [14.5.0] - 2023-11-13 diff --git a/src/git/remotes/github.ts b/src/git/remotes/github.ts index cab81987087bf..1edc7b78cbf29 100644 --- a/src/git/remotes/github.ts +++ b/src/git/remotes/github.ts @@ -14,7 +14,7 @@ import { fromNow } from '../../system/date'; import { log } from '../../system/decorators/log'; import { memoize } from '../../system/decorators/memoize'; import { encodeUrl } from '../../system/encoding'; -import { equalsIgnoreCase, escapeMarkdown } from '../../system/string'; +import { equalsIgnoreCase, escapeMarkdown, unescapeMarkdown } from '../../system/string'; import { supportedInVSCodeVersion } from '../../system/utils'; import type { Account } from '../models/author'; import type { DefaultBranch } from '../models/defaultBranch'; @@ -97,7 +97,9 @@ export class GitHubRemote extends RichRemoteProvider return outputFormat === 'plaintext' ? text : text.replace(autolinkFullIssuesRegex, (linkText: string, repo: string, num: string) => { - const url = encodeUrl(`${this.protocol}://${this.domain}/${repo}/issues/${num}`); + const url = encodeUrl( + `${this.protocol}://${this.domain}/${unescapeMarkdown(repo)}/issues/${num}`, + ); const title = ` "Open Issue or Pull Request #${num} from ${repo} on ${this.name}"`; const token = `\x00${tokenMapping.size}\x00`; diff --git a/src/git/remotes/gitlab.ts b/src/git/remotes/gitlab.ts index 55ef6ab86e680..2550889e831ff 100644 --- a/src/git/remotes/gitlab.ts +++ b/src/git/remotes/gitlab.ts @@ -13,7 +13,7 @@ import type { Brand, Unbrand } from '../../system/brand'; import { fromNow } from '../../system/date'; import { log } from '../../system/decorators/log'; import { encodeUrl } from '../../system/encoding'; -import { equalsIgnoreCase, escapeMarkdown } from '../../system/string'; +import { equalsIgnoreCase, escapeMarkdown, unescapeMarkdown } from '../../system/string'; import { supportedInVSCodeVersion } from '../../system/utils'; import type { Account } from '../models/author'; import type { DefaultBranch } from '../models/defaultBranch'; @@ -96,7 +96,9 @@ export class GitLabRemote extends RichRemoteProvider return outputFormat === 'plaintext' ? text : text.replace(autolinkFullIssuesRegex, (linkText: string, repo: string, num: string) => { - const url = encodeUrl(`${this.protocol}://${this.domain}/${repo}/-/issues/${num}`); + const url = encodeUrl( + `${this.protocol}://${this.domain}/${unescapeMarkdown(repo)}/-/issues/${num}`, + ); const title = ` "Open Issue #${num} from ${repo} on ${this.name}"`; const token = `\x00${tokenMapping.size}\x00`; diff --git a/src/system/string.ts b/src/system/string.ts index 6129fa19a3280..f92bfb1575d8a 100644 --- a/src/system/string.ts +++ b/src/system/string.ts @@ -126,7 +126,11 @@ export function encodeHtmlWeak(s: string | undefined): string | undefined { } const escapeMarkdownRegex = /[\\`*_{}[\]()#+\-.!]/g; +const unescapeMarkdownRegex = /\\([\\`*_{}[\]()#+\-.!])/g; + const escapeMarkdownHeaderRegex = /^===/gm; +const unescapeMarkdownHeaderRegex = /^\u200b===/gm; + // const sampleMarkdown = '## message `not code` *not important* _no underline_ \n> don\'t quote me \n- don\'t list me \n+ don\'t list me \n1. don\'t list me \nnot h1 \n=== \nnot h2 \n---\n***\n---\n___'; const markdownQuotedRegex = /\r?\n/g; @@ -143,6 +147,16 @@ export function escapeMarkdown(s: string, options: { quoted?: boolean } = {}): s return s.trim().replace(markdownQuotedRegex, '\t\\\n> '); } +export function unescapeMarkdown(s: string): string { + return ( + s + // Unescape markdown + .replace(unescapeMarkdownRegex, '$1') + // Unescape markdown header + .replace(unescapeMarkdownHeaderRegex, '===') + ); +} + export function escapeRegex(s: string) { return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } From 466a5aa30c1ec3987d94bc24576a46fd5267732c Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Nov 2023 17:11:09 -0500 Subject: [PATCH 0246/1012] Refines AI limits & retries --- src/ai/aiProviderService.ts | 40 ++++++ src/ai/anthropicProvider.ts | 180 ++++++++++++++------------ src/ai/openaiProvider.ts | 251 +++++++++++++++++++----------------- 3 files changed, 270 insertions(+), 201 deletions(-) diff --git a/src/ai/aiProviderService.ts b/src/ai/aiProviderService.ts index d48b42c2ddeb8..1e44ef9168cd2 100644 --- a/src/ai/aiProviderService.ts +++ b/src/ai/aiProviderService.ts @@ -10,7 +10,9 @@ import type { Repository } from '../git/models/repository'; import { isRepository } from '../git/models/repository'; import { configuration } from '../system/configuration'; import type { Storage } from '../system/storage'; +import type { AnthropicModels } from './anthropicProvider'; import { AnthropicProvider } from './anthropicProvider'; +import type { OpenAIModels } from './openaiProvider'; import { OpenAIProvider } from './openaiProvider'; export interface AIProvider extends Disposable { @@ -192,3 +194,41 @@ async function confirmAIProviderToS(provider: AIProvider, storage: Storage): Pro return false; } + +export function getMaxCharacters(model: OpenAIModels | AnthropicModels, outputLength: number): number { + const tokensPerCharacter = 3.1; + + let tokens; + switch (model) { + case 'gpt-4-1106-preview': // 128,000 tokens (4,096 max output tokens) + tokens = 128000; + break; + case 'gpt-4-32k': // 32,768 tokens + case 'gpt-4-32k-0613': + tokens = 32768; + break; + case 'gpt-4': // 8,192 tokens + case 'gpt-4-0613': + tokens = 8192; + break; + case 'gpt-3.5-turbo-1106': // 16,385 tokens (4,096 max output tokens) + tokens = 16385; + break; + case 'gpt-3.5-turbo-16k': // 16,385 tokens; Will point to gpt-3.5-turbo-1106 starting Dec 11, 2023 + tokens = 16385; + break; + case 'gpt-3.5-turbo': // Will point to gpt-3.5-turbo-1106 starting Dec 11, 2023 + tokens = 4096; + break; + case 'claude-2': // 100,000 tokens + case 'claude-instant-1': + tokens = 100000; + break; + default: // 4,096 tokens + tokens = 4096; + break; + } + + const max = tokens * tokensPerCharacter - outputLength / tokensPerCharacter; + return Math.floor(max - max * 0.1); +} diff --git a/src/ai/anthropicProvider.ts b/src/ai/anthropicProvider.ts index da9970c239549..1823c1f0172a6 100644 --- a/src/ai/anthropicProvider.ts +++ b/src/ai/anthropicProvider.ts @@ -5,7 +5,8 @@ import type { Container } from '../container'; import { configuration } from '../system/configuration'; import type { Storage } from '../system/storage'; import { supportedInVSCodeVersion } from '../system/utils'; -import type { AIProvider } from './aiProviderService'; +import type {AIProvider} from './aiProviderService'; +import { getMaxCharacters } from './aiProviderService'; export class AnthropicProvider implements AIProvider { readonly id = 'anthropic'; @@ -24,21 +25,18 @@ export class AnthropicProvider implements AIProvider { if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model, 1600); - const code = diff.substring(0, maxCodeCharacters); - if (diff.length > maxCodeCharacters) { - void window.showWarningMessage( - `The diff of the staged changes had to be truncated to ${maxCodeCharacters} characters to fit within the Anthropic's limits.`, - ); - } + let retries = 0; + let maxCodeCharacters = getMaxCharacters(model, 2600); + while (true) { + const code = diff.substring(0, maxCodeCharacters); - let customPrompt = configuration.get('experimental.generateCommitMessagePrompt'); - if (!customPrompt.endsWith('.')) { - customPrompt += '.'; - } + let customPrompt = configuration.get('experimental.generateCommitMessagePrompt'); + if (!customPrompt.endsWith('.')) { + customPrompt += '.'; + } - const prompt = `\n\nHuman: You are an advanced AI programming assistant tasked with summarizing code changes into a concise and meaningful commit message. Compose a commit message that: + const prompt = `\n\nHuman: You are an advanced AI programming assistant tasked with summarizing code changes into a concise and meaningful commit message. Compose a commit message that: - Strictly synthesizes meaningful information from the provided code diff - Utilizes any additional user-provided context to comprehend the rationale behind the code changes - Is clear and brief, with an informal yet professional tone, and without superfluous descriptions @@ -62,31 +60,48 @@ Human: ${customPrompt} Assistant:`; - const request: AnthropicCompletionRequest = { - model: model, - prompt: prompt, - stream: false, - max_tokens_to_sample: 5000, - stop_sequences: ['\n\nHuman:'], - }; - const rsp = await this.fetch(apiKey, request); - if (!rsp.ok) { - let json; - try { - json = (await rsp.json()) as { error: { type: string; message: string } } | undefined; - } catch {} - - debugger; - throw new Error( - `Unable to generate commit message: (${this.name}:${rsp.status}) ${ - json?.error.message || rsp.statusText - })`, - ); - } + const request: AnthropicCompletionRequest = { + model: model, + prompt: prompt, + stream: false, + max_tokens_to_sample: 5000, + stop_sequences: ['\n\nHuman:'], + }; + const rsp = await this.fetch(apiKey, request); + if (!rsp.ok) { + let json; + try { + json = (await rsp.json()) as { error?: { type: string; message: string } } | undefined; + } catch {} + + debugger; + + if ( + retries++ < 2 && + json?.error?.type === 'invalid_request_error' && + json?.error?.message?.includes('prompt is too long') + ) { + maxCodeCharacters -= 500 * retries; + continue; + } + + throw new Error( + `Unable to generate commit message: (${this.name}:${rsp.status}) ${ + json?.error?.message || rsp.statusText + })`, + ); + } - const data: AnthropicCompletionResponse = await rsp.json(); - const message = data.completion.trim(); - return message; + if (diff.length > maxCodeCharacters) { + void window.showWarningMessage( + `The diff of the staged changes had to be truncated to ${maxCodeCharacters} characters to fit within the Anthropic's limits.`, + ); + } + + const data: AnthropicCompletionResponse = await rsp.json(); + const message = data.completion.trim(); + return message; + } } async explainChanges(message: string, diff: string): Promise { @@ -94,16 +109,13 @@ Assistant:`; if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model, 2400); - const code = diff.substring(0, maxCodeCharacters); - if (diff.length > maxCodeCharacters) { - void window.showWarningMessage( - `The diff of the commit changes had to be truncated to ${maxCodeCharacters} characters to fit within the OpenAI's limits.`, - ); - } + let retries = 0; + let maxCodeCharacters = getMaxCharacters(model, 3000); + while (true) { + const code = diff.substring(0, maxCodeCharacters); - const prompt = `\n\nHuman: You are an advanced AI programming assistant tasked with summarizing code changes into an explanation that is both easy to understand and meaningful. Construct an explanation that: + const prompt = `\n\nHuman: You are an advanced AI programming assistant tasked with summarizing code changes into an explanation that is both easy to understand and meaningful. Construct an explanation that: - Concisely synthesizes meaningful information from the provided code diff - Incorporates any additional context provided by the user to understand the rationale behind the code changes - Places the emphasis on the 'why' of the change, clarifying its benefits or addressing the problem that necessitated the change, beyond just detailing the 'what' has changed @@ -122,30 +134,47 @@ Human: Remember to frame your explanation in a way that is suitable for a review Assistant:`; - const request: AnthropicCompletionRequest = { - model: model, - prompt: prompt, - stream: false, - max_tokens_to_sample: 5000, - stop_sequences: ['\n\nHuman:'], - }; - - const rsp = await this.fetch(apiKey, request); - if (!rsp.ok) { - let json; - try { - json = (await rsp.json()) as { error: { type: string; message: string } } | undefined; - } catch {} - - debugger; - throw new Error( - `Unable to explain commit: (${this.name}:${rsp.status}) ${json?.error.message || rsp.statusText})`, - ); - } + const request: AnthropicCompletionRequest = { + model: model, + prompt: prompt, + stream: false, + max_tokens_to_sample: 5000, + stop_sequences: ['\n\nHuman:'], + }; + + const rsp = await this.fetch(apiKey, request); + if (!rsp.ok) { + let json; + try { + json = (await rsp.json()) as { error?: { type: string; message: string } } | undefined; + } catch {} + + debugger; + + if ( + retries++ < 2 && + json?.error?.type === 'invalid_request_error' && + json?.error?.message?.includes('prompt is too long') + ) { + maxCodeCharacters -= 500 * retries; + continue; + } + + throw new Error( + `Unable to explain commit: (${this.name}:${rsp.status}) ${json?.error?.message || rsp.statusText})`, + ); + } + + if (diff.length > maxCodeCharacters) { + void window.showWarningMessage( + `The diff of the commit changes had to be truncated to ${maxCodeCharacters} characters to fit within the OpenAI's limits.`, + ); + } - const data: AnthropicCompletionResponse = await rsp.json(); - const summary = data.completion.trim(); - return summary; + const data: AnthropicCompletionResponse = await rsp.json(); + const summary = data.completion.trim(); + return summary; + } } private fetch(apiKey: string, request: AnthropicCompletionRequest) { @@ -226,21 +255,6 @@ async function getApiKey(storage: Storage): Promise { return apiKey; } -function getMaxCharacters(model: AnthropicModels, outputLength: number): number { - let tokens; - switch (model) { - case 'claude-2': // 100,000 tokens - case 'claude-instant-1': - tokens = 100000; - break; - default: // 4,096 tokens - tokens = 4096; - break; - } - - return tokens * 4 - outputLength / 4; -} - export type AnthropicModels = 'claude-instant-1' | 'claude-2'; interface AnthropicCompletionRequest { diff --git a/src/ai/openaiProvider.ts b/src/ai/openaiProvider.ts index aa652a777bdfe..79c62d66c9a14 100644 --- a/src/ai/openaiProvider.ts +++ b/src/ai/openaiProvider.ts @@ -6,6 +6,7 @@ import { configuration } from '../system/configuration'; import type { Storage } from '../system/storage'; import { supportedInVSCodeVersion } from '../system/utils'; import type { AIProvider } from './aiProviderService'; +import { getMaxCharacters } from './aiProviderService'; export class OpenAIProvider implements AIProvider { readonly id = 'openai'; @@ -28,26 +29,23 @@ export class OpenAIProvider implements AIProvider { if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model, 1600); - const code = diff.substring(0, maxCodeCharacters); - if (diff.length > maxCodeCharacters) { - void window.showWarningMessage( - `The diff of the staged changes had to be truncated to ${maxCodeCharacters} characters to fit within the OpenAI's limits.`, - ); - } + let retries = 0; + let maxCodeCharacters = getMaxCharacters(model, 2600); + while (true) { + const code = diff.substring(0, maxCodeCharacters); - let customPrompt = configuration.get('experimental.generateCommitMessagePrompt'); - if (!customPrompt.endsWith('.')) { - customPrompt += '.'; - } + let customPrompt = configuration.get('experimental.generateCommitMessagePrompt'); + if (!customPrompt.endsWith('.')) { + customPrompt += '.'; + } - const request: OpenAIChatCompletionRequest = { - model: model, - messages: [ - { - role: 'system', - content: `You are an advanced AI programming assistant tasked with summarizing code changes into a concise and meaningful commit message. Compose a commit message that: + const request: OpenAIChatCompletionRequest = { + model: model, + messages: [ + { + role: 'system', + content: `You are an advanced AI programming assistant tasked with summarizing code changes into a concise and meaningful commit message. Compose a commit message that: - Strictly synthesizes meaningful information from the provided code diff - Utilizes any additional user-provided context to comprehend the rationale behind the code changes - Is clear and brief, with an informal yet professional tone, and without superfluous descriptions @@ -56,40 +54,68 @@ export class OpenAIProvider implements AIProvider { - Most importantly emphasizes the 'why' of the change, its benefits, or the problem it addresses rather than only the 'what' that changed Follow the user's instructions carefully, don't repeat yourself, don't include the code in the output, or make anything up!`, - }, - { - role: 'user', - content: `Here is the code diff to use to generate the commit message:\n\n${code}`, - }, - ...(options?.context - ? [ - { - role: 'user' as const, - content: `Here is additional context which should be taken into account when generating the commit message:\n\n${options.context}`, - }, - ] - : []), - { - role: 'user', - content: customPrompt, - }, - ], - }; + }, + { + role: 'user', + content: `Here is the code diff to use to generate the commit message:\n\n${code}`, + }, + ...(options?.context + ? [ + { + role: 'user' as const, + content: `Here is additional context which should be taken into account when generating the commit message:\n\n${options.context}`, + }, + ] + : []), + { + role: 'user', + content: customPrompt, + }, + ], + }; + + const rsp = await this.fetch(apiKey, request); + if (!rsp.ok) { + if (rsp.status === 404) { + throw new Error( + `Unable to generate commit message: Your API key doesn't seem to have access to the selected '${model}' model`, + ); + } + if (rsp.status === 429) { + throw new Error( + `Unable to generate commit message: (${this.name}:${rsp.status}) Too many requests (rate limit exceeded) or your API key is associated with an expired trial`, + ); + } + + let json; + try { + json = (await rsp.json()) as { error?: { code: string; message: string } } | undefined; + } catch {} + + debugger; + + if (retries++ < 2 && json?.error?.code === 'context_length_exceeded') { + maxCodeCharacters -= 500 * retries; + continue; + } - const rsp = await this.fetch(apiKey, request); - if (!rsp.ok) { - debugger; - if (rsp.status === 429) { throw new Error( - `Unable to generate commit message: (${this.name}:${rsp.status}) Too many requests (rate limit exceeded) or your API key is associated with an expired trial`, + `Unable to generate commit message: (${this.name}:${rsp.status}) ${ + json?.error?.message || rsp.statusText + }`, + ); + } + + if (diff.length > maxCodeCharacters) { + void window.showWarningMessage( + `The diff of the staged changes had to be truncated to ${maxCodeCharacters} characters to fit within the OpenAI's limits.`, ); } - throw new Error(`Unable to generate commit message: (${this.name}:${rsp.status}) ${rsp.statusText}`); - } - const data: OpenAIChatCompletionResponse = await rsp.json(); - const message = data.choices[0].message.content.trim(); - return message; + const data: OpenAIChatCompletionResponse = await rsp.json(); + const message = data.choices[0].message.content.trim(); + return message; + } } async explainChanges(message: string, diff: string): Promise { @@ -97,62 +123,80 @@ Follow the user's instructions carefully, don't repeat yourself, don't include t if (apiKey == null) return undefined; const model = this.model; - const maxCodeCharacters = getMaxCharacters(model, 2400); - - const code = diff.substring(0, maxCodeCharacters); - if (diff.length > maxCodeCharacters) { - void window.showWarningMessage( - `The diff of the commit changes had to be truncated to ${maxCodeCharacters} characters to fit within the OpenAI's limits.`, - ); - } - const request: OpenAIChatCompletionRequest = { - model: model, - messages: [ - { - role: 'system', - content: `You are an advanced AI programming assistant tasked with summarizing code changes into an explanation that is both easy to understand and meaningful. Construct an explanation that: + let retries = 0; + let maxCodeCharacters = getMaxCharacters(model, 3000); + while (true) { + const code = diff.substring(0, maxCodeCharacters); + + const request: OpenAIChatCompletionRequest = { + model: model, + messages: [ + { + role: 'system', + content: `You are an advanced AI programming assistant tasked with summarizing code changes into an explanation that is both easy to understand and meaningful. Construct an explanation that: - Concisely synthesizes meaningful information from the provided code diff - Incorporates any additional context provided by the user to understand the rationale behind the code changes - Places the emphasis on the 'why' of the change, clarifying its benefits or addressing the problem that necessitated the change, beyond just detailing the 'what' has changed Do not make any assumptions or invent details that are not supported by the code diff or the user-provided context.`, - }, - { - role: 'user', - content: `Here is additional context provided by the author of the changes, which should provide some explanation to why these changes where made. Please strongly consider this information when generating your explanation:\n\n${message}`, - }, - { - role: 'user', - content: `Now, kindly explain the following code diff in a way that would be clear to someone reviewing or trying to understand these changes:\n\n${code}`, - }, - { - role: 'user', - content: - 'Remember to frame your explanation in a way that is suitable for a reviewer to quickly grasp the essence of the changes, the issues they resolve, and their implications on the codebase.', - }, - ], - }; + }, + { + role: 'user', + content: `Here is additional context provided by the author of the changes, which should provide some explanation to why these changes where made. Please strongly consider this information when generating your explanation:\n\n${message}`, + }, + { + role: 'user', + content: `Now, kindly explain the following code diff in a way that would be clear to someone reviewing or trying to understand these changes:\n\n${code}`, + }, + { + role: 'user', + content: + 'Remember to frame your explanation in a way that is suitable for a reviewer to quickly grasp the essence of the changes, the issues they resolve, and their implications on the codebase.', + }, + ], + }; + + const rsp = await this.fetch(apiKey, request); + if (!rsp.ok) { + if (rsp.status === 404) { + throw new Error( + `Unable to explain commit: Your API key doesn't seem to have access to the selected '${model}' model`, + ); + } + if (rsp.status === 429) { + throw new Error( + `Unable to explain commit: (${this.name}:${rsp.status}) Too many requests (rate limit exceeded) or your API key is associated with an expired trial`, + ); + } + + let json; + try { + json = (await rsp.json()) as { error?: { code: string; message: string } } | undefined; + } catch {} + + debugger; + + if (retries++ < 2 && json?.error?.code === 'context_length_exceeded') { + maxCodeCharacters -= 500 * retries; + continue; + } - const rsp = await this.fetch(apiKey, request); - if (!rsp.ok) { - debugger; - if (rsp.status === 404) { throw new Error( - `Unable to explain commit: Your API key doesn't seem to have access to the selected '${model}' model`, + `Unable to explain commit: (${this.name}:${rsp.status}) ${json?.error?.message || rsp.statusText}`, ); } - if (rsp.status === 429) { - throw new Error( - `Unable to explain commit: (${this.name}:${rsp.status}) Too many requests (rate limit exceeded) or your API key is associated with an expired trial`, + + if (diff.length > maxCodeCharacters) { + void window.showWarningMessage( + `The diff of the commit changes had to be truncated to ${maxCodeCharacters} characters to fit within the OpenAI's limits.`, ); } - throw new Error(`Unable to explain commit: (${this.name}:${rsp.status}) ${rsp.statusText}`); - } - const data: OpenAIChatCompletionResponse = await rsp.json(); - const summary = data.choices[0].message.content.trim(); - return summary; + const data: OpenAIChatCompletionResponse = await rsp.json(); + const summary = data.choices[0].message.content.trim(); + return summary; + } } private fetch(apiKey: string, request: OpenAIChatCompletionRequest) { @@ -233,35 +277,6 @@ async function getApiKey(storage: Storage): Promise { return openaiApiKey; } -function getMaxCharacters(model: OpenAIModels, outputLength: number): number { - let tokens; - switch (model) { - case 'gpt-4-1106-preview': // 128,000 tokens (4,096 max output tokens) - tokens = 128000; - break; - case 'gpt-4-32k': // 32,768 tokens - case 'gpt-4-32k-0613': - tokens = 32768; - break; - case 'gpt-4': // 8,192 tokens - case 'gpt-4-0613': - tokens = 8192; - break; - case 'gpt-3.5-turbo-1106': // 16,385 tokens (4,096 max output tokens) - tokens = 16385; - break; - case 'gpt-3.5-turbo-16k': // 16,385 tokens; Will point to gpt-3.5-turbo-1106 starting Dec 11, 2023 - tokens = 16385; - break; - case 'gpt-3.5-turbo': // Will point to gpt-3.5-turbo-1106 starting Dec 11, 2023 - default: // 4,096 tokens - tokens = 4096; - break; - } - - return tokens * 4 - outputLength / 4; -} - export type OpenAIModels = | 'gpt-3.5-turbo-1106' | 'gpt-3.5-turbo' From ded8f8ab7f96cefd819f5478276957978595d766 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Nov 2023 18:00:04 -0500 Subject: [PATCH 0247/1012] Slims logging --- src/webviews/webviewsController.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webviews/webviewsController.ts b/src/webviews/webviewsController.ts index 53431834c5165..331c6885e30e6 100644 --- a/src/webviews/webviewsController.ts +++ b/src/webviews/webviewsController.ts @@ -241,6 +241,7 @@ export class WebviewsController implements Disposable { 2: false, 3: false, }, + singleLine: true, }) registerWebviewPanel( command: { From 66d3beb91f3e0953e354be10102f1dde02721918 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Nov 2023 18:00:47 -0500 Subject: [PATCH 0248/1012] Updates subscription logging --- src/plus/gk/account/subscriptionService.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plus/gk/account/subscriptionService.ts b/src/plus/gk/account/subscriptionService.ts index 1da6710e85451..6af6b0b98f520 100644 --- a/src/plus/gk/account/subscriptionService.ts +++ b/src/plus/gk/account/subscriptionService.ts @@ -34,7 +34,7 @@ import { debug, log } from '../../../system/decorators/log'; import type { Deferrable } from '../../../system/function'; import { debounce, once } from '../../../system/function'; import { Logger } from '../../../system/logger'; -import { getLogScope } from '../../../system/logger.scope'; +import { getLogScope, setLogScopeExit } from '../../../system/logger.scope'; import { flatten } from '../../../system/object'; import { pluralize } from '../../../system/string'; import { openWalkthrough } from '../../../system/utils'; @@ -667,7 +667,7 @@ export class SubscriptionService implements Disposable { session = null; if (ex instanceof Error && ex.message.includes('User did not consent')) { - Logger.debug(scope, 'User declined authentication'); + setLogScopeExit(scope, ' \u2022 User declined authentication'); await this.logoutCore(); return null; } @@ -676,7 +676,7 @@ export class SubscriptionService implements Disposable { } if (session == null) { - Logger.debug(scope, 'No valid session was found'); + setLogScopeExit(scope, ' \u2022 No valid session was found'); await this.logoutCore(); return session ?? null; } @@ -694,7 +694,11 @@ export class SubscriptionService implements Disposable { statusCode: ex.statusCode, }); - Logger.debug(scope, `Account validation failed (${ex.statusCode ?? ex.original?.code})`); + setLogScopeExit( + scope, + ` \u2022 Account validation failed (${ex.statusCode ?? ex.original?.code})`, + 'FAILED', + ); if (ex instanceof AccountValidationError) { const name = session.account.label; From 7d08d60589efe7c78fb5216d61ecbc9c9008bf4e Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Nov 2023 18:02:23 -0500 Subject: [PATCH 0249/1012] Slims logging --- src/env/node/git/localGitProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 29a69127f5f09..0c5c6184d2477 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -560,7 +560,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return opened; } - @debug() + @debug({ singleLine: true }) openRepositoryInitWatcher(): RepositoryInitWatcher { const watcher = workspace.createFileSystemWatcher('**/.git', false, true, true); return { From 0b4bab9eed52f63bf8b6f25e8c27c526ea283878 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Nov 2023 18:38:14 -0500 Subject: [PATCH 0250/1012] Refines logging --- src/extension.ts | 2 +- src/trackers/lineTracker.ts | 11 ++++++----- src/webviews/webviewsController.ts | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index d40e64cc91cd3..9f8841f7c8635 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -220,7 +220,7 @@ export async function activate(context: ExtensionContext): Promise implements Disposable { protected onStart?(): Disposable | undefined; - @debug({ args: false }) + @debug({ args: false, singleLine: true }) subscribe(subscriber: unknown, subscription: Disposable): Disposable { const scope = getLogScope(); @@ -138,7 +137,7 @@ export class LineTracker implements Disposable { } if (first) { - Logger.debug(scope, 'Starting line tracker...'); + setLogScopeExit(scope, ' \u2022 starting line tracker...'); this._disposable = Disposable.from( window.onDidChangeActiveTextEditor(debounce(this.onActiveTextEditorChanged, 0), this), @@ -147,12 +146,14 @@ export class LineTracker implements Disposable { ); queueMicrotask(() => this.onActiveTextEditorChanged(window.activeTextEditor)); + } else { + setLogScopeExit(scope, ' \u2022 already started...'); } return disposable; } - @debug({ args: false }) + @debug({ args: false, singleLine: true }) unsubscribe(subscriber: unknown) { const subs = this._subscriptions.get(subscriber); if (subs == null) return; diff --git a/src/webviews/webviewsController.ts b/src/webviews/webviewsController.ts index 331c6885e30e6..09bb4f9e7ae14 100644 --- a/src/webviews/webviewsController.ts +++ b/src/webviews/webviewsController.ts @@ -121,6 +121,7 @@ export class WebviewsController implements Disposable { 1: false, 2: false, }, + singleLine: true, }) registerWebviewView( descriptor: WebviewViewDescriptor, From 62b23e2bf0473af21149990ab3f9117f5a6469a0 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 17 Nov 2023 18:38:41 -0500 Subject: [PATCH 0251/1012] Adds more logging & fixes gating on checkin --- src/plus/gk/account/subscriptionService.ts | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/plus/gk/account/subscriptionService.ts b/src/plus/gk/account/subscriptionService.ts index 6af6b0b98f520..54e4e3e4e538f 100644 --- a/src/plus/gk/account/subscriptionService.ts +++ b/src/plus/gk/account/subscriptionService.ts @@ -25,10 +25,11 @@ import { Commands } from '../../../constants'; import type { Container } from '../../../container'; import { AccountValidationError } from '../../../errors'; import type { RepositoriesChangeEvent } from '../../../git/gitProviderService'; +import { pauseOnCancelOrTimeout } from '../../../system/cancellation'; import { executeCommand, registerCommand } from '../../../system/command'; import { configuration } from '../../../system/configuration'; import { setContext } from '../../../system/context'; -import { createFromDateDelta } from '../../../system/date'; +import { createFromDateDelta, fromNow } from '../../../system/date'; import { gate } from '../../../system/decorators/gate'; import { debug, log } from '../../../system/decorators/log'; import type { Deferrable } from '../../../system/function'; @@ -491,7 +492,7 @@ export class SubscriptionService implements Disposable { } } - @gate() + @gate(o => `${o?.force ?? false}`) @log() async validate(options?: { force?: boolean }): Promise { const scope = getLogScope(); @@ -511,11 +512,14 @@ export class SubscriptionService implements Disposable { } private _lastValidatedDate: Date | undefined; - @gate(s => s.account.id) + + @debug({ args: { 0: s => s?.account?.label } }) private async checkInAndValidate( session: AuthenticationSession, options?: { force?: boolean; showSlowProgress?: boolean }, ): Promise { + const scope = getLogScope(); + // Only check in if we haven't in the last 12 hours if ( !options?.force && @@ -523,29 +527,25 @@ export class SubscriptionService implements Disposable { Date.now() - this._lastValidatedDate.getTime() < 12 * 60 * 60 * 1000 && !isSubscriptionExpired(this._subscription) ) { + setLogScopeExit(scope, ` (${fromNow(this._lastValidatedDate.getTime(), true)})...`, 'skipped'); return; } - if (!options?.showSlowProgress) return this.checkInAndValidateCore(session); - const validating = this.checkInAndValidateCore(session); - const result = await Promise.race([ - validating, - new Promise(resolve => setTimeout(resolve, 3000, true)), - ]); + if (!options?.showSlowProgress) return validating; - if (result) { + // Show progress if we are waiting too long + const result = await pauseOnCancelOrTimeout(validating, undefined, 3000); + if (result.paused) { await window.withProgress( - { - location: ProgressLocation.Notification, - title: 'Validating your GitKraken account...', - }, - () => validating, + { location: ProgressLocation.Notification, title: 'Validating your GitKraken account...' }, + () => result.value, ); } } - @debug({ args: { 0: s => s?.account.label } }) + @gate(s => s.account.id) + @debug({ args: { 0: s => s?.account?.label } }) private async checkInAndValidateCore(session: AuthenticationSession): Promise { const scope = getLogScope(); this._lastValidatedDate = undefined; From 4a2fd4ce4da3f36599a5753ae4e968fe13dd5abf Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 19 Nov 2023 16:48:10 -0500 Subject: [PATCH 0252/1012] =?UTF-8?q?=F0=9F=92=84&=20updates=20lint=20rule?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.base.json | 7 +------ package.json | 3 ++- src/ai/anthropicProvider.ts | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.eslintrc.base.json b/.eslintrc.base.json index 83577746fc704..a5c13d877c3f3 100644 --- a/.eslintrc.base.json +++ b/.eslintrc.base.json @@ -205,7 +205,6 @@ } } ], - "@typescript-eslint/class-literal-property-style": "off", "@typescript-eslint/consistent-type-assertions": [ "error", { @@ -213,9 +212,7 @@ "objectLiteralTypeAssertions": "allow-as-parameter" } ], - "@typescript-eslint/consistent-type-definitions": "off", "@typescript-eslint/consistent-type-imports": ["error", { "disallowTypeAnnotations": false }], - "@typescript-eslint/dot-notation": "off", "@typescript-eslint/naming-convention": [ "error", { @@ -266,7 +263,6 @@ "error", { "ignoreArrowShorthand": true, "ignoreVoidOperator": true } ], - "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-inferrable-types": ["warn", { "ignoreParameters": true, "ignoreProperties": true }], "@typescript-eslint/no-invalid-void-type": "off", // Seems to error on `void` return types @@ -278,6 +274,7 @@ "@typescript-eslint/no-unsafe-argument": "off", "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-enum-comparison": "off", "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unused-expressions": ["warn", { "allowShortCircuit": true }], "@typescript-eslint/no-unused-vars": [ @@ -289,12 +286,10 @@ "varsIgnorePattern": "^_$" } ], - "@typescript-eslint/no-unsafe-enum-comparison": "off", "@typescript-eslint/no-use-before-define": ["error", { "functions": false, "classes": false }], "@typescript-eslint/prefer-for-of": "warn", "@typescript-eslint/prefer-includes": "warn", "@typescript-eslint/prefer-literal-enum-member": ["warn", { "allowBitwiseExpressions": true }], - "@typescript-eslint/prefer-nullish-coalescing": "off", // warn "@typescript-eslint/prefer-optional-chain": "warn", "@typescript-eslint/prefer-reduce-type-parameter": "warn", "@typescript-eslint/restrict-template-expressions": [ diff --git a/package.json b/package.json index 3b90398bbad12..d4285565bf2b1 100644 --- a/package.json +++ b/package.json @@ -15728,8 +15728,9 @@ "clean": "npx rimraf dist out .vscode-test .vscode-test-web .eslintcache* tsconfig*.tsbuildinfo", "copy:images": "webpack --config webpack.config.images.js", "graph:link": "yarn link @gitkraken/gitkraken-components", - "graph:link:main": "pushd \"../GitKrakenComponents\" && yarn link && popd && yarn link @gitkraken/gitkraken-components", + "graph:link:main": "pushd \"../GitKrakenComponents\" && yarn link && popd && yarn graph:link", "graph:unlink": "yarn unlink @gitkraken/gitkraken-components && yarn install --force", + "graph:unlink:main": "yarn graph:unlink && pushd \"../GitKrakenComponents\" && yarn unlink && popd", "icons:apply": "node ./scripts/applyIconsContribution.js", "icons:svgo": "svgo -q -f ./images/icons/ --config svgo.config.js", "lint": "eslint \"src/**/*.ts?(x)\"", diff --git a/src/ai/anthropicProvider.ts b/src/ai/anthropicProvider.ts index 1823c1f0172a6..299092bf263eb 100644 --- a/src/ai/anthropicProvider.ts +++ b/src/ai/anthropicProvider.ts @@ -5,8 +5,8 @@ import type { Container } from '../container'; import { configuration } from '../system/configuration'; import type { Storage } from '../system/storage'; import { supportedInVSCodeVersion } from '../system/utils'; -import type {AIProvider} from './aiProviderService'; -import { getMaxCharacters } from './aiProviderService'; +import type { AIProvider } from './aiProviderService'; +import { getMaxCharacters } from './aiProviderService'; export class AnthropicProvider implements AIProvider { readonly id = 'anthropic'; From f39cf7840fd565da849c65aee8bf169078ce5070 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 18 Nov 2023 14:04:50 -0500 Subject: [PATCH 0253/1012] Updates dependencies --- ThirdPartyNotices.txt | 4 +- package.json | 14 +- yarn.lock | 409 +++++++++++++++++++++--------------------- 3 files changed, 213 insertions(+), 214 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index b9d77c83a9f39..f93dcab18d3ef 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -3,7 +3,7 @@ GitLens THIRD-PARTY SOFTWARE NOTICES AND INFORMATION This project incorporates components from the projects listed below. -1. @lit/react version 1.0.1 (https://github.com/lit/lit) +1. @lit/react version 1.0.2 (https://github.com/lit/lit) 2. @microsoft/fast-element version 1.12.0 (https://github.com/Microsoft/fast) 3. @octokit/graphql version 7.0.2 (https://github.com/octokit/graphql.js) 4. @octokit/request version 8.1.5 (https://github.com/octokit/request.js) @@ -16,7 +16,7 @@ This project incorporates components from the projects listed below. 11. billboard.js version 3.10.3 (https://github.com/naver/billboard.js) 12. https-proxy-agent version 5.0.1 (https://github.com/TooTallNate/node-https-proxy-agent) 13. iconv-lite version 0.6.3 (https://github.com/ashtuchkin/iconv-lite) -14. lit version 3.0.2 (https://github.com/lit/lit) +14. lit version 3.1.0 (https://github.com/lit/lit) 15. microsoft/vscode (https://github.com/microsoft/vscode) 16. node-fetch version 2.7.0 (https://github.com/bitinn/node-fetch) 17. os-browserify version 0.3.0 (https://github.com/CoderPuppy/os-browserify) diff --git a/package.json b/package.json index d4285565bf2b1..39adc985bc91d 100644 --- a/package.json +++ b/package.json @@ -15763,7 +15763,7 @@ "dependencies": { "@gitkraken/gitkraken-components": "10.2.5", "@gitkraken/shared-web-components": "0.1.1-rc.15", - "@lit/react": "1.0.1", + "@lit/react": "1.0.2", "@microsoft/fast-element": "1.12.0", "@octokit/graphql": "7.0.2", "@octokit/request": "8.1.5", @@ -15776,7 +15776,7 @@ "billboard.js": "3.10.3", "https-proxy-agent": "5.0.1", "iconv-lite": "0.6.3", - "lit": "3.0.2", + "lit": "3.1.0", "node-fetch": "2.7.0", "os-browserify": "0.3.0", "path-browserify": "1.0.1", @@ -15805,10 +15805,10 @@ "css-loader": "6.8.1", "css-minimizer-webpack-plugin": "5.0.1", "cssnano-preset-advanced": "6.0.1", - "esbuild": "0.19.5", + "esbuild": "0.19.6", "esbuild-loader": "4.0.2", "esbuild-sass-plugin": "2.16.0", - "eslint": "8.53.0", + "eslint": "8.54.0", "eslint-cli": "1.1.1", "eslint-config-prettier": "9.0.0", "eslint-import-resolver-typescript": "3.6.1", @@ -15830,13 +15830,13 @@ "sass-loader": "13.3.2", "schema-utils": "4.2.0", "sharp": "0.32.6", - "svgo": "3.0.3", + "svgo": "3.0.4", "terser-webpack-plugin": "5.3.9", - "ts-loader": "9.5.0", + "ts-loader": "9.5.1", "tsc-alias": "1.8.8", "typescript": "5.3.1-rc", "webpack": "5.89.0", - "webpack-bundle-analyzer": "4.10.0", + "webpack-bundle-analyzer": "4.10.1", "webpack-cli": "5.1.4", "webpack-node-externals": "3.0.0", "webpack-require-from": "1.8.6" diff --git a/yarn.lock b/yarn.lock index a9deb5cfa7fde..f3a0fe1be9e1b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -61,115 +61,115 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@esbuild/android-arm64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz#276c5f99604054d3dbb733577e09adae944baa90" - integrity sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ== - -"@esbuild/android-arm@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.5.tgz#4a3cbf14758166abaae8ba9c01a80e68342a4eec" - integrity sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA== - -"@esbuild/android-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.5.tgz#21a3d11cd4613d2d3c5ccb9e746c254eb9265b0a" - integrity sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA== - -"@esbuild/darwin-arm64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz#714cb839f467d6a67b151ee8255886498e2b9bf6" - integrity sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw== - -"@esbuild/darwin-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz#2c553e97a6d2b4ae76a884e35e6cbab85a990bbf" - integrity sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA== - -"@esbuild/freebsd-arm64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz#d554f556718adb31917a0da24277bf84b6ee87f3" - integrity sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ== - -"@esbuild/freebsd-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz#288f7358a3bb15d99e73c65c9adaa3dabb497432" - integrity sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ== - -"@esbuild/linux-arm64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz#95933ae86325c93cb6b5e8333d22120ecfdc901b" - integrity sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA== - -"@esbuild/linux-arm@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz#0acef93aa3e0579e46d33b666627bddb06636664" - integrity sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ== - -"@esbuild/linux-ia32@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz#b6e5c9e80b42131cbd6b1ddaa48c92835f1ed67f" - integrity sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ== - -"@esbuild/linux-loong64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz#e5f0cf95a180158b01ff5f417da796a1c09dfbea" - integrity sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw== - -"@esbuild/linux-mips64el@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz#ae36fb86c7d5f641f3a0c8472e83dcb6ea36a408" - integrity sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg== - -"@esbuild/linux-ppc64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz#7960cb1666f0340ddd9eef7b26dcea3835d472d0" - integrity sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q== - -"@esbuild/linux-riscv64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz#32207df26af60a3a9feea1783fc21b9817bade19" - integrity sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag== - -"@esbuild/linux-s390x@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz#b38d5681db89a3723862dfa792812397b1510a7d" - integrity sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw== - -"@esbuild/linux-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz#46feba2ad041a241379d150f415b472fe3885075" - integrity sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A== - -"@esbuild/netbsd-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz#3b5c1fb068f26bfc681d31f682adf1bea4ef0702" - integrity sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g== - -"@esbuild/openbsd-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz#ca6830316ca68056c5c88a875f103ad3235e00db" - integrity sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA== - -"@esbuild/sunos-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz#9efc4eb9539a7be7d5a05ada52ee43cda0d8e2dd" - integrity sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg== - -"@esbuild/win32-arm64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz#29f8184afa7a02a956ebda4ed638099f4b8ff198" - integrity sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg== - -"@esbuild/win32-ia32@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz#f3de07afb292ecad651ae4bb8727789de2d95b05" - integrity sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw== - -"@esbuild/win32-x64@0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz#faad84c41ba12e3a0acb52571df9bff37bee75f6" - integrity sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw== +"@esbuild/android-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.6.tgz#13d98a34bbbde4237867cc232307a20ded139b6f" + integrity sha512-KQ/hbe9SJvIJ4sR+2PcZ41IBV+LPJyYp6V1K1P1xcMRup9iYsBoQn4MzE3mhMLOld27Au2eDcLlIREeKGUXpHQ== + +"@esbuild/android-arm@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.6.tgz#68898d949672c56f10451f540fd92301dc713fb3" + integrity sha512-muPzBqXJKCbMYoNbb1JpZh/ynl0xS6/+pLjrofcR3Nad82SbsCogYzUE6Aq9QT3cLP0jR/IVK/NHC9b90mSHtg== + +"@esbuild/android-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.6.tgz#51a0ab83680dedc6dd1ae26133def26b178ed3a1" + integrity sha512-VVJVZQ7p5BBOKoNxd0Ly3xUM78Y4DyOoFKdkdAe2m11jbh0LEU4bPles4e/72EMl4tapko8o915UalN/5zhspg== + +"@esbuild/darwin-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.6.tgz#2883f14197111febb118c0463c080930a30883e5" + integrity sha512-91LoRp/uZAKx6ESNspL3I46ypwzdqyDLXZH7x2QYCLgtnaU08+AXEbabY2yExIz03/am0DivsTtbdxzGejfXpA== + +"@esbuild/darwin-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.6.tgz#400bf20f9a35a7d68a17f5898c0f9ecb099f062b" + integrity sha512-QCGHw770ubjBU1J3ZkFJh671MFajGTYMZumPs9E/rqU52md6lIil97BR0CbPq6U+vTh3xnTNDHKRdR8ggHnmxQ== + +"@esbuild/freebsd-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.6.tgz#8af07bd848afa2470b8a2339b203ce29a721152b" + integrity sha512-J53d0jGsDcLzWk9d9SPmlyF+wzVxjXpOH7jVW5ae7PvrDst4kiAz6sX+E8btz0GB6oH12zC+aHRD945jdjF2Vg== + +"@esbuild/freebsd-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.6.tgz#ae0230860e27df204a616671e028ff8fdffa009a" + integrity sha512-hn9qvkjHSIB5Z9JgCCjED6YYVGCNpqB7dEGavBdG6EjBD8S/UcNUIlGcB35NCkMETkdYwfZSvD9VoDJX6VeUVA== + +"@esbuild/linux-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.6.tgz#3042bc423a978deab44a72244b863f743fd9fda1" + integrity sha512-HQCOrk9XlH3KngASLaBfHpcoYEGUt829A9MyxaI8RMkfRA8SakG6YQEITAuwmtzFdEu5GU4eyhKcpv27dFaOBg== + +"@esbuild/linux-arm@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.6.tgz#50a537de609315979509120b0181882978294db1" + integrity sha512-G8IR5zFgpXad/Zp7gr7ZyTKyqZuThU6z1JjmRyN1vSF8j0bOlGzUwFSMTbctLAdd7QHpeyu0cRiuKrqK1ZTwvQ== + +"@esbuild/linux-ia32@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.6.tgz#f99c48b597facf9cbf8e1a2522ce379b2ad7b0c4" + integrity sha512-22eOR08zL/OXkmEhxOfshfOGo8P69k8oKHkwkDrUlcB12S/sw/+COM4PhAPT0cAYW/gpqY2uXp3TpjQVJitz7w== + +"@esbuild/linux-loong64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.6.tgz#9fe79be31ce305564aa62da190f38e199d6d26b7" + integrity sha512-82RvaYAh/SUJyjWA8jDpyZCHQjmEggL//sC7F3VKYcBMumQjUL3C5WDl/tJpEiKtt7XrWmgjaLkrk205zfvwTA== + +"@esbuild/linux-mips64el@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.6.tgz#5a922dad90fc8a83fd0631c136b46128153ffb6f" + integrity sha512-8tvnwyYJpR618vboIv2l8tK2SuK/RqUIGMfMENkeDGo3hsEIrpGldMGYFcWxWeEILe5Fi72zoXLmhZ7PR23oQA== + +"@esbuild/linux-ppc64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.6.tgz#a7fccf924824999b301546843adb4f51051965e8" + integrity sha512-Qt+D7xiPajxVNk5tQiEJwhmarNnLPdjXAoA5uWMpbfStZB0+YU6a3CtbWYSy+sgAsnyx4IGZjWsTzBzrvg/fMA== + +"@esbuild/linux-riscv64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.6.tgz#41d2db11550662d6c03902d9d8d26b0ed5bb8d55" + integrity sha512-lxRdk0iJ9CWYDH1Wpnnnc640ajF4RmQ+w6oHFZmAIYu577meE9Ka/DCtpOrwr9McMY11ocbp4jirgGgCi7Ls/g== + +"@esbuild/linux-s390x@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.6.tgz#d7a843a2620e73c5c9d65c482e2fbddc7e0f7753" + integrity sha512-MopyYV39vnfuykHanRWHGRcRC3AwU7b0QY4TI8ISLfAGfK+tMkXyFuyT1epw/lM0pflQlS53JoD22yN83DHZgA== + +"@esbuild/linux-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.6.tgz#d3f20f0c2bdaa1b9ed1c0df7db034771e7aa5234" + integrity sha512-UWcieaBzsN8WYbzFF5Jq7QULETPcQvlX7KL4xWGIB54OknXJjBO37sPqk7N82WU13JGWvmDzFBi1weVBajPovg== + +"@esbuild/netbsd-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.6.tgz#6108d7270599ee37cd57bb14e4516a83541885d5" + integrity sha512-EpWiLX0fzvZn1wxtLxZrEW+oQED9Pwpnh+w4Ffv8ZLuMhUoqR9q9rL4+qHW8F4Mg5oQEKxAoT0G+8JYNqCiR6g== + +"@esbuild/openbsd-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.6.tgz#b1b5aaa2c9028e90a2bef6774a9c67451f53f164" + integrity sha512-fFqTVEktM1PGs2sLKH4M5mhAVEzGpeZJuasAMRnvDZNCV0Cjvm1Hu35moL2vC0DOrAQjNTvj4zWrol/lwQ8Deg== + +"@esbuild/sunos-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.6.tgz#b51b648cea77c62b1934a4fdcfee7aaa9de174cb" + integrity sha512-M+XIAnBpaNvaVAhbe3uBXtgWyWynSdlww/JNZws0FlMPSBy+EpatPXNIlKAdtbFVII9OpX91ZfMb17TU3JKTBA== + +"@esbuild/win32-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.6.tgz#34e5665f239047c302c8d153406c87db22afd58a" + integrity sha512-2DchFXn7vp/B6Tc2eKdTsLzE0ygqKkNUhUBCNtMx2Llk4POIVMUq5rUYjdcedFlGLeRe1uLCpVvCmE+G8XYybA== + +"@esbuild/win32-ia32@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.6.tgz#f7aaebe325e67f44c0a738e80a98221504677b4a" + integrity sha512-PBo/HPDQllyWdjwAVX+Gl2hH0dfBydL97BAH/grHKC8fubqp02aL4S63otZ25q3sBdINtOBbz1qTZQfXbP4VBg== + +"@esbuild/win32-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.6.tgz#7134e5dea1f5943b013e96fc34f9638a5f3d7e3e" + integrity sha512-OE7yIdbDif2kKfrGa+V0vx/B3FJv2L4KnIiLlvtibPyO9UkgO3rzYE0HhpREo2vmJ1Ixq1zwm9/0er+3VOSZJA== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" @@ -198,10 +198,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d" - integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w== +"@eslint/js@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.54.0.tgz#4fab9a2ff7860082c304f750e94acd644cf984cf" + integrity sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ== "@floating-ui/core@^1.4.2": version "1.5.0" @@ -363,15 +363,15 @@ resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz#d693d972974a354034454ec1317eb6afd0b00312" integrity sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g== -"@lit/react@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@lit/react/-/react-1.0.1.tgz#00dc227c60947abd3cbdaa03bb9cca7f5b815451" - integrity sha512-io4yIAl9ZFY5coI2ix+nSly4rmEKLFyZM66mxOr9xvxDqwtjdVU/g6Tchb7bo+A23+5Uu/1RZpLCpvHLCGi0rw== +"@lit/react@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@lit/react/-/react-1.0.2.tgz#4951ff1590d69aad912d0a950b3518d19eb7e220" + integrity sha512-UJ5TQ46DPcJDIzyjbwbj6Iye0XcpCxL2yb03zcWq1BpWchpXS3Z0BPVhg7zDfZLF6JemPml8u/gt/+KwJ/23sg== "@lit/reactive-element@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.0.1.tgz#b17d8818d9c72ccc489f44e35d87cfa18a9c8c93" - integrity sha512-eu50SQXHRthFwWJMp0oAFg95Rvm6MTPjxSXWuvAu7It90WVFLFpNBoIno7XOXSDvVgTrtKnUV4OLJqys2Svn4g== + version "2.0.2" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.0.2.tgz#779ae9d265407daaf7737cb892df5ec2a86e22a0" + integrity sha512-SVOwLAWUQg3Ji1egtOt1UiFe4zdDpnWHyc5qctSceJ5XIu0Uc76YmGpIjZgx9YJ0XtdW0Jm507sDvjOu+HnB8w== dependencies: "@lit-labs/ssr-dom-shim" "^1.1.2" @@ -593,11 +593,11 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@playwright/browser-chromium@^1.39.0": - version "1.39.0" - resolved "https://registry.yarnpkg.com/@playwright/browser-chromium/-/browser-chromium-1.39.0.tgz#549ea67a4734e8a17d5d3fdeabcdcf1e02cffd84" - integrity sha512-s1WPO0qOE7PIZcdcJEd4CHQgXf9rOwy00Den8DsXTI26n/Eqa2HzFSbLRE1Eh2nIJZFSGyKLbopHR0HkT8ClZw== + version "1.40.0" + resolved "https://registry.yarnpkg.com/@playwright/browser-chromium/-/browser-chromium-1.40.0.tgz#459266c181d621d589aed125e4f86dd3cab80a22" + integrity sha512-+MxALUvUcUx8NEKSv2fXfkXrnBe9qcKPAqXjQsLu52gYhIxbF/C63fedLbZsWJU5hnmxIVWVDHMszq2cVl55mw== dependencies: - playwright-core "1.39.0" + playwright-core "1.40.0" "@polka/url@^1.0.0-next.20": version "1.0.0-next.23" @@ -733,9 +733,9 @@ integrity sha512-xKU7bUjiFTIttpWaIZ9qvgg+22O1nmbA+HRxdlR+u6TWsGfmFdXrheJoK4fFxrHNVIOBDvDNKZG+LYBpMHpX3w== "@types/node@*": - version "20.9.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298" - integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw== + version "20.9.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.2.tgz#002815c8e87fe0c9369121c78b52e800fadc0ac6" + integrity sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg== dependencies: undici-types "~5.26.4" @@ -1652,9 +1652,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001562" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001562.tgz#9d16c5fd7e9c592c4cd5e304bc0f75b0008b2759" - integrity sha512-kfte3Hym//51EdX4239i+Rmp20EsLIYGdPkERegTgU19hQWCRhsRFGKHTliUlsry53tv17K7n077Kqa0WJU4ng== + version "1.0.30001563" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz#aa68a64188903e98f36eb9c56e48fba0c1fe2a32" + integrity sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw== capital-case@^1.0.4: version "1.0.4" @@ -2621,9 +2621,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.535: - version "1.4.583" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.583.tgz#7b0ac4f36388da4b5485788adb92cd7dd0abffc4" - integrity sha512-93y1gcONABZ7uqYe/JWDVQP/Pj/sQSunF0HVAPdlg/pfBnOyBMLlQUxWvkqcljJg1+W6cjvPuYD+r1Th9Tn8mA== + version "1.4.588" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.588.tgz#d553f3c008e73488fb181fdf2601fdb0b1ffbb78" + integrity sha512-soytjxwbgcCu7nh5Pf4S2/4wa6UIu+A3p03U2yVr53qGxi1/VTR3ENI+p50v+UxqqZAfl48j3z55ud7VHIOr9w== emoji-regex@^8.0.0: version "8.0.0" @@ -2797,33 +2797,33 @@ esbuild-sass-plugin@2.16.0: resolve "^1.22.6" sass "^1.7.3" -esbuild@0.19.5, esbuild@^0.19.0: - version "0.19.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.5.tgz#53a0e19dfbf61ba6c827d51a80813cf071239a8c" - integrity sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ== +esbuild@0.19.6, esbuild@^0.19.0: + version "0.19.6" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.6.tgz#baa0e8b6b9e655c54ffd57f1772e44677a7931cc" + integrity sha512-Xl7dntjA2OEIvpr9j0DVxxnog2fyTGnyVoQXAMQI6eR3mf9zCQds7VIKUDCotDgE/p4ncTgeRqgX8t5d6oP4Gw== optionalDependencies: - "@esbuild/android-arm" "0.19.5" - "@esbuild/android-arm64" "0.19.5" - "@esbuild/android-x64" "0.19.5" - "@esbuild/darwin-arm64" "0.19.5" - "@esbuild/darwin-x64" "0.19.5" - "@esbuild/freebsd-arm64" "0.19.5" - "@esbuild/freebsd-x64" "0.19.5" - "@esbuild/linux-arm" "0.19.5" - "@esbuild/linux-arm64" "0.19.5" - "@esbuild/linux-ia32" "0.19.5" - "@esbuild/linux-loong64" "0.19.5" - "@esbuild/linux-mips64el" "0.19.5" - "@esbuild/linux-ppc64" "0.19.5" - "@esbuild/linux-riscv64" "0.19.5" - "@esbuild/linux-s390x" "0.19.5" - "@esbuild/linux-x64" "0.19.5" - "@esbuild/netbsd-x64" "0.19.5" - "@esbuild/openbsd-x64" "0.19.5" - "@esbuild/sunos-x64" "0.19.5" - "@esbuild/win32-arm64" "0.19.5" - "@esbuild/win32-ia32" "0.19.5" - "@esbuild/win32-x64" "0.19.5" + "@esbuild/android-arm" "0.19.6" + "@esbuild/android-arm64" "0.19.6" + "@esbuild/android-x64" "0.19.6" + "@esbuild/darwin-arm64" "0.19.6" + "@esbuild/darwin-x64" "0.19.6" + "@esbuild/freebsd-arm64" "0.19.6" + "@esbuild/freebsd-x64" "0.19.6" + "@esbuild/linux-arm" "0.19.6" + "@esbuild/linux-arm64" "0.19.6" + "@esbuild/linux-ia32" "0.19.6" + "@esbuild/linux-loong64" "0.19.6" + "@esbuild/linux-mips64el" "0.19.6" + "@esbuild/linux-ppc64" "0.19.6" + "@esbuild/linux-riscv64" "0.19.6" + "@esbuild/linux-s390x" "0.19.6" + "@esbuild/linux-x64" "0.19.6" + "@esbuild/netbsd-x64" "0.19.6" + "@esbuild/openbsd-x64" "0.19.6" + "@esbuild/sunos-x64" "0.19.6" + "@esbuild/win32-arm64" "0.19.6" + "@esbuild/win32-ia32" "0.19.6" + "@esbuild/win32-x64" "0.19.6" escalade@^3.1.1: version "3.1.1" @@ -2956,15 +2956,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@8.53.0: - version "8.53.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce" - integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag== +eslint@8.54.0: + version "8.54.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.54.0.tgz#588e0dd4388af91a2e8fa37ea64924074c783537" + integrity sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.3" - "@eslint/js" "8.53.0" + "@eslint/js" "8.54.0" "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -3767,9 +3767,9 @@ ieee754@^1.1.13: integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^5.1.9, ignore@^5.2.0, ignore@^5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + version "5.3.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== image-minimizer-webpack-plugin@3.8.3: version "3.8.3" @@ -4405,29 +4405,29 @@ linkify-it@^3.0.1: uc.micro "^1.0.1" lit-element@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-4.0.1.tgz#fe9d82e2d034f819156f561f6f23b0ed0c9d19dc" - integrity sha512-OxRMJem4HKZt0320HplLkBPoi4KHiEHoPHKd8Lzf07ZQVAOKIjZ32yPLRKRDEolFU1RgrQBfSHQMoxKZ72V3Kw== + version "4.0.2" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-4.0.2.tgz#1a519896d5ab7c7be7a8729f400499e38779c093" + integrity sha512-/W6WQZUa5VEXwC7H9tbtDMdSs9aWil3Ou8hU6z2cOKWbsm/tXPAcsoaHVEtrDo0zcOIE5GF6QgU55tlGL2Nihg== dependencies: "@lit-labs/ssr-dom-shim" "^1.1.2" "@lit/reactive-element" "^2.0.0" - lit-html "^3.0.0" + lit-html "^3.1.0" -lit-html@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-3.0.2.tgz#25d2718b1e095a148a54c63bcd780c7550bb82f8" - integrity sha512-Q1A5lHza3bnmxoWJn6yS6vQZQdExl4fghk8W1G+jnAEdoFNYo5oeBBb/Ol7zSEdKd3TR7+r0zsJQyuWEVguiyQ== +lit-html@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-3.1.0.tgz#a7b93dd682073f2e2029656f4e9cd91e8034c196" + integrity sha512-FwAjq3iNsaO6SOZXEIpeROlJLUlrbyMkn4iuv4f4u1H40Jw8wkeR/OUXZUHUoiYabGk8Y4Y0F/rgq+R4MrOLmA== dependencies: "@types/trusted-types" "^2.0.2" -lit@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lit/-/lit-3.0.2.tgz#e22e90c2cbcc3f37bf3c2558df66f3af4331c9cf" - integrity sha512-ZoVUPGgXOQocP4OvxehEOBmC4rWB4cRYDPaz7aFmH8DFytsCi/NeACbr4C6vNPGDEC07BrhUos7uVNayDKLQ2Q== +lit@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lit/-/lit-3.1.0.tgz#76429b85dc1f5169fed499a0f7e89e2e619010c9" + integrity sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w== dependencies: "@lit/reactive-element" "^2.0.0" lit-element "^4.0.0" - lit-html "^3.0.0" + lit-html "^3.1.0" loader-runner@^4.2.0: version "4.3.0" @@ -4517,11 +4517,9 @@ lru-cache@^7.5.1, lru-cache@^7.7.1: integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== "lru-cache@^9.1.1 || ^10.0.0": - version "10.0.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.2.tgz#34504678cc3266b09b8dfd6fab4e1515258271b7" - integrity sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg== - dependencies: - semver "^7.3.5" + version "10.0.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.3.tgz#b40014d7d2d16d94130b87297a04a1f24874ae7c" + integrity sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg== lz-string@1.5.0: version "1.5.0" @@ -5359,17 +5357,17 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -playwright-core@1.39.0: - version "1.39.0" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.39.0.tgz#efeaea754af4fb170d11845b8da30b2323287c63" - integrity sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw== +playwright-core@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.40.0.tgz#82f61e5504cb3097803b6f8bbd98190dd34bdf14" + integrity sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q== playwright@^1.39.0: - version "1.39.0" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.39.0.tgz#184c81cd6478f8da28bcd9e60e94fcebf566e077" - integrity sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw== + version "1.40.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.40.0.tgz#2a1824b9fe5c4fe52ed53db9ea68003543a99df0" + integrity sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw== dependencies: - playwright-core "1.39.0" + playwright-core "1.40.0" optionalDependencies: fsevents "2.3.2" @@ -6700,15 +6698,16 @@ svgicons2svgfont@^12.0.0: sax "^1.2.4" svg-pathdata "^6.0.3" -svgo@3.0.3, svgo@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.3.tgz#8cdfece6d4a0dc1dc116766d806daf817c1798b8" - integrity sha512-X4UZvLhOglD5Xrp834HzGHf8RKUW0Ahigg/08yRO1no9t2NxffOkMiQ0WmaMIbaGlVTlSst2zWANsdhz5ybXgA== +svgo@3.0.4, svgo@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.4.tgz#67b40a710743e358e8d19ec288de8f1e388afbb4" + integrity sha512-T+Xul3JwuJ6VGXKo/p2ndqx1ibxNKnLTvRc1ZTWKCfyKS/GgNjRZcYsK84fxTsy/izr91g/Rwx6fGnVgaFSI5g== dependencies: "@trysound/sax" "0.2.0" commander "^7.2.0" css-select "^5.1.0" css-tree "^2.2.1" + css-what "^6.1.0" csso "5.0.5" picocolors "^1.0.0" @@ -6871,10 +6870,10 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== -ts-loader@9.5.0: - version "9.5.0" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.0.tgz#f0a51dda37cc4d8e43e6cb14edebbc599b0c3aa2" - integrity sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg== +ts-loader@9.5.1: + version "9.5.1" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.1.tgz#63d5912a86312f1fbe32cef0859fb8b2193d9b89" + integrity sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg== dependencies: chalk "^4.1.0" enhanced-resolve "^5.0.0" @@ -7189,10 +7188,10 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -webpack-bundle-analyzer@4.10.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.0.tgz#eecb0ade9bd1944d3d2e38262ec9793da6f13e69" - integrity sha512-j+apH0Cs+FY8IOIwxLbkgEJnbQgEPEG8uqLVnRb9tAoGbyKNxQA1u9wNDrTQHK3PinO4Pckew7AE7pnX/RS3wA== +webpack-bundle-analyzer@4.10.1: + version "4.10.1" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz#84b7473b630a7b8c21c741f81d8fe4593208b454" + integrity sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ== dependencies: "@discoveryjs/json-ext" "0.5.7" acorn "^8.0.4" From ef251d934fa296af4a199f1084b9f7c28bbba646 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Thu, 16 Nov 2023 11:09:00 -0500 Subject: [PATCH 0254/1012] Removes dead tab code in patch details --- .../components/patch-details-app.ts | 32 +------------------ .../apps/plus/patchDetails/patchDetails.scss | 3 -- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/webviews/apps/plus/patchDetails/components/patch-details-app.ts b/src/webviews/apps/plus/patchDetails/components/patch-details-app.ts index eda706281e01b..66eab208c44a8 100644 --- a/src/webviews/apps/plus/patchDetails/components/patch-details-app.ts +++ b/src/webviews/apps/plus/patchDetails/components/patch-details-app.ts @@ -1,5 +1,5 @@ import { Badge, defineGkElement, Menu, MenuItem, Popover } from '@gitkraken/shared-web-components'; -import { html, nothing } from 'lit'; +import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import type { DraftDetails, Mode, State } from '../../../../../plus/webviews/patchDetails/protocol'; @@ -108,39 +108,9 @@ export class GlPatchDetailsApp extends GlElement { } } - private renderTabs() { - return nothing; - // return html` - //

- // `; - } - override render() { return html`
- ${this.renderTabs()}
${when( this.mode === 'view', diff --git a/src/webviews/apps/plus/patchDetails/patchDetails.scss b/src/webviews/apps/plus/patchDetails/patchDetails.scss index f1f30c1d99cde..c4d399d0d5037 100644 --- a/src/webviews/apps/plus/patchDetails/patchDetails.scss +++ b/src/webviews/apps/plus/patchDetails/patchDetails.scss @@ -166,9 +166,6 @@ textarea.message-input__control { flex-direction: column; overflow: hidden; } -.details-tab { - flex: none; -} main { flex: 1 1 auto; From 2c85af90e1d93f03db553af6605fc1dde262a8dc Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Fri, 17 Nov 2023 17:02:33 -0500 Subject: [PATCH 0255/1012] Updates commit details to new tree component --- .../apps/commitDetails/commitDetails.ts | 69 +- .../components/commit-details-app.ts | 16 + .../components/gl-commit-details.ts | 39 ++ .../components/gl-details-base.ts | 609 ++++++++++++------ .../components/gl-wip-details.ts | 14 + .../commitDetails/commitDetailsWebview.ts | 4 +- src/webviews/commitDetails/protocol.ts | 2 +- 7 files changed, 522 insertions(+), 231 deletions(-) diff --git a/src/webviews/apps/commitDetails/commitDetails.ts b/src/webviews/apps/commitDetails/commitDetails.ts index f8be93a08c9b7..0c93efd0a68a2 100644 --- a/src/webviews/apps/commitDetails/commitDetails.ts +++ b/src/webviews/apps/commitDetails/commitDetails.ts @@ -27,10 +27,11 @@ import { import type { IpcMessage } from '../../protocol'; import { ExecuteCommandType, onIpc } from '../../protocol'; import { App } from '../shared/appBase'; -import type { FileChangeListItem, FileChangeListItemDetail } from '../shared/components/list/file-change-list-item'; import type { WebviewPane, WebviewPaneExpandedChangeEventDetail } from '../shared/components/webview-pane'; import { DOM } from '../shared/dom'; import type { GlCommitDetailsApp } from './components/commit-details-app'; +import type { GlCommitDetails } from './components/gl-commit-details'; +import type { FileChangeListItemDetail } from './components/gl-details-base'; import './commitDetails.scss'; import '../shared/components/actions/action-item'; import '../shared/components/actions/action-nav'; @@ -61,27 +62,6 @@ export class CommitDetailsApp extends App> { override onBind() { const disposables = [ - DOM.on('file-change-list-item', 'file-open-on-remote', e => - this.onOpenFileOnRemote(e.detail), - ), - DOM.on('file-change-list-item', 'file-open', e => - this.onOpenFile(e.detail), - ), - DOM.on('file-change-list-item', 'file-compare-working', e => - this.onCompareFileWithWorking(e.detail), - ), - DOM.on('file-change-list-item', 'file-compare-previous', e => - this.onCompareFileWithPrevious(e.detail), - ), - DOM.on('file-change-list-item', 'file-more-actions', e => - this.onFileMoreActions(e.detail), - ), - DOM.on('file-change-list-item', 'file-stage', e => - this.onStageFile(e.detail), - ), - DOM.on('file-change-list-item', 'file-unstage', e => - this.onUnstageFile(e.detail), - ), DOM.on('[data-action="commit-actions"]', 'click', e => this.onCommitActions(e)), DOM.on('[data-action="pick-commit"]', 'click', e => this.onPickCommit(e)), DOM.on('[data-action="wip"]', 'click', e => this.onSwitchMode(e, 'wip')), @@ -92,7 +72,7 @@ export class CommitDetailsApp extends App> { DOM.on('[data-action="pin"]', 'click', e => this.onTogglePin(e)), DOM.on('[data-action="back"]', 'click', e => this.onNavigate('back', e)), DOM.on('[data-action="forward"]', 'click', e => this.onNavigate('forward', e)), - DOM.on('[data-action="create-patch"]', 'click', e => this.onCreatePatchFromWip(e)), + DOM.on('[data-action="create-patch"]', 'click', _e => this.onCreatePatchFromWip(true)), DOM.on( '[data-region="rich-pane"]', 'expanded-change', @@ -100,6 +80,33 @@ export class CommitDetailsApp extends App> { ), DOM.on('[data-action="explain-commit"]', 'click', e => this.onExplainCommit(e)), DOM.on('[data-action="switch-ai"]', 'click', e => this.onSwitchAiModel(e)), + DOM.on('gl-wip-details', 'create-patch', e => + this.onCreatePatchFromWip(e.detail.checked), + ), + + DOM.on('gl-commit-details', 'file-open-on-remote', e => + this.onOpenFileOnRemote(e.detail), + ), + DOM.on('gl-commit-details,gl-wip-details', 'file-open', e => + this.onOpenFile(e.detail), + ), + DOM.on('gl-commit-details', 'file-compare-working', e => + this.onCompareFileWithWorking(e.detail), + ), + DOM.on( + 'gl-commit-details,gl-wip-details', + 'file-compare-previous', + e => this.onCompareFileWithPrevious(e.detail), + ), + DOM.on('gl-commit-details', 'file-more-actions', e => + this.onFileMoreActions(e.detail), + ), + DOM.on('gl-wip-details', 'file-stage', e => + this.onStageFile(e.detail), + ), + DOM.on('gl-wip-details', 'file-unstage', e => + this.onUnstageFile(e.detail), + ), ]; return disposables; @@ -153,21 +160,9 @@ export class CommitDetailsApp extends App> { } } - private onCreatePatchFromWip(e: MouseEvent) { + private onCreatePatchFromWip(checked: boolean | 'staged' = true) { if (this.state.wip?.changes == null) return; - - const wipCheckedParam = ((e.target as HTMLElement)?.closest('[data-wip-checked]') as HTMLElement | undefined) - ?.dataset.wipChecked; - let wipChecked: boolean | 'staged'; - if (wipCheckedParam == null) { - wipChecked = true; - } else if (wipCheckedParam === 'staged') { - wipChecked = wipCheckedParam; - } else { - wipChecked = wipCheckedParam === 'true'; - } - - this.sendCommand(CreatePatchFromWipCommandType, { changes: this.state.wip?.changes, checked: wipChecked }); + this.sendCommand(CreatePatchFromWipCommandType, { changes: this.state.wip?.changes, checked: checked }); } private onCommandClickedCore(action?: string) { diff --git a/src/webviews/apps/commitDetails/components/commit-details-app.ts b/src/webviews/apps/commitDetails/components/commit-details-app.ts index 545b60167e9f4..1151282f0042d 100644 --- a/src/webviews/apps/commitDetails/components/commit-details-app.ts +++ b/src/webviews/apps/commitDetails/components/commit-details-app.ts @@ -68,6 +68,22 @@ export class GlCommitDetailsApp extends LitElement { defineGkElement(Badge); } + private indentPreference = 16; + private updateDocumentProperties() { + const preference = this.state?.preferences?.indent; + if (preference === this.indentPreference) return; + this.indentPreference = preference ?? 16; + + const rootStyle = document.documentElement.style; + rootStyle.setProperty('--gitlens-tree-indent', `${this.indentPreference}px`); + } + + override updated(changedProperties: Map) { + if (changedProperties.has('state')) { + this.updateDocumentProperties(); + } + } + override render() { const wip = this.state?.wip; diff --git a/src/webviews/apps/commitDetails/components/gl-commit-details.ts b/src/webviews/apps/commitDetails/components/gl-commit-details.ts index c3fcb00c4e508..c4a07ab5dd663 100644 --- a/src/webviews/apps/commitDetails/components/gl-commit-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-commit-details.ts @@ -8,7 +8,9 @@ import type { PullRequestShape } from '../../../../git/models/pullRequest'; import type { Serialized } from '../../../../system/serialize'; import type { State } from '../../../commitDetails/protocol'; import { messageHeadlineSplitterToken } from '../../../commitDetails/protocol'; +import type { TreeItemAction, TreeItemBase } from '../../shared/components/tree/base'; import { uncommittedSha } from '../commitDetails'; +import type { File } from './gl-details-base'; import { GlDetailsBase } from './gl-details-base'; interface ExplainState { @@ -522,4 +524,41 @@ export class GlCommitDetails extends GlDetailsBase { const { added, deleted, changed } = stats.changedFiles; return html``; } + + override getFileActions(_file: File, _options?: Partial): TreeItemAction[] { + const actions = [ + { + icon: 'go-to-file', + label: 'Open file', + action: 'file-open', + }, + ]; + + if (this.isUncommitted) { + return actions; + } + + actions.push({ + icon: 'git-compare', + label: 'Open Changes with Working File', + action: 'file-compare-working', + }); + + if (!this.isStash) { + actions.push( + { + icon: 'globe', + label: 'Open on remote', + action: 'file-open-on-remote', + }, + { + icon: 'ellipsis', + label: 'Show more actions', + action: 'file-more-actions', + }, + ); + } + + return actions; + } } diff --git a/src/webviews/apps/commitDetails/components/gl-details-base.ts b/src/webviews/apps/commitDetails/components/gl-details-base.ts index 2cee5cafe01ea..4b63ddff50c0b 100644 --- a/src/webviews/apps/commitDetails/components/gl-details-base.ts +++ b/src/webviews/apps/commitDetails/components/gl-details-base.ts @@ -1,16 +1,31 @@ import type { TemplateResult } from 'lit'; import { html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; -import { ifDefined } from 'lit/directives/if-defined.js'; -import { when } from 'lit/directives/when.js'; +import type { TextDocumentShowOptions } from 'vscode'; import type { HierarchicalItem } from '../../../../system/array'; import { makeHierarchical } from '../../../../system/array'; import type { Preferences, State } from '../../../commitDetails/protocol'; +import type { + TreeItemAction, + TreeItemActionDetail, + TreeItemBase, + TreeItemCheckedDetail, + TreeItemSelectionDetail, + TreeModel, +} from '../../shared/components/tree/base'; +import '../../shared/components/tree/tree-generator'; type Files = Mutable['files']>>; -type File = Files[0]; +export type File = Files[0]; type Mode = 'commit' | 'stash' | 'wip'; +// Can only import types from 'vscode' +const BesideViewColumn = -2; /*ViewColumn.Beside*/ + +export interface FileChangeListItemDetail extends File { + showOptions?: TextDocumentShowOptions; +} + export class GlDetailsBase extends LitElement { readonly tab: 'wip' | 'commit' = 'commit'; @@ -26,165 +41,43 @@ export class GlDetailsBase extends LitElement { @property({ attribute: 'empty-text' }) emptyText? = 'No Files'; - private renderWipCategory(staged = true, hasFiles = true) { - const label = staged ? 'Staged Changes' : 'Unstaged Changes'; - const shareLabel = `Share ${label}`; - return html` - - ${label} - ${when( - this.tab === 'wip', - () => - html` `, - )} - `; + get fileLayout() { + return this.preferences?.files?.layout ?? 'auto'; } - private renderFileList(mode: Mode, files: Files) { - let items; - let classes; - - if (this.isUncommitted) { - items = []; - classes = `indentGuides-${this.preferences?.indentGuides}`; - - const staged = files.filter(f => f.staged); - if (staged.length) { - // items.push(html`Staged Changes`); - items.push(this.renderWipCategory(true, true)); - - for (const f of staged) { - items.push(this.renderFile(mode, f, 2, true)); - } - } - - const unstaged = files.filter(f => !f.staged); - if (unstaged.length) { - // items.push(html`Unstaged Changes`); - items.push(this.renderWipCategory(false, true)); - - for (const f of unstaged) { - items.push(this.renderFile(mode, f, 2, true)); - } - } - } else { - items = files.map(f => this.renderFile(mode, f)); - } - - return html`${items}`; + get isCompact() { + return this.preferences?.files?.compact ?? true; } - private renderFileTree(mode: Mode, files: Files) { - const compact = this.preferences?.files?.compact ?? true; - - let items; - - if (this.isUncommitted) { - items = []; - - const staged = files.filter(f => f.staged); - if (staged.length) { - // items.push(html`Staged Changes`); - items.push(this.renderWipCategory(true, true)); - items.push(...this.renderFileSubtree(mode, staged, 1, compact)); - } - - const unstaged = files.filter(f => !f.staged); - if (unstaged.length) { - // items.push(html`Unstaged Changes`); - items.push(this.renderWipCategory(false, true)); - items.push(...this.renderFileSubtree(mode, unstaged, 1, compact)); - } - } else { - items = this.renderFileSubtree(mode, files, 0, compact); - } - - return html`${items}`; - } - - private renderFileSubtree(mode: Mode, files: Files, rootLevel: number, compact: boolean) { - const tree = makeHierarchical( - files, - n => n.path.split('/'), - (...parts: string[]) => parts.join('/'), - compact, - ); - const flatTree = flattenHeirarchy(tree); - return flatTree.map(({ level, item }) => { - if (item.name === '') return undefined; - - if (item.value == null) { - return html` - - - ${item.name} - - `; - } - - return this.renderFile(mode, item.value, rootLevel + level, true); - }); - } - - private renderFile(mode: Mode, file: File, level: number = 1, tree: boolean = false): TemplateResult<1> { - return html` - - `; + get indentGuides(): 'none' | 'onHover' | 'always' { + return this.preferences?.indentGuides ?? 'none'; } protected renderChangedFiles(mode: Mode, subtitle?: TemplateResult<1>) { - const layout = this.preferences?.files?.layout ?? 'auto'; - + const isTree = this.isTree(this.files?.length ?? 0); let value = 'tree'; let icon = 'list-tree'; let label = 'View as Tree'; - let isTree = false; - if (this.preferences != null && this.files != null) { - if (layout === 'auto') { - isTree = this.files.length > (this.preferences.files?.threshold ?? 5); - } else { - isTree = layout === 'tree'; - } - - switch (layout) { - case 'auto': - value = 'list'; - icon = 'gl-list-auto'; - label = 'View as List'; - break; - case 'list': - value = 'tree'; - icon = 'list-flat'; - label = 'View as Tree'; - break; - case 'tree': - value = 'auto'; - icon = 'list-tree'; - label = 'View as Auto'; - break; - } + switch (this.fileLayout) { + case 'auto': + value = 'list'; + icon = 'gl-list-auto'; + label = 'View as List'; + break; + case 'list': + value = 'tree'; + icon = 'list-flat'; + label = 'View as Tree'; + break; + case 'tree': + value = 'auto'; + icon = 'list-tree'; + label = 'View as Auto'; + break; } + const treeModel = this.createTreeModel(mode, this.files ?? [], isTree, this.isCompact); + return html` Files changed @@ -198,31 +91,7 @@ export class GlDetailsBase extends LitElement { > -
- ${when( - this.files == null, - () => html` -
- -
-
- -
-
- -
- `, - () => - when( - this.files!.length > 0, - () => - isTree - ? this.renderFileTree(mode, this.files!) - : this.renderFileList(mode, this.files!), - () => html`

${this.emptyText}

`, - ), - )} -
+ ${this.renderTreeFileModel(treeModel)}
`; } @@ -240,36 +109,392 @@ export class GlDetailsBase extends LitElement { protected override createRenderRoot() { return this; } -} -function flattenHeirarchy(item: HierarchicalItem, level = 0): { level: number; item: HierarchicalItem }[] { - const flattened: { level: number; item: HierarchicalItem }[] = []; - if (item == null) return flattened; + // Tree Model changes + protected isTree(count: number) { + if (this.fileLayout === 'auto') { + return count > (this.preferences?.files?.threshold ?? 5); + } + return this.fileLayout === 'tree'; + } - flattened.push({ level: level, item: item }); + protected createTreeModel(mode: Mode, files: Files, isTree = false, compact = true): TreeModel[] { + if (!this.isUncommitted) { + return this.createFileTreeModel(mode, files, isTree, compact); + } - if (item.children != null) { - const children = Array.from(item.children.values()); - children.sort((a, b) => { - if (!a.value || !b.value) { - return (a.value ? 1 : -1) - (b.value ? 1 : -1); + const children = []; + const staged: Files = []; + const unstaged: Files = []; + for (const f of files) { + if (f.staged) { + staged.push(f); + } else { + unstaged.push(f); } + } - if (a.relativePath < b.relativePath) { - return -1; + if (staged.length === 0 || unstaged.length === 0) { + children.push(...this.createFileTreeModel(mode, files, isTree, compact)); + } else { + if (staged.length) { + children.push({ + label: 'Staged Changes', + path: '', + level: 1, // isMulti ? 2 : 1, + branch: true, + checkable: false, + expanded: true, + checked: false, // change.checked !== false, + // disableCheck: true, + context: ['staged'], + children: this.createFileTreeModel(mode, staged, isTree, compact, { level: 2 }), + actions: this.getStagedActions(), + }); } - if (a.relativePath > b.relativePath) { - return 1; + if (unstaged.length) { + children.push({ + label: 'Unstaged Changes', + path: '', + level: 1, // isMulti ? 2 : 1, + branch: true, + checkable: false, + expanded: true, + checked: false, // change.checked === true, + context: ['unstaged'], + children: this.createFileTreeModel(mode, unstaged, isTree, compact, { level: 2 }), + actions: this.getUnstagedActions(), + }); } + } + + return children; + } + + protected sortChildren(children: TreeModel[]): TreeModel[] { + children.sort((a, b) => { + if (a.branch && !b.branch) return -1; + if (!a.branch && b.branch) return 1; + + if (a.label < b.label) return -1; + if (a.label > b.label) return 1; return 0; }); - children.forEach(child => { - flattened.push(...flattenHeirarchy(child, level + 1)); + return children; + } + + protected createFileTreeModel( + mode: Mode, + files: Files, + isTree = false, + compact = true, + options: Partial = { level: 1 }, + ): TreeModel[] { + if (options.level === undefined) { + options.level = 1; + } + + if (!files.length) { + return [ + { + label: 'No changes', + path: '', + level: options.level, + branch: false, + checkable: false, + expanded: true, + checked: false, + }, + ]; + } + + const children: TreeModel[] = []; + if (isTree) { + const fileTree = makeHierarchical( + files, + n => n.path.split('/'), + (...parts: string[]) => parts.join('/'), + compact, + ); + if (fileTree.children != null) { + for (const child of fileTree.children.values()) { + const childModel = this.walkFileTree(child, { level: options.level }); + children.push(childModel); + } + } + } else { + for (const file of files) { + const child = this.fileToTreeModel(file, { level: options.level, branch: false }, true); + children.push(child); + } + } + + this.sortChildren(children); + + return children; + } + + protected walkFileTree(item: HierarchicalItem, options: Partial = { level: 1 }): TreeModel { + if (options.level === undefined) { + options.level = 1; + } + + let model: TreeModel; + if (item.value == null) { + model = this.folderToTreeModel(item.name, options); + } else { + model = this.fileToTreeModel(item.value, options); + } + + if (item.children != null) { + const children = []; + for (const child of item.children.values()) { + const childModel = this.walkFileTree(child, { ...options, level: options.level + 1 }); + children.push(childModel); + } + + if (children.length > 0) { + this.sortChildren(children); + model.branch = true; + model.children = children; + } + } + + return model; + } + + protected getStagedActions(_options?: Partial): TreeItemAction[] { + if (this.tab === 'wip') { + return [ + { + icon: 'gl-cloud-patch-share', + label: 'Share Staged Changes', + action: 'staged-create-patch', + }, + ]; + } + return []; + } + + protected getUnstagedActions(_options?: Partial): TreeItemAction[] { + if (this.tab === 'wip') { + return [ + { + icon: 'gl-cloud-patch-share', + label: 'Share Unstaged Changes', + action: 'unstaged-create-patch', + }, + ]; + } + return []; + } + + protected getFileActions(_file: File, _options?: Partial): TreeItemAction[] { + return []; + } + + protected fileToTreeModel( + file: File, + options?: Partial, + flat = false, + glue = '/', + ): TreeModel { + const pathIndex = file.path.lastIndexOf(glue); + const fileName = pathIndex !== -1 ? file.path.substring(pathIndex + 1) : file.path; + const filePath = flat && pathIndex !== -1 ? file.path.substring(0, pathIndex) : ''; + + return { + branch: false, + expanded: true, + path: file.path, + level: 1, + checkable: false, + checked: false, + icon: 'file', //{ type: 'status', name: file.status }, + label: fileName, + description: flat === true ? filePath : undefined, + context: [file], + actions: this.getFileActions(file, options), + decorations: [{ type: 'text', label: file.status }], + ...options, + }; + } + + protected folderToTreeModel(name: string, options?: Partial): TreeModel { + return { + branch: false, + expanded: true, + path: name, + level: 1, + checkable: false, + checked: false, + icon: 'folder', + label: name, + ...options, + }; + } + + protected renderTreeFileModel(treeModel: TreeModel[]) { + return html``; + } + + // Tree Model action events + // protected onTreeItemActionClicked?(_e: CustomEvent): void; + protected onTreeItemActionClicked(e: CustomEvent) { + if (!e.detail.context || !e.detail.action) return; + + const action = e.detail.action; + switch (action.action) { + // stage actions + case 'staged-create-patch': + this.onCreatePatch(e); + break; + case 'unstaged-create-patch': + this.onCreatePatch(e, true); + break; + // file actions + case 'file-open': + this.onOpenFile(e); + break; + case 'file-unstage': + this.onUnstageFile(e); + break; + case 'file-stage': + this.onStageFile(e); + break; + case 'file-compare-working': + this.onCompareWorking(e); + break; + case 'file-open-on-remote': + this.onOpenFileOnRemote(e); + break; + case 'file-more-actions': + this.onMoreActions(e); + break; + } + } + + protected onTreeItemChecked?(_e: CustomEvent): void; + + // protected onTreeItemSelected?(_e: CustomEvent): void; + protected onTreeItemSelected(e: CustomEvent) { + if (!e.detail.context) return; + + this.onComparePrevious(e); + } + onCreatePatch(_e: CustomEvent, isAll = false) { + const event = new CustomEvent('create-patch', { + detail: { + checked: isAll ? true : 'staged', + }, + }); + this.dispatchEvent(event); + } + onOpenFile(e: CustomEvent) { + if (!e.detail.context) return; + + const [file] = e.detail.context; + const event = new CustomEvent('file-open', { + detail: this.getEventDetail(file, { + preview: false, + viewColumn: e.detail.altKey ? BesideViewColumn : undefined, + }), + }); + this.dispatchEvent(event); + } + + onOpenFileOnRemote(e: CustomEvent) { + if (!e.detail.context) return; + + const [file] = e.detail.context; + const event = new CustomEvent('file-open-on-remote', { + detail: this.getEventDetail(file, { + preview: false, + viewColumn: e.detail.altKey ? BesideViewColumn : undefined, + }), + }); + this.dispatchEvent(event); + } + + onCompareWorking(e: CustomEvent) { + if (!e.detail.context) return; + + const [file] = e.detail.context; + const event = new CustomEvent('file-compare-working', { + detail: this.getEventDetail(file, { + preview: false, + viewColumn: e.detail.altKey ? BesideViewColumn : undefined, + }), + }); + this.dispatchEvent(event); + } + + onComparePrevious(e: CustomEvent) { + if (!e.detail.context) return; + + const [file] = e.detail.context; + const event = new CustomEvent('file-compare-previous', { + detail: this.getEventDetail(file, { + preview: false, + viewColumn: e.detail.altKey ? BesideViewColumn : undefined, + }), + }); + this.dispatchEvent(event); + } + + onMoreActions(e: CustomEvent) { + if (!e.detail.context) return; + + const [file] = e.detail.context; + const event = new CustomEvent('file-more-actions', { + detail: this.getEventDetail(file), + }); + this.dispatchEvent(event); + } + + onStageFile(e: CustomEvent) { + if (!e.detail.context) return; + + const [file] = e.detail.context; + const event = new CustomEvent('file-stage', { + detail: this.getEventDetail(file, { + preview: false, + viewColumn: e.detail.altKey ? BesideViewColumn : undefined, + }), }); + this.dispatchEvent(event); } - return flattened; + onUnstageFile(e: CustomEvent) { + if (!e.detail.context) return; + + const [file] = e.detail.context; + const event = new CustomEvent('file-unstage', { + detail: this.getEventDetail(file, { + preview: false, + viewColumn: e.detail.altKey ? BesideViewColumn : undefined, + }), + }); + this.dispatchEvent(event); + } + + private getEventDetail(file: File, showOptions?: TextDocumentShowOptions): FileChangeListItemDetail { + return { + path: file.path, + repoPath: file.repoPath, + status: file.status, + // originalPath: this.originalPath, + staged: file.staged, + showOptions: showOptions, + }; + } } diff --git a/src/webviews/apps/commitDetails/components/gl-wip-details.ts b/src/webviews/apps/commitDetails/components/gl-wip-details.ts index d2d3bba62b75d..4739e71549da7 100644 --- a/src/webviews/apps/commitDetails/components/gl-wip-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-wip-details.ts @@ -3,6 +3,8 @@ import { customElement, property } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import { pluralize } from '../../../../system/string'; import type { Wip } from '../../../commitDetails/protocol'; +import type { TreeItemAction, TreeItemBase } from '../../shared/components/tree/base'; +import type { File } from './gl-details-base'; import { GlDetailsBase } from './gl-details-base'; @customElement('gl-wip-details') @@ -76,4 +78,16 @@ export class GlWipDetails extends GlDetailsBase { ${this.renderChangedFiles('wip')} `; } + + override getFileActions(file: File, _options?: Partial): TreeItemAction[] { + const openFile = { + icon: 'go-to-file', + label: 'Open file', + action: 'file-open', + }; + if (file.staged === true) { + return [openFile, { icon: 'remove', label: 'Unstage changes', action: 'file-unstage' }]; + } + return [openFile, { icon: 'plus', label: 'Stage changes', action: 'file-stage' }]; + } } diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index 69d31ea602fc3..1f1108ee347a2 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -399,7 +399,8 @@ export class CommitDetailsWebviewProvider 'views.commitDetails.files', 'views.commitDetails.avatars', ]) || - configuration.changedAny(e, 'workbench.tree.renderIndentGuides') + configuration.changedAny(e, 'workbench.tree.renderIndentGuides') || + configuration.changedAny(e, 'workbench.tree.indent') ) { this.updatePendingContext({ preferences: { @@ -430,6 +431,7 @@ export class CommitDetailsWebviewProvider configuration.getAny( 'workbench.tree.renderIndentGuides', ) ?? 'onHover', + indent: configuration.getAny('workbench.tree.indent'), }; } diff --git a/src/webviews/commitDetails/protocol.ts b/src/webviews/commitDetails/protocol.ts index 7989e442c149d..0a4c1038964b6 100644 --- a/src/webviews/commitDetails/protocol.ts +++ b/src/webviews/commitDetails/protocol.ts @@ -37,7 +37,7 @@ export interface Preferences { avatars: boolean; dateFormat: DateTimeFormat | string; files: Config['views']['commitDetails']['files']; - // indent: number; + indent: number | undefined; indentGuides: 'none' | 'onHover' | 'always'; } export type UpdateablePreferences = Partial>; From d2bcd89a1666339bc0da406e02d0524ca25ac775 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Mon, 20 Nov 2023 11:46:47 -0500 Subject: [PATCH 0256/1012] Fixes explain ai button style and interactions --- .../apps/commitDetails/components/gl-commit-details.ts | 2 +- src/webviews/commitDetails/commitDetailsWebview.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/webviews/apps/commitDetails/components/gl-commit-details.ts b/src/webviews/apps/commitDetails/components/gl-commit-details.ts index c4a07ab5dd663..ddbffaef4129a 100644 --- a/src/webviews/apps/commitDetails/components/gl-commit-details.ts +++ b/src/webviews/apps/commitDetails/components/gl-commit-details.ts @@ -321,7 +321,7 @@ export class GlCommitDetails extends GlDetailsBase {

Let AI assist in understanding the changes made with this commit.

- +

Cloud Patches + Cloud Patches ☁️ Preview

@@ -541,6 +544,7 @@

Popular views

Cloud Patches ☁️ { this.updateState(); }); break; + case DidChangeOrgSettingsType.method: + onIpc(DidChangeOrgSettingsType, msg, params => { + this.state.orgSettings = params.orgSettings; + this.setState(this.state); + this.updateOrgSettings(); + }); + break; default: super.onMessageReceived?.(msg); break; @@ -94,6 +105,16 @@ export class WelcomeApp extends App { this.updateRepoState(); this.updateAccountState(); this.updatePromo(); + this.updateOrgSettings(); + } + + private updateOrgSettings() { + const { + orgSettings: { drafts, ai }, + } = this.state; + + document.body.dataset.orgDrafts = drafts ? 'allowed' : 'blocked'; + document.body.dataset.orgAi = ai ? 'allowed' : 'blocked'; } private updatePromo() { diff --git a/src/webviews/home/homeWebview.ts b/src/webviews/home/homeWebview.ts index 2652413b83843..097e747b6a344 100644 --- a/src/webviews/home/homeWebview.ts +++ b/src/webviews/home/homeWebview.ts @@ -1,12 +1,14 @@ import { Disposable, workspace } from 'vscode'; +import type { ContextKeys } from '../../constants'; import type { Container } from '../../container'; import type { Subscription } from '../../plus/gk/account/subscription'; import { isSubscriptionExpired, isSubscriptionPaid, isSubscriptionTrial } from '../../plus/gk/account/subscription'; import type { SubscriptionChangeEvent } from '../../plus/gk/account/subscriptionService'; import { registerCommand } from '../../system/command'; +import { getContext, onDidChangeContext } from '../../system/context'; import type { WebviewController, WebviewProvider } from '../webviewController'; import type { DidChangeRepositoriesParams, State } from './protocol'; -import { DidChangeRepositoriesType, DidChangeSubscriptionType } from './protocol'; +import { DidChangeOrgSettingsType, DidChangeRepositoriesType, DidChangeSubscriptionType } from './protocol'; const emptyDisposable = Object.freeze({ dispose: () => { @@ -27,6 +29,7 @@ export class HomeWebviewProvider implements WebviewProvider { ? workspace.onDidGrantWorkspaceTrust(this.notifyDidChangeRepositories, this) : emptyDisposable, this.container.subscription.onDidChange(this.onSubscriptionChanged, this), + onDidChangeContext(this.onContextChanged, this), ); } @@ -50,6 +53,18 @@ export class HomeWebviewProvider implements WebviewProvider { this.notifyDidChangeRepositories(); } + private getOrgSettings(): State['orgSettings'] { + return { + drafts: !getContext('gitlens:gk:organization:drafts:disabled', false), + }; + } + + private onContextChanged(key: ContextKeys) { + if (key === 'gitlens:gk:organization:drafts:disabled') { + this.notifyDidChangeOrgSettings(); + } + } + private onSubscriptionChanged(e: SubscriptionChangeEvent) { void this.notifyDidChangeSubscription(e.current); } @@ -60,6 +75,7 @@ export class HomeWebviewProvider implements WebviewProvider { repositories: this.getRepositoriesState(), webroot: this.host.getWebRoot(), promoStates: await this.getCanShowPromos(subscription), + orgSettings: this.getOrgSettings(), }; } @@ -98,4 +114,10 @@ export class HomeWebviewProvider implements WebviewProvider { promoStates: await this.getCanShowPromos(subscription), }); } + + private notifyDidChangeOrgSettings() { + void this.host.notify(DidChangeOrgSettingsType, { + orgSettings: this.getOrgSettings(), + }); + } } diff --git a/src/webviews/home/protocol.ts b/src/webviews/home/protocol.ts index 70c4e14f22b3f..07fa6c2f86a8c 100644 --- a/src/webviews/home/protocol.ts +++ b/src/webviews/home/protocol.ts @@ -5,6 +5,9 @@ export interface State extends WebviewState { repositories: DidChangeRepositoriesParams; webroot?: string; promoStates: Record; + orgSettings: { + drafts: boolean; + }; } export interface DidChangeRepositoriesParams { @@ -19,3 +22,8 @@ export interface DidChangeSubscriptionParams { promoStates: Record; } export const DidChangeSubscriptionType = new IpcNotificationType('subscription/didChange'); + +export interface DidChangeOrgSettingsParams { + orgSettings: State['orgSettings']; +} +export const DidChangeOrgSettingsType = new IpcNotificationType('org/settings/didChange'); diff --git a/src/webviews/welcome/protocol.ts b/src/webviews/welcome/protocol.ts index a0bd30b2488c9..11533aaac1cd3 100644 --- a/src/webviews/welcome/protocol.ts +++ b/src/webviews/welcome/protocol.ts @@ -11,6 +11,10 @@ export interface State extends WebviewState { repoFeaturesBlocked?: boolean; isTrialOrPaid: boolean; canShowPromo: boolean; + orgSettings: { + ai: boolean; + drafts: boolean; + }; } export interface UpdateConfigurationParams { @@ -25,3 +29,8 @@ export interface DidChangeParams { state: State; } export const DidChangeNotificationType = new IpcNotificationType('welcome/didChange', true); + +export interface DidChangeOrgSettingsParams { + orgSettings: State['orgSettings']; +} +export const DidChangeOrgSettingsType = new IpcNotificationType('org/settings/didChange'); diff --git a/src/webviews/welcome/welcomeWebview.ts b/src/webviews/welcome/welcomeWebview.ts index 47c1d07012100..cb5e251ad1d3c 100644 --- a/src/webviews/welcome/welcomeWebview.ts +++ b/src/webviews/welcome/welcomeWebview.ts @@ -1,15 +1,17 @@ import type { ConfigurationChangeEvent } from 'vscode'; import { Disposable, workspace } from 'vscode'; +import type { ContextKeys } from '../../constants'; import type { Container } from '../../container'; import type { Subscription } from '../../plus/gk/account/subscription'; import { isSubscriptionPaid, SubscriptionState } from '../../plus/gk/account/subscription'; import type { SubscriptionChangeEvent } from '../../plus/gk/account/subscriptionService'; import { configuration } from '../../system/configuration'; +import { getContext, onDidChangeContext } from '../../system/context'; import type { IpcMessage } from '../protocol'; import { onIpc } from '../protocol'; import type { WebviewController, WebviewProvider } from '../webviewController'; import type { State, UpdateConfigurationParams } from './protocol'; -import { DidChangeNotificationType, UpdateConfigurationCommandType } from './protocol'; +import { DidChangeNotificationType, DidChangeOrgSettingsType, UpdateConfigurationCommandType } from './protocol'; const emptyDisposable = Object.freeze({ dispose: () => { @@ -31,6 +33,7 @@ export class WelcomeWebviewProvider implements WebviewProvider { ? workspace.onDidGrantWorkspaceTrust(() => this.notifyDidChange(), this) : emptyDisposable, this.container.subscription.onDidChange(this.onSubscriptionChanged, this), + onDidChangeContext(this.onContextChanged, this), ); } @@ -46,6 +49,19 @@ export class WelcomeWebviewProvider implements WebviewProvider { void this.notifyDidChange(); } + private getOrgSettings(): State['orgSettings'] { + return { + ai: !getContext('gitlens:gk:organization:ai:disabled', false), + drafts: !getContext('gitlens:gk:organization:drafts:disabled', false), + }; + } + + private onContextChanged(key: ContextKeys) { + if (['gitlens:gk:organization:ai:disabled', 'gitlens:gk:organization:drafts:disabled'].includes(key)) { + this.notifyDidChangeOrgSettings(); + } + } + private onSubscriptionChanged(e: SubscriptionChangeEvent) { void this.notifyDidChange(e.current); } @@ -78,6 +94,7 @@ export class WelcomeWebviewProvider implements WebviewProvider { this.container.git.hasUnsafeRepositories(), isTrialOrPaid: await this.getTrialOrPaidState(subscription), canShowPromo: await this.getCanShowPromo(subscription), + orgSettings: this.getOrgSettings(), }; } @@ -108,4 +125,10 @@ export class WelcomeWebviewProvider implements WebviewProvider { private async notifyDidChange(subscription?: Subscription) { void this.host.notify(DidChangeNotificationType, { state: await this.getState(subscription) }); } + + private notifyDidChangeOrgSettings() { + void this.host.notify(DidChangeOrgSettingsType, { + orgSettings: this.getOrgSettings(), + }); + } } From ceb22af67bc3700bd23cc959990f272c00b39786 Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 31 Jan 2024 15:43:43 -0500 Subject: [PATCH 0479/1012] Fixes keyboard a11y for gl-button --- src/webviews/apps/shared/components/button.ts | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/webviews/apps/shared/components/button.ts b/src/webviews/apps/shared/components/button.ts index 759fb4f73180b..86b41c7e5fe24 100644 --- a/src/webviews/apps/shared/components/button.ts +++ b/src/webviews/apps/shared/components/button.ts @@ -1,11 +1,16 @@ import type { PropertyValueMap } from 'lit'; import { css, html, LitElement } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; +import { customElement, property, query } from 'lit/decorators.js'; import { focusOutline } from './styles/lit/a11y.css'; import { elementBase } from './styles/lit/base.css'; @customElement('gl-button') export class GlButton extends LitElement { + static override shadowRootOptions: ShadowRootInit = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static override styles = [ elementBase, css` @@ -33,11 +38,7 @@ export class GlButton extends LitElement { border-radius: var(--gk-action-radius); } - :host(:not([href])) { - padding: var(--button-padding); - } - - :host([href]) > a { + .control { display: inline-block; padding: var(--button-padding); @@ -46,13 +47,24 @@ export class GlButton extends LitElement { width: 100%; height: 100%; + cursor: pointer; + } + + button.control { + appearance: none; + background: transparent; + border: none; + } + + .control:focus { + outline: none; } :host(:hover) { background: var(--button-hover-background); } - :host(:focus) { + :host(:focus-within) { ${focusOutline} } @@ -111,6 +123,9 @@ export class GlButton extends LitElement { `, ]; + @query('.control') + protected control!: HTMLElement; + @property({ type: Boolean, reflect: true }) full = false; @@ -131,20 +146,38 @@ export class GlButton extends LitElement { @property() appearance?: string; - @property({ type: Number, reflect: true }) - override tabIndex = 0; - protected override updated(changedProperties: PropertyValueMap | Map): void { super.updated(changedProperties); if (changedProperties.has('disabled')) { - this.tabIndex = this.disabled ? -1 : 0; this.setAttribute('aria-disabled', this.disabled.toString()); } } override render() { - const main = html``; - return this.href != null ? html`${main}` : main; + if (this.href != null) { + return html``; + } + return html``; + } + + override focus(options?: FocusOptions) { + this.control.focus(options); + } + + override blur() { + this.control.blur(); + } + + override click() { + this.control.click(); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'gl-button': GlButton; } } From a0223cd70062be8b50be54df08e752a3dc2bba0d Mon Sep 17 00:00:00 2001 From: Keith Daulton Date: Wed, 31 Jan 2024 17:13:20 -0500 Subject: [PATCH 0480/1012] Inverts context keys for org settings --- package.json | 32 +++++++++---------- src/constants.ts | 4 +-- src/plus/drafts/draftsService.ts | 7 +--- src/plus/gk/account/organizationService.ts | 8 ++--- .../patchDetails/patchDetailsWebview.ts | 4 +-- .../commitDetails/commitDetailsWebview.ts | 6 ++-- src/webviews/home/homeWebview.ts | 4 +-- src/webviews/welcome/welcomeWebview.ts | 6 ++-- 8 files changed, 33 insertions(+), 38 deletions(-) diff --git a/package.json b/package.json index 8139ab7d50fc4..f8b7a09ffe72e 100644 --- a/package.json +++ b/package.json @@ -8893,7 +8893,7 @@ }, { "command": "gitlens.showPatchDetailsPage", - "when": "gitlens:enabled && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled" + "when": "gitlens:enabled && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled" }, { "command": "gitlens.createPatch", @@ -8901,11 +8901,11 @@ }, { "command": "gitlens.createCloudPatch", - "when": "gitlens:enabled && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled" + "when": "gitlens:enabled && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled" }, { "command": "gitlens.shareAsCloudPatch", - "when": "gitlens:enabled && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled" + "when": "gitlens:enabled && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled" }, { "command": "gitlens.openCloudPatch", @@ -8937,7 +8937,7 @@ }, { "command": "gitlens.showDraftsView", - "when": "gitlens:enabled && !gitlens:gk:organization:drafts:disabled" + "when": "gitlens:enabled && gitlens:gk:organization:drafts:enabled" }, { "command": "gitlens.showFileHistoryView", @@ -9381,7 +9381,7 @@ }, { "command": "gitlens.switchAIModel", - "when": "gitlens:enabled && !gitlens:gk:organization:ai:disabled" + "when": "gitlens:enabled && gitlens:gk:organization:ai:enabled" }, { "command": "gitlens.switchMode", @@ -11241,11 +11241,11 @@ }, { "command": "gitlens.generateCommitMessage", - "when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:ai:disabled && config.gitlens.ai.experimental.generateCommitMessage.enabled" + "when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:ai:enabled && config.gitlens.ai.experimental.generateCommitMessage.enabled" }, { "command": "gitlens.resetAIKey", - "when": "gitlens:enabled && !gitlens:gk:organization:ai:disabled" + "when": "gitlens:enabled && gitlens:gk:organization:ai:enabled" } ], "editor/context": [ @@ -11605,7 +11605,7 @@ }, { "command": "gitlens.generateCommitMessage", - "when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:ai:disabled && config.gitlens.ai.experimental.generateCommitMessage.enabled && config.gitlens.menus.scmRepository.generateCommitMessage", + "when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:ai:enabled && config.gitlens.ai.experimental.generateCommitMessage.enabled && config.gitlens.menus.scmRepository.generateCommitMessage", "group": "4_gitlens@2" } ], @@ -11641,7 +11641,7 @@ }, { "command": "gitlens.generateCommitMessage", - "when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:ai:disabled && config.gitlens.ai.experimental.generateCommitMessage.enabled && scmProvider == git && config.gitlens.menus.scmRepository.generateCommitMessage", + "when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:ai:enabled && config.gitlens.ai.experimental.generateCommitMessage.enabled && scmProvider == git && config.gitlens.menus.scmRepository.generateCommitMessage", "group": "2_z_gitlens@2" }, { @@ -12978,7 +12978,7 @@ }, { "command": "gitlens.createCloudPatch", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:(commit|stash)\\b/", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:(commit|stash)\\b/", "group": "1_gitlens_actions_1@3" }, { @@ -13873,7 +13873,7 @@ }, { "command": "gitlens.createCloudPatch", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:compare:results(?!:)\\b/", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:compare:results(?!:)\\b/", "group": "1_gitlens_secondary_actions@2" }, { @@ -14271,7 +14271,7 @@ }, { "command": "gitlens.createCloudPatch", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled && webviewItem =~ /gitlens:(commit|stash)\\b/", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && webviewItem =~ /gitlens:(commit|stash)\\b/", "group": "1_gitlens_actions_1@3" }, { @@ -14534,12 +14534,12 @@ "gitlens/share": [ { "command": "gitlens.shareAsCloudPatch", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:((commit|stash|compare:results(?!:)|)\\b|file\\b(?=.*?\\b\\+committed\\b))/", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:((commit|stash|compare:results(?!:)|)\\b|file\\b(?=.*?\\b\\+committed\\b))/", "group": "1_a_gitlens@1" }, { "command": "gitlens.graph.shareAsCloudPatch", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled && webviewItem =~ /gitlens:(commit|stash)\\b/", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && webviewItem =~ /gitlens:(commit|stash)\\b/", "group": "1_a_gitlens@1" }, { @@ -14787,7 +14787,7 @@ }, { "command": "gitlens.createCloudPatch", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/", "group": "1_gitlens_secondary_actions@3" }, { @@ -16021,7 +16021,7 @@ { "id": "gitlens.views.drafts", "name": "Cloud Patches", - "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && !gitlens:gk:organization:drafts:disabled && config.gitlens.cloudPatches.enabled", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled", "contextualTitle": "GitLens", "icon": "$(gitlens-cloud-patch)", "initialSize": 2, diff --git a/src/constants.ts b/src/constants.ts index dc08174d7d0af..3f6ec91b9c1d6 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -633,9 +633,9 @@ export type ContextKeys = | `${typeof extensionPrefix}:disabled` | `${typeof extensionPrefix}:enabled` | `${typeof extensionPrefix}:gk:hasOrganizations` - | `${typeof extensionPrefix}:gk:organization:ai:disabled` + | `${typeof extensionPrefix}:gk:organization:ai:enabled` | `${typeof extensionPrefix}:gk:organization:drafts:byob` - | `${typeof extensionPrefix}:gk:organization:drafts:disabled` + | `${typeof extensionPrefix}:gk:organization:drafts:enabled` | `${typeof extensionPrefix}:hasConnectedRemotes` | `${typeof extensionPrefix}:hasRemotes` | `${typeof extensionPrefix}:hasRichRemotes` diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index 8523b7b482612..bab36ee9b6c5e 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -402,12 +402,7 @@ export class DraftService implements Disposable { const rsp = await this.connection.fetchGkDevApi('/v1/drafts', { method: 'GET' }); if (!rsp.ok) { - let message = 'Unable to open drafts'; - if (rsp.status === 403) { - message = - "The Cloud Patches feature has been disabled by your organization. Please contact your organization's admin to enable it"; - } - await handleBadDraftResponse(message, rsp, scope); + await handleBadDraftResponse('Unable to open drafts', rsp, scope); } const draft = ((await rsp.json()) as Result).data; diff --git a/src/plus/gk/account/organizationService.ts b/src/plus/gk/account/organizationService.ts index 1f6058e07e000..8972f6a952b0d 100644 --- a/src/plus/gk/account/organizationService.ts +++ b/src/plus/gk/account/organizationService.ts @@ -139,14 +139,14 @@ export class OrganizationService implements Disposable { private async updateOrganizationPermissions(orgId: string | undefined): Promise { const settings = orgId != null ? await this.getOrganizationSettings(orgId) : undefined; if (settings == null) { - void setContext('gitlens:gk:organization:ai:disabled', false); - void setContext('gitlens:gk:organization:drafts:disabled', false); + void setContext('gitlens:gk:organization:ai:enabled', true); + void setContext('gitlens:gk:organization:drafts:enabled', true); void setContext('gitlens:gk:organization:drafts:byob', false); return; } - void setContext('gitlens:gk:organization:ai:disabled', settings.aiSettings.enabled === false); - void setContext('gitlens:gk:organization:drafts:disabled', settings.draftsSettings.enabled === false); + void setContext('gitlens:gk:organization:ai:enabled', settings.aiSettings.enabled ?? true); + void setContext('gitlens:gk:organization:drafts:enabled', settings.draftsSettings.enabled ?? true); void setContext('gitlens:gk:organization:drafts:byob', settings.draftsSettings.bucket != null); } diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 96cefb244ce53..84ad6e0ae828d 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -325,7 +325,7 @@ export class PatchDetailsWebviewProvider } private onContextChanged(key: ContextKeys) { - if (['gitlens:gk:organization:ai:disabled', 'gitlens:gk:organization:drafts:disabled'].includes(key)) { + if (['gitlens:gk:organization:ai:enabled', 'gitlens:gk:organization:drafts:enabled'].includes(key)) { this._context.orgSettings = this.getOrgSettings(); this.updateState(); } @@ -333,7 +333,7 @@ export class PatchDetailsWebviewProvider private getOrgSettings(): State['orgSettings'] { return { - ai: !getContext('gitlens:gk:organization:ai:disabled', false), + ai: getContext('gitlens:gk:organization:ai:enabled', false), byob: getContext('gitlens:gk:organization:drafts:byob', false), }; } diff --git a/src/webviews/commitDetails/commitDetailsWebview.ts b/src/webviews/commitDetails/commitDetailsWebview.ts index 2fb7f25be4e1f..296e975bea4d9 100644 --- a/src/webviews/commitDetails/commitDetailsWebview.ts +++ b/src/webviews/commitDetails/commitDetailsWebview.ts @@ -438,7 +438,7 @@ export class CommitDetailsWebviewProvider } private onContextChanged(key: ContextKeys) { - if (['gitlens:gk:organization:ai:disabled', 'gitlens:gk:organization:drafts:disabled'].includes(key)) { + if (['gitlens:gk:organization:ai:enabled', 'gitlens:gk:organization:drafts:enabled'].includes(key)) { this.updatePendingContext({ orgSettings: this.getOrgSettings() }); this.updateState(); } @@ -446,8 +446,8 @@ export class CommitDetailsWebviewProvider private getOrgSettings(): State['orgSettings'] { return { - ai: !getContext('gitlens:gk:organization:ai:disabled', false), - drafts: !getContext('gitlens:gk:organization:drafts:disabled', false), + ai: getContext('gitlens:gk:organization:ai:enabled', false), + drafts: getContext('gitlens:gk:organization:drafts:enabled', false), }; } diff --git a/src/webviews/home/homeWebview.ts b/src/webviews/home/homeWebview.ts index 097e747b6a344..8cfa28ec2bd5a 100644 --- a/src/webviews/home/homeWebview.ts +++ b/src/webviews/home/homeWebview.ts @@ -55,12 +55,12 @@ export class HomeWebviewProvider implements WebviewProvider { private getOrgSettings(): State['orgSettings'] { return { - drafts: !getContext('gitlens:gk:organization:drafts:disabled', false), + drafts: getContext('gitlens:gk:organization:drafts:enabled', false), }; } private onContextChanged(key: ContextKeys) { - if (key === 'gitlens:gk:organization:drafts:disabled') { + if (key === 'gitlens:gk:organization:drafts:enabled') { this.notifyDidChangeOrgSettings(); } } diff --git a/src/webviews/welcome/welcomeWebview.ts b/src/webviews/welcome/welcomeWebview.ts index cb5e251ad1d3c..a94b0f45e5edd 100644 --- a/src/webviews/welcome/welcomeWebview.ts +++ b/src/webviews/welcome/welcomeWebview.ts @@ -51,13 +51,13 @@ export class WelcomeWebviewProvider implements WebviewProvider { private getOrgSettings(): State['orgSettings'] { return { - ai: !getContext('gitlens:gk:organization:ai:disabled', false), - drafts: !getContext('gitlens:gk:organization:drafts:disabled', false), + ai: getContext('gitlens:gk:organization:ai:enabled', false), + drafts: getContext('gitlens:gk:organization:drafts:enabled', false), }; } private onContextChanged(key: ContextKeys) { - if (['gitlens:gk:organization:ai:disabled', 'gitlens:gk:organization:drafts:disabled'].includes(key)) { + if (['gitlens:gk:organization:ai:enabled', 'gitlens:gk:organization:drafts:enabled'].includes(key)) { this.notifyDidChangeOrgSettings(); } } From 23fffa47e66de30e15827536bcf800d7e5afcf62 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 31 Jan 2024 18:12:45 -0500 Subject: [PATCH 0481/1012] Adds open changes/compare features to PRs in the Graph Adds "Open in Commit Graph" option to prs in the views Renames "Compare Pull Request with Base" to "Compare Pull Request" --- CHANGELOG.md | 5 +- package.json | 62 ++++++++++++++++++-- src/plus/webviews/graph/graphWebview.ts | 75 ++++++++++++++++++++++--- src/plus/webviews/graph/protocol.ts | 5 ++ src/plus/webviews/graph/registration.ts | 15 +++++ src/views/nodes/pullRequestNode.ts | 27 +++++++++ 6 files changed, 174 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e8a331b3855a..db1c946d17518 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added - Adds new comparison features to pull requests in GitLens views - - Adds an _Open Pull Request Changes_ inline button and context menu command to pull requests to view the pull request changes in a multi-diff editor (single tab) + - Adds an _Open Pull Request Changes_ context menu command on pull requests in the _Commit Graph_ and other GitLens views to view pull request changes in a multi-diff editor (single tab) - Requires VS Code `1.85` or later with `multiDiffEditor.experimental.enabled` and `gitlens.experimental.openChangesInMultiDiffEditor` to be enabled - - Adds a _Compare Pull Request with Base_ inline button and context menu command to pull requests to open a comparison for the pull request + - Adds a _Compare Pull Request_ context menu command on pull requests in the _Commit Graph_ and other GitLens views to open a comparison between the head and base of the pull request for easy reviewing +- Adds an _Open in Commit Graph_ context menu command on pull requests in GitLens view to open the tip commit in the _Commit Graph_ - Adds an _Open All Changes_ inline button to branch status (upstream) and branch status files in GitLens views - Adds an _Open Changes_ submenu to branch status (upstream) and branch status files in GitLens views - Adds an alternate flow (pick another file) when using the _Open File at Revision..._ and _Open Changes with Revision..._ commands to open a file that has been renamed and the rename is currently unstaged — closes [#3109](https://github.com/gitkraken/vscode-gitlens/issues/3109) diff --git a/package.json b/package.json index f8b7a09ffe72e..36a5f44938c5a 100644 --- a/package.json +++ b/package.json @@ -6941,7 +6941,7 @@ }, { "command": "gitlens.views.openPullRequestComparison", - "title": "Compare Pull Request with Base", + "title": "Compare Pull Request", "category": "GitLens", "icon": "$(compare-changes)" }, @@ -8316,6 +8316,24 @@ "category": "GitLens", "icon": "$(git-pull-request-create)" }, + { + "command": "gitlens.graph.openPullRequest", + "title": "Open Pull Request", + "category": "GitLens", + "icon": "$(git-pull-request)" + }, + { + "command": "gitlens.graph.openPullRequestChanges", + "title": "Open Pull Request Changes", + "category": "GitLens", + "icon": "$(diff-multiple)" + }, + { + "command": "gitlens.graph.openPullRequestComparison", + "title": "Compare Pull Request", + "category": "GitLens", + "icon": "$(compare-changes)" + }, { "command": "gitlens.graph.openPullRequestOnRemote", "title": "Open Pull Request on Remote", @@ -11067,6 +11085,18 @@ "command": "gitlens.graph.createPullRequest", "when": "false" }, + { + "command": "gitlens.graph.openPullRequest", + "when": "false" + }, + { + "command": "gitlens.graph.openPullRequestChanges", + "when": "false" + }, + { + "command": "gitlens.graph.openPullRequestComparison", + "when": "false" + }, { "command": "gitlens.graph.openPullRequestOnRemote", "when": "false" @@ -13265,13 +13295,13 @@ "alt": "gitlens.copyRemotePullRequestUrl" }, { - "command": "gitlens.views.openPullRequest", - "when": "gitlens:action:openPullRequest > 1 && viewItem =~ /gitlens:pullrequest\\b/", + "command": "gitlens.views.openPullRequestChanges", + "when": "config.gitlens.experimental.openChangesInMultiDiffEditor && viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", "group": "1_gitlens_actions@1" }, { - "command": "gitlens.views.openPullRequestChanges", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor && viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", + "command": "gitlens.views.openPullRequest", + "when": "gitlens:action:openPullRequest > 1 && viewItem =~ /gitlens:pullrequest\\b/", "group": "1_gitlens_actions@98" }, { @@ -13280,6 +13310,11 @@ "group": "1_gitlens_actions@99", "alt": "gitlens.copyRemotePullRequestUrl" }, + { + "command": "gitlens.showInCommitGraph", + "when": "viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", + "group": "3_gitlens_explore@1" + }, { "command": "gitlens.views.openPullRequestComparison", "when": "viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", @@ -14355,10 +14390,25 @@ "when": "webviewItem =~ /gitlens:tag\\b/", "group": "8_gitlens_actions@10" }, + { + "command": "gitlens.graph.openPullRequestChanges", + "when": "config.gitlens.experimental.openChangesInMultiDiffEditor && webviewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", + "group": "1_gitlens_actions@1" + }, + { + "command": "gitlens.graph.openPullRequest", + "when": "gitlens:action:openPullRequest > 1 && webviewItem =~ /gitlens:pullrequest\\b/", + "group": "1_gitlens_actions@98" + }, { "command": "gitlens.graph.openPullRequestOnRemote", "when": "webviewItem =~ /gitlens:pullrequest\\b/", - "group": "1_gitlens_actions@1" + "group": "1_gitlens_actions@99" + }, + { + "command": "gitlens.graph.openPullRequestComparison", + "when": "webviewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", + "group": "4_gitlens_compare@1" }, { "command": "gitlens.graph.push", diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 918c1d129d771..7573efe4b4a55 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -1,6 +1,6 @@ import type { ColorTheme, ConfigurationChangeEvent, Uri } from 'vscode'; import { CancellationTokenSource, Disposable, env, window } from 'vscode'; -import type { CreatePullRequestActionContext } from '../../../api/gitlens'; +import type { CreatePullRequestActionContext, OpenPullRequestActionContext } from '../../../api/gitlens'; import { getAvatarUri } from '../../../avatars'; import { parseCommandContext } from '../../../commands/base'; import type { CopyDeepLinkCommandArgs } from '../../../commands/copyDeepLink'; @@ -454,6 +454,9 @@ export class GraphWebviewProvider implements WebviewProvider({ - webviewItem: 'gitlens:pullrequest', + webviewItem: `gitlens:pullrequest${pr.refs ? '+refs' : ''}`, webviewItemValue: { type: 'pullrequest', id: pr.id, url: pr.url, + repoPath: repoPath, + refs: pr.refs, + provider: { + id: pr.provider.id, + name: pr.provider.name, + domain: pr.provider.domain, + icon: pr.provider.icon, + }, }, }), }; @@ -2644,13 +2655,63 @@ export class GraphWebviewProvider implements WebviewProvider('openPullRequest', { + repoPath: pr.repoPath, + provider: { + id: pr.provider.id, + name: pr.provider.name, + domain: pr.provider.domain, + }, + pullRequest: { + id: pr.id, + url: pr.url, + }, + }); + } + + return Promise.resolve(); + } + + @debug() + private openPullRequestChanges(item?: GraphItemContext) { + if (isGraphItemTypedContext(item, 'pullrequest')) { + const pr = item.webviewItemValue; + if (pr.refs?.base != null && pr.refs.head != null) { + return this.container.searchAndCompareView.openComparisonChanges( + pr.repoPath, + { ref: pr.refs.head.sha, label: pr.refs.head.branch }, + { ref: pr.refs.base.sha, label: pr.refs.base.branch }, + { title: `Changes in Pull Request #${pr.id}` }, + ); + } + } + + return Promise.resolve(); + } + + @debug() + private openPullRequestComparison(item?: GraphItemContext) { + if (isGraphItemTypedContext(item, 'pullrequest')) { + const pr = item.webviewItemValue; + if (pr.refs?.base != null && pr.refs.head != null) { + return this.container.searchAndCompareView.compare( + pr.repoPath, + { ref: pr.refs.head.sha, label: pr.refs.head.branch }, + { ref: pr.refs.base.sha, label: pr.refs.base.branch }, + ); + } + } + + return Promise.resolve(); + } + @debug() private openPullRequestOnRemote(item?: GraphItemContext, clipboard?: boolean) { - if ( - isGraphItemContext(item) && - typeof item.webviewItemValue === 'object' && - item.webviewItemValue.type === 'pullrequest' - ) { + if (isGraphItemTypedContext(item, 'pullrequest')) { const { url } = item.webviewItemValue; return executeCommand(Commands.OpenPullRequestOnRemote, { pr: { url: url }, diff --git a/src/plus/webviews/graph/protocol.ts b/src/plus/webviews/graph/protocol.ts index e3f07b98062da..4a75c83179b82 100644 --- a/src/plus/webviews/graph/protocol.ts +++ b/src/plus/webviews/graph/protocol.ts @@ -26,6 +26,7 @@ import type { Config, DateStyle } from '../../../config'; import type { RepositoryVisibility } from '../../../git/gitProvider'; import type { GitTrackingState } from '../../../git/models/branch'; import type { GitGraphRowType } from '../../../git/models/graph'; +import type { PullRequestRefs } from '../../../git/models/pullRequest'; import type { GitBranchReference, GitReference, @@ -33,6 +34,7 @@ import type { GitStashReference, GitTagReference, } from '../../../git/models/reference'; +import type { RemoteProviderReference } from '../../../git/models/remoteProvider'; import type { GitSearchResultData, SearchQuery } from '../../../git/search'; import type { DateTimeFormat } from '../../../system/date'; import type { WebviewItemContext, WebviewItemGroupContext } from '../../../system/webview'; @@ -485,6 +487,9 @@ export interface GraphPullRequestContextValue { type: 'pullrequest'; id: string; url: string; + repoPath: string; + refs?: PullRequestRefs; + provider: RemoteProviderReference; } export interface GraphBranchContextValue { diff --git a/src/plus/webviews/graph/registration.ts b/src/plus/webviews/graph/registration.ts index 73c6165719d67..69056cc90ab18 100644 --- a/src/plus/webviews/graph/registration.ts +++ b/src/plus/webviews/graph/registration.ts @@ -11,6 +11,7 @@ import { ViewNode } from '../../../views/nodes/abstract/viewNode'; import type { BranchNode } from '../../../views/nodes/branchNode'; import type { CommitFileNode } from '../../../views/nodes/commitFileNode'; import type { CommitNode } from '../../../views/nodes/commitNode'; +import { PullRequestNode } from '../../../views/nodes/pullRequestNode'; import type { StashNode } from '../../../views/nodes/stashNode'; import type { TagNode } from '../../../views/nodes/tagNode'; import type { @@ -137,9 +138,16 @@ export function registerGraphWebviewCommands( | BranchNode | CommitNode | CommitFileNode + | PullRequestNode | StashNode | TagNode, ) => { + if (args instanceof PullRequestNode) { + if (args.ref == null) return; + + args = { ref: args.ref }; + } + const preserveFocus = 'preserveFocus' in args ? args.preserveFocus ?? false : false; if (configuration.get('graph.layout') === 'panel') { if (!container.graphView.visible) { @@ -165,9 +173,16 @@ export function registerGraphWebviewCommands( | BranchNode | CommitNode | CommitFileNode + | PullRequestNode | StashNode | TagNode, ) => { + if (args instanceof PullRequestNode) { + if (args.ref == null) return; + + args = { ref: args.ref }; + } + const preserveFocus = 'preserveFocus' in args ? args.preserveFocus ?? false : false; void container.graphView.show({ preserveFocus: preserveFocus }, args); }, diff --git a/src/views/nodes/pullRequestNode.ts b/src/views/nodes/pullRequestNode.ts index af1e93a4507f5..12041d9f9e172 100644 --- a/src/views/nodes/pullRequestNode.ts +++ b/src/views/nodes/pullRequestNode.ts @@ -4,6 +4,7 @@ import { GitBranch } from '../../git/models/branch'; import type { GitCommit } from '../../git/models/commit'; import { getIssueOrPullRequestMarkdownIcon, getIssueOrPullRequestThemeIcon } from '../../git/models/issue'; import type { PullRequest } from '../../git/models/pullRequest'; +import type { GitBranchReference } from '../../git/models/reference'; import type { ViewsWithCommits } from '../viewBase'; import { ContextValues, getViewNodeId, ViewNode } from './abstract/viewNode'; @@ -47,6 +48,32 @@ export class PullRequestNode extends ViewNode<'pullrequest', ViewsWithCommits> { return this.pullRequest.url; } + get baseRef(): GitBranchReference | undefined { + if (this.pullRequest.refs?.base != null) { + return { + refType: 'branch', + repoPath: this.repoPath, + ref: this.pullRequest.refs.base.sha, + name: this.pullRequest.refs.base.branch, + remote: true, + }; + } + return undefined; + } + + get ref(): GitBranchReference | undefined { + if (this.pullRequest.refs?.head != null) { + return { + refType: 'branch', + repoPath: this.repoPath, + ref: this.pullRequest.refs.head.sha, + name: this.pullRequest.refs.head.branch, + remote: true, + }; + } + return undefined; + } + getChildren(): ViewNode[] { return []; } From a02e1a9aa8451b1fff7b6f1b3d900306470339a8 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 31 Jan 2024 18:32:37 -0500 Subject: [PATCH 0482/1012] Renames FocusService to EnrichmentService --- src/container.ts | 20 +++---- .../{focusService.ts => enrichmentService.ts} | 56 +++++++++++++------ src/plus/webviews/focus/focusWebview.ts | 37 ++++++------ src/plus/webviews/focus/protocol.ts | 2 +- 4 files changed, 69 insertions(+), 46 deletions(-) rename src/plus/focus/{focusService.ts => enrichmentService.ts} (72%) diff --git a/src/container.ts b/src/container.ts index fab99f76d2bd8..47934eaf73baf 100644 --- a/src/container.ts +++ b/src/container.ts @@ -19,7 +19,7 @@ import { GitProviderService } from './git/gitProviderService'; import { LineHoverController } from './hovers/lineHoverController'; import type { RepositoryPathMappingProvider } from './pathMapping/repositoryPathMappingProvider'; import { DraftService } from './plus/drafts/draftsService'; -import { FocusService } from './plus/focus/focusService'; +import { EnrichmentService } from './plus/focus/enrichmentService'; import { AccountAuthenticationProvider } from './plus/gk/account/authenticationProvider'; import { OrganizationService } from './plus/gk/account/organizationService'; import { SubscriptionService } from './plus/gk/account/subscriptionService'; @@ -460,6 +460,15 @@ export class Container { return this._documentTracker; } + private _enrichments: EnrichmentService | undefined; + get enrichments() { + if (this._enrichments == null) { + this._disposables.push((this._enrichments = new EnrichmentService(this, new ServerConnection(this)))); + } + + return this._enrichments; + } + @memoize() get env(): Environment { if (this.prereleaseOrDebugging) { @@ -486,15 +495,6 @@ export class Container { return this._fileHistoryView; } - private _focus: FocusService | undefined; - get focus() { - if (this._focus == null) { - this._disposables.push((this._focus = new FocusService(this, new ServerConnection(this)))); - } - - return this._focus; - } - private readonly _git: GitProviderService; get git() { return this._git; diff --git a/src/plus/focus/focusService.ts b/src/plus/focus/enrichmentService.ts similarity index 72% rename from src/plus/focus/focusService.ts rename to src/plus/focus/enrichmentService.ts index 09d87008eb1c8..4f7ba2b464d15 100644 --- a/src/plus/focus/focusService.ts +++ b/src/plus/focus/enrichmentService.ts @@ -1,7 +1,6 @@ -import type { Disposable } from 'vscode'; +import type { CancellationToken, Disposable } from 'vscode'; import type { Container } from '../../container'; -import { AuthenticationRequiredError } from '../../errors'; -import type { GitRemote } from '../../git/models/remote'; +import { AuthenticationRequiredError, CancellationError } from '../../errors'; import type { RemoteProvider } from '../../git/remotes/remoteProvider'; import { log } from '../../system/decorators/log'; import { Logger } from '../../system/logger'; @@ -9,10 +8,10 @@ import { getLogScope } from '../../system/logger.scope'; import type { ServerConnection } from '../gk/serverConnection'; import { ensureAccount, ensurePaidPlan } from '../utils'; -export interface FocusItem { +export interface EnrichableItem { type: EnrichedItemResponse['entityType']; id: string; - remote: GitRemote; + provider: EnrichedItemResponse['provider']; url: string; expiresAt?: string; } @@ -55,7 +54,7 @@ type EnrichedItemResponse = { expiresAt?: string; }; -export class FocusService implements Disposable { +export class EnrichmentService implements Disposable { constructor( private readonly container: Container, private readonly connection: ServerConnection, @@ -78,15 +77,18 @@ export class FocusService implements Disposable { } @log() - async get(type?: EnrichedItemResponse['type']): Promise { + async get(type?: EnrichedItemResponse['type'], cancellation?: CancellationToken): Promise { const scope = getLogScope(); try { type Result = { data: EnrichedItemResponse[] }; const rsp = await this.connection.fetchGkDevApi('v1/enrich-items', { method: 'GET' }); + if (cancellation?.isCancellationRequested) throw new CancellationError(); const result = (await rsp.json()) as Result; + if (cancellation?.isCancellationRequested) throw new CancellationError(); + return type == null ? result.data : result.data.filter(i => i.type === type); } catch (ex) { if (ex instanceof AuthenticationRequiredError) return []; @@ -98,17 +100,17 @@ export class FocusService implements Disposable { } @log() - getPins(): Promise { - return this.get('pin'); + getPins(cancellation?: CancellationToken): Promise { + return this.get('pin', cancellation); } @log() - getSnoozed(): Promise { - return this.get('snooze'); + getSnoozed(cancellation?: CancellationToken): Promise { + return this.get('snooze', cancellation); } - @log({ args: { 0: i => `${i.id} (${i.remote.provider.name} ${i.type})` } }) - async pinItem(item: FocusItem): Promise { + @log({ args: { 0: i => `${i.id} (${i.provider} ${i.type})` } }) + async pinItem(item: EnrichableItem): Promise { const scope = getLogScope(); try { @@ -119,7 +121,7 @@ export class FocusService implements Disposable { type Result = { data: EnrichedItemResponse }; const rq: EnrichedItemRequest = { - provider: item.remote.provider.id as EnrichedItemResponse['provider'], + provider: item.provider, entityType: item.type, entityId: item.id, entityUrl: item.url, @@ -150,8 +152,8 @@ export class FocusService implements Disposable { return this.delete(id, 'unpin'); } - @log({ args: { 0: i => `${i.id} (${i.remote.provider.name} ${i.type})` } }) - async snoozeItem(item: FocusItem): Promise { + @log({ args: { 0: i => `${i.id} (${i.provider} ${i.type})` } }) + async snoozeItem(item: EnrichableItem): Promise { const scope = getLogScope(); try { @@ -162,7 +164,7 @@ export class FocusService implements Disposable { type Result = { data: EnrichedItemResponse }; const rq: EnrichedItemRequest = { - provider: item.remote.provider.id as EnrichedItemResponse['provider'], + provider: item.provider, entityType: item.type, entityId: item.id, entityUrl: item.url, @@ -196,3 +198,23 @@ export class FocusService implements Disposable { return this.delete(id, 'unsnooze'); } } + +export function convertRemoteProviderToEnrichProvider(provider: RemoteProvider): EnrichedItemResponse['provider'] { + switch (provider.id) { + case 'azure-devops': + return 'azure'; + + case 'bitbucket': + case 'bitbucket-server': + return 'bitbucket'; + + case 'github': + return 'github'; + + case 'gitlab': + return 'gitlab'; + + default: + throw new Error(`Unknown remote provider '${provider.id}'`); + } +} diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index 6765947bc6b8e..0672dd3992dd3 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -33,7 +33,8 @@ import { getSettledValue } from '../../../system/promise'; import type { IpcMessage } from '../../../webviews/protocol'; import { onIpc } from '../../../webviews/protocol'; import type { WebviewController, WebviewProvider } from '../../../webviews/webviewController'; -import type { EnrichedItem, FocusItem } from '../../focus/focusService'; +import type { EnrichableItem, EnrichedItem } from '../../focus/enrichmentService'; +import { convertRemoteProviderToEnrichProvider } from '../../focus/enrichmentService'; import type { SubscriptionChangeEvent } from '../../gk/account/subscriptionService'; import type { ShowInCommitGraphCommandArgs } from '../graph/protocol'; import type { @@ -151,17 +152,17 @@ export class FocusWebviewProvider implements WebviewProvider { if (issueWithRemote == null) return; if (pin) { - await this.container.focus.unpinItem(pin); + await this.container.enrichments.unpinItem(pin); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== pin); issueWithRemote.enriched = issueWithRemote.enriched?.filter(e => e.id !== pin); } else { - const focusItem: FocusItem = { + const focusItem: EnrichableItem = { type: 'issue', id: issueWithRemote.issue.nodeId!, - remote: issueWithRemote.repoAndRemote.remote, + provider: convertRemoteProviderToEnrichProvider(issueWithRemote.repoAndRemote.remote.provider), url: issueWithRemote.issue.url, }; - const enrichedItem = await this.container.focus.pinItem(focusItem); + const enrichedItem = await this.container.enrichments.pinItem(focusItem); if (enrichedItem == null) return; if (this._enrichedItems == null) { this._enrichedItems = []; @@ -182,20 +183,20 @@ export class FocusWebviewProvider implements WebviewProvider { if (issueWithRemote == null) return; if (snooze) { - await this.container.focus.unsnoozeItem(snooze); + await this.container.enrichments.unsnoozeItem(snooze); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== snooze); issueWithRemote.enriched = issueWithRemote.enriched?.filter(e => e.id !== snooze); } else { - const focusItem: FocusItem = { + const focusItem: EnrichableItem = { type: 'issue', id: issueWithRemote.issue.nodeId!, - remote: issueWithRemote.repoAndRemote.remote, + provider: convertRemoteProviderToEnrichProvider(issueWithRemote.repoAndRemote.remote.provider), url: issueWithRemote.issue.url, }; if (expiresAt != null) { focusItem.expiresAt = expiresAt; } - const enrichedItem = await this.container.focus.snoozeItem(focusItem); + const enrichedItem = await this.container.enrichments.snoozeItem(focusItem); if (enrichedItem == null) return; if (this._enrichedItems == null) { this._enrichedItems = []; @@ -216,17 +217,17 @@ export class FocusWebviewProvider implements WebviewProvider { if (prWithRemote == null) return; if (pin) { - await this.container.focus.unpinItem(pin); + await this.container.enrichments.unpinItem(pin); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== pin); prWithRemote.enriched = prWithRemote.enriched?.filter(e => e.id !== pin); } else { - const focusItem: FocusItem = { + const focusItem: EnrichableItem = { type: 'pr', id: prWithRemote.pullRequest.nodeId!, - remote: prWithRemote.repoAndRemote.remote, + provider: convertRemoteProviderToEnrichProvider(prWithRemote.repoAndRemote.remote.provider), url: prWithRemote.pullRequest.url, }; - const enrichedItem = await this.container.focus.pinItem(focusItem); + const enrichedItem = await this.container.enrichments.pinItem(focusItem); if (enrichedItem == null) return; if (this._enrichedItems == null) { this._enrichedItems = []; @@ -247,20 +248,20 @@ export class FocusWebviewProvider implements WebviewProvider { if (prWithRemote == null) return; if (snooze) { - await this.container.focus.unsnoozeItem(snooze); + await this.container.enrichments.unsnoozeItem(snooze); this._enrichedItems = this._enrichedItems?.filter(e => e.id !== snooze); prWithRemote.enriched = prWithRemote.enriched?.filter(e => e.id !== snooze); } else { - const focusItem: FocusItem = { + const focusItem: EnrichableItem = { type: 'pr', id: prWithRemote.pullRequest.nodeId!, - remote: prWithRemote.repoAndRemote.remote, + provider: convertRemoteProviderToEnrichProvider(prWithRemote.repoAndRemote.remote.provider), url: prWithRemote.pullRequest.url, }; if (expiresAt != null) { focusItem.expiresAt = expiresAt; } - const enrichedItem = await this.container.focus.snoozeItem(focusItem); + const enrichedItem = await this.container.enrichments.snoozeItem(focusItem); if (enrichedItem == null) return; if (this._enrichedItems == null) { this._enrichedItems = []; @@ -770,7 +771,7 @@ export class FocusWebviewProvider implements WebviewProvider { private async getEnrichedItems(force?: boolean): Promise { // TODO needs cache invalidation if (force || this._enrichedItems == null) { - const enrichedItems = await this.container.focus.get(); + const enrichedItems = await this.container.enrichments.get(); this._enrichedItems = enrichedItems; } return this._enrichedItems; diff --git a/src/plus/webviews/focus/protocol.ts b/src/plus/webviews/focus/protocol.ts index e7fe3cebbe5ef..e6b3c3d3b0050 100644 --- a/src/plus/webviews/focus/protocol.ts +++ b/src/plus/webviews/focus/protocol.ts @@ -3,7 +3,7 @@ import type { IssueShape } from '../../../git/models/issue'; import type { PullRequestShape } from '../../../git/models/pullRequest'; import type { WebviewState } from '../../../webviews/protocol'; import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol'; -import type { EnrichedItem } from '../../focus/focusService'; +import type { EnrichedItem } from '../../focus/enrichmentService'; export interface State extends WebviewState { access: FeatureAccess; From c72e9f7fb658c55ec4da7671a1cd26b27a89ad81 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 2 Feb 2024 10:50:46 -0500 Subject: [PATCH 0483/1012] Moves some array fns to iterable --- src/git/gitProviderService.ts | 4 +- src/git/models/repository.ts | 3 +- .../integrations/providers/github/github.ts | 16 +++-- src/system/array.ts | 70 ------------------- src/system/iterable.ts | 66 +++++++++++++++++ src/views/draftsView.ts | 2 +- src/views/nodes/UncommittedFilesNode.ts | 4 +- .../nodes/branchTrackingStatusFilesNode.ts | 4 +- src/views/nodes/statusFilesNode.ts | 4 +- .../apps/plus/graph/minimap/minimap.ts | 3 +- 10 files changed, 86 insertions(+), 90 deletions(-) diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index f613479f2d4eb..fd7f75e079700 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -22,7 +22,7 @@ import type { SubscriptionChangeEvent } from '../plus/gk/account/subscriptionSer import type { ProviderIntegration } from '../plus/integrations/providerIntegration'; import type { RepoComparisonKey } from '../repositories'; import { asRepoComparisonKey, Repositories } from '../repositories'; -import { groupByFilterMap, groupByMap, joinUnique } from '../system/array'; +import { joinUnique } from '../system/array'; import { registerCommand } from '../system/command'; import { configuration } from '../system/configuration'; import { setContext } from '../system/context'; @@ -30,7 +30,7 @@ import { gate } from '../system/decorators/gate'; import { debug, log } from '../system/decorators/log'; import type { Deferrable } from '../system/function'; import { debounce } from '../system/function'; -import { count, filter, first, flatMap, join, map, some } from '../system/iterable'; +import { count, filter, first, flatMap, groupByFilterMap, groupByMap, join, map, some } from '../system/iterable'; import { Logger } from '../system/logger'; import { getLogScope, setLogScopeExit } from '../system/logger.scope'; import { getBestPath, getScheme, isAbsolute, maybeUri, normalizePath } from '../system/path'; diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index b1384f71485a6..9f6484685f504 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -9,7 +9,6 @@ import type { FeatureAccess, Features, PlusFeatures } from '../../features'; import { showCreatePullRequestPrompt, showGenericErrorMessage } from '../../messages'; import type { ProviderIntegration } from '../../plus/integrations/providerIntegration'; import { asRepoComparisonKey } from '../../repositories'; -import { groupByMap } from '../../system/array'; import { executeActionCommand } from '../../system/command'; import { configuration } from '../../system/configuration'; import { formatDate, fromNow } from '../../system/date'; @@ -17,7 +16,7 @@ import { gate } from '../../system/decorators/gate'; import { debug, log, logName } from '../../system/decorators/log'; import type { Deferrable } from '../../system/function'; import { debounce } from '../../system/function'; -import { filter, join, min, some } from '../../system/iterable'; +import { filter, groupByMap, join, min, some } from '../../system/iterable'; import { getLoggableName, Logger } from '../../system/logger'; import { getLogScope } from '../../system/logger.scope'; import { updateRecordValue } from '../../system/object'; diff --git a/src/plus/integrations/providers/github/github.ts b/src/plus/integrations/providers/github/github.ts index 15c9fd8597553..64b83c3035c84 100644 --- a/src/plus/integrations/providers/github/github.ts +++ b/src/plus/integrations/providers/github/github.ts @@ -30,9 +30,9 @@ import { showIntegrationRequestFailed500WarningMessage, showIntegrationRequestTimedOutWarningMessage, } from '../../../../messages'; -import { uniqueBy } from '../../../../system/array'; import { configuration } from '../../../../system/configuration'; import { debug } from '../../../../system/decorators/log'; +import { uniqueBy } from '../../../../system/iterable'; import { Logger } from '../../../../system/logger'; import type { LogScope } from '../../../../system/logger.scope'; import { getLogScope } from '../../../../system/logger.scope'; @@ -2847,10 +2847,12 @@ function isGitHubDotCom(options?: { baseUrl?: string }) { } function uniqueWithReasons(items: T[], lookup: (item: T) => unknown): T[] { - return uniqueBy(items, lookup, (original, current) => { - if (current.reasons.length !== 0) { - original.reasons.push(...current.reasons); - } - return original; - }); + return [ + ...uniqueBy(items, lookup, (original, current) => { + if (current.reasons.length !== 0) { + original.reasons.push(...current.reasons); + } + return original; + }), + ]; } diff --git a/src/system/array.ts b/src/system/array.ts index f337df2217e6a..4f3a6c00fa1f2 100644 --- a/src/system/array.ts +++ b/src/system/array.ts @@ -78,55 +78,6 @@ export function findLastIndex(source: T[], predicate: (value: T, index: numbe return -1; } -export function groupBy(source: readonly T[], groupingKey: (item: T) => string): Record { - return source.reduce>((groupings, current) => { - const value = groupingKey(current); - const group = groupings[value]; - if (group === undefined) { - groupings[value] = [current]; - } else { - group.push(current); - } - return groupings; - }, Object.create(null)); -} - -export function groupByMap( - source: readonly TValue[], - groupingKey: (item: TValue) => TKey, -): Map { - return source.reduce((groupings, current) => { - const value = groupingKey(current); - const group = groupings.get(value); - if (group === undefined) { - groupings.set(value, [current]); - } else { - group.push(current); - } - return groupings; - }, new Map()); -} - -export function groupByFilterMap( - source: readonly TValue[], - groupingKey: (item: TValue) => TKey, - predicateMapper: (item: TValue) => TMapped | null | undefined, -): Map { - return source.reduce((groupings, current) => { - const mapped = predicateMapper(current); - if (mapped != null) { - const value = groupingKey(current); - const group = groupings.get(value); - if (group === undefined) { - groupings.set(value, [mapped]); - } else { - group.push(mapped); - } - } - return groupings; - }, new Map()); -} - export function intersection(sources: T[][], comparator: (a: T, b: T) => boolean): T[] { const results: T[] = []; @@ -253,24 +204,3 @@ export function joinUnique(source: readonly T[], separator: string): string { export function splitAt(source: T[], index: number): [T[], T[]] { return index < 0 ? [source, []] : [source.slice(0, index), source.slice(index)]; } - -export function uniqueBy( - source: readonly TValue[], - uniqueKey: (item: TValue) => TKey, - onDuplicate: (original: TValue, current: TValue) => TValue | void, -): TValue[] { - const map = source.reduce((uniques, current) => { - const value = uniqueKey(current); - const original = uniques.get(value); - if (original === undefined) { - uniques.set(value, current); - } else { - const updated = onDuplicate(original, current); - if (updated !== undefined) { - uniques.set(value, updated); - } - } - return uniques; - }, new Map()); - return [...map.values()]; -} diff --git a/src/system/iterable.ts b/src/system/iterable.ts index f69502491d340..445ecec7e01af 100644 --- a/src/system/iterable.ts +++ b/src/system/iterable.ts @@ -145,6 +145,72 @@ export function flatten(source: Iterable> | IterableIterator i); } +export function groupBy( + source: Iterable | IterableIterator, + groupingKey: (item: T) => string, +): Record { + const groupings: Record = Object.create(null); + + for (const current of source) { + const value = groupingKey(current); + const group = groupings[value]; + if (group === undefined) { + groupings[value] = [current]; + } else { + group.push(current); + } + } + + return groupings; +} + +export function groupByMap( + source: Iterable | IterableIterator, + groupingKey: (item: TValue) => TKey, + options?: { filterNullGroups?: boolean }, +): Map { + const groupings = new Map(); + + const filterNullGroups = options?.filterNullGroups ?? false; + + for (const current of source) { + const value = groupingKey(current); + if (value == null && filterNullGroups) continue; + + const group = groupings.get(value); + if (group === undefined) { + groupings.set(value, [current]); + } else { + group.push(current); + } + } + + return groupings; +} + +export function groupByFilterMap( + source: Iterable | IterableIterator, + groupingKey: (item: TValue) => TKey, + predicateMapper: (item: TValue) => TMapped | null | undefined, +): Map { + const groupings = new Map(); + + for (const current of source) { + const mapped = predicateMapper(current); + if (mapped == null) continue; + + const value = groupingKey(current); + const group = groupings.get(value); + if (group === undefined) { + groupings.set(value, [mapped]); + } else { + group.push(mapped); + } + } + + return groupings; +} + export function has(source: Iterable | IterableIterator, item: T): boolean { return some(source, i => i === item); } diff --git a/src/views/draftsView.ts b/src/views/draftsView.ts index b6d591a8576f5..4557bbcb8546b 100644 --- a/src/views/draftsView.ts +++ b/src/views/draftsView.ts @@ -8,9 +8,9 @@ import { unknownGitUri } from '../git/gitUri'; import type { Draft } from '../gk/models/drafts'; import { showPatchesView } from '../plus/drafts/actions'; import { ensurePlusFeaturesEnabled } from '../plus/gk/utils'; -import { groupByFilterMap } from '../system/array'; import { executeCommand } from '../system/command'; import { gate } from '../system/decorators/gate'; +import { groupByFilterMap } from '../system/iterable'; import { CacheableChildrenViewNode } from './nodes/abstract/cacheableChildrenViewNode'; import { DraftNode } from './nodes/draftNode'; import { GroupingNode } from './nodes/groupingNode'; diff --git a/src/views/nodes/UncommittedFilesNode.ts b/src/views/nodes/UncommittedFilesNode.ts index d3d3e0bc3376e..b660e5a412224 100644 --- a/src/views/nodes/UncommittedFilesNode.ts +++ b/src/views/nodes/UncommittedFilesNode.ts @@ -3,8 +3,8 @@ import { GitUri } from '../../git/gitUri'; import type { GitTrackingState } from '../../git/models/branch'; import type { GitFileWithCommit } from '../../git/models/file'; import type { GitStatus, GitStatusFile } from '../../git/models/status'; -import { groupBy, makeHierarchical } from '../../system/array'; -import { flatMap } from '../../system/iterable'; +import { makeHierarchical } from '../../system/array'; +import { flatMap, groupBy } from '../../system/iterable'; import { joinPaths, normalizePath } from '../../system/path'; import type { ViewsWithWorkingTree } from '../viewBase'; import { ContextValues, getViewNodeId, ViewNode } from './abstract/viewNode'; diff --git a/src/views/nodes/branchTrackingStatusFilesNode.ts b/src/views/nodes/branchTrackingStatusFilesNode.ts index f27944f828743..080f6451d5f8f 100644 --- a/src/views/nodes/branchTrackingStatusFilesNode.ts +++ b/src/views/nodes/branchTrackingStatusFilesNode.ts @@ -4,8 +4,8 @@ import { GitUri } from '../../git/gitUri'; import type { GitBranch } from '../../git/models/branch'; import type { GitFileWithCommit } from '../../git/models/file'; import { createRevisionRange } from '../../git/models/reference'; -import { groupByMap, makeHierarchical } from '../../system/array'; -import { filter, flatMap, map } from '../../system/iterable'; +import { makeHierarchical } from '../../system/array'; +import { filter, flatMap, groupByMap, map } from '../../system/iterable'; import { joinPaths, normalizePath } from '../../system/path'; import { pluralize, sortCompare } from '../../system/string'; import type { ViewsWithCommits } from '../viewBase'; diff --git a/src/views/nodes/statusFilesNode.ts b/src/views/nodes/statusFilesNode.ts index aed0ead02b298..48f6e765ba711 100644 --- a/src/views/nodes/statusFilesNode.ts +++ b/src/views/nodes/statusFilesNode.ts @@ -5,8 +5,8 @@ import type { GitCommit } from '../../git/models/commit'; import type { GitFileWithCommit } from '../../git/models/file'; import type { GitLog } from '../../git/models/log'; import type { GitStatus, GitStatusFile } from '../../git/models/status'; -import { groupBy, makeHierarchical } from '../../system/array'; -import { filter, flatMap, map } from '../../system/iterable'; +import { makeHierarchical } from '../../system/array'; +import { filter, flatMap, groupBy, map } from '../../system/iterable'; import { joinPaths, normalizePath } from '../../system/path'; import { pluralize, sortCompare } from '../../system/string'; import type { ViewsWithWorkingTree } from '../viewBase'; diff --git a/src/webviews/apps/plus/graph/minimap/minimap.ts b/src/webviews/apps/plus/graph/minimap/minimap.ts index a8073f61860d0..f3bbbda79d2ee 100644 --- a/src/webviews/apps/plus/graph/minimap/minimap.ts +++ b/src/webviews/apps/plus/graph/minimap/minimap.ts @@ -1,9 +1,8 @@ import { css, customElement, FASTElement, html, observable, ref } from '@microsoft/fast-element'; import type { Chart, DataItem, RegionOptions } from 'billboard.js'; -import { groupByMap } from '../../../../../system/array'; import { debug } from '../../../../../system/decorators/log'; import { debounce } from '../../../../../system/function'; -import { first, flatMap, map, union } from '../../../../../system/iterable'; +import { first, flatMap, groupByMap, map, union } from '../../../../../system/iterable'; import { pluralize } from '../../../../../system/string'; import { formatDate, formatNumeric, fromNow } from '../../../shared/date'; From dc1fa65d8c1076e2fe2736ab6a01aa042b354281 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 3 Feb 2024 19:28:41 -0500 Subject: [PATCH 0484/1012] Closes #3134 adds font settings for file blame --- CHANGELOG.md | 1 + package.json | 21 +++++++++++++++++ src/annotations/annotations.ts | 8 +++++-- .../gutterBlameAnnotationProvider.ts | 23 ++++++++++++++++++- src/config.ts | 3 +++ 5 files changed, 53 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db1c946d17518..ea69973178bd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Adds an _Open Changes_ submenu to branch status (upstream) and branch status files in GitLens views - Adds an alternate flow (pick another file) when using the _Open File at Revision..._ and _Open Changes with Revision..._ commands to open a file that has been renamed and the rename is currently unstaged — closes [#3109](https://github.com/gitkraken/vscode-gitlens/issues/3109) - Adds an _Open File Annotation Settings_ command to the _File Annotations_ submenu in the editor toolbar to open the GitLens Settings editor to the file annotations sections +- Adds new font settings to control the font family, size, and weight of the _File Blame_ annotations — closes [#3134](https://github.com/gitkraken/vscode-gitlens/issues/3134) ### Changed diff --git a/package.json b/package.json index 36a5f44938c5a..7fb1b2fa3ca26 100644 --- a/package.json +++ b/package.json @@ -2209,6 +2209,27 @@ "scope": "window", "order": 20 }, + "gitlens.blame.fontFamily": { + "type": "string", + "default": "", + "markdownDescription": "Specifies the font family of the file blame annotations", + "scope": "window", + "order": 21 + }, + "gitlens.blame.fontSize": { + "type": "number", + "default": 0, + "markdownDescription": "Specifies the font size of the file blame annotations", + "scope": "window", + "order": 22 + }, + "gitlens.blame.fontWeight": { + "type": "string", + "default": "normal", + "markdownDescription": "Specifies the font weight of the file blame annotations", + "scope": "window", + "order": 22 + }, "gitlens.blame.heatmap.enabled": { "type": "boolean", "default": true, diff --git a/src/annotations/annotations.ts b/src/annotations/annotations.ts index 9d37eade8e9a6..13a806f8cdb58 100644 --- a/src/annotations/annotations.ts +++ b/src/annotations/annotations.ts @@ -16,6 +16,7 @@ import type { GitCommit } from '../git/models/commit'; import { scale, toRgba } from '../system/color'; import { configuration } from '../system/configuration'; import { getWidth, interpolate, pad } from '../system/string'; +import type { BlameFontOptions } from './gutterBlameAnnotationProvider'; export interface ComputedHeatmap { coldThresholdTimestamp: number; @@ -166,6 +167,7 @@ export function getGutterRenderOptions( avatars: boolean, format: string, options: CommitFormatOptions, + fontOptions: BlameFontOptions, ): RenderOptions { // Get the character count of all the tokens, assuming there there is a cap (bail if not) let chars = 0; @@ -212,12 +214,14 @@ export function getGutterRenderOptions( borderStyle: borderStyle, borderWidth: borderWidth, color: new ThemeColor('gitlens.gutterForegroundColor' satisfies Colors), - fontWeight: 'normal', - fontStyle: 'normal', + fontWeight: fontOptions.weight ?? 'normal', + fontStyle: fontOptions.weight ?? 'normal', height: '100%', margin: '0 26px -1px 0', textDecoration: `${separateLines ? 'overline solid rgba(0, 0, 0, .2)' : 'none'};box-sizing: border-box${ avatars ? ';padding: 0 0 0 18px' : '' + }${fontOptions.family ? `;font-family: ${fontOptions.family}` : ''}${ + fontOptions.size ? `;font-size: ${fontOptions.size}px` : '' }`, width: width, uncommittedColor: new ThemeColor('gitlens.gutterUncommittedForegroundColor' satisfies Colors), diff --git a/src/annotations/gutterBlameAnnotationProvider.ts b/src/annotations/gutterBlameAnnotationProvider.ts index 98afce8c299a1..91675261cf14b 100644 --- a/src/annotations/gutterBlameAnnotationProvider.ts +++ b/src/annotations/gutterBlameAnnotationProvider.ts @@ -22,6 +22,12 @@ import { Decorations } from './fileAnnotationController'; const maxSmallIntegerV8 = 2 ** 30; // Max number that can be stored in V8's smis (small integers) +export interface BlameFontOptions { + family: string; + size: number; + weight: string; +} + export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase { constructor(container: Container, editor: TextEditor, trackedDocument: TrackedGitDocument) { super(container, 'blame', editor, trackedDocument); @@ -68,10 +74,23 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase { tokenOptions: tokenOptions, }; + const fontOptions: BlameFontOptions = { + family: configuration.get('blame.fontFamily'), + size: configuration.get('blame.fontSize'), + weight: configuration.get('blame.fontWeight'), + }; + const avatars = cfg.avatars; const gravatarDefault = configuration.get('defaultGravatarsStyle'); const separateLines = cfg.separateLines; - const renderOptions = getGutterRenderOptions(separateLines, cfg.heatmap, cfg.avatars, cfg.format, options); + const renderOptions = getGutterRenderOptions( + separateLines, + cfg.heatmap, + cfg.avatars, + cfg.format, + options, + fontOptions, + ); const decorationOptions = []; const decorationsMap = new Map(); @@ -109,6 +128,8 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase { if (separateLines) { gutter.renderOptions.before!.textDecoration = `none;box-sizing: border-box${ avatars ? ';padding: 0 0 0 18px' : '' + }${fontOptions.family ? `;font-family: ${fontOptions.family}` : ''}${ + fontOptions.size ? `;font-size: ${fontOptions.size}px` : '' }`; } diff --git a/src/config.ts b/src/config.ts index 82d7da7a54e73..34e2c45599783 100644 --- a/src/config.ts +++ b/src/config.ts @@ -25,6 +25,9 @@ export interface Config { readonly avatars: boolean; readonly compact: boolean; readonly dateFormat: DateTimeFormat | (string & object) | null; + readonly fontFamily: string; + readonly fontSize: number; + readonly fontWeight: string; readonly format: string; readonly heatmap: { readonly enabled: boolean; From 4af8bb7b8b60143c0a75b9f7c95e13cdd8bf0a5a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 4 Feb 2024 15:15:00 -0500 Subject: [PATCH 0485/1012] Removes unneeded eslint-config-prettier --- .eslintrc.base.json | 3 +-- package.json | 1 - yarn.lock | 5 ----- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.eslintrc.base.json b/.eslintrc.base.json index 48a8d9336121c..c1509d5a8c98e 100644 --- a/.eslintrc.base.json +++ b/.eslintrc.base.json @@ -6,8 +6,7 @@ "eslint:recommended", "plugin:@typescript-eslint/strict-type-checked", "plugin:import/recommended", - "plugin:import/typescript", - "prettier" + "plugin:import/typescript" ], "parser": "@typescript-eslint/parser", "parserOptions": { diff --git a/package.json b/package.json index 7fb1b2fa3ca26..9046784a0964d 100644 --- a/package.json +++ b/package.json @@ -16486,7 +16486,6 @@ "esbuild-sass-plugin": "3.0.0", "eslint": "8.56.0", "eslint-cli": "1.1.1", - "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-anti-trojan-source": "1.1.1", "eslint-plugin-import": "2.29.1", diff --git a/yarn.lock b/yarn.lock index 8999ee078dc69..4b585f1219757 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3138,11 +3138,6 @@ eslint-cli@1.1.1: debug "^2.6.8" resolve "^1.3.3" -eslint-config-prettier@9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" - integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== - eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" From e1f752d3386f4b106c065183f1cebd86391dcace Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 4 Feb 2024 15:32:43 -0500 Subject: [PATCH 0486/1012] Updates dependencies --- package.json | 8 +- yarn.lock | 216 ++++++++++++++++++++++++++------------------------- 2 files changed, 115 insertions(+), 109 deletions(-) diff --git a/package.json b/package.json index 9046784a0964d..97c06e31e85e7 100644 --- a/package.json +++ b/package.json @@ -16478,7 +16478,7 @@ "concurrently": "8.2.2", "copy-webpack-plugin": "12.0.2", "csp-html-webpack-plugin": "5.1.0", - "css-loader": "6.9.1", + "css-loader": "6.10.0", "css-minimizer-webpack-plugin": "6.0.0", "cssnano-preset-advanced": "6.0.3", "esbuild": "0.20.0", @@ -16498,11 +16498,11 @@ "image-minimizer-webpack-plugin": "4.0.0", "license-checker-rseidelsohn": "4.3.0", "lz-string": "1.5.0", - "mini-css-extract-plugin": "2.7.7", + "mini-css-extract-plugin": "2.8.0", "mocha": "10.2.0", "prettier": "3.1.0", "sass": "1.70.0", - "sass-loader": "14.0.0", + "sass-loader": "14.1.0", "schema-utils": "4.2.0", "sharp": "0.32.6", "svgo": "3.2.0", @@ -16510,7 +16510,7 @@ "ts-loader": "9.5.1", "tsc-alias": "1.8.8", "typescript": "5.3.3", - "webpack": "5.90.0", + "webpack": "5.90.1", "webpack-bundle-analyzer": "4.10.1", "webpack-cli": "5.1.4", "webpack-node-externals": "3.0.0", diff --git a/yarn.lock b/yarn.lock index 4b585f1219757..00b533240a854 100644 --- a/yarn.lock +++ b/yarn.lock @@ -57,9 +57,9 @@ regenerator-runtime "^0.14.0" "@bufbuild/protobuf@^1.0.0": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.7.1.tgz#ce295b06d3f2f38c2671ee315c4ad296bbcbb337" - integrity sha512-UlI3lKLFBjZQJ0cHf47YUH6DzZxZYWk3sf6dKYyPUaXrfXq4z+zZqNO3q0lPUzyJgh14s6VscjcNFBaQBhYd9Q== + version "1.7.2" + resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.7.2.tgz#1b3d6c66ebd987f7da7f1e3f0546cffaa87f8732" + integrity sha512-i5GE2Dk5ekdlK1TR7SugY4LWRrKSfb5T1Qn4unpIMbfxoeGKERKQ59HG3iYewacGD10SR7UzevfPnh6my4tNmQ== "@discoveryjs/json-ext@0.5.7", "@discoveryjs/json-ext@^0.5.0": version "0.5.7" @@ -500,22 +500,22 @@ methods "^1.1.2" path-to-regexp "^6.2.1" -"@lit-labs/ssr-dom-shim@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz#d693d972974a354034454ec1317eb6afd0b00312" - integrity sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g== +"@lit-labs/ssr-dom-shim@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz#353ce4a76c83fadec272ea5674ede767650762fd" + integrity sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g== "@lit/react@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@lit/react/-/react-1.0.2.tgz#4951ff1590d69aad912d0a950b3518d19eb7e220" integrity sha512-UJ5TQ46DPcJDIzyjbwbj6Iye0XcpCxL2yb03zcWq1BpWchpXS3Z0BPVhg7zDfZLF6JemPml8u/gt/+KwJ/23sg== -"@lit/reactive-element@^2.0.0": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.0.3.tgz#29d7d4ee8d9b00804be957cc6937577eb4d3db63" - integrity sha512-e067EuTNNgOHm1tZcc0Ia7TCzD/9ZpoPegHKgesrGK6pSDRGkGDAQbYuQclqLPIoJ9eC8Kb9mYtGryWcM5AywA== +"@lit/reactive-element@^2.0.0", "@lit/reactive-element@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.0.4.tgz#8f2ed950a848016383894a26180ff06c56ae001b" + integrity sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ== dependencies: - "@lit-labs/ssr-dom-shim" "^1.1.2" + "@lit-labs/ssr-dom-shim" "^1.2.0" "@microsoft/fast-element@1.12.0", "@microsoft/fast-element@^1.12.0", "@microsoft/fast-element@^1.6.2", "@microsoft/fast-element@^1.9.0": version "1.12.0" @@ -733,11 +733,11 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@playwright/browser-chromium@^1.41.1": - version "1.41.1" - resolved "https://registry.yarnpkg.com/@playwright/browser-chromium/-/browser-chromium-1.41.1.tgz#800f9f4f5b10a87e9728d5999dd9e705c1352f7a" - integrity sha512-rgPTuAmA+8zQLb7+GDY7hrdnCRMrL2C/JPFylWeQBJkQtldJsk2pELUR7NESeJtXVzML/x+aFnGPRY0r5+YO3Q== + version "1.41.2" + resolved "https://registry.yarnpkg.com/@playwright/browser-chromium/-/browser-chromium-1.41.2.tgz#f6b2e51b95bb98e916e7c42c9a6f885923cfcd4b" + integrity sha512-vzobqNg2K6cJPyXCVaUxq8uDV54l3pEJvkO58XK0CBV2nl9IBySXvEqcgwsQc8PmQ930yVDrz0oCrMR6H/Qv3A== dependencies: - playwright-core "1.41.1" + playwright-core "1.41.2" "@polka/url@^1.0.0-next.24": version "1.0.0-next.24" @@ -957,9 +957,9 @@ integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== "@types/node@*": - version "20.11.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.10.tgz#6c3de8974d65c362f82ee29db6b5adf4205462f9" - integrity sha512-rZEfe/hJSGYmdfX9tvcPMYeYPW2sNl50nsw4jZmRcaG0HIAb0WYEpsB05GOb53vjqpyE9GUhlDQ4jLSoB5q9kg== + version "20.11.16" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.16.tgz#4411f79411514eb8e2926f036c86c9f0e4ec6708" + integrity sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ== dependencies: undici-types "~5.26.4" @@ -1544,12 +1544,12 @@ argparse@^2.0.1: integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" + call-bind "^1.0.5" + is-array-buffer "^3.0.4" array-find-index@^1.0.2: version "1.0.2" @@ -1660,10 +1660,10 @@ autoprefixer@^10.4.16: picocolors "^1.0.0" postcss-value-parser "^4.2.0" -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz#ac812d8ce5a6b976d738e1c45f08d0b00bc7d725" + integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== azure-devops-node-api@^11.0.1: version "11.2.0" @@ -1853,7 +1853,7 @@ cache-content-type@^1.0.0: mime-types "^2.1.18" ylru "^1.2.0" -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== @@ -1901,9 +1901,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001578, caniuse-lite@^1.0.30001580: - version "1.0.30001581" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz#0dfd4db9e94edbdca67d57348ebc070dece279f4" - integrity sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ== + version "1.0.30001583" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001583.tgz#abb2970cc370801dc7e27bf290509dc132cfa390" + integrity sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q== capital-case@^1.0.4: version "1.0.4" @@ -2289,10 +2289,10 @@ css-declaration-sorter@^7.1.1: resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-7.1.1.tgz#9796bcc257b4647c39993bda8d431ce32b666f80" integrity sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ== -css-loader@6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.9.1.tgz#9ec9a434368f2bdfeffbf8f6901a1ce773586c6b" - integrity sha512-OzABOh0+26JKFdMzlK6PY1u5Zx8+Ck7CVRlcGNZoY9qwJjdfu2VWFuprTIpPW+Av5TZTVViYWcFQaEEQURLknQ== +css-loader@6.10.0: + version "6.10.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.10.0.tgz#7c172b270ec7b833951b52c348861206b184a4b7" + integrity sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw== dependencies: icss-utils "^5.1.0" postcss "^8.4.33" @@ -2875,9 +2875,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.648: - version "1.4.650" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.650.tgz#b38ef9de16991b9f7b924246770576ab91ab3d64" - integrity sha512-sYSQhJCJa4aGA1wYol5cMQgekDBlbVfTRavlGZVr3WZpDdOPcp6a6xUnFfrt8TqZhsBYYbDxJZCjGfHuGupCRQ== + version "1.4.656" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.656.tgz#b374fb7cab9b782a5bc967c0ce0e19826186b9c9" + integrity sha512-9AQB5eFTHyR3Gvt2t/NwR0le2jBSUNwCnMbUCejFWHD+so4tH40/dRLgoE+jxlPeWS43XJewyvCv+I8LPMl49Q== emoji-regex@^8.0.0: version "8.0.0" @@ -2942,9 +2942,9 @@ env-paths@^2.2.0: integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== envinfo@^7.7.3: - version "7.11.0" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.0.tgz#c3793f44284a55ff8c82faf1ffd91bc6478ea01f" - integrity sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg== + version "7.11.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.1.tgz#2ffef77591057081b0129a8fd8cf6118da1b94e1" + integrity sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg== err-code@^2.0.2: version "2.0.3" @@ -3003,6 +3003,11 @@ es-abstract@^1.22.1: unbox-primitive "^1.0.2" which-typed-array "^1.1.13" +es-errors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.0.0.tgz#1936450fb8cff7bffb969335d0e55dfca7279aab" + integrity sha512-yHV74THqMJUyFKkHyN7hyENcEZM3Dj2a2IrdClY+IT4BFQHkIVwlh8s6uZfjsFydMdNHv0F5mWgAA3ajFbsvVQ== + es-module-lexer@^1.2.1: version "1.4.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5" @@ -3585,11 +3590,12 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" - integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.3.tgz#9d2d284a238e62672f556361e7d4e1a4686ae50e" + integrity sha512-JIcZczvcMVE7AUOP+X72bh8HqHBRxFdz5PDHYtNG/lE3yk9b3KZBJlwFcTyPYjg3L4RLLmZJzvjxhaZVapxFrQ== dependencies: + es-errors "^1.0.0" function-bind "^1.1.2" has-proto "^1.0.1" has-symbols "^1.0.3" @@ -3826,12 +3832,12 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-tostringtag@^1.0.0, has-tostringtag@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - has-symbols "^1.0.2" + has-symbols "^1.0.3" has-unicode@^2.0.1: version "2.0.1" @@ -4054,9 +4060,9 @@ ieee754@^1.1.13: integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^5.1.9, ignore@^5.2.0, ignore@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" - integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== image-minimizer-webpack-plugin@4.0.0: version "4.0.0" @@ -4166,14 +4172,13 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== +is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" + get-intrinsic "^1.2.1" is-arrayish@^0.2.1: version "0.2.1" @@ -4363,11 +4368,11 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: has-symbols "^1.0.2" is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - which-typed-array "^1.1.11" + which-typed-array "^1.1.14" is-unicode-supported@^0.1.0: version "0.1.0" @@ -4692,18 +4697,18 @@ linkify-it@^3.0.1: uc.micro "^1.0.1" lit-element@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-4.0.3.tgz#18239840a7c1a6a6e09c6ed3b5cd3db0512ebf15" - integrity sha512-2vhidmC7gGLfnVx41P8UZpzyS0Fb8wYhS5RCm16cMW3oERO0Khd3EsKwtRpOnttuByI5rURjT2dfoA7NlInCNw== + version "4.0.4" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-4.0.4.tgz#e0b37ebbe2394bcb9578d611a409f49475dff361" + integrity sha512-98CvgulX6eCPs6TyAIQoJZBCQPo80rgXR+dVBs61cstJXqtI+USQZAbA4gFHh6L/mxBx9MrgPLHLsUgDUHAcCQ== dependencies: - "@lit-labs/ssr-dom-shim" "^1.1.2" - "@lit/reactive-element" "^2.0.0" - lit-html "^3.1.0" + "@lit-labs/ssr-dom-shim" "^1.2.0" + "@lit/reactive-element" "^2.0.4" + lit-html "^3.1.2" -lit-html@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-3.1.1.tgz#50c2e74a2074f85fc9816676ac11cf0c96f257c3" - integrity sha512-x/EwfGk2D/f4odSFM40hcGumzqoKv0/SUh6fBO+1Ragez81APrcAMPo1jIrCDd9Sn+Z4CT867HWKViByvkDZUA== +lit-html@^3.1.0, lit-html@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-3.1.2.tgz#6655ce82367472de7680c62b1bcb0beb0e426fa1" + integrity sha512-3OBZSUrPnAHoKJ9AMjRL/m01YJxQMf+TMHanNtTHG68ubjnZxK0RFl102DPzsw4mWnHibfZIBJm3LWCZ/LmMvg== dependencies: "@types/trusted-types" "^2.0.2" @@ -4956,12 +4961,13 @@ min-indent@^1.0.1: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -mini-css-extract-plugin@2.7.7: - version "2.7.7" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.7.tgz#4acf02f362c641c38fb913bfcb7ca2fc4a7cf339" - integrity sha512-+0n11YGyRavUR3IlaOzJ0/4Il1avMvJ1VJfhWfCn24ITQXhRr1gghbhhrda6tgtNcpZaWKdSuwKq20Jb7fnlyw== +mini-css-extract-plugin@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.0.tgz#1aeae2a90a954b6426c9e8311eab36b450f553a0" + integrity sha512-CxmUYPFcTgET1zImteG/LZOy/4T5rTojesQXkSNBiquhydn78tfbCE9sjIjnJ/UcjNjOC1bphTCCW5rrS7cXAg== dependencies: schema-utils "^4.0.0" + tapable "^2.2.1" minimatch@5.0.1: version "5.0.1" @@ -5649,17 +5655,17 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -playwright-core@1.41.1: - version "1.41.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.41.1.tgz#9c152670010d9d6f970f34b68e3e935d3c487431" - integrity sha512-/KPO5DzXSMlxSX77wy+HihKGOunh3hqndhqeo/nMxfigiKzogn8kfL0ZBDu0L1RKgan5XHCPmn6zXd2NUJgjhg== +playwright-core@1.41.2: + version "1.41.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.41.2.tgz#db22372c708926c697acc261f0ef8406606802d9" + integrity sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA== playwright@^1.41.1: - version "1.41.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.41.1.tgz#83325f34165840d019355c2a78a50f21ed9b9c85" - integrity sha512-gdZAWG97oUnbBdRL3GuBvX3nDDmUOuqzV/D24dytqlKt+eI5KbwusluZRGljx1YoJKZ2NRPaeWiFTeGZO7SosQ== + version "1.41.2" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.41.2.tgz#4e760b1c79f33d9129a8c65cc27953be6dd35042" + integrity sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A== dependencies: - playwright-core "1.41.1" + playwright-core "1.41.2" optionalDependencies: fsevents "2.3.2" @@ -6548,10 +6554,10 @@ sass-embedded@^1.70.0: sass-embedded-win32-ia32 "1.70.0" sass-embedded-win32-x64 "1.70.0" -sass-loader@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-14.0.0.tgz#fc8390f7cc16863622cd16f3ea07b36ba6ea8f91" - integrity sha512-oceP9wWbep/yRJ2+sMbCzk0UsXsDzdNis+N8nu9i5GwPXjy6v3DNB6TqfJLSpPO9k4+B8x8p/CEgjA9ZLkoLug== +sass-loader@14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-14.1.0.tgz#43ba90e0cd8a15a1e932e818c525b0115a0ce8a3" + integrity sha512-LS2mLeFWA+orYxHNu+O18Xe4jR0kyamNOOUsE3NyBP4DvIL+8stHpNX0arYTItdPe80kluIiJ7Wfe/9iHSRO0Q== dependencies: neo-async "^2.6.2" @@ -6942,9 +6948,9 @@ stream-shift@^1.0.0: integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== streamx@^2.15.0: - version "2.15.6" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.6.tgz#28bf36997ebc7bf6c08f9eba958735231b833887" - integrity sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw== + version "2.15.7" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.7.tgz#a12fe09faa3fda2483e8044c406b72286994a138" + integrity sha512-NPEKS5+yjyo597eafGbKW5ujh7Sm6lDLHZQd/lRSz6S0VarpADBJItqfB4PnwpS+472oob1GX5cCY9vzfJpHUA== dependencies: fast-fifo "^1.1.0" queue-tick "^1.0.1" @@ -7133,7 +7139,7 @@ tapable@^1.0.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== @@ -7675,10 +7681,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.90.0, webpack@^5: - version "5.90.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.90.0.tgz#313bfe16080d8b2fee6e29b6c986c0714ad4290e" - integrity sha512-bdmyXRCXeeNIePv6R6tGPyy20aUobw4Zy8r0LUS2EWO+U+Ke/gYDgsCh7bl5rB6jPpr4r0SZa6dPxBxLooDT3w== +webpack@5.90.1, webpack@^5: + version "5.90.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.90.1.tgz#62ab0c097d7cbe83d32523dbfbb645cdb7c3c01c" + integrity sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.5" @@ -7724,16 +7730,16 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.11, which-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" - integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== +which-typed-array@^1.1.13, which-typed-array@^1.1.14: + version "1.1.14" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" + integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.4" + available-typed-arrays "^1.0.6" + call-bind "^1.0.5" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.0" + has-tostringtag "^1.0.1" which@^2.0.1, which@^2.0.2: version "2.0.2" From 2e2f8724ea0a9da4417cfb50660317d9ee044351 Mon Sep 17 00:00:00 2001 From: yutotnh <57719497+yutotnh@users.noreply.github.com> Date: Mon, 22 Jan 2024 03:08:04 +0900 Subject: [PATCH 0487/1012] Fix typos in README.md and package.json --- README.md | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6106758ca50c3..5aa6bc3fd2f27 100644 --- a/README.md +++ b/README.md @@ -427,7 +427,8 @@ A big thanks to the people that have contributed to this project 🙏❤️: - WofWca ([@WofWca](https://github.com/WofWca)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=WofWca) - 不见月 ([@nooooooom](https://github.com/nooooooom)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=nooooooom) - Ian Chamberlain ([@ian-h-chamberlain](https://github.com/ian-h-chamberlain)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=ian-h-chamberlain) -- Brandon Cheng ([@gluxon](https://github.com/gluxon)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=gluxon)` +- Brandon Cheng ([@gluxon](https://github.com/gluxon)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=gluxon) +- yutotnh ([@yutotnh](https://github.com/yutotnh)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=yutotnh) Also special thanks to the people that have provided support, testing, brainstorming, etc: diff --git a/package.json b/package.json index 97c06e31e85e7..e59d7ad3c3a2f 100644 --- a/package.json +++ b/package.json @@ -3331,7 +3331,7 @@ "null" ], "default": null, - "markdownDescription": "Specifies the locale, a [BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag#List_of_major_primary_language_subtags), to use for date formatting, defaults to the VS Code locale. Use `system` to follow the current system locale, or choose a specific locale, e.g `en-US` — US English, `en-GB` — British English, `de-DE` — German, 'ja-JP = Japanese, etc.", + "markdownDescription": "Specifies the locale, a [BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag#List_of_major_primary_language_subtags), to use for date formatting, defaults to the VS Code locale. Use `system` to follow the current system locale, or choose a specific locale, e.g `en-US` — US English, `en-GB` — British English, `de-DE` — German, `ja-JP` = Japanese, etc.", "scope": "window", "order": 21 }, From 61feb7608b8bfcd8ee6a2848bcc434aa8210e835 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 5 Feb 2024 14:45:56 -0500 Subject: [PATCH 0488/1012] Adds copy/paste for patches --- CHANGELOG.md | 6 +- package.json | 73 +++++++- src/commands/patches.ts | 159 ++++++++++++++++-- src/constants.ts | 2 + src/env/node/git/localGitProvider.ts | 90 ++++++---- src/git/errors.ts | 25 +++ src/git/gitProvider.ts | 3 +- src/git/gitProviderService.ts | 12 +- .../patchDetails/patchDetailsWebview.ts | 14 +- 9 files changed, 328 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea69973178bd8..30e1d4342c413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Requires VS Code `1.85` or later with `multiDiffEditor.experimental.enabled` and `gitlens.experimental.openChangesInMultiDiffEditor` to be enabled - Adds a _Compare Pull Request_ context menu command on pull requests in the _Commit Graph_ and other GitLens views to open a comparison between the head and base of the pull request for easy reviewing - Adds an _Open in Commit Graph_ context menu command on pull requests in GitLens view to open the tip commit in the _Commit Graph_ +- Adds ability to copy changes, commits, stashes, and comparison as a patch to the clipboard + - Adds a _Copy as Patch_ context menu command on files, commits, stashes, and comparisons in GitLens views + - Adds a _Copy as Patch_ context menu command on files in the _Changes_ and _Staged Changes_ groups as well as the groups themselves in the _Source Control_ view + - Adds a _Apply Copied Patch_ command in the command palette to apply a patch from the clipboard - Adds an _Open All Changes_ inline button to branch status (upstream) and branch status files in GitLens views - Adds an _Open Changes_ submenu to branch status (upstream) and branch status files in GitLens views - Adds an alternate flow (pick another file) when using the _Open File at Revision..._ and _Open Changes with Revision..._ commands to open a file that has been renamed and the rename is currently unstaged — closes [#3109](https://github.com/gitkraken/vscode-gitlens/issues/3109) @@ -89,7 +93,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Cloud Patches that have been explicitly shared with you, i.e. you are a collaborator, now will appear in the _Cloud Patches_ view under _Shared with Me_ - Adds timed snoozing for items in the _Focus View_ — choose from a selection of times when snoozing and the item will automatically move out of the snoozed tab when that time expires - Adds the ability to open folder changes — closes [#3020](https://github.com/gitkraken/vscode-gitlens/issues/3020) - - Adds _Open Folder Changes with Revision..._ & _Open Folder Changes with Branch or Tag..._ commands to the Command Palette and to the _Explorer_ and _Source Control_ views + - Adds _Open Folder Changes with Revision..._ & _Open Folder Changes with Branch or Tag..._ commands to the command palette and to the _Explorer_ and _Source Control_ views - Requires VS Code `1.85` or later and `multiDiffEditor.experimental.enabled` to be enabled - Adds last modified time of the file when showing blame annotations for uncommitted changes - Adds search results to the minimap tooltips on the _Commit Graph_ diff --git a/package.json b/package.json index e59d7ad3c3a2f..036881a72a3a4 100644 --- a/package.json +++ b/package.json @@ -5166,6 +5166,16 @@ "title": "Show Patch Details", "category": "GitLens" }, + { + "command": "gitlens.applyPatchFromClipboard", + "title": "Apply Copied Patch", + "category": "GitLens" + }, + { + "command": "gitlens.copyPatchToClipboard", + "title": "Copy as Patch", + "category": "GitLens" + }, { "command": "gitlens.createPatch", "title": "Create Patch...", @@ -8934,9 +8944,17 @@ "command": "gitlens.showPatchDetailsPage", "when": "gitlens:enabled && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled" }, + { + "command": "gitlens.applyPatchFromClipboard", + "when": "gitlens:enabled && !gitlens:untrusted && !gitlens:hasVirtualFolders" + }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "gitlens:enabled && !gitlens:untrusted && !gitlens:hasVirtualFolders" + }, { "command": "gitlens.createPatch", - "when": "false && gitlens:enabled" + "when": "false && gitlens:enabled && !gitlens:untrusted && !gitlens:hasVirtualFolders" }, { "command": "gitlens.createCloudPatch", @@ -11714,7 +11732,7 @@ }, { "submenu": "gitlens/scm/resourceGroup/changes", - "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index)$/ && config.gitlens.menus.scmGroup.compare", + "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index|merge)$/ && config.gitlens.menus.scmGroup.compare", "group": "2_gitlens@1" }, { @@ -11730,7 +11748,12 @@ { "command": "gitlens.openOnlyChangedFiles", "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index)$/ && config.gitlens.menus.scmGroup.openClose", - "group": "3_gitlens@2" + "group": "3_gitlens@3" + }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index)$/ && config.gitlens.menus.scmGroup.compare", + "group": "7_cutcopypaste@97" } ], "scm/resourceFolder/context": [ @@ -11738,6 +11761,11 @@ "submenu": "gitlens/scm/resourceFolder/changes", "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index|merge)$/ && config.gitlens.menus.scmItem.compare", "group": "2_gitlens@1" + }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index)$/ && config.gitlens.menus.scmGroup.compare", + "group": "7_cutcopypaste@97" } ], "scm/resourceState/context": [ @@ -11771,6 +11799,11 @@ "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index|merge)$/ && config.gitlens.menus.scmItem.share", "group": "7_a_gitlens_share@1" }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "gitlens:enabled && scmProvider == git && scmResourceGroup =~ /^(workingTree|index)$/ && config.gitlens.menus.scmItem.compare", + "group": "7_cutcopypaste@97" + }, { "command": "gitlens.copyRelativePathToClipboard", "when": "gitlens:enabled && gitlens:hasRemotes && scmProvider == git && scmResourceGroup =~ /^(workingTree|index|merge)$/ && config.gitlens.menus.scmItem.clipboard", @@ -13027,6 +13060,11 @@ "when": "false && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:(commit|stash)\\b/", "group": "1_gitlens_actions_1@2" }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:(commit|stash)\\b/", + "group": "7_gitlens_cutcopypaste@97" + }, { "command": "gitlens.createCloudPatch", "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:(commit|stash)\\b/", @@ -13081,14 +13119,29 @@ }, { "command": "gitlens.copyShaToClipboard", - "when": "(viewItem =~ /gitlens:(commit|stash)\\b/) || (viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && view =~ /gitlens\\.views\\.(file|line)History/)", + "when": "viewItem =~ /gitlens:(commit|stash)\\b/", "group": "7_gitlens_cutcopypaste@3" }, { "command": "gitlens.copyMessageToClipboard", - "when": "(viewItem =~ /gitlens:(commit|stash)\\b/) || (viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && view =~ /gitlens\\.views\\.(file|line)History/)", + "when": "viewItem =~ /gitlens:(commit|stash)\\b/", "group": "7_gitlens_cutcopypaste@4" }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/", + "group": "7_gitlens_cutcopypaste@3" + }, + { + "command": "gitlens.copyShaToClipboard", + "when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && view =~ /gitlens\\.views\\.(file|line)History/", + "group": "7_gitlens_cutcopypaste@97" + }, + { + "command": "gitlens.copyMessageToClipboard", + "when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/ && view =~ /gitlens\\.views\\.(file|line)History/", + "group": "7_gitlens_cutcopypaste@98" + }, { "submenu": "gitlens/commit/copy", "when": "viewItem =~ /gitlens:(branch|commit|remote|repo-folder|repository|stash|tag|file\\b(?=.*?\\b\\+committed\\b))\\b/", @@ -13927,6 +13980,11 @@ "when": "false && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:compare:results(?!:)\\b/", "group": "1_gitlens_secondary_actions@1" }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:compare:results(?!:)\\b/", + "group": "7_gitlens_cutcopypaste@97" + }, { "command": "gitlens.createCloudPatch", "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && viewItem =~ /gitlens:compare:results(?!:)\\b/", @@ -14325,6 +14383,11 @@ "when": "false && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:(commit|stash)\\b/", "group": "1_gitlens_actions_1@2" }, + { + "command": "gitlens.copyPatchToClipboard", + "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:(commit|stash)\\b/", + "group": "7_cutcopypaste@97" + }, { "command": "gitlens.createCloudPatch", "when": "!gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:gk:organization:drafts:enabled && config.gitlens.cloudPatches.enabled && webviewItem =~ /gitlens:(commit|stash)\\b/", diff --git a/src/commands/patches.ts b/src/commands/patches.ts index 93db64e264a01..4a1b764ba90a0 100644 --- a/src/commands/patches.ts +++ b/src/commands/patches.ts @@ -1,7 +1,12 @@ import type { TextEditor } from 'vscode'; -import { window, workspace } from 'vscode'; +import { env, Uri, window, workspace } from 'vscode'; +import type { ScmResource } from '../@types/vscode.git.resources'; +import { ScmResourceGroupType } from '../@types/vscode.git.resources.enums'; import { Commands } from '../constants'; import type { Container } from '../container'; +import { ApplyPatchCommitError, ApplyPatchCommitErrorReason } from '../git/errors'; +import { uncommitted, uncommittedStaged } from '../git/models/constants'; +import type { GitDiff } from '../git/models/diff'; import { isSha, shortenRevision } from '../git/models/reference'; import type { Repository } from '../git/models/repository'; import type { Draft, LocalDraft } from '../gk/models/drafts'; @@ -9,6 +14,7 @@ import { showPatchesView } from '../plus/drafts/actions'; import type { Change, CreateDraft } from '../plus/webviews/patchDetails/protocol'; import { getRepositoryOrShowPicker } from '../quickpicks/repositoryPicker'; import { command } from '../system/command'; +import { map } from '../system/iterable'; import { Logger } from '../system/logger'; import type { CommandContext } from './base'; import { @@ -16,28 +22,75 @@ import { Command, isCommandContextViewNodeHasCommit, isCommandContextViewNodeHasComparison, + isCommandContextViewNodeHasFileCommit, } from './base'; export interface CreatePatchCommandArgs { to?: string; from?: string; repoPath?: string; + uris?: Uri[]; } -@command() -export class CreatePatchCommand extends Command { - constructor(private readonly container: Container) { - super(Commands.CreatePatch); +abstract class CreatePatchCommandBase extends Command { + constructor( + private readonly container: Container, + command: Commands | Commands[], + ) { + super(command); } - protected override preExecute(context: CommandContext, args?: CreatePatchCommandArgs) { + protected override async preExecute(context: CommandContext, args?: CreatePatchCommandArgs) { if (args == null) { - if (context.type === 'viewItem') { + if (context.type === 'scm-states') { + const resourcesByGroup = new Map(); + const uris = new Set(); + + let repo; + for (const resource of context.scmResourceStates as ScmResource[]) { + repo ??= await this.container.git.getOrOpenRepository(resource.resourceUri); + + uris.add(resource.resourceUri.toString()); + + let groupResources = resourcesByGroup.get(resource.resourceGroupType!); + if (groupResources == null) { + groupResources = []; + resourcesByGroup.set(resource.resourceGroupType!, groupResources); + } else { + groupResources.push(resource); + } + } + + args = { + repoPath: repo?.path, + to: + resourcesByGroup.size == 1 && resourcesByGroup.has(ScmResourceGroupType.Index) + ? uncommittedStaged + : uncommitted, + from: 'HEAD', + uris: [...map(uris, u => Uri.parse(u))], + }; + } else if (context.type === 'scm-groups') { + const group = context.scmResourceGroups[0]; + if (!group?.resourceStates?.length) return; + + const repo = await this.container.git.getOrOpenRepository(group.resourceStates[0].resourceUri); + + args = { + repoPath: repo?.path, + to: group.id === 'index' ? uncommittedStaged : uncommitted, + from: 'HEAD', + }; + } else if (context.type === 'viewItem') { if (isCommandContextViewNodeHasCommit(context)) { args = { repoPath: context.node.commit.repoPath, to: context.node.commit.ref, + from: `${context.node.commit.ref}^`, }; + if (isCommandContextViewNodeHasFileCommit(context)) { + args.uris = [context.node.uri]; + } } else if (isCommandContextViewNodeHasComparison(context)) { args = { repoPath: context.node.uri.fsPath, @@ -51,17 +104,33 @@ export class CreatePatchCommand extends Command { return this.execute(args); } - async execute(args?: CreatePatchCommandArgs) { + protected async getDiff(title: string, args?: CreatePatchCommandArgs): Promise { let repo; - if (args?.repoPath == null) { - repo = await getRepositoryOrShowPicker('Create Patch'); - } else { + if (args?.repoPath != null) { repo = this.container.git.getRepository(args.repoPath); } - if (repo == null) return undefined; - if (args?.to == null) return; + repo ??= await getRepositoryOrShowPicker(title); + if (repo == null) return; + + return this.container.git.getDiff( + repo.uri, + args?.to ?? uncommitted, + args?.from ?? 'HEAD', + args?.uris?.length ? { uris: args.uris } : undefined, + ); + } - const diff = await this.container.git.getDiff(repo.uri, args.to ?? 'HEAD', args.from); + abstract override execute(args?: CreatePatchCommandArgs): Promise; +} + +@command() +export class CreatePatchCommand extends CreatePatchCommandBase { + constructor(container: Container) { + super(container, Commands.CreatePatch); + } + + async execute(args?: CreatePatchCommandArgs) { + const diff = await this.getDiff('Create Patch', args); if (diff == null) return; const d = await workspace.openTextDocument({ content: diff.contents, language: 'diff' }); @@ -77,6 +146,68 @@ export class CreatePatchCommand extends Command { } } +@command() +export class CopyPatchToClipboardCommand extends CreatePatchCommandBase { + constructor(container: Container) { + super(container, Commands.CopyPatchToClipboard); + } + + async execute(args?: CreatePatchCommandArgs) { + const diff = await this.getDiff('Copy as Patch', args); + if (diff == null) return; + + await env.clipboard.writeText(diff.contents); + void window.showInformationMessage( + "Copied patch \u2014 use 'Apply Copied Patch' in another window to apply it", + ); + } +} + +@command() +export class ApplyPatchFromClipboardCommand extends Command { + constructor(private readonly container: Container) { + super(Commands.ApplyPatchFromClipboard); + } + + async execute() { + const patch = await env.clipboard.readText(); + let repo = this.container.git.highlander; + + // Make sure it looks like a valid patch + const valid = patch.length ? await this.container.git.validatePatch(repo?.uri ?? Uri.file(''), patch) : false; + if (!valid) { + void window.showWarningMessage('No valid patch found in the clipboard'); + return; + } + + repo ??= await getRepositoryOrShowPicker('Apply Copied Patch'); + if (repo == null) return; + + try { + const commit = await this.container.git.createUnreachableCommitForPatch( + repo.uri, + patch, + 'HEAD', + 'Pasted Patch', + ); + if (commit == null) return; + + await this.container.git.applyUnreachableCommitForPatch(repo.uri, commit.sha); + void window.showInformationMessage(`Patch applied successfully`); + } catch (ex) { + if (ex instanceof ApplyPatchCommitError) { + if (ex.reason === ApplyPatchCommitErrorReason.AppliedWithConflicts) { + void window.showWarningMessage('Patch applied with conflicts'); + } else { + void window.showErrorMessage(ex.message); + } + } else { + void window.showErrorMessage(`Unable apply patch: ${ex.message}`); + } + } + } +} + @command() export class CreateCloudPatchCommand extends Command { constructor(private readonly container: Container) { diff --git a/src/constants.ts b/src/constants.ts index 3f6ec91b9c1d6..0ea56451a0dd4 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -146,6 +146,8 @@ export const enum Commands { CopyRemoteRepositoryUrl = 'gitlens.copyRemoteRepositoryUrl', CopyShaToClipboard = 'gitlens.copyShaToClipboard', CopyRelativePathToClipboard = 'gitlens.copyRelativePathToClipboard', + ApplyPatchFromClipboard = 'gitlens.applyPatchFromClipboard', + CopyPatchToClipboard = 'gitlens.copyPatchToClipboard', CreatePatch = 'gitlens.createPatch', CreateCloudPatch = 'gitlens.createCloudPatch', CreatePullRequestOnRemote = 'gitlens.createPullRequestOnRemote', diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 1204c90666c73..7b24b0e462bec 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -16,6 +16,8 @@ import { emojify } from '../../../emojis'; import { Features } from '../../../features'; import { GitErrorHandling } from '../../../git/commandOptions'; import { + ApplyPatchCommitError, + ApplyPatchCommitErrorReason, BlameIgnoreRevsFileBadRevisionError, BlameIgnoreRevsFileError, CherryPickError, @@ -1091,13 +1093,13 @@ export class LocalGitProvider implements GitProvider, Disposable { await this.git.stash__push(repoPath, undefined, { includeUntracked: true }); } catch (ex) { Logger.error(ex, scope); - if (ex instanceof StashPushError) { - void showGenericErrorMessage(`Error applying patch - unable to stash changes: ${ex.message}`); - } else { - void showGenericErrorMessage(`Error applying patch - unable to stash changes`); - } - - return; + throw new ApplyPatchCommitError( + ApplyPatchCommitErrorReason.StashFailed, + `Unable to apply patch; failed stashing working changes changes${ + ex instanceof StashPushError ? `: ${ex.message}` : '' + }`, + ex, + ); } } @@ -1114,8 +1116,10 @@ export class LocalGitProvider implements GitProvider, Disposable { // worktree cannot be opened and we cannot handle issues elegantly. if (options?.createWorktreePath != null) { if (options?.branchName === null || options.branchName === currentBranch?.name) { - void showGenericErrorMessage(`Error applying patch - unable to create worktree`); - return; + throw new ApplyPatchCommitError( + ApplyPatchCommitErrorReason.CreateWorktreeFailed, + 'Unable to apply patch; failed creating worktree', + ); } try { @@ -1125,13 +1129,13 @@ export class LocalGitProvider implements GitProvider, Disposable { }); } catch (ex) { Logger.error(ex, scope); - if (ex instanceof WorktreeCreateError) { - void showGenericErrorMessage(`Error applying patch - unable to create worktree: ${ex.message}`); - } else { - void showGenericErrorMessage(`Error applying patch - unable to create worktree`); - } - - return; + throw new ApplyPatchCommitError( + ApplyPatchCommitErrorReason.CreateWorktreeFailed, + `Unable to apply patch; failed creating worktree${ + ex instanceof WorktreeCreateError ? `: ${ex.message}` : '' + }`, + ex, + ); } const worktree = await this.container.git.getWorktree( @@ -1139,8 +1143,10 @@ export class LocalGitProvider implements GitProvider, Disposable { w => normalizePath(w.uri.fsPath) === normalizePath(options.createWorktreePath!), ); if (worktree == null) { - void showGenericErrorMessage(`Error applying patch - unable to create worktree`); - return; + throw new ApplyPatchCommitError( + ApplyPatchCommitErrorReason.CreateWorktreeFailed, + 'Unable to apply patch; failed creating worktree', + ); } targetPath = worktree.uri.fsPath; @@ -1158,22 +1164,20 @@ export class LocalGitProvider implements GitProvider, Disposable { await this.git.cherrypick(targetPath, ref, { noCommit: true, errors: GitErrorHandling.Throw }); } catch (ex) { Logger.error(ex, scope); - if (ex instanceof CherryPickError) { - if (ex.reason === CherryPickErrorReason.Conflict) { - void showGenericErrorMessage( - `Error applying patch - conflicts detected. Please resolve conflicts.`, - ); - } else { - void showGenericErrorMessage(`Error applying patch - unable to apply patch changes: ${ex.message}`); - } - } else { - void showGenericErrorMessage(`Error applying patch - unable to apply patch changes`); + if (ex instanceof CherryPickError && ex.reason === CherryPickErrorReason.Conflict) { + throw new ApplyPatchCommitError( + ApplyPatchCommitErrorReason.AppliedWithConflicts, + `Patch applied with conflicts`, + ex, + ); } - return; + throw new ApplyPatchCommitError( + ApplyPatchCommitErrorReason.ApplyFailed, + `Unable to apply patch${ex instanceof CherryPickError ? `: ${ex.message}` : ''}`, + ex, + ); } - - void window.showInformationMessage(`Patch applied successfully`); } @log() @@ -3012,7 +3016,7 @@ export class LocalGitProvider implements GitProvider, Disposable { repoPath: string, to: string, from?: string, - options?: { context?: number }, + options?: { context?: number; uris?: Uri[] }, ): Promise { const scope = getLogScope(); const params = [`-U${options?.context ?? 3}`]; @@ -3044,6 +3048,10 @@ export class LocalGitProvider implements GitProvider, Disposable { params.push(from, to); } + if (options?.uris) { + params.push('--', ...options.uris.map(u => u.fsPath)); + } + let data; try { data = await this.git.diff2(repoPath, { errors: GitErrorHandling.Throw }, ...params); @@ -5489,6 +5497,24 @@ export class LocalGitProvider implements GitProvider, Disposable { return this.git.check_ref_format(ref, repoPath); } + @log({ args: { 1: false } }) + async validatePatch(repoPath: string | undefined, contents: string): Promise { + try { + await this.git.apply2(repoPath!, { stdin: contents }, '--check'); + return true; + } catch (ex) { + if (ex instanceof Error && ex.message) { + if (ex.message.includes('No valid patches in input')) { + return false; + } + + return true; + } + + return false; + } + } + @log() async validateReference(repoPath: string, ref: string): Promise { if (ref == null || ref.length === 0) return false; diff --git a/src/git/errors.ts b/src/git/errors.ts index ba9696b87fd31..806c97c855039 100644 --- a/src/git/errors.ts +++ b/src/git/errors.ts @@ -6,6 +6,31 @@ export class GitSearchError extends Error { } } +export const enum ApplyPatchCommitErrorReason { + StashFailed = 1, + CreateWorktreeFailed = 2, + ApplyFailed = 3, + AppliedWithConflicts = 4, +} + +export class ApplyPatchCommitError extends Error { + static is(ex: unknown, reason?: ApplyPatchCommitErrorReason): ex is ApplyPatchCommitError { + return ex instanceof ApplyPatchCommitError && (reason == null || ex.reason === reason); + } + + readonly original?: Error; + readonly reason: ApplyPatchCommitErrorReason | undefined; + + constructor(reason: ApplyPatchCommitErrorReason, message?: string, original?: Error) { + message ||= 'Unable to apply patch'; + super(message); + + this.original = original; + this.reason = reason; + Error.captureStackTrace?.(this, ApplyPatchCommitError); + } +} + export class BlameIgnoreRevsFileError extends Error { static is(ex: unknown): ex is BlameIgnoreRevsFileError { return ex instanceof BlameIgnoreRevsFileError; diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 2af5634d39803..d9f01394d7411 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -292,7 +292,7 @@ export interface GitProvider extends Disposable { repoPath: string | Uri, to: string, from?: string, - options?: { context?: number }, + options?: { context?: number; uris?: Uri[] }, ): Promise; getDiffFiles?(repoPath: string | Uri, contents: string): Promise; /** @@ -488,6 +488,7 @@ export interface GitProvider extends Disposable { ): Promise; validateBranchOrTagName(repoPath: string, ref: string): Promise; + validatePatch?(repoPath: string | undefined, contents: string): Promise; validateReference(repoPath: string, ref: string): Promise; stageFile(repoPath: string, pathOrUri: string | Uri): Promise; diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index fd7f75e079700..7c8c522da97ab 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -1773,7 +1773,7 @@ export class GitProviderService implements Disposable { repoPath: string | Uri, to: string, from?: string, - options?: { context?: number }, + options?: { context?: number; uris?: Uri[] }, ): Promise { const { provider, path } = this.getProvider(repoPath); return provider.getDiff?.(path, to, from, options); @@ -2637,6 +2637,16 @@ export class GitProviderService implements Disposable { return provider.validateBranchOrTagName(path, ref); } + @log({ args: { 1: false }, exit: true }) + async validatePatch(repoPath: string | Uri, contents: string): Promise { + try { + const { provider, path } = this.getProvider(repoPath); + return (await provider.validatePatch?.(path || undefined, contents)) ?? false; + } catch { + return false; + } + } + @log({ exit: true }) async validateReference(repoPath: string | Uri, ref: string): Promise { if (ref == null || ref.length === 0) return false; diff --git a/src/plus/webviews/patchDetails/patchDetailsWebview.ts b/src/plus/webviews/patchDetails/patchDetailsWebview.ts index 84ad6e0ae828d..a209375159771 100644 --- a/src/plus/webviews/patchDetails/patchDetailsWebview.ts +++ b/src/plus/webviews/patchDetails/patchDetailsWebview.ts @@ -6,6 +6,7 @@ import type { ContextKeys } from '../../../constants'; import { Commands, GlyphChars } from '../../../constants'; import type { Container } from '../../../container'; import { openChanges, openChangesWithWorking, openFile } from '../../../git/actions/commit'; +import { ApplyPatchCommitError, ApplyPatchCommitErrorReason } from '../../../git/errors'; import type { RepositoriesChangeEvent } from '../../../git/gitProviderService'; import type { GitCommit } from '../../../git/models/commit'; import { uncommitted, uncommittedStaged } from '../../../git/models/constants'; @@ -445,9 +446,18 @@ export class PatchDetailsWebviewProvider }; } - void this.container.git.applyUnreachableCommitForPatch(commit.repoPath, commit.ref, options); + await this.container.git.applyUnreachableCommitForPatch(commit.repoPath, commit.ref, options); + void window.showInformationMessage(`Patch applied successfully`); } catch (ex) { - void window.showErrorMessage(`Unable apply patch to '${patch.baseRef}': ${ex.message}`); + if (ex instanceof ApplyPatchCommitError) { + if (ex.reason === ApplyPatchCommitErrorReason.AppliedWithConflicts) { + void window.showWarningMessage('Patch applied with conflicts'); + } else { + void window.showErrorMessage(ex.message); + } + } else { + void window.showErrorMessage(`Unable apply patch to '${patch.baseRef}': ${ex.message}`); + } } } } From 5aa561d1720dc41af112096dda798b3e6a5a8d20 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 5 Feb 2024 15:31:45 -0500 Subject: [PATCH 0489/1012] Graduates `openChangesInMultiDiffEditor` to be on by default --- CHANGELOG.md | 9 +++++++- package.json | 62 ++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30e1d4342c413..c9adc741cee3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added +- Adds ability to open multiple changes in VS Code's new multi-diff editor, previously experimental and now enabled by default + - Adds an inline _Open All Changes_ command to commits, stashes, and comparisons in the views + - Changes _Open All Changes_ & _Open All Changes with Working Tree_ commands to use the new multi-diff editor when enabled + - Adds _Open All Changes, Individually_ & _Open All Changes with Working Tree, Individually_ commands to provide access to the previous behavior + - Adds a `gitlens.views.openChangesInMultiDiffEditor` setting, which is enabled by default, to specify whether to open changes in the multi-diff editor (single tab) or in individual diff editors (multiple tabs) + - Requires VS Code `1.86` or later, or VS Code `1.85` with `multiDiffEditor.experimental.enabled` enabled - Adds new comparison features to pull requests in GitLens views - Adds an _Open Pull Request Changes_ context menu command on pull requests in the _Commit Graph_ and other GitLens views to view pull request changes in a multi-diff editor (single tab) - - Requires VS Code `1.85` or later with `multiDiffEditor.experimental.enabled` and `gitlens.experimental.openChangesInMultiDiffEditor` to be enabled + - Requires VS Code `1.86` or later, or VS Code `1.85` with `multiDiffEditor.experimental.enabled` enabled - Adds a _Compare Pull Request_ context menu command on pull requests in the _Commit Graph_ and other GitLens views to open a comparison between the head and base of the pull request for easy reviewing - Adds an _Open in Commit Graph_ context menu command on pull requests in GitLens view to open the tip commit in the _Commit Graph_ - Adds ability to copy changes, commits, stashes, and comparison as a patch to the clipboard @@ -27,6 +33,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Moves the pull request to be first item in the _Commits_ view, when applicable - Moves the branch comparison to be below the branch status in the _Commits_ view to keep top focus on the status over the comparison +- Renames the `gitlens.experimental.openChangesInMultiDiffEditor` setting to `gitlens.views.openChangesInMultiDiffEditor` as it is no longer experimental and enabled by default ### Fixed diff --git a/package.json b/package.json index 036881a72a3a4..c9d985412d52f 100644 --- a/package.json +++ b/package.json @@ -655,10 +655,10 @@ "scope": "window", "order": 51 }, - "gitlens.views.experimental.multiSelect.enabled": { + "gitlens.views.openChangesInMultiDiffEditor": { "type": "boolean", - "default": false, - "markdownDescription": "Specifies whether to enable experimental multi-select support in the views.\n**NOTE**: Requires a restart to take effect.", + "default": true, + "markdownDescription": "Specifies whether to open multiple changes in VS Code's experimental multi-diff editor (single tab) or in individual diff editors (multiple tabs)", "scope": "window", "order": 60 }, @@ -2718,21 +2718,6 @@ "markdownDescription": "Specifies whether to enable the preview of _Cloud Patches_, which allow you to easily and securely share code with your teammates or other developers", "scope": "window", "order": 10 - }, - "gitlens.cloudPatches.experimental.layout": { - "type": "string", - "default": "view", - "enum": [ - "editor", - "view" - ], - "enumDescriptions": [ - "Prefer showing Cloud Patches in the editor area", - "Prefer showing Cloud Patches in a view" - ], - "markdownDescription": "Specifies the preferred layout of for _Cloud Patches_ (experimental)", - "scope": "window", - "order": 11 } } }, @@ -4056,19 +4041,34 @@ "title": "Experimental", "order": 9500, "properties": { - "gitlens.experimental.openChangesInMultiDiffEditor": { + "gitlens.experimental.allowAnnotationsWhenDirty": { "type": "boolean", "default": false, - "markdownDescription": "(Experimental) Specifies whether to open multiple changes in VS Code's experimental multi-diff editor (single tab) or in individual diff editors (multiple tabs)", + "markdownDescription": "(Experimental) Specifies whether file annotations are allowed on files with unsaved changes (dirty). Use `#gitlens.advanced.blame.delayAfterEdit#` to control how long to wait before the annotation will update while the file is still dirty", "scope": "window", "order": 10 }, - "gitlens.experimental.allowAnnotationsWhenDirty": { + "gitlens.cloudPatches.experimental.layout": { + "type": "string", + "default": "view", + "enum": [ + "editor", + "view" + ], + "enumDescriptions": [ + "Prefer showing Cloud Patches in the editor area", + "Prefer showing Cloud Patches in a view" + ], + "markdownDescription": "(Experimental) Specifies the preferred layout of for _Cloud Patches_", + "scope": "window", + "order": 20 + }, + "gitlens.views.experimental.multiSelect.enabled": { "type": "boolean", "default": false, - "markdownDescription": "(Experimental) Specifies whether file annotations are allowed on files with unsaved changes (dirty). Use `#gitlens.advanced.blame.delayAfterEdit#` to control how long to wait before the annotation will update while the file is still dirty", + "markdownDescription": "(Experimental) Specifies whether to enable experimental multi-select support in the views.\n**NOTE**: Requires a restart to take effect.", "scope": "window", - "order": 20 + "order": 30 } } }, @@ -13077,7 +13077,7 @@ }, { "command": "gitlens.views.openChangedFileDiffs", - "when": "viewItem =~ /gitlens:(compare:results(?!:)\\b(?!.*?\\b\\+filtered\\b)|commit|stash|results:files|status-branch:files|status:upstream:(ahead|behind))\\b/ && config.gitlens.experimental.openChangesInMultiDiffEditor", + "when": "viewItem =~ /gitlens:(compare:results(?!:)\\b(?!.*?\\b\\+filtered\\b)|commit|stash|results:files|status-branch:files|status:upstream:(ahead|behind))\\b/ && config.gitlens.views.openChangesInMultiDiffEditor && config.multiDiffEditor.experimental.enabled", "group": "inline@90", "alt": "gitlens.views.openChangedFileDiffsWithWorking" }, @@ -13354,7 +13354,7 @@ }, { "command": "gitlens.views.openPullRequestChanges", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor && viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", + "when": "viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/ && config.multiDiffEditor.experimental.enabled", "group": "inline@2" }, { @@ -13370,7 +13370,7 @@ }, { "command": "gitlens.views.openPullRequestChanges", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor && viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", + "when": "viewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/ && config.multiDiffEditor.experimental.enabled", "group": "1_gitlens_actions@1" }, { @@ -14476,7 +14476,7 @@ }, { "command": "gitlens.graph.openPullRequestChanges", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor && webviewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/", + "when": "webviewItem =~ /gitlens:pullrequest\\b(?=.*?\\b\\+refs\\b)/ && config.multiDiffEditor.experimental.enabled", "group": "1_gitlens_actions@1" }, { @@ -14789,7 +14789,7 @@ }, { "command": "gitlens.views.openChangedFileDiffsIndividually", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor", + "when": "config.gitlens.views.openChangesInMultiDiffEditor && config.multiDiffEditor.experimental.enabled", "group": "1_gitlens@2" }, { @@ -14798,7 +14798,7 @@ }, { "command": "gitlens.views.openChangedFileDiffsWithWorkingIndividually", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor", + "when": "config.gitlens.views.openChangesInMultiDiffEditor && config.multiDiffEditor.experimental.enabled", "group": "1_gitlens@4" }, { @@ -14821,7 +14821,7 @@ }, { "command": "gitlens.graph.openChangedFileDiffsIndividually", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor", + "when": "config.gitlens.views.openChangesInMultiDiffEditor && config.multiDiffEditor.experimental.enabled", "group": "1_gitlens@2" }, { @@ -14831,7 +14831,7 @@ }, { "command": "gitlens.graph.openChangedFileDiffsWithWorkingIndividually", - "when": "config.gitlens.experimental.openChangesInMultiDiffEditor", + "when": "config.gitlens.views.openChangesInMultiDiffEditor && config.multiDiffEditor.experimental.enabled", "group": "1_gitlens@4" }, { From 0501679d3ea9f63b8ccacb35ebceaeb8ab763aaf Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 5 Feb 2024 15:42:42 -0500 Subject: [PATCH 0490/1012] Fixes missing rename --- src/config.ts | 2 +- src/git/actions/commit.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/config.ts b/src/config.ts index 34e2c45599783..4fb49f11e38a6 100644 --- a/src/config.ts +++ b/src/config.ts @@ -77,7 +77,6 @@ export interface Config { readonly experimental: { readonly allowAnnotationsWhenDirty: boolean; readonly generateCommitMessagePrompt: string; - readonly openChangesInMultiDiffEditor: boolean; }; readonly fileAnnotations: { readonly command: string | null; @@ -569,6 +568,7 @@ export interface ViewsCommonConfig { readonly description: string; }; }; + readonly openChangesInMultiDiffEditor: boolean; readonly pageItemLimit: number; readonly showRelativeDateMarkers: boolean; diff --git a/src/git/actions/commit.ts b/src/git/actions/commit.ts index 4c076b7b321b4..1d1042f9e499e 100644 --- a/src/git/actions/commit.ts +++ b/src/git/actions/commit.ts @@ -117,13 +117,13 @@ export async function openAllChanges( maybeOptions?: TextDocumentShowOptions & { title?: string }, ): Promise { if (isCommit(commitOrFiles)) { - if (configuration.get('experimental.openChangesInMultiDiffEditor')) { + if (configuration.get('views.openChangesInMultiDiffEditor')) { return openAllChangesInChangesEditor(commitOrFiles, refsOrOptions as TextDocumentShowOptions | undefined); } return openAllChangesIndividually(commitOrFiles, refsOrOptions as TextDocumentShowOptions | undefined); } - if (configuration.get('experimental.openChangesInMultiDiffEditor')) { + if (configuration.get('views.openChangesInMultiDiffEditor')) { return openAllChangesInChangesEditor(commitOrFiles, refsOrOptions as RefRange, maybeOptions); } return openAllChangesIndividually(commitOrFiles, refsOrOptions as RefRange, maybeOptions); @@ -263,7 +263,7 @@ export async function openAllChangesWithWorking( maybeOptions?: TextDocumentShowOptions & { title?: string }, ) { if (isCommit(commitOrFiles)) { - if (configuration.get('experimental.openChangesInMultiDiffEditor')) { + if (configuration.get('views.openChangesInMultiDiffEditor')) { return openAllChangesInChangesEditor(commitOrFiles, refOrOptions as TextDocumentShowOptions | undefined); } return openAllChangesWithWorkingIndividually( @@ -272,7 +272,7 @@ export async function openAllChangesWithWorking( ); } - if (configuration.get('experimental.openChangesInMultiDiffEditor')) { + if (configuration.get('views.openChangesInMultiDiffEditor')) { return openAllChangesInChangesEditor( commitOrFiles, { From 0c59a640ed0870a770f008f7343d99ad4940c393 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 5 Feb 2024 21:46:12 -0500 Subject: [PATCH 0491/1012] Fixes focus issues on Settings UI --- src/webviews/apps/settings/partials/autolinks.html | 2 +- src/webviews/apps/settings/partials/blame.html | 2 +- src/webviews/apps/settings/partials/changes.html | 2 +- src/webviews/apps/settings/partials/code-lens.html | 2 +- src/webviews/apps/settings/partials/commit-graph.html | 2 +- src/webviews/apps/settings/partials/current-line.html | 2 +- src/webviews/apps/settings/partials/dates.html | 2 +- src/webviews/apps/settings/partials/heatmap.html | 2 +- src/webviews/apps/settings/partials/hovers.html | 2 +- src/webviews/apps/settings/partials/menus.html | 2 +- src/webviews/apps/settings/partials/modes.html | 2 +- src/webviews/apps/settings/partials/rebase-editor.html | 2 +- src/webviews/apps/settings/partials/shortcuts.html | 2 +- src/webviews/apps/settings/partials/sorting.html | 2 +- src/webviews/apps/settings/partials/status-bar.html | 2 +- src/webviews/apps/settings/partials/terminal-links.html | 2 +- src/webviews/apps/settings/partials/views.branches.html | 2 +- .../apps/settings/partials/views.commitDetails.html | 2 +- src/webviews/apps/settings/partials/views.commits.html | 2 +- .../apps/settings/partials/views.contributors.html | 2 +- .../apps/settings/partials/views.file-history.html | 2 +- .../apps/settings/partials/views.line-history.html | 2 +- src/webviews/apps/settings/partials/views.remotes.html | 2 +- .../apps/settings/partials/views.repositories.html | 2 +- .../apps/settings/partials/views.searchAndCompare.html | 2 +- src/webviews/apps/settings/partials/views.stashes.html | 2 +- src/webviews/apps/settings/partials/views.tags.html | 2 +- src/webviews/apps/settings/partials/views.worktrees.html | 2 +- src/webviews/apps/settings/settings.ts | 7 ++++++- 29 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/webviews/apps/settings/partials/autolinks.html b/src/webviews/apps/settings/partials/autolinks.html index 7c3a99fb24290..e4c3c12a71df1 100644 --- a/src/webviews/apps/settings/partials/autolinks.html +++ b/src/webviews/apps/settings/partials/autolinks.html @@ -1,4 +1,4 @@ -