浏览代码

Refines graph ref hiding actions

- Avoids polluting GitReference with graph specific data
 - Avoids Git tips ordering for proper group context
 - Reworks group context to merge with base context
main
Eric Amodio 2 年前
父节点
当前提交
e41d489d21
共有 11 个文件被更改,包括 316 次插入197 次删除
  1. +25
    -11
      package.json
  2. +6
    -1
      src/commands/gitCommands.actions.ts
  3. +151
    -98
      src/env/node/git/localGitProvider.ts
  4. +2
    -0
      src/git/models/graph.ts
  5. +19
    -35
      src/git/models/reference.ts
  6. +1
    -1
      src/git/models/tag.ts
  7. +4
    -0
      src/plus/github/githubGitProvider.ts
  8. +88
    -45
      src/plus/webviews/graph/graphWebview.ts
  9. +5
    -3
      src/plus/webviews/graph/protocol.ts
  10. +2
    -2
      src/storage.ts
  11. +13
    -1
      src/system/webview.ts

+ 25
- 11
package.json 查看文件

@ -6349,18 +6349,23 @@
"icon": "$(gitlens-switch)"
},
{
"command": "gitlens.graph.hideBranch",
"title": "Hide Branch...",
"command": "gitlens.graph.hideLocalBranch",
"title": "Hide Local Branch",
"category": "GitLens"
},
{
"command": "gitlens.graph.hideRemoteBranch",
"title": "Hide Remote Branch",
"category": "GitLens"
},
{
"command": "gitlens.graph.hideTag",
"title": "Hide Tag...",
"title": "Hide Tag",
"category": "GitLens"
},
{
"command": "gitlens.graph.hideGroupedBranch",
"title": "Hide from Graph...",
"command": "gitlens.graph.hideRefGroup",
"title": "Hide",
"category": "GitLens"
},
{
@ -8387,7 +8392,11 @@
"when": "false"
},
{
"command": "gitlens.graph.hideBranch",
"command": "gitlens.graph.hideLocalBranch",
"when": "false"
},
{
"command": "gitlens.graph.hideRemoteBranch",
"when": "false"
},
{
@ -8395,7 +8404,7 @@
"when": "false"
},
{
"command": "gitlens.graph.hideGroupedBranch",
"command": "gitlens.graph.hideRefGroup",
"when": "false"
},
{
@ -11028,13 +11037,18 @@
"group": "1_gitlens_actions_@10"
},
{
"command": "gitlens.graph.hideBranch",
"when": "webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(grouped|current)\\b)/",
"command": "gitlens.graph.hideLocalBranch",
"when": "webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|remote)\\b)/",
"group": "8_gitlens_actions@10"
},
{
"command": "gitlens.graph.hideRemoteBranch",
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+remote\\b)(?!.*?\\b\\+current\\b)/",
"group": "8_gitlens_actions@10"
},
{
"command": "gitlens.graph.hideGroupedBranch",
"when": "webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)/ && webviewItem =~ /gitlens:branch\\+grouped\\b/",
"command": "gitlens.graph.hideRefGroup",
"when": "webviewItemGroup =~ /gitlens:refGroup\\b(?!.*?\\b\\+current\\b)/",
"group": "8_gitlens_actions@11"
},
{

+ 6
- 1
src/commands/gitCommands.actions.ts 查看文件

@ -109,10 +109,15 @@ export namespace GitActions {
});
}
export function switchTo(repos?: string | string[] | Repository | Repository[], ref?: GitReference) {
export function switchTo(
repos?: string | string[] | Repository | Repository[],
ref?: GitReference,
confirm?: boolean,
) {
return executeGitCommand({
command: 'switch',
state: { repos: repos, reference: ref },
confirm: confirm,
});
}

+ 151
- 98
src/env/node/git/localGitProvider.ts 查看文件

@ -122,7 +122,13 @@ import {
showGitMissingErrorMessage,
showGitVersionUnsupportedErrorMessage,
} from '../../../messages';
import type { GraphItemContext, GraphItemRefContext } from '../../../plus/webviews/graph/graphWebview';
import type {
GraphBranchContextValue,
GraphItemContext,
GraphItemRefContext,
GraphItemRefGroupContext,
GraphTagContextValue,
} from '../../../plus/webviews/graph/graphWebview';
import { countStringLength, filterMap } from '../../../system/array';
import { TimedCancellationSource } from '../../../system/cancellation';
import { gate } from '../../../system/decorators/gate';
@ -142,7 +148,14 @@ import {
} from '../../../system/path';
import type { PromiseOrValue } from '../../../system/promise';
import { any, fastestSettled, getSettledValue } from '../../../system/promise';
import { equalsIgnoreCase, getDurationMilliseconds, interpolate, md5, splitSingle } from '../../../system/string';
import {
equalsIgnoreCase,
getDurationMilliseconds,
interpolate,
md5,
sortCompare,
splitSingle,
} from '../../../system/string';
import { PathTrie } from '../../../system/trie';
import { compare, fromString } from '../../../system/version';
import { serializeWebviewItemContext } from '../../../system/webview';
@ -1648,10 +1661,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const currentUser = getSettledValue(currentUserResult);
const remotes = getSettledValue(remotesResult);
const remoteMap =
remotes != null
? new Map(remotes.map(r => [r.name, r]))
: new Map<string, GitRemote<RemoteProvider | RichRemoteProvider | undefined>>();
const remoteMap = remotes != null ? new Map(remotes.map(r => [r.name, r])) : new Map<string, GitRemote>();
const selectSha = first(refParser.parse(getSettledValue(refResult) ?? ''));
let stdin: string | undefined;
@ -1712,7 +1722,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
if (cursorIndex === -1) {
// If we didn't find any new commits, we must have them all so return that we have everything
if (size === data.length) {
return { repoPath: repoPath, avatars: avatars, ids: ids, rows: [] };
return { repoPath: repoPath, avatars: avatars, ids: ids, remotes: remoteMap, rows: [] };
}
size = data.length;
@ -1738,7 +1748,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
}
if (!data) return { repoPath: repoPath, avatars: avatars, ids: ids, rows: [] };
if (!data) return { repoPath: repoPath, avatars: avatars, ids: ids, remotes: remoteMap, rows: [] };
log = data;
if (limit !== 0) {
@ -1750,20 +1760,38 @@ export class LocalGitProvider implements GitProvider, Disposable {
const rows: GitGraphRow[] = [];
let avatarUri: Uri | undefined;
let avatarUrl: string | undefined;
let branch: GitBranch | undefined;
let branchId: string;
let branchName: string;
let context:
| GraphItemRefContext<GraphBranchContextValue>
| GraphItemRefContext<GraphTagContextValue>
| undefined;
let contexts: GitGraphRowContexts | undefined;
let group;
const groupedRefs = new Map<
string,
{ head?: boolean; local?: GitBranchReference; remotes?: GitBranchReference[] }
>();
let head = false;
let isCurrentUser = false;
let refHead: GitGraphRowHead;
let refHeads: GitGraphRowHead[];
let refRemoteHead: GitGraphRowRemoteHead;
let refRemoteHeads: GitGraphRowRemoteHead[];
let refTag: GitGraphRowTag;
let refTags: GitGraphRowTag[];
let parent: string;
let parents: string[];
let remote: GitRemote<RemoteProvider | RichRemoteProvider | undefined> | undefined;
let remoteBranchId: string;
let remoteName: string;
let stashCommit: GitStashCommit | undefined;
let tag: GitGraphRowTag;
let contexts: GitGraphRowContexts | undefined;
let tagId: string;
let tagName: string;
let tip: string;
let count = 0;
@ -1780,34 +1808,38 @@ export class LocalGitProvider implements GitProvider, Disposable {
refHeads = [];
refRemoteHeads = [];
refTags = [];
contexts = undefined;
contexts = {};
head = false;
if (commit.tips) {
for (let tip of commit.tips.split(', ')) {
groupedRefs.clear();
for (tip of commit.tips.split(', ')) {
if (tip === 'refs/stash') continue;
if (tip.startsWith('tag: ')) {
const tagName = tip.substring(5);
const tagId = getTagId(repoPath, tagName);
tag = {
id: tagId,
name: tagName,
// Not currently used, so don't bother looking it up
annotated: true,
};
tag.context = serializeWebviewItemContext<GraphItemRefContext>({
tagName = tip.substring(5);
tagId = getTagId(repoPath, tagName);
context = {
webviewItem: 'gitlens:tag',
webviewItemValue: {
type: 'tag',
ref: GitReference.create(tag.name, repoPath, {
ref: GitReference.create(tagName, repoPath, {
id: tagId,
refType: 'tag',
name: tag.name,
name: tagName,
}),
},
});
refTags.push(tag);
};
refTag = {
id: tagId,
name: tagName,
// Not currently used, so don't bother looking it up
annotated: true,
context: serializeWebviewItemContext<GraphItemRefContext>(context),
};
refTags.push(refTag);
continue;
}
@ -1828,94 +1860,115 @@ export class LocalGitProvider implements GitProvider, Disposable {
branchName = getBranchNameWithoutRemote(tip);
if (branchName === 'HEAD') continue;
const remoteBranchId = getBranchId(repoPath, true, tip);
const avatarUrl = (
remoteBranchId = getBranchId(repoPath, true, tip);
avatarUrl = (
(useAvatars ? remote.provider?.avatarUri : undefined) ??
getRemoteIconUri(this.container, remote, asWebviewUri)
)?.toString(true);
context = {
webviewItem: 'gitlens:branch+remote',
webviewItemValue: {
type: 'branch',
ref: GitReference.create(tip, repoPath, {
id: remoteBranchId,
refType: 'branch',
name: tip,
remote: true,
upstream: { name: remote.name, missing: false },
}),
},
};
refRemoteHeads.push({
refRemoteHead = {
id: remoteBranchId,
name: branchName,
owner: remote.name,
url: remote.url,
avatarUrl: avatarUrl,
context: serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: 'gitlens:branch+remote',
webviewItemValue: {
type: 'branch',
ref: GitReference.create(tip, repoPath, {
id: remoteBranchId,
refType: 'branch',
name: tip,
remote: true,
upstream: { name: remote.name, missing: false },
avatarUrl: avatarUrl,
}),
},
}),
});
context: serializeWebviewItemContext<GraphItemRefContext>(context),
};
refRemoteHeads.push(refRemoteHead);
group = groupedRefs.get(branchName);
if (group == null) {
group = { remotes: [] };
groupedRefs.set(branchName, group);
}
if (group.remotes == null) {
group.remotes = [];
}
group.remotes.push(context.webviewItemValue.ref);
continue;
}
}
branch = branchMap.get(tip);
const branchId = branch?.id ?? getBranchId(repoPath, false, tip);
const groupedRefs: GitReference[] = [];
for (const refRemoteHead of refRemoteHeads) {
if (refRemoteHead.name == tip && refRemoteHead.context) {
const refContext = typeof refRemoteHead.context === 'string'
? JSON.parse(refRemoteHead.context)
: refRemoteHead.context;
const ref = refContext?.webviewItemValue?.ref;
if (ref) {
groupedRefs.push(ref);
}
}
}
branchId = branch?.id ?? getBranchId(repoPath, false, tip);
context = {
webviewItem: `gitlens:branch${head ? '+current' : ''}${
branch?.upstream != null ? '+tracking' : ''
}`,
webviewItemValue: {
type: 'branch',
ref: GitReference.create(tip, repoPath, {
id: branchId,
refType: 'branch',
name: tip,
remote: false,
upstream: branch?.upstream,
}),
},
};
refHeads.push({
refHead = {
id: branchId,
name: tip,
isCurrentHead: head,
context: serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: `gitlens:branch${head ? '+current' : ''}${
branch?.upstream != null ? '+tracking' : ''
}`,
webviewItemValue: {
type: 'branch',
ref: GitReference.create(tip, repoPath, {
id: branchId,
refType: 'branch',
name: tip,
remote: false,
upstream: branch?.upstream,
groupedRefs: groupedRefs,
}),
},
}),
contextGroup:
groupedRefs.length > 0
? serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: `gitlens:branch+grouped${head ? '+current' : ''}${
branch?.upstream != null ? '+tracking' : ''
}`,
webviewItemValue: {
type: 'branch',
ref: GitReference.create(tip, repoPath, {
id: branchId,
refType: 'branch',
name: tip,
remote: false,
upstream: branch?.upstream,
groupedRefs: groupedRefs,
}),
},
})
: undefined,
});
context: serializeWebviewItemContext<GraphItemRefContext>(context),
};
refHeads.push(refHead);
group = groupedRefs.get(tip);
if (group == null) {
group = {};
groupedRefs.set(tip, group);
}
if (head) {
group.head = true;
}
group.local = context.webviewItemValue.ref;
}
for (group of groupedRefs.values()) {
if (
group.remotes != null &&
((group.local != null && group.remotes.length > 0) || group.remotes.length > 1)
) {
if (group.remotes != null && group.remotes.length > 1) {
group.remotes.sort(
(a, b) =>
(a.upstream!.name === 'origin' ? -1 : 1) -
(b.upstream!.name === 'origin' ? -1 : 1) ||
(a.upstream!.name === 'upstream' ? -1 : 1) -
(b.upstream!.name === 'upstream' ? -1 : 1) ||
sortCompare(a.upstream!.name, b.upstream!.name),
);
}
if (contexts.refGroups == null) {
contexts.refGroups = {};
}
contexts.refGroups[group.local?.name ?? group.remotes[0].name] =
serializeWebviewItemContext<GraphItemRefGroupContext>({
webviewItemGroup: `gitlens:refGroup${group.head ? '+current' : ''}`,
webviewItemGroupValue: {
type: 'refGroup',
refs: group.local != null ? [group.local, ...group.remotes] : group.remotes,
},
});
}
}
}
@ -1938,15 +1991,14 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
if (stashCommit == null && !avatars.has(commit.authorEmail)) {
const uri = getCachedAvatarUri(commit.authorEmail);
if (uri != null) {
avatars.set(commit.authorEmail, uri.toString(true));
avatarUri = getCachedAvatarUri(commit.authorEmail);
if (avatarUri != null) {
avatars.set(commit.authorEmail, avatarUri.toString(true));
}
}
isCurrentUser = isUserMatch(currentUser, commit.author, commit.authorEmail);
contexts = {};
if (stashCommit != null) {
contexts.row = serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: 'gitlens:stash',
@ -2021,6 +2073,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
avatars: avatars,
ids: ids,
skippedIds: skippedIds,
remotes: remoteMap,
rows: rows,
id: sha,

+ 2
- 0
src/git/models/graph.ts 查看文件

@ -1,4 +1,5 @@
import type { GraphRow, Head, Remote, RowContexts, Tag } from '@gitkraken/gitkraken-components';
import type { GitRemote } from './remote';
export type GitGraphRowHead = Head;
export type GitGraphRowRemoteHead = Remote;
@ -29,6 +30,7 @@ export interface GitGraph {
readonly ids: Set<string>;
/** A set of all skipped commit ids -- typically for stash index/untracked commits */
readonly skippedIds?: Set<string>;
readonly remotes: Map<string, GitRemote>;
/** The rows for the set of commits requested */
readonly rows: GitGraphRow[];
readonly id?: string;

+ 19
- 35
src/git/models/reference.ts 查看文件

@ -109,11 +109,6 @@ export interface GitBranchReference {
repoPath: string;
}
export interface GraphGitBranchReference extends GitBranchReference {
avatarUrl?: string;
groupedRefs?: GitReference[];
}
export interface GitRevisionReference {
readonly refType: 'revision' | 'stash';
id?: undefined;
@ -144,27 +139,20 @@ export interface GitTagReference {
repoPath: string;
}
export type GitReference =
| GitBranchReference
| GraphGitBranchReference
| GitRevisionReference
| GitStashReference
| GitTagReference;
export type GitReference = GitBranchReference | GitRevisionReference | GitStashReference | GitTagReference;
export namespace GitReference {
export function create(
ref: string,
repoPath: string,
options: {
id?: string;
refType: 'branch';
name: string;
id?: string;
remote: boolean;
upstream?: { name: string; missing: boolean };
avatarUrl?: string;
groupedRefs?: GitReference[];
},
): GraphGitBranchReference | GitBranchReference;
): GitBranchReference;
export function create(
ref: string,
repoPath: string,
@ -178,7 +166,7 @@ export namespace GitReference {
export function create(
ref: string,
repoPath: string,
options: { id?: string; refType: 'tag'; name: string },
options: { refType: 'tag'; name: string; id?: string },
): GitTagReference;
export function create(
ref: string,
@ -189,8 +177,7 @@ export namespace GitReference {
refType: 'branch';
name: string;
remote: boolean;
avatarUrl?: string;
groupedRefs?: GitReference[];
upstream?: { name: string; missing: boolean };
}
| { refType?: 'revision'; name?: string; message?: string }
| { refType: 'stash'; name: string; number: string | undefined; message?: string }
@ -199,53 +186,50 @@ export namespace GitReference {
switch (options.refType) {
case 'branch':
return {
id: options.id,
name: options.name,
ref: ref,
refType: 'branch',
remote: options.remote,
repoPath: repoPath,
avatarUrl: options.avatarUrl,
groupedRefs: options.groupedRefs,
ref: ref,
name: options.name,
id: options.id,
remote: options.remote,
upstream: options.upstream,
};
case 'stash':
return {
name: options.name,
ref: ref,
refType: 'stash',
repoPath: repoPath,
ref: ref,
name: options.name,
number: options.number,
message: options.message,
};
case 'tag':
return {
id: options.id,
name: options.name,
ref: ref,
refType: 'tag',
repoPath: repoPath,
ref: ref,
name: options.name,
id: options.id,
};
default:
return {
name:
options.name ?? GitRevision.shorten(ref, { force: true, strings: { working: 'Working Tree' } }),
ref: ref,
refType: 'revision',
repoPath: repoPath,
ref: ref,
name:
options.name ?? GitRevision.shorten(ref, { force: true, strings: { working: 'Working Tree' } }),
message: options.message,
};
}
}
export function fromBranch(branch: GraphGitBranchReference) {
export function fromBranch(branch: GitBranchReference) {
return create(branch.ref, branch.repoPath, {
id: branch.id,
refType: branch.refType,
name: branch.name,
remote: branch.remote,
upstream: branch.upstream,
avatarUrl: branch.avatarUrl,
groupedRefs: branch.groupedRefs,
});
}

+ 1
- 1
src/git/models/tag.ts 查看文件

@ -11,7 +11,7 @@ export interface TagSortOptions {
}
export function getTagId(repoPath: string, name: string): string {
return `${repoPath}/tag/${name}`;
return `${repoPath}|tag/${name}`;
}
export class GitTag implements GitTagReference {

+ 4
- 0
src/plus/github/githubGitProvider.ts 查看文件

@ -1123,11 +1123,13 @@ export class GitHubGitProvider implements GitProvider, Disposable {
useAvatars?: boolean;
},
): Promise<GitGraph> {
const remoteMap = remote != null ? new Map([[remote.name, remote]]) : new Map<string, GitRemote>();
if (log == null) {
return {
repoPath: repoPath,
avatars: avatars,
ids: ids,
remotes: remoteMap,
rows: [],
};
}
@ -1138,6 +1140,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
repoPath: repoPath,
avatars: avatars,
ids: ids,
remotes: remoteMap,
rows: [],
};
}
@ -1293,6 +1296,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
repoPath: repoPath,
avatars: avatars,
ids: ids,
remotes: remoteMap,
rows: rows,
id: options?.ref,

+ 88
- 45
src/plus/webviews/graph/graphWebview.ts 查看文件

@ -1,4 +1,3 @@
import type { GraphRefType } from '@gitkraken/gitkraken-components';
import type {
ColorTheme,
ConfigurationChangeEvent,
@ -36,7 +35,7 @@ import type { Container } from '../../../container';
import { getContext, onDidChangeContext, setContext } from '../../../context';
import { PlusFeatures } from '../../../features';
import { GitSearchError } from '../../../git/errors';
import { getBranchNameWithoutRemote } from '../../../git/models/branch';
import { getBranchNameWithoutRemote, getRemoteNameFromBranchName } from '../../../git/models/branch';
import type { GitCommit } from '../../../git/models/commit';
import { GitContributor } from '../../../git/models/contributor';
import { GitGraphRowType } from '../../../git/models/graph';
@ -48,6 +47,7 @@ import type {
GitTagReference,
} from '../../../git/models/reference';
import { GitReference, GitRevision } from '../../../git/models/reference';
import { getRemoteIconUri } from '../../../git/models/remote';
import type {
Repository,
RepositoryChangeEvent,
@ -56,6 +56,7 @@ import type {
import { RepositoryChange, RepositoryChangeComparisonMode } from '../../../git/models/repository';
import type { GitSearch } from '../../../git/search';
import { getSearchQueryComparisonKey } from '../../../git/search';
import type { StoredGraphHiddenRef } from '../../../storage';
import { executeActionCommand, executeCommand, executeCoreGitCommand, registerCommand } from '../../../system/command';
import { gate } from '../../../system/decorators/gate';
import { debug } from '../../../system/decorators/log';
@ -65,8 +66,8 @@ import { last } from '../../../system/iterable';
import { updateRecordValue } from '../../../system/object';
import { getSettledValue } from '../../../system/promise';
import { isDarkTheme, isLightTheme } from '../../../system/utils';
import type { WebviewItemContext } from '../../../system/webview';
import { isWebviewItemContext, serializeWebviewItemContext } from '../../../system/webview';
import type { WebviewItemContext, WebviewItemGroupContext } from '../../../system/webview';
import { isWebviewItemContext, isWebviewItemGroupContext, serializeWebviewItemContext } from '../../../system/webview';
import type { BranchNode } from '../../../views/nodes/branchNode';
import type { CommitFileNode } from '../../../views/nodes/commitFileNode';
import type { CommitNode } from '../../../views/nodes/commitNode';
@ -323,9 +324,10 @@ export class GraphWebview extends WebviewBase {
registerCommand('gitlens.graph.switchToAnotherBranch', this.switchToAnother, this),
registerCommand('gitlens.graph.switchToBranch', this.switchTo, this),
registerCommand('gitlens.graph.hideBranch', this.hideRef, this),
registerCommand('gitlens.graph.hideLocalBranch', this.hideRef, this),
registerCommand('gitlens.graph.hideRemoteBranch', this.hideRef, this),
registerCommand('gitlens.graph.hideTag', this.hideRef, this),
registerCommand('gitlens.graph.hideGroupedBranch', this.hideRef, this),
registerCommand('gitlens.graph.hideRefGroup', item => this.hideRef(item, true), this),
registerCommand('gitlens.graph.cherryPick', this.cherryPick, this),
registerCommand('gitlens.graph.copyRemoteCommitUrl', item => this.openCommitOnRemote(item, true), this),
@ -946,7 +948,7 @@ export class GraphWebview extends WebviewBase {
}
return this.notify(DidChangeRefsVisibilityNotificationType, {
hiddenRefs: this.getHiddenRefs(),
hiddenRefs: this.getHiddenRefs(this._graph),
});
}
@ -1119,18 +1121,33 @@ export class GraphWebview extends WebviewBase {
return this.container.storage.getWorkspace('graph:columns');
}
private getHiddenRefs(): Record<string, GraphHiddenRef> | undefined {
return this.filterHiddenRefs(this.container.storage.getWorkspace('graph:hiddenRefs'));
private getHiddenRefs(graph: GitGraph | undefined): Record<string, GraphHiddenRef> | undefined {
return this.filterHiddenRefs(this.container.storage.getWorkspace('graph:hiddenRefs'), graph);
}
private filterHiddenRefs(hiddenRefs: Record<string, GraphHiddenRef> | undefined): GraphHiddenRefs | undefined {
if (hiddenRefs == null || this.repository == null) return undefined;
private filterHiddenRefs(
hiddenRefs: Record<string, StoredGraphHiddenRef> | undefined,
graph: GitGraph | undefined,
): GraphHiddenRefs | undefined {
if (hiddenRefs == null || graph == null) return undefined;
const useAvatars = configuration.get('graph.avatars', undefined, true);
const filteredRefs: GraphHiddenRefs = {};
for (const id in hiddenRefs) {
if (getRepoPathFromBranchOrTagId(id) === this.repository.path) {
filteredRefs[id] = hiddenRefs[id];
if (getRepoPathFromBranchOrTagId(id) === graph.repoPath) {
const ref: GraphHiddenRef = { ...hiddenRefs[id] };
if (ref.type === 'remote' && ref.owner) {
const remote = graph.remotes.get(ref.owner);
if (remote != null) {
ref.avatarUrl = (
(useAvatars ? remote.provider?.avatarUri : undefined) ??
getRemoteIconUri(this.container, remote, this._panel!.webview.asWebviewUri.bind(this))
)?.toString(true);
}
}
filteredRefs[id] = ref;
}
}
@ -1296,6 +1313,7 @@ export class GraphWebview extends WebviewBase {
this.setGraph(data);
this.setSelectedRows(data.id);
void this.notifyDidChangeRefsVisibility();
void this.notifyDidChangeRows(true);
});
} else {
@ -1331,7 +1349,7 @@ export class GraphWebview extends WebviewBase {
context: {
header: this.getColumnHeaderContext(columns),
},
hiddenRefs: this.getHiddenRefs(),
hiddenRefs: data != null ? this.getHiddenRefs(data) : undefined,
nonce: this.cspNonce,
workingTreeStats: getSettledValue(workingStatsResult) ?? { added: 0, deleted: 0, modified: 0 },
};
@ -1345,11 +1363,16 @@ export class GraphWebview extends WebviewBase {
}
private updateHiddenRefs(refs: GraphHiddenRef[], visible: boolean) {
let hiddenRefs = this.container.storage.getWorkspace('graph:hiddenRefs');
let storedHiddenRefs = this.container.storage.getWorkspace('graph:hiddenRefs');
for (const ref of refs) {
hiddenRefs = updateRecordValue(hiddenRefs, ref.id, visible ? undefined : ref);
storedHiddenRefs = updateRecordValue(
storedHiddenRefs,
ref.id,
visible ? undefined : { id: ref.id, type: ref.type, name: ref.name, owner: ref.owner },
);
}
void this.container.storage.storeWorkspace('graph:hiddenRefs', hiddenRefs);
void this.container.storage.storeWorkspace('graph:hiddenRefs', storedHiddenRefs);
void this.notifyDidChangeRefsVisibility();
}
@ -1631,35 +1654,30 @@ export class GraphWebview extends WebviewBase {
}
@debug()
private hideRef(item: GraphItemContext) {
if (isGraphItemRefContext(item)) {
private hideRef(item: GraphItemContext, group?: boolean) {
let refs;
if (group && isGraphItemRefGroupContext(item)) {
({ refs } = item.webviewItemGroupValue);
} else if (!group && isGraphItemRefContext(item)) {
const { ref } = item.webviewItemValue;
const groupedRefs: GitReference[] = (ref as any).groupedRefs ?? [];
const refsToHide: GitReference[] = [...groupedRefs, ref];
const graphHiddenRefs: GraphHiddenRef[] = [];
for (const refToHide of refsToHide) {
if (refToHide?.id) {
let isRemoteBranch = false;
let graphRefType: GraphRefType = 'tag';
if (refToHide.refType === 'branch') {
isRemoteBranch = refToHide.remote;
graphRefType = isRemoteBranch ? 'remote' : 'head';
}
graphHiddenRefs.push({
id: refToHide.id,
name: isRemoteBranch ? getBranchNameWithoutRemote(refToHide.name) : refToHide.name,
type: graphRefType,
avatarUrl: (refToHide as any).avatarUrl,
});
}
if (ref.id != null) {
refs = [ref];
}
}
if (graphHiddenRefs.length > 0) {
this.updateHiddenRefs(graphHiddenRefs, false);
}
if (refs != null) {
this.updateHiddenRefs(
refs.map(r => {
const remoteBranch = r.refType === 'branch' && r.remote;
return {
id: r.id!,
name: remoteBranch ? getBranchNameWithoutRemote(r.name) : r.name,
owner: remoteBranch ? getRemoteNameFromBranchName(r.name) : undefined,
type: r.refType === 'branch' ? (r.remote ? 'remote' : 'head') : 'tag',
};
}),
false,
);
}
return Promise.resolve();
@ -1898,6 +1916,11 @@ function formatRepositories(repositories: Repository[]): GraphRepository[] {
}
export type GraphItemContext = WebviewItemContext<GraphItemContextValue>;
export type GraphItemContextValue = GraphColumnsContextValue | GraphItemTypedContextValue | GraphItemRefContextValue;
export type GraphItemGroupContext = WebviewItemGroupContext<GraphItemGroupContextValue>;
export type GraphItemGroupContextValue = GraphItemRefGroupContextValue;
export type GraphItemRefContext<T = GraphItemRefContextValue> = WebviewItemContext<T>;
export type GraphItemRefContextValue =
| GraphBranchContextValue
@ -1905,11 +1928,15 @@ export type GraphItemRefContextValue =
| GraphStashContextValue
| GraphTagContextValue;
export type GraphItemRefGroupContext<T = GraphItemRefGroupContextValue> = WebviewItemGroupContext<T>;
export interface GraphItemRefGroupContextValue {
type: 'refGroup';
refs: (GitBranchReference | GitTagReference)[];
}
export type GraphItemTypedContext<T = GraphItemTypedContextValue> = WebviewItemContext<T>;
export type GraphItemTypedContextValue = GraphContributorContextValue | GraphPullRequestContextValue;
export type GraphItemContextValue = GraphColumnsContextValue | GraphItemTypedContextValue | GraphItemRefContextValue;
export type GraphColumnsContextValue = string;
export interface GraphContributorContextValue {
@ -1952,6 +1979,12 @@ function isGraphItemContext(item: unknown): item is GraphItemContext {
return isWebviewItemContext(item) && item.webview === 'gitlens.graph';
}
function isGraphItemGroupContext(item: unknown): item is GraphItemGroupContext {
if (item == null) return false;
return isWebviewItemGroupContext(item) && item.webview === 'gitlens.graph';
}
function isGraphItemTypedContext(
item: unknown,
type: 'contributor',
@ -1969,6 +2002,16 @@ function isGraphItemTypedContext(
return isGraphItemContext(item) && typeof item.webviewItemValue === 'object' && item.webviewItemValue.type === type;
}
function isGraphItemRefGroupContext(item: unknown): item is GraphItemRefGroupContext {
if (item == null) return false;
return (
isGraphItemGroupContext(item) &&
typeof item.webviewItemGroupValue === 'object' &&
item.webviewItemGroupValue.type === 'refGroup'
);
}
function isGraphItemRefContext(item: unknown): item is GraphItemRefContext;
function isGraphItemRefContext(item: unknown, refType: 'branch'): item is GraphItemRefContext<GraphBranchContextValue>;
function isGraphItemRefContext(

+ 5
- 3
src/plus/webviews/graph/protocol.ts 查看文件

@ -5,12 +5,14 @@ import type {
GraphRefOptData,
GraphRow,
GraphZoneType,
Head,
HiddenRefsById,
HostingServiceType,
PullRequestMetadata,
RefMetadata,
RefMetadataType,
Remote,
Tag,
WorkDirStats,
} from '@gitkraken/gitkraken-components';
import type { DateStyle } from '../../../config';
@ -91,8 +93,8 @@ export interface GraphCommit {
avatarUrl: string | undefined;
}
export type GraphRemote = Remote;
export type GraphTag = Record<string, any>;
export type GraphBranch = Record<string, any>;
export type GraphTag = Tag;
export type GraphBranch = Head;
export interface GraphComponentConfig {
avatars?: boolean;
@ -237,7 +239,7 @@ export const DidChangeColumnsNotificationType = new IpcNotificationType
);
export interface DidChangeRefsVisibilityParams {
hiddenRefs?: Record<string, GraphHiddenRefspan>>;
hiddenRefs?: GraphHiddenRefs;
}
export const DidChangeRefsVisibilityNotificationType = new IpcNotificationType<DidChangeRefsVisibilityParams>(
'graph/refs/didChangeVisibility',

+ 2
- 2
src/storage.ts 查看文件

@ -238,9 +238,9 @@ export type StoredGraphRefType = 'head' | 'remote' | 'tag';
export interface StoredGraphHiddenRef {
id: string;
name: string;
type: StoredGraphRefType;
avatarUrl?: string;
name: string;
owner?: string;
}
export interface StoredNamedRef {

+ 13
- 1
src/system/webview.ts 查看文件

@ -10,6 +10,18 @@ export function isWebviewItemContext(item: unknown): item is W
return 'webview' in item && 'webviewItem' in item;
}
export function serializeWebviewItemContext<T = WebviewItemContext>(context: T): string {
export interface WebviewItemGroupContext<TValue = unknown> {
webview?: string;
webviewItemGroup: string;
webviewItemGroupValue: TValue;
}
export function isWebviewItemGroupContext<TValue = unknown>(item: unknown): item is WebviewItemGroupContext<TValue> {
if (item == null) return false;
return 'webview' in item && 'webviewItemGroup' in item;
}
export function serializeWebviewItemContext<T = WebviewItemContext | WebviewItemGroupContext>(context: T): string {
return JSON.stringify(context);
}

正在加载...
取消
保存