Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var Model; |
3 | ||
4 | 1 | Model = require('../utils/ractive/model.coffee'); |
5 | ||
6 | 1 | module.exports = new Model({ |
7 | 'name': 'models/config', | |
8 | "data": { | |
9 | "firebase": "burnchart", | |
10 | "provider": "github", | |
11 | "fields": { | |
12 | "milestone": ["closed_issues", "created_at", "description", "due_on", "number", "open_issues", "title", "updated_at"] | |
13 | }, | |
14 | "chart": { | |
15 | "off_days": [], | |
16 | "size_label": /^size (\d+)$/, | |
17 | "points": 'ONE_SIZE' | |
18 | }, | |
19 | "request": { | |
20 | "timeout": 5e3 | |
21 | } | |
22 | } | |
23 | }); | |
24 | ||
25 | }).call(this); | |
26 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var Model, config, lscache, semver, sortedIndex, stats, user, _, |
3 | __slice = [].slice; | |
4 | ||
5 | 1 | _ = require('lodash'); |
6 | ||
7 | 1 | lscache = require('lscache'); |
8 | ||
9 | 1 | sortedIndex = require('sortedindex-compare'); |
10 | ||
11 | 1 | semver = require('semver'); |
12 | ||
13 | 1 | Model = require('../utils/ractive/model.coffee'); |
14 | ||
15 | 1 | config = require('../models/config.coffee'); |
16 | ||
17 | 1 | stats = require('../modules/stats.coffee'); |
18 | ||
19 | 1 | user = require('./user.coffee'); |
20 | ||
21 | 1 | module.exports = new Model({ |
22 | 'name': 'models/projects', | |
23 | 'data': { | |
24 | 'sortBy': 'priority', | |
25 | 'sortFns': ['progress', 'priority', 'name'] | |
26 | }, | |
27 | comparator: function() { | |
28 | 14 | var deIdx, defaults, list, sortBy, _ref; |
29 | 14 | _ref = this.data, list = _ref.list, sortBy = _ref.sortBy; |
30 | 14 | deIdx = (function(_this) { |
31 | 14 | return function(fn) { |
32 | 14 | return function() { |
33 | 11 | var i, j, rest, _arg; |
34 | 11 | _arg = arguments[0], rest = 2 <= arguments.length ? __slice.call(arguments, 1) : []; |
35 | 11 | i = _arg[0], j = _arg[1]; |
36 | 11 | return fn.apply(_this, [[list[i], list[i].milestones[j]]].concat(rest)); |
37 | }; | |
38 | }; | |
39 | })(this); | |
40 | 14 | defaults = function(arr, hash) { |
41 | 7 | var i, item, k, keys, p, ref, v, _i, _len, _results; |
42 | 7 | _results = []; |
43 | 7 | for (_i = 0, _len = arr.length; _i < _len; _i++) { |
44 | 14 | item = arr[_i]; |
45 | 14 | _results.push((function() { |
46 | 14 | var _results1; |
47 | 14 | _results1 = []; |
48 | 14 | for (k in hash) { |
49 | 26 | v = hash[k]; |
50 | 26 | ref = item; |
51 | 26 | _results1.push((function() { |
52 | 26 | var _j, _len1, _ref1, _results2; |
53 | 26 | _ref1 = keys = k.split('.'); |
54 | 26 | _results2 = []; |
55 | 26 | for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) { |
56 | 66 | p = _ref1[i]; |
57 | 66 | if (i === keys.length - 1) { |
58 | 26 | _results2.push(ref[p] != null ? ref[p] : ref[p] = v); |
59 | } else { | |
60 | 40 | _results2.push(ref = ref[p] != null ? ref[p] : ref[p] = {}); |
61 | } | |
62 | } | |
63 | 26 | return _results2; |
64 | })()); | |
65 | } | |
66 | 14 | return _results1; |
67 | })()); | |
68 | } | |
69 | 7 | return _results; |
70 | }; | |
71 | 14 | switch (sortBy) { |
72 | case 'progress': | |
73 | 2 | return deIdx(function(_arg, _arg1) { |
74 | 1 | var aM, aP, bM, bP; |
75 | 1 | aP = _arg[0], aM = _arg[1]; |
76 | 1 | bP = _arg1[0], bM = _arg1[1]; |
77 | 1 | defaults([aM, bM], { |
78 | 'stats.progress.points': 0 | |
79 | }); | |
80 | 1 | return aM.stats.progress.points - bM.stats.progress.points; |
81 | }); | |
82 | case 'priority': | |
83 | 7 | return deIdx(function(_arg, _arg1) { |
84 | 6 | var $a, $b, aM, aP, bM, bP, _ref1; |
85 | 6 | aP = _arg[0], aM = _arg[1]; |
86 | 6 | bP = _arg1[0], bM = _arg1[1]; |
87 | 6 | defaults([aM, bM], { |
88 | 'stats.progress.time': 0, | |
89 | 'stats.days': 1e3 | |
90 | }); | |
91 | 6 | _ref1 = _.map([aM, bM], function(_arg2) { |
92 | 12 | var stats; |
93 | 12 | stats = _arg2.stats; |
94 | 12 | return (stats.progress.points - stats.progress.time) * stats.days; |
95 | }), $a = _ref1[0], $b = _ref1[1]; | |
96 | 6 | return $b - $a; |
97 | }); | |
98 | case 'name': | |
99 | 5 | return deIdx(function(_arg, _arg1) { |
100 | 4 | var aM, aP, bM, bP, name, owner; |
101 | 4 | aP = _arg[0], aM = _arg[1]; |
102 | 4 | bP = _arg1[0], bM = _arg1[1]; |
103 | 4 | if (owner = bP.owner.localeCompare(aP.owner)) { |
104 | 0 | return owner; |
105 | } | |
106 | 4 | if (name = bP.name.localeCompare(aP.name)) { |
107 | 0 | return name; |
108 | } | |
109 | 4 | if (semver.valid(bM.title) && semver.valid(aM.title)) { |
110 | 1 | return semver.gt(bM.title, aM.title); |
111 | } else { | |
112 | 3 | return bM.title.localeCompare(aM.title); |
113 | } | |
114 | }); | |
115 | default: | |
116 | 0 | return function() { |
117 | 0 | return 0; |
118 | }; | |
119 | } | |
120 | }, | |
121 | find: function(project) { | |
122 | 0 | return _.find(this.data.list, project); |
123 | }, | |
124 | exists: function() { | |
125 | 0 | return !!this.find.apply(this, arguments); |
126 | }, | |
127 | add: function(project) { | |
128 | 0 | if (!this.exists(project)) { |
129 | 0 | return this.push('list', project); |
130 | } | |
131 | }, | |
132 | findIndex: function(_arg) { | |
133 | 14 | var name, owner; |
134 | 14 | owner = _arg.owner, name = _arg.name; |
135 | 14 | return _.findIndex(this.data.list, { |
136 | owner: owner, | |
137 | name: name | |
138 | }); | |
139 | }, | |
140 | addMilestone: function(project, milestone) { | |
141 | 14 | var i, j; |
142 | 14 | _.extend(milestone, { |
143 | 'stats': stats(milestone) | |
144 | }); | |
145 | 14 | if ((i = this.findIndex(project)) < 0) { |
146 | 0 | throw 500; |
147 | } | |
148 | 14 | if (project.milestones != null) { |
149 | 8 | this.push("list." + i + ".milestones", milestone); |
150 | 8 | j = this.data.list[i].milestones.length - 1; |
151 | } else { | |
152 | 6 | this.set("list." + i + ".milestones", [milestone]); |
153 | 6 | j = 0; |
154 | } | |
155 | 14 | return this.sort([i, j], [project, milestone]); |
156 | }, | |
157 | saveError: function(project, err) { | |
158 | 0 | var idx; |
159 | 0 | if ((idx = this.findIndex(project)) > -1) { |
160 | 0 | if (project.errors != null) { |
161 | 0 | return this.push("list." + idx + ".errors", err); |
162 | } else { | |
163 | 0 | return this.set("list." + idx + ".errors", [err]); |
164 | } | |
165 | } else { | |
166 | 0 | throw 500; |
167 | } | |
168 | }, | |
169 | demo: function() { | |
170 | 0 | return this.set({ |
171 | 'list': [ | |
172 | { | |
173 | 'owner': 'mbostock', | |
174 | 'name': 'd3' | |
175 | }, { | |
176 | 'owner': 'medic', | |
177 | 'name': 'medic-webapp' | |
178 | }, { | |
179 | 'owner': 'ractivejs', | |
180 | 'name': 'ractive' | |
181 | }, { | |
182 | 'owner': 'radekstepan', | |
183 | 'name': 'disposable' | |
184 | }, { | |
185 | 'owner': 'rails', | |
186 | 'name': 'rails' | |
187 | }, { | |
188 | 'owner': 'rails', | |
189 | 'name': 'spring' | |
190 | } | |
191 | ], | |
192 | 'index': [] | |
193 | }); | |
194 | }, | |
195 | clear: function() { | |
196 | 6 | return this.set({ |
197 | 'list': [], | |
198 | 'index': [] | |
199 | }); | |
200 | }, | |
201 | sort: function(ref, data) { | |
202 | 17 | var i, idx, index, j, m, p, _i, _j, _len, _len1, _ref, _ref1; |
203 | 17 | index = this.data.index || []; |
204 | 17 | if (ref) { |
205 | 14 | idx = sortedIndex(index, data, this.comparator()); |
206 | 14 | index.splice(idx, 0, ref); |
207 | } else { | |
208 | 3 | _ref = this.data.list; |
209 | 3 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { |
210 | 0 | p = _ref[i]; |
211 | 0 | if (p.milestones == null) { |
212 | 0 | continue; |
213 | } | |
214 | 0 | _ref1 = p.milestones; |
215 | 0 | for (j = _j = 0, _len1 = _ref1.length; _j < _len1; j = ++_j) { |
216 | 0 | m = _ref1[j]; |
217 | 0 | idx = sortedIndex(index, [p, m], this.comparator()); |
218 | 0 | index.splice(idx, 0, [i, j]); |
219 | } | |
220 | } | |
221 | } | |
222 | 17 | return this.set('index', index); |
223 | }, | |
224 | onconstruct: function() { | |
225 | 1 | this.subscribe('!projects/add', this.add, this); |
226 | 1 | return this.subscribe('!projects/demo', this.demo, this); |
227 | }, | |
228 | onrender: function() { | |
229 | 1 | this.set('list', lscache.get('projects') || []); |
230 | 1 | this.observe('list', function(projects) { |
231 | 26 | return lscache.set('projects', _.pluckMany(projects, ['owner', 'name'])); |
232 | }, { | |
233 | 'init': false | |
234 | }); | |
235 | 1 | return this.observe('sortBy', function() { |
236 | 3 | this.set('index', null); |
237 | 3 | return this.sort(); |
238 | }, { | |
239 | 'init': false | |
240 | }); | |
241 | } | |
242 | }); | |
243 | ||
244 | }).call(this); | |
245 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var Model; |
3 | ||
4 | 1 | Model = require('../utils/ractive/model.coffee'); |
5 | ||
6 | 1 | module.exports = new Model({ |
7 | 'name': 'models/user', | |
8 | 'data': { | |
9 | 'uid': null | |
10 | } | |
11 | }); | |
12 | ||
13 | }).call(this); | |
14 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var config, d3, moment, _, |
3 | 0 | __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; |
4 | ||
5 | 1 | _ = require('lodash'); |
6 | ||
7 | 1 | d3 = require('d3'); |
8 | ||
9 | 1 | moment = require('moment'); |
10 | ||
11 | 1 | config = require('../../models/config.coffee'); |
12 | ||
13 | 1 | module.exports = { |
14 | actual: function(issues, created_at, total) { | |
15 | 1 | var head, max, min, range, rest; |
16 | 1 | head = [ |
17 | { | |
18 | 'date': moment(created_at, moment.ISO_8601).toJSON(), | |
19 | 'points': total | |
20 | } | |
21 | ]; | |
22 | 1 | min = +Infinity; |
23 | 1 | max = -Infinity; |
24 | 1 | rest = _.map(issues, function(issue) { |
25 | 3 | var closed_at, size; |
26 | 3 | size = issue.size, closed_at = issue.closed_at; |
27 | 3 | if (size < min) { |
28 | 3 | min = size; |
29 | } | |
30 | 3 | if (size > max) { |
31 | 1 | max = size; |
32 | } | |
33 | 3 | issue.date = moment(closed_at, moment.ISO_8601).toJSON(); |
34 | 3 | issue.points = total -= size; |
35 | 3 | return issue; |
36 | }); | |
37 | 1 | range = d3.scale.linear().domain([min, max]).range([5, 8]); |
38 | 1 | rest = _.map(rest, function(issue) { |
39 | 3 | issue.radius = range(issue.size); |
40 | 3 | return issue; |
41 | }); | |
42 | 1 | return [].concat(head, rest); |
43 | }, | |
44 | ideal: function(a, b, total) { | |
45 | 1 | var days, length, now, once, velocity, _ref; |
46 | 1 | if (b < a) { |
47 | 0 | _ref = [a, b], b = _ref[0], a = _ref[1]; |
48 | } | |
49 | 1 | a = moment(a, moment.ISO_8601); |
50 | 1 | b = b != null ? moment(b, moment.ISO_8601) : moment.utc(); |
51 | 1 | days = []; |
52 | 1 | length = 0; |
53 | 1 | (once = function(inc) { |
54 | 3 | var day, day_of; |
55 | 3 | day = a.add(1, 'days'); |
56 | 3 | if (!(day_of = day.weekday())) { |
57 | 1 | day_of = 7; |
58 | } | |
59 | 3 | if (__indexOf.call(config.data.chart.off_days, day_of) >= 0) { |
60 | 0 | days.push({ |
61 | 'date': day.toJSON(), | |
62 | 'off_day': true | |
63 | }); | |
64 | } else { | |
65 | 3 | length += 1; |
66 | 3 | days.push({ |
67 | 'date': day.toJSON() | |
68 | }); | |
69 | } | |
70 | 3 | if (!(day > b)) { |
71 | 2 | return once(inc + 1); |
72 | } | |
73 | })(0); | |
74 | 1 | velocity = total / (length - 1); |
75 | 1 | days = _.map(days, function(day, i) { |
76 | 3 | day.points = total; |
77 | 3 | if (days[i] && !days[i].off_day) { |
78 | 3 | total -= velocity; |
79 | } | |
80 | 3 | return day; |
81 | }); | |
82 | 1 | if ((now = moment.utc()) > b) { |
83 | 1 | days.push({ |
84 | 'date': now.toJSON(), | |
85 | 'points': 0 | |
86 | }); | |
87 | } | |
88 | 1 | return days; |
89 | }, | |
90 | trend: function(actual, created_at, due_on) { | |
91 | 1 | var a, b, b1, c1, e, first, fn, intercept, l, last, now, slope, start, values; |
92 | 1 | if (!actual.length) { |
93 | 0 | return []; |
94 | } | |
95 | 1 | first = actual[0], last = actual[actual.length - 1]; |
96 | 1 | start = moment(first.date, moment.ISO_8601); |
97 | 1 | values = _.map(actual, function(_arg) { |
98 | 3 | var date, points; |
99 | 3 | date = _arg.date, points = _arg.points; |
100 | 3 | return [moment(date, moment.ISO_8601).diff(start), points]; |
101 | }); | |
102 | 1 | now = moment.utc(); |
103 | 1 | values.push([now.diff(start), last.points]); |
104 | 1 | b1 = 0; |
105 | 1 | e = 0; |
106 | 1 | c1 = 0; |
107 | 1 | a = (l = values.length) * _.reduce(values, function(sum, _arg) { |
108 | 4 | var a, b; |
109 | 4 | a = _arg[0], b = _arg[1]; |
110 | 4 | b1 += a; |
111 | 4 | e += b; |
112 | 4 | c1 += Math.pow(a, 2); |
113 | 4 | return sum + (a * b); |
114 | }, 0); | |
115 | 1 | slope = (a - (b1 * e)) / ((l * c1) - (Math.pow(b1, 2))); |
116 | 1 | intercept = (e - (slope * b1)) / l; |
117 | 1 | fn = function(x) { |
118 | 2 | return slope * x + intercept; |
119 | }; | |
120 | 1 | created_at = moment(created_at, moment.ISO_8601); |
121 | 1 | if (due_on) { |
122 | 1 | due_on = moment(due_on, moment.ISO_8601); |
123 | 1 | if (now > due_on) { |
124 | 1 | due_on = now; |
125 | } | |
126 | } else { | |
127 | 0 | due_on = now; |
128 | } | |
129 | 1 | a = created_at.diff(start); |
130 | 1 | b = due_on.diff(start); |
131 | 1 | return [ |
132 | { | |
133 | 'date': created_at.toJSON(), | |
134 | 'points': fn(a) | |
135 | }, { | |
136 | 'date': due_on.toJSON(), | |
137 | 'points': fn(b) | |
138 | } | |
139 | ]; | |
140 | } | |
141 | }; | |
142 | ||
143 | }).call(this); | |
144 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var async, calcSize, config, oneStatus, request, _; |
3 | ||
4 | 1 | _ = require('lodash'); |
5 | ||
6 | 1 | async = require('async'); |
7 | ||
8 | 1 | config = require('../../models/config.coffee'); |
9 | ||
10 | 1 | request = require('./request.coffee'); |
11 | ||
12 | 1 | module.exports = { |
13 | fetchAll: function(repo, cb) { | |
14 | 14 | return async.parallel([_.partial(oneStatus, repo, 'open'), _.partial(oneStatus, repo, 'closed')], function(err, _arg) { |
15 | 14 | var closed, open; |
16 | 14 | open = _arg[0], closed = _arg[1]; |
17 | 14 | if (err == null) { |
18 | 13 | err = null; |
19 | } | |
20 | 14 | return cb(err, { |
21 | open: open, | |
22 | closed: closed | |
23 | }); | |
24 | }); | |
25 | } | |
26 | }; | |
27 | ||
28 | 1 | calcSize = function(list) { |
29 | 26 | var issue, size, _i, _len; |
30 | 26 | switch (config.data.chart.points) { |
31 | case 'ONE_SIZE': | |
32 | 16 | size = list.length; |
33 | 16 | for (_i = 0, _len = list.length; _i < _len; _i++) { |
34 | 1006 | issue = list[_i]; |
35 | 1006 | issue.size = 1; |
36 | } | |
37 | 16 | break; |
38 | case 'LABELS': | |
39 | 10 | size = 0; |
40 | 10 | list = _.filter(list, function(issue) { |
41 | 16 | var labels; |
42 | 16 | if (!(labels = issue.labels)) { |
43 | 2 | return false; |
44 | } | |
45 | 14 | issue.size = _.reduce(labels, function(sum, label) { |
46 | 16 | var matches; |
47 | 16 | if (!(matches = label.name.match(config.data.chart.size_label))) { |
48 | 6 | return sum; |
49 | } | |
50 | 10 | return sum += parseInt(matches[1]); |
51 | }, 0); | |
52 | 14 | size += issue.size; |
53 | 14 | return !!issue.size; |
54 | }); | |
55 | 10 | break; |
56 | default: | |
57 | 0 | throw 500; |
58 | } | |
59 | 26 | return { |
60 | list: list, | |
61 | size: size | |
62 | }; | |
63 | }; | |
64 | ||
65 | 1 | oneStatus = function(repo, state, cb) { |
66 | 28 | var done, fetchPage, results; |
67 | 28 | results = []; |
68 | 28 | done = function(err) { |
69 | 28 | if (err) { |
70 | 2 | return cb(err); |
71 | } | |
72 | 26 | return cb(null, calcSize(_.sortBy(results, 'closed_at'))); |
73 | }; | |
74 | 28 | return (fetchPage = function(page) { |
75 | 36 | return request.allIssues(repo, { |
76 | state: state, | |
77 | page: page | |
78 | }, function(err, data) { | |
79 | 36 | if (err) { |
80 | 2 | return done(err); |
81 | } | |
82 | 34 | if (!data.length) { |
83 | 6 | return done(null, results); |
84 | } | |
85 | 28 | results = results.concat(data); |
86 | 28 | if (data.length < 100) { |
87 | 20 | return done(null, results); |
88 | } | |
89 | 8 | return fetchPage(page + 1); |
90 | }); | |
91 | })(1); | |
92 | }; | |
93 | ||
94 | }).call(this); | |
95 |
Line | Hits | Source |
---|---|---|
1 | 2 | (function() { |
2 | 2 | var config, defaults, error, headers, isReady, isValid, mediator, ready, request, response, stack, superagent, user, _; |
3 | ||
4 | 2 | _ = require('lodash'); |
5 | ||
6 | 2 | superagent = require('superagent'); |
7 | ||
8 | 2 | require('../../utils/mixins.coffee'); |
9 | ||
10 | 2 | config = require('../../models/config.coffee'); |
11 | ||
12 | 2 | user = require('../../models/user.coffee'); |
13 | ||
14 | 2 | mediator = require('../mediator.coffee'); |
15 | ||
16 | 2 | superagent.parse = { |
17 | 'application/json': function(res) { | |
18 | 0 | var e; |
19 | 0 | try { |
20 | 0 | return JSON.parse(res); |
21 | } catch (_error) { | |
22 | 0 | e = _error; |
23 | 0 | return {}; |
24 | } | |
25 | } | |
26 | }; | |
27 | ||
28 | 2 | defaults = { |
29 | 'github': { | |
30 | 'host': 'api.github.com', | |
31 | 'protocol': 'https' | |
32 | } | |
33 | }; | |
34 | ||
35 | 2 | module.exports = { |
36 | repo: function(_arg, cb) { | |
37 | 1 | var name, owner; |
38 | 1 | owner = _arg.owner, name = _arg.name; |
39 | 1 | if (!isValid({ |
40 | owner: owner, | |
41 | name: name | |
42 | })) { | |
43 | 0 | return cb('Request is malformed'); |
44 | } | |
45 | 1 | return ready(function() { |
46 | 1 | var data, _ref; |
47 | 1 | data = _.defaults({ |
48 | 'path': "/repos/" + owner + "/" + name, | |
49 | 'headers': headers((_ref = user.data.github) != null ? _ref.accessToken : void 0) | |
50 | }, defaults.github); | |
51 | 1 | return request(data, cb); |
52 | }); | |
53 | }, | |
54 | allMilestones: function(_arg, cb) { | |
55 | 1 | var name, owner; |
56 | 1 | owner = _arg.owner, name = _arg.name; |
57 | 1 | if (!isValid({ |
58 | owner: owner, | |
59 | name: name | |
60 | })) { | |
61 | 0 | return cb('Request is malformed'); |
62 | } | |
63 | 1 | return ready(function() { |
64 | 1 | var data, _ref; |
65 | 1 | data = _.defaults({ |
66 | 'path': "/repos/" + owner + "/" + name + "/milestones", | |
67 | 'query': { | |
68 | 'state': 'open', | |
69 | 'sort': 'due_date', | |
70 | 'direction': 'asc' | |
71 | }, | |
72 | 'headers': headers((_ref = user.data.github) != null ? _ref.accessToken : void 0) | |
73 | }, defaults.github); | |
74 | 1 | return request(data, cb); |
75 | }); | |
76 | }, | |
77 | oneMilestone: function(_arg, cb) { | |
78 | 4 | var milestone, name, owner; |
79 | 4 | owner = _arg.owner, name = _arg.name, milestone = _arg.milestone; |
80 | 4 | if (!isValid({ |
81 | owner: owner, | |
82 | name: name, | |
83 | milestone: milestone | |
84 | })) { | |
85 | 0 | return cb('Request is malformed'); |
86 | } | |
87 | 4 | return ready(function() { |
88 | 4 | var data, _ref; |
89 | 4 | data = _.defaults({ |
90 | 'path': "/repos/" + owner + "/" + name + "/milestones/" + milestone, | |
91 | 'query': { | |
92 | 'state': 'open', | |
93 | 'sort': 'due_date', | |
94 | 'direction': 'asc' | |
95 | }, | |
96 | 'headers': headers((_ref = user.data.github) != null ? _ref.accessToken : void 0) | |
97 | }, defaults.github); | |
98 | 4 | return request(data, cb); |
99 | }); | |
100 | }, | |
101 | allIssues: function(_arg, query, cb) { | |
102 | 2 | var milestone, name, owner; |
103 | 2 | owner = _arg.owner, name = _arg.name, milestone = _arg.milestone; |
104 | 2 | if (!isValid({ |
105 | owner: owner, | |
106 | name: name, | |
107 | milestone: milestone | |
108 | })) { | |
109 | 0 | return cb('Request is malformed'); |
110 | } | |
111 | 2 | return ready(function() { |
112 | 2 | var data, _ref; |
113 | 2 | data = _.defaults({ |
114 | 'path': "/repos/" + owner + "/" + name + "/issues", | |
115 | 'query': _.extend(query, { | |
116 | milestone: milestone, | |
117 | 'per_page': '100' | |
118 | }), | |
119 | 'headers': headers((_ref = user.data.github) != null ? _ref.accessToken : void 0) | |
120 | }, defaults.github); | |
121 | 2 | return request(data, cb); |
122 | }); | |
123 | } | |
124 | }; | |
125 | ||
126 | 2 | request = function(_arg, cb) { |
127 | 8 | var exited, headers, host, k, path, protocol, q, query, req, timeout, v; |
128 | 8 | protocol = _arg.protocol, host = _arg.host, path = _arg.path, query = _arg.query, headers = _arg.headers; |
129 | 8 | exited = false; |
130 | 8 | q = query ? '?' + ((function() { |
131 | 7 | var _results; |
132 | 7 | _results = []; |
133 | 7 | for (k in query) { |
134 | 19 | v = query[k]; |
135 | 19 | _results.push("" + k + "=" + v); |
136 | } | |
137 | 7 | return _results; |
138 | })()).join('&') : ''; | |
139 | 8 | req = superagent.get("" + protocol + "://" + host + path + q); |
140 | 8 | for (k in headers) { |
141 | 17 | v = headers[k]; |
142 | 17 | req.set(k, v); |
143 | } | |
144 | 8 | timeout = setTimeout(function() { |
145 | 2 | exited = true; |
146 | 2 | return cb('Request has timed out'); |
147 | }, config.data.request.timeout); | |
148 | 8 | return req.end(function(err, data) { |
149 | 7 | if (exited) { |
150 | 1 | return; |
151 | } | |
152 | 6 | exited = true; |
153 | 6 | clearTimeout(timeout); |
154 | 6 | return response(err, data, cb); |
155 | }); | |
156 | }; | |
157 | ||
158 | 2 | response = function(err, data, cb) { |
159 | 6 | if (err) { |
160 | 0 | return cb(error(err)); |
161 | } | |
162 | 6 | if (data.statusType !== 2) { |
163 | 3 | return cb(error(data.body)); |
164 | } | |
165 | 3 | return cb(null, data.body); |
166 | }; | |
167 | ||
168 | 2 | headers = function(token) { |
169 | 8 | var h; |
170 | 8 | h = { |
171 | 'Content-Type': 'application/json', | |
172 | 'Accept': 'application/vnd.github.v3' | |
173 | }; | |
174 | 8 | if (token != null) { |
175 | 1 | h.Authorization = "token " + token; |
176 | } | |
177 | 8 | return h; |
178 | }; | |
179 | ||
180 | 2 | isValid = function(obj) { |
181 | 8 | var key, rules, val; |
182 | 8 | rules = { |
183 | 'owner': function(val) { | |
184 | 8 | return val != null; |
185 | }, | |
186 | 'name': function(val) { | |
187 | 8 | return val != null; |
188 | }, | |
189 | 'milestone': function(val) { | |
190 | 6 | return _.isInt(val); |
191 | } | |
192 | }; | |
193 | 8 | for (key in obj) { |
194 | 22 | val = obj[key]; |
195 | 22 | if (key in rules && !rules[key](val)) { |
196 | 0 | return false; |
197 | } | |
198 | } | |
199 | 8 | return true; |
200 | }; | |
201 | ||
202 | 2 | isReady = user.data.ready; |
203 | ||
204 | 2 | stack = []; |
205 | ||
206 | 2 | ready = function(cb) { |
207 | 8 | if (isReady) { |
208 | 8 | return cb(); |
209 | } else { | |
210 | 0 | return stack.push(cb); |
211 | } | |
212 | }; | |
213 | ||
214 | 2 | user.observe('ready', function(val) { |
215 | 4 | var _results; |
216 | 4 | isReady = val; |
217 | 4 | if (val) { |
218 | 2 | _results = []; |
219 | 2 | while (stack.length) { |
220 | 0 | _results.push(stack.shift()()); |
221 | } | |
222 | 2 | return _results; |
223 | } | |
224 | }); | |
225 | ||
226 | 2 | error = function(err) { |
227 | 3 | var text, type; |
228 | 3 | switch (false) { |
229 | case !_.isString(err): | |
230 | 0 | text = err; |
231 | 0 | break; |
232 | case !_.isArray(err): | |
233 | 0 | text = err[1]; |
234 | 0 | break; |
235 | case !(_.isObject(err) && _.isString(err.message)): | |
236 | 2 | text = err.message; |
237 | } | |
238 | 3 | if (!text) { |
239 | 1 | try { |
240 | 1 | text = JSON.stringify(err); |
241 | } catch (_error) { | |
242 | 0 | text = err.toString(); |
243 | } | |
244 | } | |
245 | 3 | if (/API rate limit exceeded/.test(text)) { |
246 | 1 | type = 'warn'; |
247 | 1 | mediator.fire('!app/notify', { |
248 | type: type, | |
249 | text: text | |
250 | }); | |
251 | } | |
252 | 3 | return text; |
253 | }; | |
254 | ||
255 | }).call(this); | |
256 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var Mediator, Ractive; |
3 | ||
4 | 1 | Ractive = require('ractive'); |
5 | ||
6 | 1 | Mediator = Ractive.extend({}); |
7 | ||
8 | 1 | module.exports = new Mediator(); |
9 | ||
10 | }).call(this); | |
11 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var moment, progress; |
3 | ||
4 | 1 | moment = require('moment'); |
5 | ||
6 | 1 | progress = function(a, b) { |
7 | 8 | if (a + b === 0) { |
8 | 0 | return 0; |
9 | } else { | |
10 | 8 | return 100 * (a / (b + a)); |
11 | } | |
12 | }; | |
13 | ||
14 | 1 | module.exports = function(milestone) { |
15 | 20 | var a, b, c, days, isDone, isEmpty, isOnTime, isOverdue, points, time; |
16 | 20 | if (milestone.stats != null) { |
17 | 14 | return milestone.stats; |
18 | } | |
19 | 6 | isDone = false; |
20 | 6 | isOnTime = true; |
21 | 6 | isOverdue = false; |
22 | 6 | isEmpty = true; |
23 | 6 | points = 0; |
24 | 6 | a = milestone.issues.closed.size; |
25 | 6 | b = milestone.issues.open.size; |
26 | 6 | if (a + b > 0) { |
27 | 4 | isEmpty = false; |
28 | 4 | points = progress(a, b); |
29 | 4 | if (points === 100) { |
30 | 2 | isDone = true; |
31 | } | |
32 | } | |
33 | 6 | if (milestone.due_on == null) { |
34 | 2 | return { |
35 | isOverdue: isOverdue, | |
36 | isOnTime: isOnTime, | |
37 | isDone: isDone, | |
38 | isEmpty: isEmpty, | |
39 | 'progress': { | |
40 | points: points | |
41 | } | |
42 | }; | |
43 | } | |
44 | 4 | a = moment(milestone.created_at, moment.ISO_8601); |
45 | 4 | b = moment.utc(); |
46 | 4 | c = moment(milestone.due_on, moment.ISO_8601); |
47 | 4 | if (b.isAfter(c) && !isDone) { |
48 | 2 | isOverdue = true; |
49 | } | |
50 | 4 | time = progress(b.diff(a), c.diff(b)); |
51 | 4 | days = (b.diff(a, 'days')) / 100; |
52 | 4 | isOnTime = points > time; |
53 | 4 | if (isDone) { |
54 | 1 | isOnTime = true; |
55 | } | |
56 | 4 | return { |
57 | isDone: isDone, | |
58 | days: days, | |
59 | isOnTime: isOnTime, | |
60 | isOverdue: isOverdue, | |
61 | 'progress': { | |
62 | points: points, | |
63 | time: time | |
64 | } | |
65 | }; | |
66 | }; | |
67 | ||
68 | }).call(this); | |
69 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var _; |
3 | ||
4 | 1 | _ = require('lodash'); |
5 | ||
6 | 1 | _.mixin({ |
7 | 'pluckMany': function(source, keys) { | |
8 | 26 | if (!_.isArray(keys)) { |
9 | 0 | throw '`keys` needs to be an Array'; |
10 | } | |
11 | 26 | return _.map(source, function(item) { |
12 | 20 | var obj; |
13 | 20 | obj = {}; |
14 | 20 | _.each(keys, function(key) { |
15 | 40 | return obj[key] = item[key]; |
16 | }); | |
17 | 20 | return obj; |
18 | }); | |
19 | }, | |
20 | 'isInt': function(val) { | |
21 | 6 | return !isNaN(val) && parseInt(Number(val)) === val && !isNaN(parseInt(val, 10)); |
22 | } | |
23 | }); | |
24 | ||
25 | }).call(this); | |
26 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var Ractive, mediator, _; |
3 | ||
4 | 1 | _ = require('lodash'); |
5 | ||
6 | 1 | Ractive = require('ractive'); |
7 | ||
8 | 1 | mediator = require('../../modules/mediator.coffee'); |
9 | ||
10 | 1 | module.exports = Ractive.extend({ |
11 | subscribe: function(name, cb, ctx) { | |
12 | 2 | if (ctx == null) { |
13 | 0 | ctx = this; |
14 | } | |
15 | 2 | if (!_.isArray(this._subs)) { |
16 | 1 | this._subs = []; |
17 | } | |
18 | 2 | if (_.isFunction(cb)) { |
19 | 2 | return this._subs.push(mediator.on(name, _.bind(cb, ctx))); |
20 | } else { | |
21 | 0 | return console.log("Warning: `cb` is not a function"); |
22 | } | |
23 | }, | |
24 | publish: function() { | |
25 | 0 | return mediator.fire.apply(mediator, arguments); |
26 | }, | |
27 | onteardown: function() { | |
28 | 0 | var sub, _i, _len, _ref, _results; |
29 | 0 | if (_.isArray(this._subs)) { |
30 | 0 | _ref = this._subs; |
31 | 0 | _results = []; |
32 | 0 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
33 | 0 | sub = _ref[_i]; |
34 | 0 | if (_.isFunction(sub.cancel)) { |
35 | 0 | _results.push(sub.cancel()); |
36 | } else { | |
37 | 0 | _results.push(console.log("Warning: `sub.cancel` is not a function")); |
38 | } | |
39 | } | |
40 | 0 | return _results; |
41 | } | |
42 | } | |
43 | }); | |
44 | ||
45 | }).call(this); | |
46 |
Line | Hits | Source |
---|---|---|
1 | 1 | (function() { |
2 | 1 | var Eventful; |
3 | ||
4 | 1 | Eventful = require('./eventful.coffee'); |
5 | ||
6 | 1 | module.exports = function(opts) { |
7 | 3 | var Model, model; |
8 | 3 | Model = Eventful.extend(opts); |
9 | 3 | model = new Model(); |
10 | 3 | model.render(); |
11 | 3 | return model; |
12 | }; | |
13 | ||
14 | }).call(this); | |
15 |