project sort working
This commit is contained in:
parent
04f6fe00de
commit
c35859fd4e
2
Makefile
2
Makefile
|
@ -28,6 +28,6 @@ build:
|
|||
${MAKE} build-css
|
||||
|
||||
test:
|
||||
${MOCHA} --compilers js:babel/register --ui exports --timeout 5000 --bail --reporter spec
|
||||
${MOCHA} --compilers js:babel-register --ui exports --timeout 5000 --bail --reporter spec
|
||||
|
||||
.PHONY: test
|
|
@ -28,12 +28,14 @@
|
|||
"babel": "^6.3.26",
|
||||
"babel-preset-es2015": "^6.3.13",
|
||||
"babel-preset-react": "^6.3.13",
|
||||
"babel-register": "^6.4.3",
|
||||
"babelify": "^7.2.0",
|
||||
"browserify": "^13.0.0",
|
||||
"chai": "^3.4.1",
|
||||
"coffeeify": "^2.0.1",
|
||||
"less": "^2.5.3",
|
||||
"mocha": "^2.3.4",
|
||||
"proxyquire": "^1.7.3",
|
||||
"superstatic": "^4.0.1",
|
||||
"uglify-js": "^2.6.1",
|
||||
"watch": "^0.17.1",
|
||||
|
|
|
@ -76,7 +76,7 @@ export default React.createClass({
|
|||
// Show projects.
|
||||
projects() {
|
||||
document.title = 'Burnchart: GitHub Burndown Chart as a Service';
|
||||
process.nextTick(() => actions.emit('projects.load'));
|
||||
actions.emit('projects.load');
|
||||
return <ProjectsPage />;
|
||||
},
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import cls from 'classnames';
|
|||
|
||||
import Format from '../mixins/Format.js';
|
||||
|
||||
import actions from '../actions/appActions.js';
|
||||
|
||||
import Icon from './Icon.jsx';
|
||||
import Link from './Link.jsx';
|
||||
|
||||
|
@ -13,9 +15,8 @@ export default React.createClass({
|
|||
|
||||
mixins: [ Format ],
|
||||
|
||||
// TODO: implement
|
||||
_onSort() {
|
||||
|
||||
actions.emit('projects.sort');
|
||||
},
|
||||
|
||||
render() {
|
||||
|
|
|
@ -22,9 +22,9 @@ export default (milestone) => {
|
|||
a = milestone.issues.closed.size;
|
||||
b = milestone.issues.open.size;
|
||||
if (a + b > 0) {
|
||||
isEmpty = false;
|
||||
points = progress(a, b);
|
||||
if (points === 100) isDone = true;
|
||||
isEmpty = false;
|
||||
points = progress(a, b);
|
||||
if (points === 100) isDone = true;
|
||||
}
|
||||
|
||||
// Milestones with no due date are always on track.
|
||||
|
|
|
@ -20,7 +20,7 @@ export default React.createClass({
|
|||
let projects = this.state.projects;
|
||||
if (projects.list.length) {
|
||||
// Show a list of projects.
|
||||
content = <div><Projects projects={projects} /></div>;
|
||||
content = <Projects projects={projects} />;
|
||||
} else {
|
||||
content = <Hero />;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,11 @@ class AppStore extends Store {
|
|||
this.set('system.loading', state);
|
||||
}
|
||||
|
||||
// TODO: implement.
|
||||
onSystemNotify() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new AppStore();
|
||||
|
|
|
@ -18,7 +18,7 @@ class ProjectsStore extends Store {
|
|||
// Initial payload.
|
||||
constructor() {
|
||||
// Init the projects.
|
||||
let list = lscache.get('projects') || [ ];
|
||||
let list = lscache.get('projects') || [];
|
||||
|
||||
super({
|
||||
// A stack of projects.
|
||||
|
@ -27,7 +27,7 @@ class ProjectsStore extends Store {
|
|||
'index': [],
|
||||
// The default sort order.
|
||||
'sortBy': 'priority',
|
||||
// Sort functions.
|
||||
// Sort functions to toggle through.
|
||||
'sortFns': [ 'progress', 'priority', 'name' ]
|
||||
});
|
||||
|
||||
|
@ -53,7 +53,7 @@ class ProjectsStore extends Store {
|
|||
|
||||
// Reset our index and re-sort.
|
||||
this.on('sortBy', () => {
|
||||
this.set('index', null);
|
||||
this.set('index', []);
|
||||
// Run the sort again.
|
||||
this.sort();
|
||||
});
|
||||
|
@ -123,6 +123,16 @@ class ProjectsStore extends Store {
|
|||
}
|
||||
}
|
||||
|
||||
// Cycle through projects sort order.
|
||||
onProjectsSort() {
|
||||
let { sortBy, sortFns } = this.get();
|
||||
|
||||
let idx = 1 + sortFns.indexOf(sortBy);
|
||||
if (idx === sortFns.length) idx = 0;
|
||||
|
||||
this.set('sortBy', sortFns[idx]);
|
||||
}
|
||||
|
||||
// Demonstration projects.
|
||||
onProjectsDemo() {
|
||||
this.set({
|
||||
|
@ -153,7 +163,9 @@ class ProjectsStore extends Store {
|
|||
let defaults = (arr, hash) => {
|
||||
for (let item of arr) {
|
||||
for (let key in hash) {
|
||||
opa.set(item, key, hash[key]);
|
||||
if (!opa.has(item, key)) {
|
||||
opa.set(item, key, hash[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -248,17 +260,18 @@ class ProjectsStore extends Store {
|
|||
// Get the existing index.
|
||||
let index = this.get('index');
|
||||
|
||||
// Do one.
|
||||
// Index one milestone in an already sorted index.
|
||||
if (ref) {
|
||||
idx = sortedIndex(index, data, this.comparator());
|
||||
index.splice(idx, 0, ref);
|
||||
// Do all.
|
||||
// Sort them all.
|
||||
} else {
|
||||
let list = this.get('list');
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let p = list[i];
|
||||
// TODO: need to show projects that failed too...
|
||||
if (p.milestones == null) continue;
|
||||
// Walk the milestones.
|
||||
for (let j = 0; j < p.milestones.length; j++) {
|
||||
let m = p.milestones[j];
|
||||
// Run a comparator here inserting into index.
|
||||
|
|
|
@ -25,6 +25,7 @@ a {
|
|||
text-decoration: none;
|
||||
color: #aaafbf;
|
||||
cursor: pointer;
|
||||
.user-select(none);
|
||||
}
|
||||
|
||||
h1, h2, h3, p {
|
||||
|
@ -174,7 +175,6 @@ ul {
|
|||
a {
|
||||
color: #e0808d;
|
||||
font-weight: bold;
|
||||
.user-select(none);
|
||||
|
||||
&.active, &:hover {
|
||||
color: #fff;
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
import { assert } from 'chai';
|
||||
|
||||
import projects from '../src/js/stores/projectsStore.js';
|
||||
|
||||
export default {
|
||||
'projects - initializes empty': (done) => {
|
||||
assert.deepEqual(projects.get('list'), []);
|
||||
done();
|
||||
},
|
||||
|
||||
'projects - sorts on new milestones': (done) => {
|
||||
projects.set({ 'list': [], 'index': [] });
|
||||
|
||||
let project = {
|
||||
'owner': 'radekstepan',
|
||||
'name': 'burnchart'
|
||||
};
|
||||
let milestone = {
|
||||
'title': '1.0.0',
|
||||
'stats': {}
|
||||
};
|
||||
|
||||
projects.push('list', project);
|
||||
projects.addMilestone(project, milestone);
|
||||
|
||||
assert.deepEqual(projects.get('index'), [[0, 0]]);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'projects - sort by progress': (done) => {
|
||||
projects.set({ 'list': [], 'index': [], 'sortBy': 'progress' });
|
||||
|
||||
let project = {
|
||||
'owner': 'radekstepan',
|
||||
'name': 'burnchart'
|
||||
};
|
||||
let milestone1 = {
|
||||
'title': '1.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 5
|
||||
}
|
||||
}
|
||||
};
|
||||
let milestone2 = {
|
||||
'title': '2.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 7
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
projects.push('list', project);
|
||||
projects.addMilestone(project, milestone1);
|
||||
projects.addMilestone(project, milestone2);
|
||||
|
||||
assert.deepEqual(projects.get('index'), [[0, 1], [0, 0]]);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'projects - sort by priority': (done) => {
|
||||
projects.set({ 'list': [], 'index': [], 'sortBy': 'priority' });
|
||||
|
||||
let project = {
|
||||
'owner': 'radekstepan',
|
||||
'name': 'burnchart'
|
||||
};
|
||||
let milestone1 = {
|
||||
'title': '1.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 2,
|
||||
'time': 1
|
||||
},
|
||||
'days': 2
|
||||
}
|
||||
};
|
||||
let milestone2 = {
|
||||
'title': '2.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 2,
|
||||
'time': 1
|
||||
},
|
||||
'days': 3
|
||||
}
|
||||
};
|
||||
let milestone3 = {
|
||||
'title': '3.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 1,
|
||||
'time': 2
|
||||
},
|
||||
'days': 4
|
||||
}
|
||||
};
|
||||
|
||||
projects.push('list', project);
|
||||
projects.addMilestone(project, milestone1);
|
||||
projects.addMilestone(project, milestone2);
|
||||
projects.addMilestone(project, milestone3);
|
||||
|
||||
assert.deepEqual(projects.get('index'), [[0, 2], [0, 0], [0, 1]]);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'projects - sort by priority defaults': (done) => {
|
||||
projects.set({ 'list': [], 'index': [], 'sortBy': 'priority' });
|
||||
|
||||
let project = {
|
||||
'owner': 'radekstepan',
|
||||
'name': 'burnchart'
|
||||
};
|
||||
let milestone1 = {
|
||||
'title': '1.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 3
|
||||
}
|
||||
}
|
||||
};
|
||||
let milestone2 = {
|
||||
'title': '2.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 2
|
||||
}
|
||||
}
|
||||
};
|
||||
let milestone3 = {
|
||||
'title': '3.0.0',
|
||||
'stats': {
|
||||
'progress': {
|
||||
'points': 1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
projects.push('list', project);
|
||||
projects.addMilestone(project, milestone1);
|
||||
projects.addMilestone(project, milestone2);
|
||||
projects.addMilestone(project, milestone3);
|
||||
|
||||
assert.deepEqual(projects.get('index'), [[0, 2], [0, 1], [0, 0]]);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'projects - sort by name': (done) => {
|
||||
projects.set({ 'list': [], 'index': [], 'sortBy': 'name' });
|
||||
|
||||
let project = {
|
||||
'owner': 'radekstepan',
|
||||
'name': 'burnchart'
|
||||
};
|
||||
let milestone1 = {
|
||||
'title': 'B',
|
||||
'stats': {}
|
||||
};
|
||||
let milestone2 = {
|
||||
'title': 'A',
|
||||
'stats': {}
|
||||
};
|
||||
|
||||
projects.push('list', project);
|
||||
projects.addMilestone(project, milestone1);
|
||||
projects.addMilestone(project, milestone2);
|
||||
|
||||
assert.deepEqual(projects.get('index'), [[0, 1], [0, 0]]);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'projects - sort by name semver': (done) => {
|
||||
projects.set({ 'list': [], 'index': [], 'sortBy': 'name' });
|
||||
|
||||
let project = {
|
||||
'owner': 'radekstepan',
|
||||
'name': 'burnchart'
|
||||
};
|
||||
let milestone1 = {
|
||||
'title': '1.2.5',
|
||||
'stats': {}
|
||||
};
|
||||
let milestone2 = {
|
||||
'title': '1.1.x',
|
||||
'stats': {}
|
||||
};
|
||||
let milestone3 = {
|
||||
'title': '1.1.7',
|
||||
'stats': {}
|
||||
};
|
||||
|
||||
projects.push('list', project);
|
||||
projects.addMilestone(project, milestone1);
|
||||
projects.addMilestone(project, milestone2);
|
||||
projects.addMilestone(project, milestone3);
|
||||
|
||||
assert.deepEqual(projects.get('index'), [[0, 2], [0, 1], [0, 0]]);
|
||||
|
||||
done();
|
||||
}
|
||||
};
|
|
@ -0,0 +1,132 @@
|
|||
import { assert } from 'chai';
|
||||
import { noCallThru } from 'proxyquire';
|
||||
import path from 'path';
|
||||
import moment from 'moment';
|
||||
|
||||
let proxy = noCallThru();
|
||||
|
||||
import stats from '../src/js/modules/stats.js';
|
||||
|
||||
export default {
|
||||
'stats - is milestone empty, on time and overdue? no due date': (done) => {
|
||||
let milestone = {
|
||||
'issues': {
|
||||
'open': {
|
||||
'size': 0
|
||||
},
|
||||
'closed': {
|
||||
'size': 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let { isEmpty, isOverdue, isOnTime } = stats(milestone);
|
||||
|
||||
assert.isTrue(isEmpty);
|
||||
assert.isFalse(isOverdue);
|
||||
assert.isTrue(isOnTime);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'stats - is milestone done?': (done) => {
|
||||
let milestone = {
|
||||
'issues': {
|
||||
'open': {
|
||||
'size': 0
|
||||
},
|
||||
'closed': {
|
||||
'size': 5
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let { isDone } = stats(milestone);
|
||||
assert.isTrue(isDone);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'stats - is milestone overdue? has due date, yes': (done) => {
|
||||
let milestone = {
|
||||
'created_at': '2011-04-02T00:00:00.000Z',
|
||||
'due_on': '2011-04-03T00:00:00.000Z',
|
||||
'issues': {
|
||||
'open': {
|
||||
'size': 0
|
||||
},
|
||||
'closed': {
|
||||
'size': 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let { isOverdue } = stats(milestone);
|
||||
assert.isTrue(isOverdue);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'stats - is milestone on time? has due date, yes': (done) => {
|
||||
let now = moment.utc();
|
||||
let milestone = {
|
||||
'created_at': now.subtract(1, 'week').toISOString(),
|
||||
'due_on': now.add(1, 'month').toISOString(),
|
||||
'issues': {
|
||||
'open': {
|
||||
'size': 1
|
||||
},
|
||||
'closed': {
|
||||
'size': 1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let { isOnTime } = stats(milestone);
|
||||
assert.isTrue(isOnTime);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'stats - is milestone on time? has due date, no': (done) => {
|
||||
let now = moment.utc();
|
||||
let milestone = {
|
||||
'created_at': now.subtract(2, 'week').toISOString(),
|
||||
'due_on': now.add(1, 'day').toISOString(),
|
||||
'issues': {
|
||||
'open': {
|
||||
'size': 2
|
||||
},
|
||||
'closed': {
|
||||
'size': 2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let { isOnTime } = stats(milestone);
|
||||
assert.isFalse(isOnTime);
|
||||
|
||||
done();
|
||||
},
|
||||
|
||||
'stats - is milestone on time? has due date, all issues closed': (done) => {
|
||||
let now = moment.utc();
|
||||
let milestone = {
|
||||
'created_at': now.subtract(2, 'week').toISOString(),
|
||||
'due_on': now.subtract(1, 'week').toISOString(),
|
||||
'issues': {
|
||||
'open': {
|
||||
'size': 0
|
||||
},
|
||||
'closed': {
|
||||
'size': 5
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let { isOnTime } = stats(milestone);
|
||||
assert.isTrue(isOnTime);
|
||||
|
||||
done();
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue