Browse Source

Fixes #1255 - adds repo cmds to repo folder nodes

main
Eric Amodio 4 years ago
parent
commit
8956bb44c5
13 changed files with 274 additions and 512 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +37
    -1
      package.json
  3. +1
    -5
      src/constants.ts
  4. +7
    -29
      src/git/models/branch.ts
  5. +26
    -13
      src/git/models/repository.ts
  6. +5
    -82
      src/views/branchesView.ts
  7. +33
    -56
      src/views/commitsView.ts
  8. +7
    -82
      src/views/contributorsView.ts
  9. +119
    -2
      src/views/nodes/viewNode.ts
  10. +5
    -76
      src/views/remotesView.ts
  11. +6
    -83
      src/views/stashesView.ts
  12. +6
    -75
      src/views/tagsView.ts
  13. +21
    -8
      src/views/viewCommands.ts

+ 1
- 0
CHANGELOG.md View File

@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Fixed
- Fixes [#1255](https://github.com/eamodio/vscode-gitlens/issues/1255) - Repository folders are missing repository actions (e.g. favorites, close repo, etc)
- Fixes [#1246](https://github.com/eamodio/vscode-gitlens/issues/1246) - Gutter Blame avatar does not use Gravatar fallback style
- Fixes [#1208](https://github.com/eamodio/vscode-gitlens/issues/1208) - Connect to Github notification is noisy
- Fixes [#526](https://github.com/eamodio/vscode-gitlens/issues/526) - FAILED in gitlens.outputLevel=verbose; likely due to regex not in quotes

+ 37
- 1
package.json View File

@ -7201,6 +7201,42 @@
"group": "8_gitlens_actions_@2"
},
{
"command": "gitlens.views.star",
"when": "viewItem =~ /gitlens:repo-folder\\b(?!.*?\\b\\+starred\\b)/",
"group": "inline@99"
},
{
"command": "gitlens.views.unstar",
"when": "viewItem =~ /gitlens:repo-folder\\b(?=.*?\\b\\+starred\\b)/",
"group": "inline@99"
},
{
"command": "gitlens.views.openInTerminal",
"when": "viewItem =~ /gitlens:repo-folder\\b/",
"group": "2_gitlens_quickopen@1"
},
{
"command": "gitlens.openRepoOnRemote",
"when": "viewItem =~ /gitlens:repo-folder\\b/ && gitlens:hasRemotes",
"group": "2_gitlens_quickopen@2",
"alt": "gitlens.copyRemoteRepositoryUrl"
},
{
"command": "gitlens.views.star",
"when": "viewItem =~ /gitlens:repo-folder\\b(?!.*?\\b\\+starred\\b)/",
"group": "8_gitlens_actions_@1"
},
{
"command": "gitlens.views.unstar",
"when": "viewItem =~ /gitlens:repo-folder\\b(?=.*?\\b\\+starred\\b)/",
"group": "8_gitlens_actions_@1"
},
{
"command": "gitlens.views.closeRepository",
"when": "viewItem =~ /gitlens:repo-folder\\b/",
"group": "8_gitlens_actions_@2"
},
{
"command": "gitlens.views.publishBranch",
"when": "gitlens:hasRemotes && !gitlens:readonly && viewItem == gitlens:status:upstream:none",
"group": "inline@1"
@ -7451,7 +7487,7 @@
},
{
"command": "gitlens.views.copy",
"when": "viewItem =~ /gitlens:(?=(branch|commit|contributor|folder|history:line|pullrequest|remote|repository|stash|tag)\\b)/",
"when": "viewItem =~ /gitlens:(?=(branch|commit|contributor|folder|history:line|pullrequest|remote|repository|repo-folder|stash|tag)\\b)/",
"group": "7_gitlens_cutcopypaste@1"
},
{

+ 1
- 5
src/constants.ts View File

@ -202,11 +202,7 @@ export interface PinnedItems {
[id: string]: PinnedItem;
}
export interface StarredBranches {
[id: string]: boolean;
}
export interface StarredRepositories {
export interface Starred {
[id: string]: boolean;
}

+ 7
- 29
src/git/models/branch.ts View File

@ -1,6 +1,6 @@
'use strict';
import { BranchSorting, configuration, DateStyle } from '../../configuration';
import { StarredBranches, WorkspaceState } from '../../constants';
import { Starred, WorkspaceState } from '../../constants';
import { Container } from '../../container';
import { GitRemote, GitRevision } from '../git';
import { GitBranchReference, GitReference, PullRequest, PullRequestState } from './models';
@ -195,42 +195,20 @@ export class GitBranch implements GitBranchReference {
separator?: string;
suffix?: string;
}): string {
return GitStatus.getUpstreamStatus(this.tracking, this.state, options);
return GitStatus.getUpstreamStatus(this.tracking, { ahead: 4, behind: 10 } /*this.state*/, options);
}
get starred() {
const starred = Container.context.workspaceState.get<StarredBranches>(WorkspaceState.StarredBranches);
const starred = Container.context.workspaceState.get<Starred>(WorkspaceState.StarredBranches);
return starred !== undefined && starred[this.id] === true;
}
star(updateViews: boolean = true) {
return this.updateStarred(true, updateViews);
async star() {
await (await Container.git.getRepository(this.repoPath))?.star(this);
}
unstar(updateViews: boolean = true) {
return this.updateStarred(false, updateViews);
}
private async updateStarred(star: boolean, updateViews: boolean = true) {
let starred = Container.context.workspaceState.get<StarredBranches>(WorkspaceState.StarredBranches);
if (starred === undefined) {
starred = Object.create(null) as StarredBranches;
}
if (star) {
starred[this.id] = true;
} else {
const { [this.id]: _, ...rest } = starred;
starred = rest;
}
await Container.context.workspaceState.update(WorkspaceState.StarredBranches, starred);
// TODO@eamodio this is UGLY
if (updateViews) {
void (await Container.branchesView.refresh());
void (await Container.remotesView.refresh());
void (await Container.repositoriesView.refresh());
}
async unstar() {
await (await Container.git.getRepository(this.repoPath))?.unstar(this);
}
static formatDetached(sha: string): string {

+ 26
- 13
src/git/models/repository.ts View File

@ -14,7 +14,7 @@ import {
WorkspaceFolder,
} from 'vscode';
import { BranchSorting, configuration, TagSorting } from '../../configuration';
import { StarredRepositories, WorkspaceState } from '../../constants';
import { Starred, WorkspaceState } from '../../constants';
import { Container } from '../../container';
import { GitBranch, GitContributor, GitDiffShortStat, GitRemote, GitStash, GitStatus, GitTag } from '../git';
import { GitService } from '../gitService';
@ -33,6 +33,7 @@ export enum RepositoryChange {
Config = 'config',
Closed = 'closed',
// FileSystem = 'file-system',
Starred = 'starred',
Heads = 'heads',
Index = 'index',
Ignores = 'ignores',
@ -654,12 +655,12 @@ export class Repository implements Disposable {
}
get starred() {
const starred = Container.context.workspaceState.get<StarredRepositories>(WorkspaceState.StarredRepositories);
const starred = Container.context.workspaceState.get<Starred>(WorkspaceState.StarredRepositories);
return starred != null && starred[this.id] === true;
}
star() {
return this.updateStarred(true);
star(branch?: GitBranch) {
return this.updateStarred(true, branch);
}
@gate(() => '')
@ -721,23 +722,35 @@ export class Repository implements Disposable {
return !(options?.validate ?? true) || this.containsUri(uri) ? uri : undefined;
}
unstar() {
return this.updateStarred(false);
unstar(branch?: GitBranch) {
return this.updateStarred(false, branch);
}
private async updateStarred(star: boolean) {
let starred = Container.context.workspaceState.get<StarredRepositories>(WorkspaceState.StarredRepositories);
if (starred == null) {
starred = Object.create(null) as StarredRepositories;
private async updateStarred(star: boolean, branch?: GitBranch) {
if (branch != null) {
await this.updateStarredCore(WorkspaceState.StarredBranches, branch.id, star);
} else {
await this.updateStarredCore(WorkspaceState.StarredRepositories, this.id, star);
}
this.fireChange(RepositoryChange.Starred);
}
private async updateStarredCore(key: WorkspaceState, id: string, star: boolean) {
let starred = Container.context.workspaceState.get<Starred>(key);
if (starred === undefined) {
starred = Object.create(null) as Starred;
}
if (star) {
starred[this.id] = true;
starred[id] = true;
} else {
const { [this.id]: _, ...rest } = starred;
const { [id]: _, ...rest } = starred;
starred = rest;
}
await Container.context.workspaceState.update(WorkspaceState.StarredRepositories, starred);
await Container.context.workspaceState.update(key, starred);
this.fireChange(RepositoryChange.Starred);
}
startWatchingFileSystem(): Disposable {

+ 5
- 82
src/views/branchesView.ts View File

@ -21,7 +21,6 @@ import {
GitLogCommit,
GitReference,
GitRevisionReference,
Repository,
RepositoryChange,
RepositoryChangeEvent,
} from '../git/git';
@ -30,35 +29,15 @@ import {
BranchesNode,
BranchNode,
BranchOrTagFolderNode,
ContextValues,
RepositoryFolderNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
ViewNode,
} from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class BranchesRepositoryNode extends SubscribeableViewNode<BranchesView> {
protected splatted = true;
private child: BranchesNode | undefined;
constructor(
uri: GitUri,
view: BranchesView,
parent: ViewNode,
public readonly repo: Repository,
splatted: boolean,
) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
export class BranchesRepositoryNode extends RepositoryFolderNode<BranchesView, BranchesNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.child == null) {
this.child = new BranchesNode(this.uri, this.view, this, this.repo);
@ -67,69 +46,13 @@ export class BranchesRepositoryNode extends SubscribeableViewNode
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
await this.child?.triggerChange(reset);
await this.ensureSubscription();
}
@debug()
protected subscribe() {
return this.repo.onDidChange(this.onRepositoryChanged, this);
}
protected get requiresResetOnVisible(): boolean {
return this._repoUpdatedAt !== this.repo.updatedAt;
}
private _repoUpdatedAt: number = this.repo.updatedAt;
@debug({
args: {
0: (e: RepositoryChangeEvent) =>
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
},
})
private onRepositoryChanged(e: RepositoryChangeEvent) {
this._repoUpdatedAt = this.repo.updatedAt;
if (e.changed(RepositoryChange.Closed)) {
this.dispose();
void this.parent?.triggerChange(true);
return;
}
if (
protected changed(e: RepositoryChangeEvent) {
return (
e.changed(RepositoryChange.Config) ||
e.changed(RepositoryChange.Heads) ||
e.changed(RepositoryChange.Remotes) ||
e.changed(RepositoryChange.Unknown)
) {
void this.triggerChange(true);
}
);
}
}

+ 33
- 56
src/views/commitsView.ts View File

@ -14,8 +14,8 @@ import { Container } from '../container';
import {
GitLogCommit,
GitReference,
GitRemote,
GitRevisionReference,
Repository,
RepositoryChange,
RepositoryChangeEvent,
} from '../git/git';
@ -24,28 +24,15 @@ import {
BranchNode,
BranchTrackingStatusNode,
ContextValues,
RepositoryFolderNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
ViewNode,
} from './nodes';
import { Dates, debug, gate } from '../system';
import { Dates, debug, gate, Strings } from '../system';
import { ViewBase } from './viewBase';
export class CommitsRepositoryNode extends SubscribeableViewNode<CommitsView> {
protected splatted = true;
private child: BranchNode | undefined;
constructor(uri: GitUri, view: CommitsView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
export class CommitsRepositoryNode extends RepositoryFolderNode<CommitsView, BranchNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.child == null) {
const branch = await this.repo.getBranch();
@ -88,7 +75,7 @@ export class CommitsRepositoryNode extends SubscribeableViewNode {
? TreeItemCollapsibleState.Expanded
: TreeItemCollapsibleState.Collapsed,
);
item.contextValue = ContextValues.RepositoryFolder;
item.contextValue = `${ContextValues.RepositoryFolder}${this.repo.starred ? '+starred' : ''}`;
if (branch != null) {
const lastFetched = (await this.repo?.getLastFetched()) ?? 0;
@ -99,17 +86,35 @@ export class CommitsRepositoryNode extends SubscribeableViewNode {
? ` ${GlyphChars.Dot} Last fetched ${Dates.getFormatter(new Date(lastFetched)).fromNow()}`
: ''
}`;
}
return item;
}
let providerName;
if (branch.tracking != null) {
const providers = GitRemote.getHighlanderProviders(await Container.git.getRemotes(branch.repoPath));
providerName = providers?.length ? providers[0].name : undefined;
} else {
const remote = await branch.getRemote();
providerName = remote?.provider?.name;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
item.tooltip = `${this.repo.formattedName ?? this.uri.repoPath ?? ''}${Strings.pad(
GlyphChars.Dash,
2,
2,
)}Last fetched on ${Dates.getFormatter(new Date(lastFetched)).format(
Container.config.defaultDateFormat ?? 'h:mma, dddd MMMM Do, YYYY',
)}${this.repo.formattedName ? `\n${this.uri.repoPath}` : ''}\n\nBranch ${branch.name}${
branch.tracking
? ` is ${branch.getTrackingStatus({
empty: `up to date with ${branch.tracking}${providerName ? ` on ${providerName}` : ''}`,
expand: true,
separator: ', ',
suffix: ` ${branch.tracking}${providerName ? ` on ${providerName}` : ''}\n`,
})}`
: `hasn't been published to ${providerName ?? 'a remote'}`
}`;
}
return this.child;
return item;
}
@gate()
@ -124,42 +129,14 @@ export class CommitsRepositoryNode extends SubscribeableViewNode {
await this.ensureSubscription();
}
@debug()
protected subscribe() {
return this.repo.onDidChange(this.onRepositoryChanged, this);
}
protected get requiresResetOnVisible(): boolean {
return this._repoUpdatedAt !== this.repo.updatedAt;
}
private _repoUpdatedAt: number = this.repo.updatedAt;
@debug({
args: {
0: (e: RepositoryChangeEvent) =>
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
},
})
private onRepositoryChanged(e: RepositoryChangeEvent) {
this._repoUpdatedAt = this.repo.updatedAt;
if (e.changed(RepositoryChange.Closed)) {
this.dispose();
void this.parent?.triggerChange(true);
return;
}
if (
protected changed(e: RepositoryChangeEvent) {
return (
e.changed(RepositoryChange.Config) ||
e.changed(RepositoryChange.Index) ||
e.changed(RepositoryChange.Heads) ||
e.changed(RepositoryChange.Remotes) ||
e.changed(RepositoryChange.Unknown)
) {
void this.triggerChange(true);
}
);
}
}

+ 7
- 82
src/views/contributorsView.ts View File

@ -3,39 +3,13 @@ import { commands, ConfigurationChangeEvent, Disposable, TreeItem, TreeItemColla
import { Avatars } from '../avatars';
import { configuration, ContributorsViewConfig, ViewFilesLayout } from '../configuration';
import { Container } from '../container';
import { Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitUri } from '../git/gitUri';
import {
ContextValues,
ContributorsNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
ViewNode,
} from './nodes';
import { ContributorsNode, RepositoryFolderNode, unknownGitUri, ViewNode } from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class ContributorsRepositoryNode extends SubscribeableViewNode<ContributorsView> {
protected splatted = true;
private child: ContributorsNode | undefined;
constructor(
uri: GitUri,
view: ContributorsView,
parent: ViewNode,
public readonly repo: Repository,
splatted: boolean,
) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
export class ContributorsRepositoryNode extends RepositoryFolderNode<ContributorsView, ContributorsNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.child == null) {
this.child = new ContributorsNode(this.uri, this.view, this, this.repo);
@ -44,70 +18,21 @@ export class ContributorsRepositoryNode extends SubscribeableViewNode
return this.child.getChildren();
}
getTreeItem(): TreeItem {
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
await this.child?.triggerChange(reset);
await this.ensureSubscription();
}
@debug()
protected subscribe() {
return Disposable.from(
this.repo.onDidChange(this.onRepositoryChanged, this),
super.subscribe(),
Avatars.onDidFetch(e => this.child?.updateAvatar(e.email)),
);
}
protected get requiresResetOnVisible(): boolean {
return this._repoUpdatedAt !== this.repo.updatedAt;
}
private _repoUpdatedAt: number = this.repo.updatedAt;
@debug({
args: {
0: (e: RepositoryChangeEvent) =>
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
},
})
private onRepositoryChanged(e: RepositoryChangeEvent) {
this._repoUpdatedAt = this.repo.updatedAt;
if (e.changed(RepositoryChange.Closed)) {
this.dispose();
void this.parent?.triggerChange(true);
return;
}
if (
protected changed(e: RepositoryChangeEvent) {
return (
e.changed(RepositoryChange.Config) ||
e.changed(RepositoryChange.Heads) ||
e.changed(RepositoryChange.Remotes) ||
e.changed(RepositoryChange.Unknown)
) {
void this.triggerChange(true);
}
);
}
}

+ 119
- 2
src/views/nodes/viewNode.ts View File

@ -1,9 +1,16 @@
'use strict';
import { Command, Disposable, Event, TreeItem, TreeItemCollapsibleState, TreeViewVisibilityChangeEvent } from 'vscode';
import { GitFile, GitReference, GitRevisionReference } from '../../git/git';
import {
GitFile,
GitReference,
GitRevisionReference,
Repository,
RepositoryChange,
RepositoryChangeEvent,
} from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { Logger } from '../../logger';
import { debug, Functions, gate, logName } from '../../system';
import { debug, Functions, gate, log, logName } from '../../system';
import { TreeViewNodeCollapsibleStateChangeEvent, View } from '../viewBase';
export enum ContextValues {
@ -289,6 +296,116 @@ export abstract class SubscribeableViewNode extends V
}
}
export abstract class RepositoryFolderNode<
TView extends View = View,
TChild extends ViewNode = ViewNode
> extends SubscribeableViewNode<TView> {
static key = ':repository';
static getId(repoPath: string): string {
return `gitlens${this.key}(${repoPath})`;
}
protected splatted = true;
protected child: TChild | undefined;
constructor(uri: GitUri, view: TView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
toClipboard(): string {
return this.repo.path;
}
get id(): string {
return RepositoryFolderNode.getId(this.repo.path);
}
getTreeItem(): TreeItem | Promise<TreeItem> {
this.splatted = false;
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = `${ContextValues.RepositoryFolder}${this.repo.starred ? '+starred' : ''}`;
item.tooltip = `${
this.repo.formattedName ? `${this.repo.formattedName}\n${this.uri.repoPath}` : this.uri.repoPath ?? ''
}`;
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
await this.child?.triggerChange(reset);
await this.ensureSubscription();
}
@log()
async star() {
await this.repo.star();
// void this.parent!.triggerChange();
}
@log()
async unstar() {
await this.repo.unstar();
// void this.parent!.triggerChange();
}
@debug()
protected subscribe() {
return this.repo.onDidChange(this.onRepositoryChanged, this);
}
protected get requiresResetOnVisible(): boolean {
return this._repoUpdatedAt !== this.repo.updatedAt;
}
private _repoUpdatedAt: number = this.repo.updatedAt;
protected abstract changed(e: RepositoryChangeEvent): boolean;
@debug({
args: {
0: (e: RepositoryChangeEvent) =>
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
},
})
private onRepositoryChanged(e: RepositoryChangeEvent) {
this._repoUpdatedAt = this.repo.updatedAt;
if (e.changed(RepositoryChange.Closed)) {
this.dispose();
void this.parent?.triggerChange(true);
return;
}
if (e.changed(RepositoryChange.Starred)) {
void this.parent?.triggerChange(true);
return;
}
if (this.changed(e)) {
void this.triggerChange(true);
}
}
}
interface AutoRefreshableView {
autoRefresh: boolean;
onDidChangeAutoRefresh: Event<void>;

+ 5
- 76
src/views/remotesView.ts View File

@ -17,7 +17,6 @@ import {
GitReference,
GitRemote,
GitRevisionReference,
Repository,
RepositoryChange,
RepositoryChangeEvent,
} from '../git/git';
@ -25,31 +24,17 @@ import { GitUri } from '../git/gitUri';
import {
BranchNode,
BranchOrTagFolderNode,
ContextValues,
RemoteNode,
RemotesNode,
RepositoryFolderNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
ViewNode,
} from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class RemotesRepositoryNode extends SubscribeableViewNode<RemotesView> {
protected splatted = true;
private child: RemotesNode | undefined;
constructor(uri: GitUri, view: RemotesView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
export class RemotesRepositoryNode extends RepositoryFolderNode<RemotesView, RemotesNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.child == null) {
this.child = new RemotesNode(this.uri, this.view, this, this.repo);
@ -58,68 +43,12 @@ export class RemotesRepositoryNode extends SubscribeableViewNode {
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
await this.child?.triggerChange(reset);
await this.ensureSubscription();
}
@debug()
protected subscribe() {
return this.repo.onDidChange(this.onRepositoryChanged, this);
}
protected get requiresResetOnVisible(): boolean {
return this._repoUpdatedAt !== this.repo.updatedAt;
}
private _repoUpdatedAt: number = this.repo.updatedAt;
@debug({
args: {
0: (e: RepositoryChangeEvent) =>
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
},
})
private onRepositoryChanged(e: RepositoryChangeEvent) {
this._repoUpdatedAt = this.repo.updatedAt;
if (e.changed(RepositoryChange.Closed)) {
this.dispose();
void this.parent?.triggerChange(true);
return;
}
if (
protected changed(e: RepositoryChangeEvent) {
return (
e.changed(RepositoryChange.Config) ||
e.changed(RepositoryChange.Remotes) ||
e.changed(RepositoryChange.Unknown)
) {
void this.triggerChange(true);
}
);
}
}

+ 6
- 83
src/views/stashesView.ts View File

@ -10,34 +10,13 @@ import {
} from 'vscode';
import { configuration, StashesViewConfig, ViewFilesLayout } from '../configuration';
import { Container } from '../container';
import { GitReference, GitStashReference, Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitReference, GitStashReference, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitUri } from '../git/gitUri';
import {
ContextValues,
RepositoryNode,
StashesNode,
StashNode,
SubscribeableViewNode,
unknownGitUri,
ViewNode,
} from './nodes';
import { RepositoryFolderNode, RepositoryNode, StashesNode, StashNode, unknownGitUri, ViewNode } from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class StashesRepositoryNode extends SubscribeableViewNode<StashesView> {
protected splatted = true;
private child: StashesNode | undefined;
constructor(uri: GitUri, view: StashesView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
export class StashesRepositoryNode extends RepositoryFolderNode<StashesView, StashesNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.child == null) {
this.child = new StashesNode(this.uri, this.view, this, this.repo);
@ -46,68 +25,12 @@ export class StashesRepositoryNode extends SubscribeableViewNode {
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
await this.child?.triggerChange(reset);
await this.ensureSubscription();
}
@debug()
protected subscribe() {
return this.repo.onDidChange(this.onRepositoryChanged, this);
}
protected get requiresResetOnVisible(): boolean {
return this._repoUpdatedAt !== this.repo.updatedAt;
}
private _repoUpdatedAt: number = this.repo.updatedAt;
@debug({
args: {
0: (e: RepositoryChangeEvent) =>
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
},
})
private onRepositoryChanged(e: RepositoryChangeEvent) {
this._repoUpdatedAt = this.repo.updatedAt;
if (e.changed(RepositoryChange.Closed)) {
this.dispose();
void this.parent?.triggerChange(true);
return;
}
if (
protected changed(e: RepositoryChangeEvent) {
return (
e.changed(RepositoryChange.Config) ||
e.changed(RepositoryChange.Stash) ||
e.changed(RepositoryChange.Unknown)
) {
void this.triggerChange(true);
}
);
}
}

+ 6
- 75
src/views/tagsView.ts View File

@ -10,27 +10,14 @@ import {
} from 'vscode';
import { configuration, TagsViewConfig, ViewBranchesLayout, ViewFilesLayout } from '../configuration';
import { Container } from '../container';
import { GitReference, GitTagReference, Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitReference, GitTagReference, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitUri } from '../git/gitUri';
import { ContextValues, RepositoryNode, SubscribeableViewNode, TagsNode, unknownGitUri, ViewNode } from './nodes';
import { RepositoryFolderNode, RepositoryNode, TagsNode, unknownGitUri, ViewNode } from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
import { BranchOrTagFolderNode } from './nodes/branchOrTagFolderNode';
export class TagsRepositoryNode extends SubscribeableViewNode<TagsView> {
protected splatted = true;
private child: TagsNode | undefined;
constructor(uri: GitUri, view: TagsView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
export class TagsRepositoryNode extends RepositoryFolderNode<TagsView, TagsNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.child == null) {
this.child = new TagsNode(this.uri, this.view, this, this.repo);
@ -39,68 +26,12 @@ export class TagsRepositoryNode extends SubscribeableViewNode {
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
await this.child?.triggerChange(reset);
await this.ensureSubscription();
}
@debug()
protected subscribe() {
return this.repo.onDidChange(this.onRepositoryChanged, this);
}
protected get requiresResetOnVisible(): boolean {
return this._repoUpdatedAt !== this.repo.updatedAt;
}
private _repoUpdatedAt: number = this.repo.updatedAt;
@debug({
args: {
0: (e: RepositoryChangeEvent) =>
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
},
})
private onRepositoryChanged(e: RepositoryChangeEvent) {
this._repoUpdatedAt = this.repo.updatedAt;
if (e.changed(RepositoryChange.Closed)) {
this.dispose();
void this.parent?.triggerChange(true);
return;
}
if (
protected changed(e: RepositoryChangeEvent) {
return (
e.changed(RepositoryChange.Config) ||
e.changed(RepositoryChange.Tags) ||
e.changed(RepositoryChange.Unknown)
) {
void this.triggerChange(true);
}
);
}
}

+ 21
- 8
src/views/viewCommands.ts View File

@ -33,6 +33,7 @@ import {
PagerNode,
PullRequestNode,
RemoteNode,
RepositoryFolderNode,
RepositoryNode,
ResultsFileNode,
ResultsFilesNode,
@ -250,8 +251,8 @@ export class ViewCommands {
}
@debug()
private closeRepository(node: RepositoryNode) {
if (!(node instanceof RepositoryNode)) return;
private closeRepository(node: RepositoryNode | RepositoryFolderNode) {
if (!(node instanceof RepositoryNode) && !(node instanceof RepositoryFolderNode)) return;
node.repo.closed = true;
}
@ -398,8 +399,8 @@ export class ViewCommands {
}
@debug()
private openInTerminal(node: RepositoryNode) {
if (!(node instanceof RepositoryNode)) return Promise.resolve();
private openInTerminal(node: RepositoryNode | RepositoryFolderNode) {
if (!(node instanceof RepositoryNode) && !(node instanceof RepositoryFolderNode)) return Promise.resolve();
return commands.executeCommand(BuiltInCommands.OpenInTerminal, Uri.file(node.repo.path));
}
@ -543,8 +544,14 @@ export class ViewCommands {
}
@debug()
private star(node: BranchNode | RepositoryNode) {
if (!(node instanceof BranchNode) && !(node instanceof RepositoryNode)) return Promise.resolve();
private star(node: BranchNode | RepositoryNode | RepositoryFolderNode) {
if (
!(node instanceof BranchNode) &&
!(node instanceof RepositoryNode) &&
!(node instanceof RepositoryFolderNode)
) {
return Promise.resolve();
}
return node.star();
}
@ -602,8 +609,14 @@ export class ViewCommands {
}
@debug()
private unstar(node: BranchNode | RepositoryNode) {
if (!(node instanceof BranchNode) && !(node instanceof RepositoryNode)) return Promise.resolve();
private unstar(node: BranchNode | RepositoryNode | RepositoryFolderNode) {
if (
!(node instanceof BranchNode) &&
!(node instanceof RepositoryNode) &&
!(node instanceof RepositoryFolderNode)
) {
return Promise.resolve();
}
return node.unstar();
}

Loading…
Cancel
Save