stop saving rubbish on chart page

This commit is contained in:
Radek Stepan 2014-10-12 17:30:18 -07:00
parent 30e19811a8
commit 7bddd337fe
8 changed files with 381 additions and 143 deletions

View File

@ -15,6 +15,7 @@
###Error Handling ###Error Handling
- [ ] second visit to a different milestone comes out blank
- [ ] verify that project exists on project page when fetching it remotely (add behind the scenes) - [ ] verify that project exists on project page when fetching it remotely (add behind the scenes)
- [ ] deal with Firebase timing out, are we still logged-in? - [ ] deal with Firebase timing out, are we still logged-in?
- [ ] visiting a chart page saves the project if it isn't saved already - [ ] visiting a chart page saves the project if it isn't saved already

View File

@ -39141,17 +39141,16 @@ Router.prototype.mount = function(routes, path) {
return user.reset(); return user.reset();
}, },
onrender: function() { onrender: function() {
var client, var client;
_this = this;
this.set('client', client = new Firebase("https://" + config.data.firebase + ".firebaseio.com")); this.set('client', client = new Firebase("https://" + config.data.firebase + ".firebaseio.com"));
return this.auth = new FirebaseSimpleLogin(client, function(err, obj) { return this.auth = new FirebaseSimpleLogin(client, function(err, obj) {
user.set('loaded', true);
if (err) { if (err) {
throw err; throw err;
} }
if (obj) { if (obj) {
return user.set(obj); user.set(obj);
} }
return user.set('ready', true);
}); });
} }
}); });
@ -39360,7 +39359,7 @@ Router.prototype.mount = function(routes, path) {
// request.coffee // request.coffee
root.require.register('burnchart/src/modules/github/request.js', function(exports, require, module) { root.require.register('burnchart/src/modules/github/request.js', function(exports, require, module) {
var defaults, error, headers, request, response, user; var defaults, error, headers, isReady, isValid, ready, request, response, stack, user;
user = require('../../models/user'); user = require('../../models/user');
@ -39385,54 +39384,92 @@ Router.prototype.mount = function(routes, path) {
module.exports = { module.exports = {
repo: function(_arg, cb) { repo: function(_arg, cb) {
var data, name, owner; var name, owner;
owner = _arg.owner, name = _arg.name; owner = _arg.owner, name = _arg.name;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name, owner: owner,
'headers': headers(user.data.token) name: name
}, defaults.github); })) {
return request(data, cb); return cb('Request is malformed');
}
return ready(function() {
var data;
data = _.defaults({
'path': "/repos/" + owner + "/" + name,
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
}, },
allMilestones: function(_arg, cb) { allMilestones: function(_arg, cb) {
var data, name, owner; var name, owner;
owner = _arg.owner, name = _arg.name; owner = _arg.owner, name = _arg.name;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name + "/milestones", owner: owner,
'query': { name: name
'state': 'open', })) {
'sort': 'due_date', return cb('Request is malformed');
'direction': 'asc' }
}, return ready(function() {
'headers': headers(user.data.token) var data;
}, defaults.github); data = _.defaults({
return request(data, cb); 'path': "/repos/" + owner + "/" + name + "/milestones",
'query': {
'state': 'open',
'sort': 'due_date',
'direction': 'asc'
},
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
}, },
oneMilestone: function(_arg, cb) { oneMilestone: function(_arg, cb) {
var data, milestone, name, owner; var milestone, name, owner;
owner = _arg.owner, name = _arg.name, milestone = _arg.milestone; owner = _arg.owner, name = _arg.name, milestone = _arg.milestone;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name + "/milestones/" + milestone, owner: owner,
'query': { name: name,
'state': 'open', milestone: milestone
'sort': 'due_date', })) {
'direction': 'asc' return cb('Request is malformed');
}, }
'headers': headers(user.data.token) return ready(function() {
}, defaults.github); var data;
return request(data, cb); data = _.defaults({
'path': "/repos/" + owner + "/" + name + "/milestones/" + milestone,
'query': {
'state': 'open',
'sort': 'due_date',
'direction': 'asc'
},
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
}, },
allIssues: function(_arg, query, cb) { allIssues: function(_arg, query, cb) {
var data, milestone, name, owner; var milestone, name, owner;
owner = _arg.owner, name = _arg.name, milestone = _arg.milestone; owner = _arg.owner, name = _arg.name, milestone = _arg.milestone;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name + "/issues", owner: owner,
'query': _.extend(query, { name: name,
milestone: milestone, milestone: milestone
'per_page': '100' })) {
}), return cb('Request is malformed');
'headers': headers(user.data.token) }
}, defaults.github); return ready(function() {
return request(data, cb); var data;
data = _.defaults({
'path': "/repos/" + owner + "/" + name + "/issues",
'query': _.extend(query, {
milestone: milestone,
'per_page': '100'
}),
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
} }
}; };
@ -39484,16 +39521,62 @@ Router.prototype.mount = function(routes, path) {
headers = function(token) { headers = function(token) {
var h; var h;
h = _.extend({}, { h = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Accept': 'application/vnd.github.v3' 'Accept': 'application/vnd.github.v3'
}); };
if (token != null) { if (token != null) {
h.Authorization = "token " + token; h.Authorization = "token " + token;
} }
return h; return h;
}; };
isValid = function(obj) {
var key, rules, val;
rules = {
'owner': function(val) {
return val != null;
},
'name': function(val) {
return val != null;
},
'milestone': function(val) {
return _.isInt(val);
}
};
for (key in obj) {
val = obj[key];
if (key in rules && !rules[key](val)) {
return false;
}
}
return true;
};
isReady = user.data.ready;
stack = [];
ready = function(cb) {
if (isReady) {
return cb();
} else {
return stack.push(cb);
}
};
user.observe('ready', function(val) {
var _results;
isReady = val;
if (val) {
_results = [];
while (stack.length) {
_results.push(stack.shift()());
}
return _results;
}
});
error = function(err) { error = function(err) {
var message; var message;
switch (false) { switch (false) {
@ -39758,7 +39841,7 @@ Router.prototype.mount = function(routes, path) {
// header.mustache // header.mustache
root.require.register('burnchart/src/templates/header.js', function(exports, require, module) { root.require.register('burnchart/src/templates/header.js', function(exports, require, module) {
module.exports = ["<div id=\"head\">"," {{#with user}}"," {{#loaded}}"," <div class=\"right\" intro=\"fade\">"," {{#displayName}}"," {{displayName}} logged in"," {{else}}"," <a class=\"github\" on-click=\"!login\"><Icons icon=\"github\"/> Sign In</a>"," {{/displayName}}"," </div>"," {{/loaded}}"," {{/with}}",""," <a id=\"icon\" href=\"#\">"," <Icons icon=\"{{icon}}\"/>"," </a>",""," <!--"," <div class=\"q\">"," <Icons icon=\"search\"/>"," <Icons icon=\"down-open\"/>"," <input type=\"text\" placeholder=\"Jump to...\">"," </div>"," -->",""," <ul>"," <li><a href=\"#new/project\" class=\"add\"><Icons icon=\"plus-circled\"/> Add a Project</a></li>"," <li><a href=\"#\" class=\"faq\">FAQ</a></li>"," <li><a href=\"#reset\">DB Reset</a></li>"," <li><a href=\"#notify\">Notify</a></li>"," </ul>","</div>"].join("\n"); module.exports = ["<div id=\"head\">"," {{#with user}}"," {{#ready}}"," <div class=\"right\" intro=\"fade\">"," {{#displayName}}"," {{displayName}} logged in"," {{else}}"," <a class=\"github\" on-click=\"!login\"><Icons icon=\"github\"/> Sign In</a>"," {{/displayName}}"," </div>"," {{/ready}}"," {{/with}}",""," <a id=\"icon\" href=\"#\">"," <Icons icon=\"{{icon}}\"/>"," </a>",""," <!--"," <div class=\"q\">"," <Icons icon=\"search\"/>"," <Icons icon=\"down-open\"/>"," <input type=\"text\" placeholder=\"Jump to...\">"," </div>"," -->",""," <ul>"," <li><a href=\"#new/project\" class=\"add\"><Icons icon=\"plus-circled\"/> Add a Project</a></li>"," <li><a href=\"#\" class=\"faq\">FAQ</a></li>"," <li><a href=\"#reset\">DB Reset</a></li>"," <li><a href=\"#notify\">Notify</a></li>"," </ul>","</div>"].join("\n");
}); });
// hero.mustache // hero.mustache
@ -39907,6 +39990,9 @@ Router.prototype.mount = function(routes, path) {
}); });
return obj; return obj;
}); });
},
'isInt': function(val) {
return !isNaN(val) && parseInt(Number(val)) === val && !isNaN(parseInt(val, 10));
} }
}); });
@ -40290,6 +40376,7 @@ Router.prototype.mount = function(routes, path) {
var done, fetchIssues, fetchMilestone, milestone, name, obj, owner, project, _ref, var done, fetchIssues, fetchMilestone, milestone, name, obj, owner, project, _ref,
_this = this; _this = this;
_ref = this.get('route'), owner = _ref[0], name = _ref[1], milestone = _ref[2]; _ref = this.get('route'), owner = _ref[0], name = _ref[1], milestone = _ref[2];
milestone = parseInt(milestone);
document.title = "" + owner + "/" + name + "/" + milestone; document.title = "" + owner + "/" + name + "/" + milestone;
project = projects.find({ project = projects.find({
owner: owner, owner: owner,
@ -40309,13 +40396,19 @@ Router.prototype.mount = function(routes, path) {
} }
done = system.async(); done = system.async();
fetchMilestone = function(cb) { fetchMilestone = function(cb) {
return milestones.fetch(_.extend(project, { return milestones.fetch({
owner: owner,
name: name,
milestone: milestone milestone: milestone
}), cb); }, cb);
}; };
fetchIssues = function(milestone, cb) { fetchIssues = function(data, cb) {
return issues.fetchAll(project, function(err, obj) { return issues.fetchAll({
return cb(err, _.extend(milestone, { owner: owner,
name: name,
milestone: milestone
}, function(err, obj) {
return cb(err, _.extend(data, {
'issues': obj 'issues': obj
})); }));
}); });
@ -40330,7 +40423,11 @@ Router.prototype.mount = function(routes, path) {
'ttl': null 'ttl': null
}); });
} }
projects.push('list', data); if (project.milestones == null) {
project.milestones = [];
}
project.milestones.push(data);
projects.update('list');
return _this.set({ return _this.set({
'milestone': data, 'milestone': data,
'ready': true 'ready': true

View File

@ -93,17 +93,16 @@
return user.reset(); return user.reset();
}, },
onrender: function() { onrender: function() {
var client, var client;
_this = this;
this.set('client', client = new Firebase("https://" + config.data.firebase + ".firebaseio.com")); this.set('client', client = new Firebase("https://" + config.data.firebase + ".firebaseio.com"));
return this.auth = new FirebaseSimpleLogin(client, function(err, obj) { return this.auth = new FirebaseSimpleLogin(client, function(err, obj) {
user.set('loaded', true);
if (err) { if (err) {
throw err; throw err;
} }
if (obj) { if (obj) {
return user.set(obj); user.set(obj);
} }
return user.set('ready', true);
}); });
} }
}); });
@ -312,7 +311,7 @@
// request.coffee // request.coffee
root.require.register('burnchart/src/modules/github/request.js', function(exports, require, module) { root.require.register('burnchart/src/modules/github/request.js', function(exports, require, module) {
var defaults, error, headers, request, response, user; var defaults, error, headers, isReady, isValid, ready, request, response, stack, user;
user = require('../../models/user'); user = require('../../models/user');
@ -337,54 +336,92 @@
module.exports = { module.exports = {
repo: function(_arg, cb) { repo: function(_arg, cb) {
var data, name, owner; var name, owner;
owner = _arg.owner, name = _arg.name; owner = _arg.owner, name = _arg.name;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name, owner: owner,
'headers': headers(user.data.token) name: name
}, defaults.github); })) {
return request(data, cb); return cb('Request is malformed');
}
return ready(function() {
var data;
data = _.defaults({
'path': "/repos/" + owner + "/" + name,
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
}, },
allMilestones: function(_arg, cb) { allMilestones: function(_arg, cb) {
var data, name, owner; var name, owner;
owner = _arg.owner, name = _arg.name; owner = _arg.owner, name = _arg.name;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name + "/milestones", owner: owner,
'query': { name: name
'state': 'open', })) {
'sort': 'due_date', return cb('Request is malformed');
'direction': 'asc' }
}, return ready(function() {
'headers': headers(user.data.token) var data;
}, defaults.github); data = _.defaults({
return request(data, cb); 'path': "/repos/" + owner + "/" + name + "/milestones",
'query': {
'state': 'open',
'sort': 'due_date',
'direction': 'asc'
},
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
}, },
oneMilestone: function(_arg, cb) { oneMilestone: function(_arg, cb) {
var data, milestone, name, owner; var milestone, name, owner;
owner = _arg.owner, name = _arg.name, milestone = _arg.milestone; owner = _arg.owner, name = _arg.name, milestone = _arg.milestone;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name + "/milestones/" + milestone, owner: owner,
'query': { name: name,
'state': 'open', milestone: milestone
'sort': 'due_date', })) {
'direction': 'asc' return cb('Request is malformed');
}, }
'headers': headers(user.data.token) return ready(function() {
}, defaults.github); var data;
return request(data, cb); data = _.defaults({
'path': "/repos/" + owner + "/" + name + "/milestones/" + milestone,
'query': {
'state': 'open',
'sort': 'due_date',
'direction': 'asc'
},
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
}, },
allIssues: function(_arg, query, cb) { allIssues: function(_arg, query, cb) {
var data, milestone, name, owner; var milestone, name, owner;
owner = _arg.owner, name = _arg.name, milestone = _arg.milestone; owner = _arg.owner, name = _arg.name, milestone = _arg.milestone;
data = _.defaults({ if (!isValid({
'path': "/repos/" + owner + "/" + name + "/issues", owner: owner,
'query': _.extend(query, { name: name,
milestone: milestone, milestone: milestone
'per_page': '100' })) {
}), return cb('Request is malformed');
'headers': headers(user.data.token) }
}, defaults.github); return ready(function() {
return request(data, cb); var data;
data = _.defaults({
'path': "/repos/" + owner + "/" + name + "/issues",
'query': _.extend(query, {
milestone: milestone,
'per_page': '100'
}),
'headers': headers(user.data.accessToken)
}, defaults.github);
return request(data, cb);
});
} }
}; };
@ -436,16 +473,62 @@
headers = function(token) { headers = function(token) {
var h; var h;
h = _.extend({}, { h = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Accept': 'application/vnd.github.v3' 'Accept': 'application/vnd.github.v3'
}); };
if (token != null) { if (token != null) {
h.Authorization = "token " + token; h.Authorization = "token " + token;
} }
return h; return h;
}; };
isValid = function(obj) {
var key, rules, val;
rules = {
'owner': function(val) {
return val != null;
},
'name': function(val) {
return val != null;
},
'milestone': function(val) {
return _.isInt(val);
}
};
for (key in obj) {
val = obj[key];
if (key in rules && !rules[key](val)) {
return false;
}
}
return true;
};
isReady = user.data.ready;
stack = [];
ready = function(cb) {
if (isReady) {
return cb();
} else {
return stack.push(cb);
}
};
user.observe('ready', function(val) {
var _results;
isReady = val;
if (val) {
_results = [];
while (stack.length) {
_results.push(stack.shift()());
}
return _results;
}
});
error = function(err) { error = function(err) {
var message; var message;
switch (false) { switch (false) {
@ -710,7 +793,7 @@
// header.mustache // header.mustache
root.require.register('burnchart/src/templates/header.js', function(exports, require, module) { root.require.register('burnchart/src/templates/header.js', function(exports, require, module) {
module.exports = ["<div id=\"head\">"," {{#with user}}"," {{#loaded}}"," <div class=\"right\" intro=\"fade\">"," {{#displayName}}"," {{displayName}} logged in"," {{else}}"," <a class=\"github\" on-click=\"!login\"><Icons icon=\"github\"/> Sign In</a>"," {{/displayName}}"," </div>"," {{/loaded}}"," {{/with}}",""," <a id=\"icon\" href=\"#\">"," <Icons icon=\"{{icon}}\"/>"," </a>",""," <!--"," <div class=\"q\">"," <Icons icon=\"search\"/>"," <Icons icon=\"down-open\"/>"," <input type=\"text\" placeholder=\"Jump to...\">"," </div>"," -->",""," <ul>"," <li><a href=\"#new/project\" class=\"add\"><Icons icon=\"plus-circled\"/> Add a Project</a></li>"," <li><a href=\"#\" class=\"faq\">FAQ</a></li>"," <li><a href=\"#reset\">DB Reset</a></li>"," <li><a href=\"#notify\">Notify</a></li>"," </ul>","</div>"].join("\n"); module.exports = ["<div id=\"head\">"," {{#with user}}"," {{#ready}}"," <div class=\"right\" intro=\"fade\">"," {{#displayName}}"," {{displayName}} logged in"," {{else}}"," <a class=\"github\" on-click=\"!login\"><Icons icon=\"github\"/> Sign In</a>"," {{/displayName}}"," </div>"," {{/ready}}"," {{/with}}",""," <a id=\"icon\" href=\"#\">"," <Icons icon=\"{{icon}}\"/>"," </a>",""," <!--"," <div class=\"q\">"," <Icons icon=\"search\"/>"," <Icons icon=\"down-open\"/>"," <input type=\"text\" placeholder=\"Jump to...\">"," </div>"," -->",""," <ul>"," <li><a href=\"#new/project\" class=\"add\"><Icons icon=\"plus-circled\"/> Add a Project</a></li>"," <li><a href=\"#\" class=\"faq\">FAQ</a></li>"," <li><a href=\"#reset\">DB Reset</a></li>"," <li><a href=\"#notify\">Notify</a></li>"," </ul>","</div>"].join("\n");
}); });
// hero.mustache // hero.mustache
@ -859,6 +942,9 @@
}); });
return obj; return obj;
}); });
},
'isInt': function(val) {
return !isNaN(val) && parseInt(Number(val)) === val && !isNaN(parseInt(val, 10));
} }
}); });
@ -1242,6 +1328,7 @@
var done, fetchIssues, fetchMilestone, milestone, name, obj, owner, project, _ref, var done, fetchIssues, fetchMilestone, milestone, name, obj, owner, project, _ref,
_this = this; _this = this;
_ref = this.get('route'), owner = _ref[0], name = _ref[1], milestone = _ref[2]; _ref = this.get('route'), owner = _ref[0], name = _ref[1], milestone = _ref[2];
milestone = parseInt(milestone);
document.title = "" + owner + "/" + name + "/" + milestone; document.title = "" + owner + "/" + name + "/" + milestone;
project = projects.find({ project = projects.find({
owner: owner, owner: owner,
@ -1261,13 +1348,19 @@
} }
done = system.async(); done = system.async();
fetchMilestone = function(cb) { fetchMilestone = function(cb) {
return milestones.fetch(_.extend(project, { return milestones.fetch({
owner: owner,
name: name,
milestone: milestone milestone: milestone
}), cb); }, cb);
}; };
fetchIssues = function(milestone, cb) { fetchIssues = function(data, cb) {
return issues.fetchAll(project, function(err, obj) { return issues.fetchAll({
return cb(err, _.extend(milestone, { owner: owner,
name: name,
milestone: milestone
}, function(err, obj) {
return cb(err, _.extend(data, {
'issues': obj 'issues': obj
})); }));
}); });
@ -1282,7 +1375,11 @@
'ttl': null 'ttl': null
}); });
} }
projects.push('list', data); if (project.milestones == null) {
project.milestones = [];
}
project.milestones.push(data);
projects.update('list');
return _this.set({ return _this.set({
'milestone': data, 'milestone': data,
'ready': true 'ready': true

View File

@ -26,10 +26,10 @@ module.exports = new Model
@set 'client', client = new Firebase "https://#{config.data.firebase}.firebaseio.com" @set 'client', client = new Firebase "https://#{config.data.firebase}.firebaseio.com"
# Check if we have a user in session. # Check if we have a user in session.
@auth = new FirebaseSimpleLogin client, (err, obj) => @auth = new FirebaseSimpleLogin client, (err, obj) ->
user.set 'loaded', yes
throw err if err throw err if err
# Save user. # Save user.
user.set obj if obj user.set obj if obj
# Say we are done.
user.set 'ready', yes

View File

@ -19,42 +19,54 @@ module.exports =
# Get a repo. # Get a repo.
repo: ({ owner, name }, cb) -> repo: ({ owner, name }, cb) ->
data = _.defaults return cb 'Request is malformed' unless isValid { owner, name }
'path': "/repos/#{owner}/#{name}"
'headers': headers user.data.token
, defaults.github
request data, cb ready ->
data = _.defaults
'path': "/repos/#{owner}/#{name}"
'headers': headers user.data.accessToken
, defaults.github
request data, cb
# Get all open milestones. # Get all open milestones.
allMilestones: ({ owner, name }, cb) -> allMilestones: ({ owner, name }, cb) ->
data = _.defaults return cb 'Request is malformed' unless isValid { owner, name }
'path': "/repos/#{owner}/#{name}/milestones"
'query': { 'state': 'open', 'sort': 'due_date', 'direction': 'asc' }
'headers': headers user.data.token
, defaults.github
request data, cb ready ->
data = _.defaults
'path': "/repos/#{owner}/#{name}/milestones"
'query': { 'state': 'open', 'sort': 'due_date', 'direction': 'asc' }
'headers': headers user.data.accessToken
, defaults.github
request data, cb
# Get one open milestone. # Get one open milestone.
oneMilestone: ({ owner, name, milestone }, cb) -> oneMilestone: ({ owner, name, milestone }, cb) ->
data = _.defaults return cb 'Request is malformed' unless isValid { owner, name, milestone }
'path': "/repos/#{owner}/#{name}/milestones/#{milestone}"
'query': { 'state': 'open', 'sort': 'due_date', 'direction': 'asc' }
'headers': headers user.data.token
, defaults.github
request data, cb ready ->
data = _.defaults
'path': "/repos/#{owner}/#{name}/milestones/#{milestone}"
'query': { 'state': 'open', 'sort': 'due_date', 'direction': 'asc' }
'headers': headers user.data.accessToken
, defaults.github
request data, cb
# Get all issues for a state. # Get all issues for a state.
allIssues: ({ owner, name, milestone }, query, cb) -> allIssues: ({ owner, name, milestone }, query, cb) ->
data = _.defaults return cb 'Request is malformed' unless isValid { owner, name, milestone }
'path': "/repos/#{owner}/#{name}/issues"
'query': _.extend query, { milestone, 'per_page': '100' }
'headers': headers user.data.token
, defaults.github
request data, cb ready ->
data = _.defaults
'path': "/repos/#{owner}/#{name}/issues"
'query': _.extend query, { milestone, 'per_page': '100' }
'headers': headers user.data.accessToken
, defaults.github
request data, cb
# Make a request using SuperAgent. # Make a request using SuperAgent.
request = ({ protocol, host, path, query, headers }, cb) -> request = ({ protocol, host, path, query, headers }, cb) ->
@ -99,13 +111,37 @@ response = (err, data, cb) ->
# Give us headers. # Give us headers.
headers = (token) -> headers = (token) ->
# The defaults. # The defaults.
h = _.extend {}, h =
'Content-Type': 'application/json' 'Content-Type': 'application/json'
'Accept': 'application/vnd.github.v3' 'Accept': 'application/vnd.github.v3'
# Add token? # Add token?
h.Authorization = "token #{token}" if token? h.Authorization = "token #{token}" if token?
h h
isValid = (obj) ->
rules =
'owner': (val) -> val?
'name': (val) -> val?
'milestone': (val) -> _.isInt val
( return no for key, val of obj when key of rules and not rules[key](val) )
yes
# Switch when user is ready.
isReady = user.data.ready
# A stack of requests to execute once ready.
stack = []
ready = (cb) ->
if isReady then do cb else stack.push cb
# Observe user's readiness.
user.observe 'ready', (val) ->
isReady = val
# Clear the stack?
( do stack.shift() while stack.length ) if val
# Parse an error. # Parse an error.
error = (err) -> error = (err) ->
switch switch

View File

@ -1,6 +1,6 @@
<div id="head"> <div id="head">
{{#with user}} {{#with user}}
{{#loaded}} {{#ready}}
<div class="right" intro="fade"> <div class="right" intro="fade">
{{#displayName}} {{#displayName}}
{{displayName}} logged in {{displayName}} logged in
@ -8,7 +8,7 @@
<a class="github" on-click="!login"><Icons icon="github"/> Sign In</a> <a class="github" on-click="!login"><Icons icon="github"/> Sign In</a>
{{/displayName}} {{/displayName}}
</div> </div>
{{/loaded}} {{/ready}}
{{/with}} {{/with}}
<a id="icon" href="#"> <a id="icon" href="#">

View File

@ -5,4 +5,7 @@ _.mixin
obj = {} obj = {}
_.each keys, (key) -> _.each keys, (key) ->
obj[key] = item[key] obj[key] = item[key]
obj obj
'isInt': (val) ->
not isNaN(val) and parseInt(Number(val)) is val and not isNaN(parseInt(val, 10))

View File

@ -22,6 +22,8 @@ module.exports = Ractive.extend
onrender: -> onrender: ->
[ owner, name, milestone ] = @get 'route' [ owner, name, milestone ] = @get 'route'
milestone = parseInt milestone
document.title = "#{owner}/#{name}/#{milestone}" document.title = "#{owner}/#{name}/#{milestone}"
# Get the associated project. # Get the associated project.
@ -38,11 +40,11 @@ module.exports = Ractive.extend
done = do system.async done = do system.async
fetchMilestone = (cb) -> fetchMilestone = (cb) ->
milestones.fetch _.extend(project, { milestone }), cb milestones.fetch { owner, name, milestone }, cb
fetchIssues = (milestone, cb) -> fetchIssues = (data, cb) ->
issues.fetchAll project, (err, obj) -> issues.fetchAll { owner, name, milestone }, (err, obj) ->
cb err, _.extend milestone, { 'issues': obj } cb err, _.extend data, { 'issues': obj }
async.waterfall [ async.waterfall [
# Get the milestone. # Get the milestone.
@ -59,7 +61,9 @@ module.exports = Ractive.extend
} if err } if err
# Save the milestone. # Save the milestone.
projects.push 'list', data project.milestones ?= []
project.milestones.push data
projects.update 'list'
# Show the page. # Show the page.
@set @set