Browse Source

Adds more status nodes for upstream state

main
Eric Amodio 4 years ago
parent
commit
3fd02e9aa8
5 changed files with 136 additions and 53 deletions
  1. +14
    -4
      package.json
  2. +20
    -8
      src/views/nodes/branchNode.ts
  3. +98
    -40
      src/views/nodes/branchTrackingStatusNode.ts
  4. +2
    -0
      src/views/nodes/viewNode.ts
  5. +2
    -1
      src/views/viewCommands.ts

+ 14
- 4
package.json View File

@ -6493,12 +6493,12 @@
{
"command": "gitlens.views.pull",
"when": "gitlens:hasRemotes && !gitlens:readonly && viewItem == gitlens:status:upstream:behind",
"group": "inline@2"
"group": "inline@1"
},
{
"command": "gitlens.views.pull",
"when": "gitlens:hasRemotes && !gitlens:readonly && viewItem == gitlens:status:upstream:behind",
"group": "1_gitlens_actions@1"
"command": "gitlens.views.fetch",
"when": "gitlens:hasRemotes && !gitlens:readonly && viewItem =~ /gitlens:status:upstream:(?!none)/",
"group": "inline@2"
},
{
"command": "gitlens.views.push",
@ -6511,6 +6511,16 @@
"group": "1_gitlens_actions@2"
},
{
"command": "gitlens.views.pull",
"when": "gitlens:hasRemotes && !gitlens:readonly && viewItem == gitlens:status:upstream:behind",
"group": "1_gitlens_actions@1"
},
{
"command": "gitlens.views.fetch",
"when": "gitlens:hasRemotes && !gitlens:readonly && viewItem =~ /gitlens:status:upstream:(?!none)/",
"group": "1_gitlens_actions@3"
},
{
"command": "gitlens.views.dismissNode",
"when": "viewItem =~ /gitlens:(compare:picker:ref|compare:results\\b(?!.*?\\b\\+pinned\\b)|search)\\b(?!:(commits|files))/",
"group": "inline@99"

+ 20
- 8
src/views/nodes/branchNode.ts View File

@ -100,7 +100,7 @@ export class BranchNode
async getChildren(): Promise<ViewNode[]> {
if (this._children == null) {
const children = [];
if (this.options.showTracking && this.branch.tracking) {
if (this.options.showTracking) {
const status = {
ref: this.branch.ref,
repoPath: this.branch.repoPath,
@ -108,15 +108,27 @@ export class BranchNode
upstream: this.branch.tracking,
};
if (this.branch.state.behind) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'behind', this.root),
);
}
if (this.branch.tracking) {
if (this.root && !status.state.behind && !status.state.ahead) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'same', this.root),
);
}
if (this.branch.state.ahead) {
if (status.state.ahead) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'ahead', this.root),
);
}
if (status.state.behind) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'behind', this.root),
);
}
} else if (this.root) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'ahead', this.root),
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'none', this.root),
);
}
}

+ 98
- 40
src/views/nodes/branchTrackingStatusNode.ts View File

@ -9,7 +9,7 @@ import { GitBranch, GitLog, GitRevision, GitTrackingState } from '../../git/git'
import { GitUri } from '../../git/gitUri';
import { insertDateMarkers } from './helpers';
import { RepositoriesView } from '../repositoriesView';
import { debug, gate, Iterables, memoize, Strings } from '../../system';
import { Dates, debug, gate, Iterables, memoize, Strings } from '../../system';
import { ViewsWithFiles } from '../viewBase';
import { ContextValues, PageableViewNode, ViewNode } from './viewNode';
@ -22,8 +22,14 @@ export interface BranchTrackingStatus {
export class BranchTrackingStatusNode extends ViewNode<ViewsWithFiles> implements PageableViewNode {
static key = ':status-branch:upstream';
static getId(repoPath: string, name: string, root: boolean, upstream: string, direction: string): string {
return `${BranchNode.getId(repoPath, name, root)}${this.key}(${upstream}|${direction})`;
static getId(
repoPath: string,
name: string,
root: boolean,
upstream: string | undefined,
upstreamType: string,
): string {
return `${BranchNode.getId(repoPath, name, root)}${this.key}(${upstream ?? ''}|${upstreamType})`;
}
constructor(
@ -31,28 +37,20 @@ export class BranchTrackingStatusNode extends ViewNode implement
parent: ViewNode,
public readonly branch: GitBranch,
public readonly status: BranchTrackingStatus,
public readonly direction: 'ahead' | 'behind',
public readonly upstreamType: 'ahead' | 'behind' | 'same' | 'none',
// Specifies that the node is shown as a root under the repository node
private readonly root: boolean = false,
) {
super(GitUri.fromRepoPath(status.repoPath), view, parent);
}
get ahead(): boolean {
return this.direction === 'ahead';
}
get behind(): boolean {
return this.direction === 'behind';
}
get id(): string {
return BranchTrackingStatusNode.getId(
this.status.repoPath,
this.status.ref,
this.root,
this.status.upstream!,
this.direction,
this.status.upstream,
this.upstreamType,
);
}
@ -61,11 +59,13 @@ export class BranchTrackingStatusNode extends ViewNode implement
}
async getChildren(): Promise<ViewNode[]> {
if (this.upstreamType === 'same' || this.upstreamType === 'none') return [];
const log = await this.getLog();
if (log == null) return [];
let children;
if (this.ahead) {
if (this.upstreamType === 'ahead') {
// Since the last commit when we are looking 'ahead' can have no previous (because of the range given) -- look it up
const commits = [...log.commits.values()];
const commit = commits[commits.length - 1];
@ -97,14 +97,14 @@ export class BranchTrackingStatusNode extends ViewNode implement
children.push(new ShowMoreNode(this.view, this, children[children.length - 1]));
}
if (!this.isReposView && this.status.upstream && this.ahead && this.status.state.ahead > 0) {
if (!this.isReposView && this.status.upstream && this.upstreamType === 'ahead' && this.status.state.ahead > 0) {
children.push(
new BranchTrackingStatusFilesNode(
this.view,
this,
this.branch,
this.status as Required<BranchTrackingStatus>,
this.direction,
this.upstreamType,
this.root,
),
);
@ -113,29 +113,84 @@ export class BranchTrackingStatusNode extends ViewNode implement
return children;
}
getTreeItem(): TreeItem {
const ahead = this.ahead;
let label = ahead
? `${Strings.pluralize('commit', this.status.state.ahead)} ahead`
: `${Strings.pluralize('commit', this.status.state.behind)} behind`;
if (!this.isReposView) {
label += `${ahead ? ' of ' : ' '}${this.status.upstream}`;
async getTreeItem(): Promise<TreeItem> {
let lastFetched = 0;
if (this.root && !this.isReposView && this.upstreamType !== 'none') {
const repo = await Container.git.getRepository(this.repoPath);
lastFetched = (await repo?.getLastFetched()) ?? 0;
}
const item = new TreeItem(
label,
ahead && !this.isReposView ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed,
);
item.id = this.id;
if (this.root) {
item.contextValue = ahead ? ContextValues.StatusAheadOfUpstream : ContextValues.StatusBehindUpstream;
} else {
item.contextValue = ahead
? ContextValues.BranchStatusAheadOfUpstream
: ContextValues.BranchStatusBehindUpstream;
let label;
let collapsibleState;
let contextValue;
let icon;
let tooltip;
switch (this.upstreamType) {
case 'ahead':
label = `${Strings.pluralize('commit', this.status.state.ahead)} ahead`;
if (!this.isReposView) {
label = `${this.root ? `${this.branch.name} is ` : ''}${label} ${this.status.upstream}`;
}
tooltip = `${label} of ${this.status.upstream}`;
collapsibleState = !this.isReposView
? TreeItemCollapsibleState.Expanded
: TreeItemCollapsibleState.Collapsed;
contextValue = this.root
? ContextValues.StatusAheadOfUpstream
: ContextValues.BranchStatusAheadOfUpstream;
icon = 'cloud-upload';
break;
case 'behind':
label = `${Strings.pluralize('commit', this.status.state.behind)} behind`;
if (!this.isReposView) {
label = `${this.root ? `${this.branch.name} is ` : ''}${label} ${this.status.upstream}`;
}
tooltip = `${label} ${this.status.upstream}`;
collapsibleState = TreeItemCollapsibleState.Collapsed;
contextValue = this.root
? ContextValues.StatusBehindUpstream
: ContextValues.BranchStatusBehindUpstream;
icon = 'cloud-download';
break;
case 'same':
label = `${this.branch.name} is up to date`;
if (!this.isReposView) {
label += ` with ${this.status.upstream}`;
}
tooltip = `${label} with ${this.status.upstream}`;
collapsibleState = TreeItemCollapsibleState.None;
contextValue = this.root ? ContextValues.StatusSameAsUpstream : undefined;
icon = 'cloud';
break;
case 'none':
label = `${this.branch.name} hasn't yet been published`;
tooltip = label;
collapsibleState = TreeItemCollapsibleState.None;
contextValue = this.root ? ContextValues.StatusNoUpstream : undefined;
icon = 'cloud-upload';
break;
}
item.iconPath = new ThemeIcon(ahead ? 'cloud-upload' : 'cloud-download');
item.tooltip = `${label}${ahead ? ' of ' : ' '}${this.status.upstream}`;
const item = new TreeItem(label, collapsibleState);
item.id = this.id;
item.contextValue = contextValue;
item.description = lastFetched
? `Last fetched ${Dates.getFormatter(new Date(lastFetched)).fromNow()}`
: undefined;
item.iconPath = new ThemeIcon(icon);
item.tooltip = tooltip;
return item;
}
@ -154,10 +209,13 @@ export class BranchTrackingStatusNode extends ViewNode implement
private _log: GitLog | undefined;
private async getLog() {
if (this.upstreamType === 'same' || this.upstreamType === 'none') return undefined;
if (this._log == null) {
const range = this.ahead
? GitRevision.createRange(this.status.upstream, this.status.ref)
: GitRevision.createRange(this.status.ref, this.status.upstream);
const range =
this.upstreamType === 'ahead'
? GitRevision.createRange(this.status.upstream, this.status.ref)
: GitRevision.createRange(this.status.ref, this.status.upstream);
this._log = await Container.git.getLog(this.uri.repoPath!, {
limit: this.limit ?? this.view.config.defaultItemLimit,

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

@ -48,6 +48,8 @@ export enum ContextValues {
StatusFiles = 'gitlens:status:files',
StatusAheadOfUpstream = 'gitlens:status:upstream:ahead',
StatusBehindUpstream = 'gitlens:status:upstream:behind',
StatusNoUpstream = 'gitlens:status:upstream:none',
StatusSameAsUpstream = 'gitlens:status:upstream:same',
Tag = 'gitlens:tag',
Tags = 'gitlens:tags',
}

+ 2
- 1
src/views/viewCommands.ts View File

@ -288,9 +288,10 @@ export class ViewCommands {
}
@debug()
private fetch(node: RemoteNode | RepositoryNode) {
private fetch(node: RemoteNode | RepositoryNode | BranchTrackingStatusNode) {
if (node instanceof RepositoryNode) return GitActions.fetch(node.repo);
if (node instanceof RemoteNode) return GitActions.Remote.fetch(node.remote.repoPath, node.remote.name);
if (node instanceof BranchTrackingStatusNode) return GitActions.fetch(node.repoPath);
return Promise.resolve();
}

Loading…
Cancel
Save