Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

performance optimizations for big repos #1277

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
We are following the [Keep a Changelog](https://keepachangelog.com/) format.

## [Unreleased](https://github.com/FredrikNoren/ungit/compare/v1.5.3...master)
## [Unreleased](https://github.com/FredrikNoren/ungit/compare/v1.5.4...master)

## [1.5.4](https://github.com/FredrikNoren/ungit/compare/v1.5.3...v1.5.4)

### Fixed
- Performance optimizations for the big org [#1091](https://github.com/FredrikNoren/ungit/issues/1091)
- ignore 'rename' filewatch event as it can cause constant update and refresh loop
- Prevent redundant ref and node calculations per each `/gitlog` api call

## [1.5.3](https://github.com/FredrikNoren/ungit/compare/v1.5.2...v1.5.3)

Expand Down
14 changes: 7 additions & 7 deletions components/graph/git-graph-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class Move extends ActionBase {


class Reset extends ActionBase {
constructor (graph, node) {
constructor(graph, node) {
super(graph, 'Reset', 'reset', octicons.trashcan.toSVG({ 'height': 18 }));
this.node = node;
this.visible = ko.computed(() => {
Expand All @@ -88,7 +88,7 @@ class Reset extends ActionBase {
return remoteRef && remoteRef.node() &&
context && context.node() &&
remoteRef.node() != context.node() &&
remoteRef.node().date < context.node().date;
remoteRef.node().timestamp < context.node().timestamp;
});
}

Expand All @@ -103,7 +103,7 @@ class Reset extends ActionBase {
perform() {
const context = this.graph.currentActionContext();
const remoteRef = context.getRemoteRef(this.graph.currentRemote());
return components.create('yesnodialog', { title: 'Are you sure?', details: 'Resetting to ref: ' + remoteRef.name + ' cannot be undone with ungit.'})
return components.create('yesnodialog', { title: 'Are you sure?', details: 'Resetting to ref: ' + remoteRef.name + ' cannot be undone with ungit.' })
.show()
.closeThen((diag) => {
if (!diag.result()) return;
Expand Down Expand Up @@ -197,10 +197,10 @@ class Push extends ActionBase {
return remoteRef.moveTo(ref.node().sha1);
} else {
return ref.createRemoteRef().then(() => {
if (this.graph.HEAD().name == ref.name) {
this.grah.HEADref().node(ref.node());
}
}).finally(() => programEvents.dispatch({ event: 'request-fetch-tags' }));
if (this.graph.HEAD().name == ref.name) {
this.grah.HEADref().node(ref.node());
}
}).finally(() => programEvents.dispatch({ event: 'request-fetch-tags' }));
}
}
}
Expand Down
81 changes: 47 additions & 34 deletions components/graph/git-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ const components = require('ungit-components');
const programEvents = require('ungit-program-events');
const Animateable = require('./animateable');
const GraphActions = require('./git-graph-actions');
const _ = require('lodash');

const maxBranchesToDisplay = parseInt(ungit.config.numRefsToShow / 5 * 3); // 3/5 of refs to show to branches
const maxTagsToDisplay = ungit.config.numRefsToShow - maxBranchesToDisplay; // 2/5 of refs to show to tags

class GitNodeViewModel extends Animateable {
constructor(graph, sha1) {
super(graph);
this.hasBeenRenderedBefore = false;
this.graph = graph;
this.sha1 = sha1;
this.isInited = false;
this.title = ko.observable();
this.parents = ko.observableArray();
this.commitTime = undefined; // commit time in string
this.date = undefined; // commit time in numeric format for sort
this.timestamp = undefined; // commit time in numeric format for sort
this.color = ko.observable();
this.ideologicalBranch = ko.observable();
this.remoteTags = ko.observableArray();
Expand Down Expand Up @@ -106,6 +108,40 @@ class GitNodeViewModel extends Animateable {
new GraphActions.Revert(this.graph, this),
new GraphActions.Squash(this.graph, this)
];

this.render = _.debounce(() => {
this.refSearchFormVisible(false);
if (!this.isInited) return;
if (this.ancestorOfHEAD()) {
this.r(30);
this.cx(610);

if (!this.aboveNode) {
this.cy(120);
} else if (this.aboveNode.ancestorOfHEAD()) {
this.cy(this.aboveNode.cy() + 120);
} else {
this.cy(this.aboveNode.cy() + 60);
}
} else {
this.r(15);
this.cx(610 + (90 * this.branchOrder()));
this.cy(this.aboveNode && !isNaN(this.aboveNode.cy()) ? this.aboveNode.cy() + 60 : 120);
}

if (this.aboveNode && this.aboveNode.selected()) {
this.cy(this.aboveNode.cy() + this.aboveNode.commitComponent.element().offsetHeight + 30);
}

this.color(this.ideologicalBranch() ? this.ideologicalBranch().color : '#666');
if (!this.hasBeenRenderedBefore) {
// push this nodes into the graph's node list to be rendered if first time.
// if been pushed before, no need to add to nodes.
this.hasBeenRenderedBefore = true;
graph.nodes.push(this);
}
this.animate();
}, 500, { leading: true })
}

getGraphAttr() {
Expand All @@ -117,39 +153,16 @@ class GitNodeViewModel extends Animateable {
this.element().setAttribute('y', val[1] - 30);
}

render() {
this.refSearchFormVisible(false);
if (!this.isInited) return;
if (this.ancestorOfHEAD()) {
this.r(30);
this.cx(610);

if (!this.aboveNode) {
this.cy(120);
} else if (this.aboveNode.ancestorOfHEAD()) {
this.cy(this.aboveNode.cy() + 120);
} else {
this.cy(this.aboveNode.cy() + 60);
}
} else {
this.r(15);
this.cx(610 + (90 * this.branchOrder()));
this.cy(this.aboveNode ? this.aboveNode.cy() + 60 : 120);
}

if (this.aboveNode && this.aboveNode.selected()) {
this.cy(this.aboveNode.cy() + this.aboveNode.commitComponent.element().offsetHeight + 30);
}

this.color(this.ideologicalBranch() ? this.ideologicalBranch().color : '#666');
this.animate();
setParent(parent) {
this.aboveNode = parent;
if (parent) parent.belowNode = this;
}

setData(logEntry) {
this.title(logEntry.message.split('\n')[0]);
this.parents(logEntry.parents || []);
this.commitTime = logEntry.commitDate;
this.date = Date.parse(this.commitTime);
this.timestamp = logEntry.timestamp || Date.parse(this.commitTime);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the commitDate is already parsed on the server is the fallback here still required?

Suggested change
this.timestamp = logEntry.timestamp || Date.parse(this.commitTime);
this.timestamp = logEntry.timestamp;

this.commitComponent.setData(logEntry);
this.signatureMade(logEntry.signatureMade);
this.signatureDate(logEntry.signatureDate);
Expand Down Expand Up @@ -183,7 +196,7 @@ class GitNodeViewModel extends Animateable {
},
messages: {
noResults: '',
results: () => {}
results: () => { }
}
}).focus(() => {
$(this).autocomplete('search', $(this).val());
Expand Down Expand Up @@ -212,7 +225,7 @@ class GitNodeViewModel extends Animateable {
createTag() {
if (!this.canCreateRef()) return;
this.graph.server.postPromise('/tags', { path: this.graph.repoPath(), name: this.newBranchName(), sha1: this.sha1 })
.then(() => this.graph.getRef(`refs/tags/${this.newBranchName()}`).node(this) )
.then(() => this.graph.getRef(`refs/tags/${this.newBranchName()}`).node(this))
.catch((e) => this.graph.server.unhandledRejection(e))
.finally(() => {
this.branchingFormVisible(false);
Expand All @@ -227,7 +240,7 @@ class GitNodeViewModel extends Animateable {
beforeBelowCR = this.belowNode.commitComponent.element().getBoundingClientRect();
}

let prevSelected = this.graph.currentActionContext();
let prevSelected = this.graph.currentActionContext();
if (!(prevSelected instanceof GitNodeViewModel)) prevSelected = null;
const prevSelectedCR = prevSelected ? prevSelected.commitComponent.element().getBoundingClientRect() : null;
this.selected(!this.selected());
Expand All @@ -239,12 +252,12 @@ class GitNodeViewModel extends Animateable {
// If the next node is showing, try to keep it in the screen (no jumping)
if (beforeBelowCR.top < window.innerHeight) {
window.scrollBy(0, afterBelowCR.top - beforeBelowCR.top);
// Otherwise just try to bring them to the middle of the screen
// Otherwise just try to bring them to the middle of the screen
} else {
window.scrollBy(0, afterBelowCR.top - window.innerHeight / 2);
}
}
// If we are selecting
// If we are selecting
} else {
const afterThisCR = this.commitComponent.element().getBoundingClientRect();
if ((prevSelectedCR && (prevSelectedCR.top < 0 || prevSelectedCR.top > window.innerHeight)) &&
Expand All @@ -267,7 +280,7 @@ class GitNodeViewModel extends Animateable {
pushRef(ref) {
if (ref.isRemoteTag && !this.remoteTags().includes(ref)) {
this.remoteTags.push(ref);
} else if(!this.branchesAndLocalTags().includes(ref)) {
} else if (!this.branchesAndLocalTags().includes(ref)) {
this.branchesAndLocalTags.push(ref);
}
}
Expand Down
24 changes: 12 additions & 12 deletions components/graph/git-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class RefViewModel extends Selectable {
// This optimization is for autocomplete display
this.value = splitedName[splitedName.length - 1];
this.label = this.localRefName;
this.dom = `${this.localRefName}<span>${octicons[(this.isTag ? 'tag': 'git-branch')].toSVG({ 'height': 18 })}</span>`;
this.dom = `${this.localRefName}<span>${octicons[(this.isTag ? 'tag' : 'git-branch')].toSVG({ 'height': 18 })}</span>`;

this.displayHtml = (largeCurrent) => {
const size = (largeCurrent && this.current()) ? 26 : 18;
Expand Down Expand Up @@ -109,8 +109,8 @@ class RefViewModel extends Selectable {
operation = '/branches';
}

if (!rewindWarnOverride && this.node().date > toNode.date) {
promise = components.create('yesnodialog', { title: 'Are you sure?', details: 'This operation potentially going back in history.'})
if (!rewindWarnOverride && this.node().timestamp > toNode.timestamp) {
promise = components.create('yesnodialog', { title: 'Are you sure?', details: 'This operation potentially going back in history.' })
.show()
.closeThen(diag => {
if (diag.result()) {
Expand Down Expand Up @@ -208,15 +208,15 @@ class RefViewModel extends Selectable {
const isLocalCurrent = this.getLocalRef() && this.getLocalRef().current();

return promise.resolve().then(() => {
if (isRemote && !isLocalCurrent) {
return this.server.postPromise('/branches', {
path: this.graph.repoPath(),
name: this.refName,
sha1: this.name,
force: true
});
}
}).then(() => this.server.postPromise('/checkout', { path: this.graph.repoPath(), name: this.refName }))
if (isRemote && !isLocalCurrent) {
return this.server.postPromise('/branches', {
path: this.graph.repoPath(),
name: this.refName,
sha1: this.name,
force: true
});
}
}).then(() => this.server.postPromise('/checkout', { path: this.graph.repoPath(), name: this.refName }))
.then(() => {
if (isRemote && isLocalCurrent) {
return this.server.postPromise('/reset', { path: this.graph.repoPath(), to: this.name, mode: 'hard' });
Expand Down
4 changes: 2 additions & 2 deletions components/graph/graph-graphics.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
<g class="load-ahead-button" data-bind="attr: { opacity: commitOpacity, visible: commitNodeEdge}, click: loadAhead">
<path data-bind="attr: { d: commitNodeEdge }", stroke="#4A4A4A" stroke-width="8" stroke-dasharray="10, 5" />
<circle data-bind="attr: { stroke: commitNodeColor }" cx="610" cy="35" r="30" data-bind="attr: { stroke: '#4A4A4A' }" stroke-dasharray="10, 7" stroke-width="10" fill="transparent"/>
<!-- ko if: skip() > 0 -->
<circle class="loadAhead" data-bind="attr: { fill: commitNodeColor }" cx="610" cy="35" r="15" />
<!-- ko if: skip() > 0 -->
<circle class="loadAhead" data-bind="attr: { fill: commitNodeColor }" cx="610" cy="35" r="15" />
<!-- /ko -->
</g>
<!-- /ko -->
Expand Down
Loading