using JSON dates internally and moment for parsing
This commit is contained in:
parent
f2cd345bcf
commit
9d247206d3
|
@ -4,7 +4,7 @@
|
|||
|
||||
GitHub Burndown Chart as a service. Answers the question "are my projects on track"?
|
||||
|
||||
[![Build Status](http://img.shields.io/codeship/44524.svg?style=flat)](<URL_HERE>)
|
||||
![Build Status](http://img.shields.io/codeship/31951cd0-42c7-0132-d601-5ea438edf284.svg?style=flat)
|
||||
[![Coverage](http://img.shields.io/coveralls/radekstepan/burnchart/master.svg?style=flat)](<https://coveralls.io/r/radekstepan/burnchart>)
|
||||
[![Dependencies](http://img.shields.io/david/radekstepan/burnchart.svg?style=flat)](https://david-dm.org/radekstepan/burnchart)
|
||||
[![License](http://img.shields.io/badge/license-AGPL--3.0-red.svg?style=flat)](LICENSE)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,7 @@
|
|||
- [ ] 4 until GH fix milestone start date then provide an option to specify it; for example a text like this: `starts: 09-10-2014` in the description which we provide regex for in the config
|
||||
- [ ] 5 be able to config options through ui that currently have to be hardcoded in the config
|
||||
- [ ] 5 be able to delete added projects; on the project page listing all milestone, enable the cog at the bottom of the table, clicking it slides a link with a dustbin next to it which deletes the project
|
||||
- [ ] 3 dates not parsing well with timezones, see ideal lines test file
|
||||
- [ ] 3 check that we are using moment and toJSON all the way until chart view; tests checking res from github in milestones and issues
|
||||
|
||||
###Normal
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
|||
- [ ] 3 In add a project form autocomplete on my username, orgs I am member of and repos I have access to, use code from [elastic-med](https://github.com/intermine/intermine-apps-c/blob/master/elastic-med/src/components/search.coffee#L24-L46) to show the first option with Tab doing the autocomplete
|
||||
- [ ] 4 show number of tasks, points, days left, progress bar in the header of a chart page, just like in Assembly
|
||||
- [ ] 3 be able to specify milestone by name (will nicely show in title), so when we type in `owner/name/name` it should resolve the number
|
||||
- [ ] 3 trendline is sometimes cutting into axes, but maybe it was just an interpolation
|
||||
- [ ] 3 trendline is sometimes cutting into axes, see `rails/rails/36`
|
||||
- [ ] 3 deal with Firebase timing out, are we still logged-in? Show a warning page telling the people to refresh the browser (adding a button to do the same)
|
||||
- [ ] 3 use issue title to determine size
|
||||
- [ ] 3 the app bundle (albeit uncompressed) clocks in at 1.5MB, reduce the size (`d3` is huge (use [grunt-smash](https://github.com/cvisco/grunt-smash), [docs here](https://github.com/mbostock/smash/wiki)))
|
||||
|
|
|
@ -25,8 +25,6 @@ module.exports = new Model
|
|||
"chart":
|
||||
# Days we are not working. Mon = 1
|
||||
"off_days": [ ]
|
||||
# How do we parse GitHub dates?
|
||||
"datetime": /^(\d{4}-\d{2}-\d{2})T(.*)/
|
||||
# How does a size label look like?
|
||||
"size_label": /^size (\d+)$/
|
||||
# Process all issues as one size (ONE_SIZE) or use labels (LABELS).
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
_ = require 'lodash'
|
||||
d3 = require 'd3'
|
||||
_ = require 'lodash'
|
||||
d3 = require 'd3'
|
||||
moment = require 'moment'
|
||||
|
||||
config = require '../../models/config.coffee'
|
||||
|
||||
|
@ -11,7 +12,7 @@ module.exports =
|
|||
# `total`: total number of points (open & closed issues)
|
||||
actual: (issues, created_at, total) ->
|
||||
head = [ {
|
||||
'date': new Date created_at
|
||||
'date': do moment(created_at).toJSON
|
||||
'points': total
|
||||
} ]
|
||||
|
||||
|
@ -25,7 +26,7 @@ module.exports =
|
|||
max = size if size > max
|
||||
|
||||
# Dropping points remaining.
|
||||
issue.date = new Date closed_at
|
||||
issue.date = do moment(closed_at).toJSON
|
||||
issue.points = total -= size
|
||||
issue
|
||||
|
||||
|
@ -43,30 +44,29 @@ module.exports =
|
|||
# `b`: milestone end date
|
||||
# `total`: total number of points (open & closed issues)
|
||||
ideal: (a, b, total) ->
|
||||
# Swap?
|
||||
# Swap if end is before the start...
|
||||
[ b, a ] = [ a, b ] if b < a
|
||||
|
||||
# We start here adding days to `d`.
|
||||
[ y, m, d ] = _.map a.match(config.data.chart.datetime)[1].split('-'), (v) -> parseInt v
|
||||
# We want to end here.
|
||||
cutoff = new Date(b)
|
||||
a = moment a
|
||||
# Do we have a due date?
|
||||
b = if b? then moment b else do moment.utc
|
||||
|
||||
# Go through the beginning to the end skipping off days.
|
||||
days = [] ; length = 0
|
||||
do once = (inc = 0) ->
|
||||
# A new day.
|
||||
day = new Date y, m - 1, d + inc
|
||||
# A new day. TODO: deal with hours and minutes!
|
||||
day = a.add 1, 'days'
|
||||
|
||||
# Does this day count?
|
||||
day_of = 7 if !day_of = day.getDay()
|
||||
day_of = 7 unless day_of = do day.weekday
|
||||
if day_of in config.data.chart.off_days
|
||||
days.push { date: day, off_day: yes }
|
||||
days.push { 'date': do day.toJSON, 'off_day': yes }
|
||||
else
|
||||
length += 1
|
||||
days.push { date: day }
|
||||
days.push { 'date': do day.toJSON }
|
||||
|
||||
# Go again?
|
||||
once(inc + 1) unless day > cutoff
|
||||
once(inc + 1) unless day > b
|
||||
|
||||
# Map points on the array of days now.
|
||||
velocity = total / (length - 1)
|
||||
|
@ -77,7 +77,7 @@ module.exports =
|
|||
day
|
||||
|
||||
# Do we need to make a link to right now?
|
||||
days.push { date: now, points: 0 } if (now = new Date) > cutoff
|
||||
days.push { 'date': do now.toJSON, 'points': 0 } if (now = do moment.utc) > b
|
||||
|
||||
days
|
||||
|
||||
|
@ -85,15 +85,17 @@ module.exports =
|
|||
trend: (actual, created_at, due_on) ->
|
||||
return [] unless actual.length
|
||||
|
||||
start = +actual[0].date
|
||||
[ first, ..., last ] = actual
|
||||
|
||||
start = moment first.date
|
||||
|
||||
# Values is a list of time from the start and points remaining.
|
||||
values = _.map actual, ({ date, points }) ->
|
||||
[ +date - start, points ]
|
||||
[ moment(date).diff(start), points ]
|
||||
|
||||
# Now is an actual point too.
|
||||
last = actual[actual.length - 1]
|
||||
values.push [ + new Date - start, last.points ]
|
||||
now = do moment.utc
|
||||
values.push [ now.diff(start), last.points ]
|
||||
|
||||
# http://classroom.synonym.com/calculate-trendline-2709.html
|
||||
b1 = 0 ; e = 0 ; c1 = 0
|
||||
|
@ -105,30 +107,30 @@ module.exports =
|
|||
|
||||
slope = (a - (b1 * e)) / ((l * c1) - (Math.pow(b1, 2)))
|
||||
intercept = (e - (slope * b1)) / l
|
||||
|
||||
fn = (x) -> slope * x + intercept
|
||||
|
||||
# Milestone always has a creation date.
|
||||
created_at = new Date created_at
|
||||
created_at = moment created_at
|
||||
|
||||
now = new Date
|
||||
# Due date specified.
|
||||
if due_on
|
||||
due_on = new Date due_on
|
||||
due_on = moment due_on
|
||||
# In the past?
|
||||
due_on = now if now > due_on
|
||||
# No due date
|
||||
else
|
||||
due_on = now
|
||||
|
||||
a = created_at - start
|
||||
b = due_on - start
|
||||
a = created_at.diff start
|
||||
b = due_on.diff start
|
||||
|
||||
[
|
||||
{
|
||||
'date': created_at
|
||||
'points': fn(a)
|
||||
'date': do created_at.toJSON
|
||||
'points': fn a
|
||||
}, {
|
||||
'date': due_on
|
||||
'points': fn(b)
|
||||
'date': do due_on.toJSON
|
||||
'points': fn b
|
||||
}
|
||||
]
|
|
@ -48,12 +48,16 @@ module.exports = Ractive.extend
|
|||
# Line generator.
|
||||
line = d3.svg.line()
|
||||
.interpolate("linear")
|
||||
.x( (d) -> x(d.date) )
|
||||
.x( (d) -> x(new Date(d.date)) ) # convert to Date only now
|
||||
.y( (d) -> y(d.points) )
|
||||
|
||||
# Get the minimum and maximum date, and initial points.
|
||||
x.domain([ ideal[0].date, ideal[ideal.length - 1].date ])
|
||||
y.domain([ 0, ideal[0].points ]).nice()
|
||||
[ first, ..., last ] = ideal
|
||||
x.domain [
|
||||
new Date(first.date)
|
||||
new Date(last.date)
|
||||
]
|
||||
y.domain([ 0, first.points ]).nice()
|
||||
|
||||
# Add an SVG element with the desired dimensions and margin.
|
||||
svg = d3.select(this.el.querySelector('#chart')).append("svg")
|
||||
|
@ -93,9 +97,9 @@ module.exports = Ractive.extend
|
|||
# Add a line showing where we are now.
|
||||
svg.append("svg:line")
|
||||
.attr("class", "today")
|
||||
.attr("x1", x(new Date()))
|
||||
.attr("x1", x(new Date))
|
||||
.attr("y1", 0)
|
||||
.attr("x2", x(new Date()))
|
||||
.attr("x2", x(new Date))
|
||||
.attr("y2", height)
|
||||
|
||||
# Add the ideal line path.
|
||||
|
@ -131,7 +135,7 @@ module.exports = Ractive.extend
|
|||
.attr("xlink:href", ({ html_url }) -> html_url )
|
||||
.attr("xlink:show", 'new')
|
||||
.append('svg:circle')
|
||||
.attr("cx", ({ date }) -> x date )
|
||||
.attr("cx", ({ date }) -> x new Date date )
|
||||
.attr("cy", ({ points }) -> y points )
|
||||
.attr("r", ({ radius }) -> 5 ) # fixed for now
|
||||
.on('mouseover', tooltip.show)
|
||||
|
|
|
@ -18,17 +18,19 @@ module.exports =
|
|||
do done
|
||||
|
||||
'lines - ideal': (done) ->
|
||||
# Dates are coming in without timezone information, so UTC.
|
||||
a = '2011-04-01T00:00:00Z'
|
||||
b = '2011-04-03T00:00:00Z'
|
||||
|
||||
line = lines.ideal(a, b, 4)[ 0...3 ]
|
||||
|
||||
assert.deepEqual line, [
|
||||
{ 'date': new Date('2011-04-01T06:00:00Z'), 'points': 4 }
|
||||
{ 'date': new Date('2011-04-02T06:00:00Z'), 'points': 2 }
|
||||
{ 'date': new Date('2011-04-03T06:00:00Z'), 'points': 0 }
|
||||
{ 'date': '2011-04-02T00:00:00.000Z', 'points': 4 }
|
||||
{ 'date': '2011-04-03T00:00:00.000Z', 'points': 2 }
|
||||
{ 'date': '2011-04-04T00:00:00.000Z', 'points': 0 }
|
||||
]
|
||||
|
||||
|
||||
do done
|
||||
|
||||
'lines - trend': (done) ->
|
||||
|
|
Loading…
Reference in New Issue