houston-roadmaps 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +358 -0
- data/MIT-LICENSE +20 -0
- data/README.md +31 -0
- data/Rakefile +25 -0
- data/app/assets/images/houston/roadmaps/.gitkeep +0 -0
- data/app/assets/javascripts/houston/roadmaps/app.coffee +2 -0
- data/app/assets/javascripts/houston/roadmaps/application.js +14 -0
- data/app/assets/javascripts/houston/roadmaps/handlebars_helpers.coffee +22 -0
- data/app/assets/javascripts/houston/roadmaps/jquery_extensions.coffee +4 -0
- data/app/assets/javascripts/houston/roadmaps/models/goal.coffee +11 -0
- data/app/assets/javascripts/houston/roadmaps/models/milestone.coffee +124 -0
- data/app/assets/javascripts/houston/roadmaps/models/roadmap.coffee +16 -0
- data/app/assets/javascripts/houston/roadmaps/models/viewport.coffee +3 -0
- data/app/assets/javascripts/houston/roadmaps/resize_listener.js +67 -0
- data/app/assets/javascripts/houston/roadmaps/views/_gantt_chart.coffee +224 -0
- data/app/assets/javascripts/houston/roadmaps/views/_show_milestone_view.coffee +204 -0
- data/app/assets/javascripts/houston/roadmaps/views/edit_gantt_chart.coffee +405 -0
- data/app/assets/javascripts/houston/roadmaps/views/edit_milestone_view.coffee +97 -0
- data/app/assets/javascripts/houston/roadmaps/views/edit_roadmap_view.coffee +80 -0
- data/app/assets/javascripts/houston/roadmaps/views/gantt_thumbnail_view.coffee +173 -0
- data/app/assets/javascripts/houston/roadmaps/views/goal_view.coffee +18 -0
- data/app/assets/javascripts/houston/roadmaps/views/project_goals_view.coffee +30 -0
- data/app/assets/javascripts/houston/roadmaps/views/roadmap_history_view.coffee +67 -0
- data/app/assets/javascripts/houston/roadmaps/views/roadmap_view.coffee +12 -0
- data/app/assets/javascripts/houston/roadmaps/views/roadmaps_view.coffee +29 -0
- data/app/assets/stylesheets/houston/roadmaps/application.css +13 -0
- data/app/assets/stylesheets/houston/roadmaps/colors.scss.erb +41 -0
- data/app/assets/stylesheets/houston/roadmaps/goals.scss +20 -0
- data/app/assets/stylesheets/houston/roadmaps/milestone.scss +58 -0
- data/app/assets/stylesheets/houston/roadmaps/roadmap.scss +276 -0
- data/app/assets/stylesheets/houston/roadmaps/roadmap_history.scss +42 -0
- data/app/assets/stylesheets/houston/roadmaps/roadmaps.scss +89 -0
- data/app/assets/templates/houston/roadmaps/goals/edit.hbs +6 -0
- data/app/assets/templates/houston/roadmaps/goals/index.hbs +9 -0
- data/app/assets/templates/houston/roadmaps/goals/new.hbs +27 -0
- data/app/assets/templates/houston/roadmaps/goals/show.hbs +6 -0
- data/app/assets/templates/houston/roadmaps/milestone/edit.hbs +67 -0
- data/app/assets/templates/houston/roadmaps/milestone/show.hbs +53 -0
- data/app/assets/templates/houston/roadmaps/milestone/ticket.hbs +28 -0
- data/app/assets/templates/houston/roadmaps/roadmap/goal.hbs +6 -0
- data/app/assets/templates/houston/roadmaps/roadmap/history.hbs +22 -0
- data/app/assets/templates/houston/roadmaps/roadmap/show.hbs +12 -0
- data/app/assets/templates/houston/roadmaps/roadmaps/index.hbs +2 -0
- data/app/assets/templates/houston/roadmaps/roadmaps/show.hbs +11 -0
- data/app/controllers/houston/roadmaps/api/v1/roadmap_controller.rb +20 -0
- data/app/controllers/houston/roadmaps/dashboard_controller.rb +34 -0
- data/app/controllers/houston/roadmaps/milestones_controller.rb +118 -0
- data/app/controllers/houston/roadmaps/project_goals_controller.rb +24 -0
- data/app/controllers/houston/roadmaps/roadmap_milestones_controller.rb +36 -0
- data/app/controllers/houston/roadmaps/roadmaps_controller.rb +77 -0
- data/app/helpers/houston/roadmaps/application_helper.rb +4 -0
- data/app/models/roadmap.rb +9 -0
- data/app/models/roadmap_commit.rb +35 -0
- data/app/models/roadmap_milestone.rb +29 -0
- data/app/models/roadmap_milestone_version.rb +8 -0
- data/app/presenters/houston/roadmaps/milestone_api_presenter.rb +27 -0
- data/app/presenters/houston/roadmaps/milestone_presenter.rb +74 -0
- data/app/presenters/houston/roadmaps/roadmap_milestone_presenter.rb +70 -0
- data/app/presenters/houston/roadmaps/roadmap_presenter.rb +37 -0
- data/app/presenters/houston/roadmaps/ticket_presenter.rb +20 -0
- data/app/views/houston/roadmaps/dashboard/show.html.erb +42 -0
- data/app/views/houston/roadmaps/milestones/show.html.erb +40 -0
- data/app/views/houston/roadmaps/project_goals/index.html.erb +42 -0
- data/app/views/houston/roadmaps/roadmaps/_form.html.erb +29 -0
- data/app/views/houston/roadmaps/roadmaps/edit.html.erb +8 -0
- data/app/views/houston/roadmaps/roadmaps/history.html.erb +41 -0
- data/app/views/houston/roadmaps/roadmaps/index.html.erb +24 -0
- data/app/views/houston/roadmaps/roadmaps/new.html.erb +7 -0
- data/app/views/houston/roadmaps/roadmaps/show.html.erb +27 -0
- data/app/views/houston/roadmaps/roadmaps/show_editable.html.erb +35 -0
- data/app/views/layouts/houston/roadmaps/application.html.erb +10 -0
- data/app/views/layouts/houston/roadmaps/dashboard.html.erb +9 -0
- data/bin/rails +8 -0
- data/config/database.yml +13 -0
- data/config/initializers/add_navigation_renderer.rb +13 -0
- data/config/routes.rb +37 -0
- data/db/.keep +0 -0
- data/db/migrate/20140831210254_add_band_to_milestones.rb +5 -0
- data/db/migrate/20140907212311_add_end_date_to_milestones.rb +19 -0
- data/db/migrate/20140916230539_add_locked_to_milestone.rb +5 -0
- data/db/migrate/20140927154728_add_closed_ticket_count_to_milestones.rb +11 -0
- data/db/migrate/20140929024130_create_roadmap_commits.rb +29 -0
- data/db/migrate/20141012023628_add_user_id_to_milestone_versions.rb +11 -0
- data/db/migrate/20150102192805_add_lanes_to_milestones.rb +5 -0
- data/db/migrate/20150119155145_add_goal_and_feedback_query_to_milestones.rb +6 -0
- data/db/migrate/20150524203903_add_project_id_to_roadmap_commits.rb +17 -0
- data/db/migrate/20150603203744_add_timestamps_to_roadmap_commits.rb +20 -0
- data/db/migrate/20160206214746_rename_roadmap_feature_to_milestones.rb +25 -0
- data/db/migrate/20160207154530_create_roadmaps.rb +125 -0
- data/db/structure.sql +2557 -0
- data/houston-roadmaps.gemspec +29 -0
- data/lib/houston-roadmaps.rb +1 -0
- data/lib/houston/roadmaps.rb +15 -0
- data/lib/houston/roadmaps/configuration.rb +14 -0
- data/lib/houston/roadmaps/engine.rb +27 -0
- data/lib/houston/roadmaps/milestone_ext.rb +14 -0
- data/lib/houston/roadmaps/project_ext.rb +20 -0
- data/lib/houston/roadmaps/railtie.rb +17 -0
- data/lib/houston/roadmaps/version.rb +5 -0
- data/lib/tasks/roadmap_tasks.rake +4 -0
- data/test/acceptance/houston_dummy_test.rb +17 -0
- data/test/dummy/houston.rb +23 -0
- data/test/fixtures/projects.yml +3 -0
- data/test/fixtures/users.yml +10 -0
- data/test/test_helper.rb +43 -0
- data/test/unit/fixtures_test.rb +11 -0
- metadata +227 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
class Roadmaps.EditMilestoneView extends Roadmaps.ShowMilestoneView
|
2
|
+
template: HandlebarsTemplates['houston/roadmaps/milestone/edit']
|
3
|
+
|
4
|
+
events:
|
5
|
+
'click .remove-button': 'removeTicket'
|
6
|
+
'click .inline-editable-link': 'startInlineEdit'
|
7
|
+
'click .btn-cancel': 'cancelInlineEdit'
|
8
|
+
'click #save_goal': 'saveGoal'
|
9
|
+
'click #save_feedback_query': 'saveFeedbackQuery'
|
10
|
+
|
11
|
+
initialize: ->
|
12
|
+
@openTickets = @options.openTickets
|
13
|
+
super
|
14
|
+
|
15
|
+
render: ->
|
16
|
+
super
|
17
|
+
|
18
|
+
@newTicketView = new FindOrCreateTicketView
|
19
|
+
ticketTracker: @projectTicketTracker
|
20
|
+
tickets: @openTickets
|
21
|
+
addTicket: _.bind(@addTicket, @)
|
22
|
+
createTicket: _.bind(@createTicket, @)
|
23
|
+
@$el.find('#find_or_create_ticket_view').appendView @newTicketView
|
24
|
+
|
25
|
+
$('#tickets').sortable
|
26
|
+
handle: '.ticket-handle'
|
27
|
+
helper: (e, ui)-> ui.children().each(-> $(@).width $(@).width()); ui
|
28
|
+
stop: (e, ui)-> ui.item.children().css('width', '')
|
29
|
+
update: (e, ui)->
|
30
|
+
$tickets = $('#tickets .ticket')
|
31
|
+
ids = _.map $tickets, (el)-> +$(el).attr('data-id')
|
32
|
+
$.put "#{window.location.pathname}/ticket_order", {order: ids}
|
33
|
+
@
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
addTicket: (ticket)->
|
38
|
+
$.post("/roadmap/milestones/#{@id}/tickets/#{ticket.id}")
|
39
|
+
.success => @_addTicket(ticket)
|
40
|
+
|
41
|
+
createTicket: (summary)->
|
42
|
+
$.post("/roadmap/milestones/#{@id}/tickets", {summary: summary})
|
43
|
+
.success (ticket)=> @_addTicket(ticket)
|
44
|
+
|
45
|
+
_addTicket: (ticket)->
|
46
|
+
unless @tickets.get(ticket.id)
|
47
|
+
@tickets.push new Ticket(ticket)
|
48
|
+
@rerenderTickets()
|
49
|
+
@renderBurndownChart(@tickets.models)
|
50
|
+
$(".ticket[data-id=#{ticket.id}]").highlight()
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
removeTicket: (e)->
|
55
|
+
e.preventDefault()
|
56
|
+
e.stopImmediatePropagation()
|
57
|
+
$button = $(e.target)
|
58
|
+
$button.prop 'disabled', true
|
59
|
+
$ticket = $button.closest('.ticket')
|
60
|
+
$ticket.addClass('deleting')
|
61
|
+
id = +$ticket.attr('data-id')
|
62
|
+
$.destroy("/roadmap/milestones/#{@id}/tickets/#{id}")
|
63
|
+
.error =>
|
64
|
+
$button.prop 'disabled', false
|
65
|
+
$ticket.removeClass('deleting')
|
66
|
+
.success =>
|
67
|
+
@tickets.remove @tickets.get(id)
|
68
|
+
$ticket.remove()
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
startInlineEdit: (e)->
|
73
|
+
$(e.target).closest('.inline-editable')
|
74
|
+
.addClass('in-edit')
|
75
|
+
.find('input, textarea').focus()
|
76
|
+
|
77
|
+
cancelInlineEdit: (e)->
|
78
|
+
e.preventDefault()
|
79
|
+
$(e.target).closest('.inline-editable').removeClass('in-edit')
|
80
|
+
|
81
|
+
saveGoal: (e)->
|
82
|
+
goal = $('#goal').val()
|
83
|
+
$.put("/roadmap/milestones/#{@id}", milestone: {goal: goal})
|
84
|
+
.success =>
|
85
|
+
@milestone.goal = goal
|
86
|
+
@render()
|
87
|
+
.error (response)=>
|
88
|
+
alertify.error(response.responseText)
|
89
|
+
|
90
|
+
saveFeedbackQuery: (e)->
|
91
|
+
feedbackQuery = $('#feedback_query').val()
|
92
|
+
$.put("/roadmap/milestones/#{@id}", milestone: {feedback_query: feedbackQuery})
|
93
|
+
.success =>
|
94
|
+
@milestone.feedbackQuery = feedbackQuery
|
95
|
+
@render()
|
96
|
+
.error (response)=>
|
97
|
+
alertify.error(response.responseText)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
class Roadmaps.EditRoadmapView extends Backbone.View
|
2
|
+
template: HandlebarsTemplates['houston/roadmaps/roadmap/show']
|
3
|
+
renderGoal: HandlebarsTemplates['houston/roadmaps/roadmap/goal']
|
4
|
+
|
5
|
+
initialize: ->
|
6
|
+
super
|
7
|
+
@roadmapId = @options.id
|
8
|
+
@milestonesUrl = "/roadmaps/#{@roadmapId}/milestones"
|
9
|
+
@milestones = @options.milestones
|
10
|
+
@goals = @options.goals
|
11
|
+
|
12
|
+
$('#reset_roadmap').click _.bind(@reset, @)
|
13
|
+
$('#save_roadmap').click _.bind(@save, @)
|
14
|
+
|
15
|
+
|
16
|
+
@milestones.bind 'change', @milestoneChanged, @
|
17
|
+
@milestones.bind 'add', @milestoneChanged, @
|
18
|
+
@milestones.bind 'remove', @milestoneChanged, @
|
19
|
+
|
20
|
+
render: ->
|
21
|
+
@$el.html @template()
|
22
|
+
@$goals = @$el.find('#goals')
|
23
|
+
@$goals_view = @$el.find('#goals_view')
|
24
|
+
@roadmap = new Roadmaps.EditGanttChart @milestones,
|
25
|
+
removeMilestoneByDroppingOn: @$goals_view
|
26
|
+
showWeekends: true
|
27
|
+
@roadmap.render()
|
28
|
+
@milestoneChanged()
|
29
|
+
|
30
|
+
setTop = =>
|
31
|
+
roadmapBottom = $('#roadmap').position().top + $('#roadmap').height() - 10
|
32
|
+
@$goals_view.css(top: roadmapBottom)
|
33
|
+
setTop()
|
34
|
+
$(window).resize(setTop)
|
35
|
+
addResizeListener $('#roadmap')[0], setTop
|
36
|
+
|
37
|
+
@
|
38
|
+
|
39
|
+
milestoneChanged: ->
|
40
|
+
@indicateIfRoadmapHasChanged()
|
41
|
+
@renderGoals()
|
42
|
+
|
43
|
+
indicateIfRoadmapHasChanged: ->
|
44
|
+
@$el.find('.buttons button')
|
45
|
+
.prop 'disabled', @milestones.changes().length is 0
|
46
|
+
|
47
|
+
renderGoals: ->
|
48
|
+
html = ""
|
49
|
+
@goals.outsideOf(@milestones.unremoved()).each (goal) =>
|
50
|
+
html += @renderGoal goal.toJSON()
|
51
|
+
@$goals.html(html)
|
52
|
+
|
53
|
+
@roadmap.dragFrom @$goals.find('.goal'), @goals
|
54
|
+
@
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
reset: (e)->
|
59
|
+
e.preventDefault()
|
60
|
+
@milestones.revert()
|
61
|
+
|
62
|
+
save: (e)->
|
63
|
+
e.preventDefault()
|
64
|
+
if message = prompt('Commit message:')
|
65
|
+
$buttons = $('#reset_roadmap, #save_roadmap')
|
66
|
+
changes = @milestones.changes()
|
67
|
+
$buttons.prop('disabled', true)
|
68
|
+
$.put(@milestonesUrl,
|
69
|
+
roadmap: changes
|
70
|
+
message: message)
|
71
|
+
.success =>
|
72
|
+
$buttons.prop('disabled', false)
|
73
|
+
@milestones.url = @milestonesUrl
|
74
|
+
@milestones.fetch
|
75
|
+
parse: true
|
76
|
+
wait: true
|
77
|
+
.error (response)->
|
78
|
+
$buttons.prop('disabled', false)
|
79
|
+
errors = Errors.fromResponse(response)
|
80
|
+
errors.renderToAlert()
|
@@ -0,0 +1,173 @@
|
|
1
|
+
class Roadmaps.ThumbnailGanttChart
|
2
|
+
today: new Date()
|
3
|
+
|
4
|
+
constructor: (options)->
|
5
|
+
@milestones = options.milestones
|
6
|
+
@parent = options.parent
|
7
|
+
@viewport = options.viewport
|
8
|
+
@showToday = options.showToday
|
9
|
+
@markers = options.markers
|
10
|
+
@milestones.bind 'add', @update, @
|
11
|
+
@milestones.bind 'remove', @update, @
|
12
|
+
@milestones.bind 'change', @update, @
|
13
|
+
@milestones.bind 'reset', @update, @
|
14
|
+
$(window).resize (e)=>
|
15
|
+
@updateWindow() if e.target is window
|
16
|
+
|
17
|
+
render: ->
|
18
|
+
@height = 46
|
19
|
+
@graphHeight = @height - 18
|
20
|
+
|
21
|
+
el = @parent.append('div')
|
22
|
+
.attr('class', 'roadmap-thumbnail')
|
23
|
+
.attr('style', "position: relative; height: #{@height}px;")
|
24
|
+
|
25
|
+
svg = el.append('svg')
|
26
|
+
.attr('height', @height)
|
27
|
+
.append('g')
|
28
|
+
.attr('transform', "translate(0,0)")
|
29
|
+
|
30
|
+
@roadmap = svg.append('g')
|
31
|
+
.attr('class', 'roadmap-bands')
|
32
|
+
|
33
|
+
@viewer = el.selectAll('.roadmap-thumbnail-viewer')
|
34
|
+
.data([@viewport])
|
35
|
+
|
36
|
+
view = @
|
37
|
+
@viewer.enter()
|
38
|
+
.append('div')
|
39
|
+
.attr('class', 'roadmap-thumbnail-viewer')
|
40
|
+
.attr('style', "top: 1px; height: #{@height - 2}px; left: 1px;")
|
41
|
+
.each ->
|
42
|
+
$(@).draggable
|
43
|
+
axis: 'x'
|
44
|
+
containment: 'parent'
|
45
|
+
drag: (e, ui)->
|
46
|
+
start = view.x.invert(ui.position.left)
|
47
|
+
offset = start - view.viewport.get('start')
|
48
|
+
end = new Date(+view.viewport.get('end') + offset)
|
49
|
+
view.viewport.set(start: start, end: end)
|
50
|
+
.resizable
|
51
|
+
handles: 'e'
|
52
|
+
containment: 'parent'
|
53
|
+
resize: (e, ui)->
|
54
|
+
end = view.x.invert(ui.position.left + ui.size.width)
|
55
|
+
view.viewport.set(end: end)
|
56
|
+
|
57
|
+
@xAxis = svg.append('g')
|
58
|
+
.attr('class', 'x axis')
|
59
|
+
.attr('transform', "translate(0,#{@graphHeight})")
|
60
|
+
|
61
|
+
@updateWindow()
|
62
|
+
|
63
|
+
updateWindow: ->
|
64
|
+
width = $('#roadmap').width() || 960
|
65
|
+
return if @width is width
|
66
|
+
@width = width
|
67
|
+
|
68
|
+
@parent.select('.roadmap-thumbnail').transition(150).attr('width', @width)
|
69
|
+
|
70
|
+
@update()
|
71
|
+
|
72
|
+
update: ->
|
73
|
+
visibleMilestones = _.select @milestones.toJSON(), (m)-> m.startDate and m.endDate and !m.removed
|
74
|
+
|
75
|
+
if visibleMilestones.length > 0
|
76
|
+
@startDate = 3.weeks().before d3.min(visibleMilestones, (m)-> m.startDate)
|
77
|
+
@endDate = 12.weeks().after d3.max(visibleMilestones, (m)-> m.endDate)
|
78
|
+
else
|
79
|
+
@startDate = 3.weeks().ago()
|
80
|
+
@endDate = 12.weeks().fromNow()
|
81
|
+
|
82
|
+
@startDate = @viewport.get('start') if @viewport.get('start') < @startDate
|
83
|
+
@endDate = @viewport.get('end') if @viewport.get('end') > @endDate
|
84
|
+
|
85
|
+
@x = d3.time.scale()
|
86
|
+
.domain([@startDate, @endDate])
|
87
|
+
.range([0, @width])
|
88
|
+
timeline = d3.svg.axis()
|
89
|
+
.scale(@x)
|
90
|
+
.orient('bottom')
|
91
|
+
.innerTickSize(4)
|
92
|
+
@xAxis.transition(150).call(timeline)
|
93
|
+
|
94
|
+
@viewer.attr('style', (viewport)=> "top: 1px; height: #{@height - 2}px; left: #{@x(viewport.get('start'))}px; width: #{@x(viewport.get('end')) - @x(viewport.get('start'))}px;")
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
milestoneBands = d3.nest()
|
99
|
+
.key (milestone)-> milestone.band
|
100
|
+
.entries(visibleMilestones)
|
101
|
+
|
102
|
+
bands = @roadmap.selectAll('.roadmap-thumbnail-band')
|
103
|
+
.data(milestoneBands, (band)-> band.key)
|
104
|
+
|
105
|
+
bands.enter()
|
106
|
+
.append('g')
|
107
|
+
.attr('class', 'roadmap-thumbnail-band')
|
108
|
+
.attr('transform', (d, i)-> "translate(0,#{2 + i * 6})")
|
109
|
+
|
110
|
+
bands.exit().remove()
|
111
|
+
|
112
|
+
milestones = bands.selectAll('.roadmap-thumbnail-milestone')
|
113
|
+
.data(((band)-> band.values), (milestone)-> milestone.cid)
|
114
|
+
|
115
|
+
# update
|
116
|
+
milestones
|
117
|
+
.attr 'class', (milestone)->
|
118
|
+
css = ['roadmap-thumbnail-milestone']
|
119
|
+
css.push 'completed' if milestone.completed
|
120
|
+
css.join(' ')
|
121
|
+
.transition(150)
|
122
|
+
.attr('height', (milestone)-> milestone.lanes * 6 - 1)
|
123
|
+
.attr('width', (milestone)=> @x(milestone.endDate) - @x(milestone.startDate))
|
124
|
+
.attr('x', (milestone)=> @x(milestone.startDate))
|
125
|
+
|
126
|
+
# enter
|
127
|
+
milestones.enter().append('rect')
|
128
|
+
.attr('rx', 1)
|
129
|
+
.attr('ry', 1)
|
130
|
+
.attr('height', (milestone)-> milestone.lanes * 6 - 1)
|
131
|
+
.attr('width', (milestone)=> @x(milestone.endDate) - @x(milestone.startDate))
|
132
|
+
.attr('x', (milestone)=> @x(milestone.startDate))
|
133
|
+
.attr 'class', (milestone)->
|
134
|
+
css = ['roadmap-thumbnail-milestone']
|
135
|
+
css.push 'completed' if milestone.completed
|
136
|
+
css.join(' ')
|
137
|
+
|
138
|
+
# exit
|
139
|
+
milestones.exit().remove()
|
140
|
+
|
141
|
+
|
142
|
+
if @showToday
|
143
|
+
todayLine = @roadmap.selectAll('.thumbnail-roadmap-today')
|
144
|
+
.data([@today])
|
145
|
+
|
146
|
+
todayLine.enter()
|
147
|
+
.append('rect')
|
148
|
+
.attr('class', 'thumbnail-roadmap-today')
|
149
|
+
.attr('height', @graphHeight - 1)
|
150
|
+
.attr('width', 1)
|
151
|
+
.attr('x', (date)=> @x(date))
|
152
|
+
.attr('y', 1)
|
153
|
+
|
154
|
+
todayLine
|
155
|
+
.attr('x', (date)=> @x(date))
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
markers = @roadmap.selectAll('.thumbnail-roadmap-marker')
|
160
|
+
.data(@markers)
|
161
|
+
|
162
|
+
markers.enter()
|
163
|
+
.append('rect')
|
164
|
+
.attr('class', 'thumbnail-roadmap-marker')
|
165
|
+
.attr('height', @graphHeight - 1)
|
166
|
+
.attr('width', 1)
|
167
|
+
.attr('x', ({date})=> @x(date))
|
168
|
+
.attr('y', 1)
|
169
|
+
|
170
|
+
markers
|
171
|
+
.attr('x', ({date})=> @x(date))
|
172
|
+
|
173
|
+
markers.exit().remove()
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class window.GoalView extends Neat.ModelEditor
|
2
|
+
tagName: 'tr'
|
3
|
+
|
4
|
+
render: ->
|
5
|
+
super
|
6
|
+
@$el.attr 'data-cid', @model.cid
|
7
|
+
@$el.toggleClass 'new', !@model.get('id')
|
8
|
+
@
|
9
|
+
|
10
|
+
cancelEdit: (e)->
|
11
|
+
return super if @model.id
|
12
|
+
|
13
|
+
# Canceling editing a new goal cancels adding a goal
|
14
|
+
@model.collection.remove @model
|
15
|
+
|
16
|
+
onSaveError: (goal, response) ->
|
17
|
+
errors = Errors.fromResponse(response)
|
18
|
+
errors.renderToAlert()
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Roadmaps.ProjectGoalsView extends Neat.CollectionEditor
|
2
|
+
renderNewGoalModal: HandlebarsTemplates['houston/roadmaps/goals/new']
|
3
|
+
resource: 'goals'
|
4
|
+
viewPath: 'houston/roadmaps/goals'
|
5
|
+
pageSize: Infinity
|
6
|
+
|
7
|
+
initialize: ->
|
8
|
+
@project = @options.project
|
9
|
+
@can = @options.can
|
10
|
+
@goals = @collection = @options.goals
|
11
|
+
super
|
12
|
+
|
13
|
+
$('#new_goal_button').click (e) =>
|
14
|
+
@newGoal(e)
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
render: ->
|
19
|
+
super
|
20
|
+
$('.table-sortable').tablesorter()
|
21
|
+
@
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
newGoal: (e)->
|
26
|
+
e.preventDefault() if e
|
27
|
+
goal = new Roadmaps.Goal
|
28
|
+
projectId: @project.id
|
29
|
+
@goals.unshift goal
|
30
|
+
@edit @views[0]
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Roadmaps.RoadmapHistoryView extends Backbone.View
|
2
|
+
el: '#roadmap_history_view'
|
3
|
+
milestones: {}
|
4
|
+
|
5
|
+
events:
|
6
|
+
'click :radio': 'changeCommit'
|
7
|
+
|
8
|
+
initialize: ->
|
9
|
+
@commits = @options.commits
|
10
|
+
@commitId = @options.commitId
|
11
|
+
|
12
|
+
dup = (milestones)-> _.clone(milestone) for milestone in milestones
|
13
|
+
|
14
|
+
# The current state of the Roadmap
|
15
|
+
# is the result of the last commit
|
16
|
+
currentMilestones = @options.milestones
|
17
|
+
@milestones[0] = dup(currentMilestones)
|
18
|
+
|
19
|
+
for commit in @commits
|
20
|
+
for change in commit.changes
|
21
|
+
milestone = _(currentMilestones).findWhere(id: change.milestoneId)
|
22
|
+
continue unless milestone
|
23
|
+
|
24
|
+
if change.number is 1
|
25
|
+
currentMilestones = _(currentMilestones).without(milestone)
|
26
|
+
else
|
27
|
+
for attribute, [before, after] of change.modifications
|
28
|
+
milestone[attribute] = before
|
29
|
+
|
30
|
+
@milestones[commit.id] = dup(currentMilestones)
|
31
|
+
|
32
|
+
@visibleMilestones = new Roadmaps.Milestones()
|
33
|
+
@updateRoadmap()
|
34
|
+
|
35
|
+
@roadmap = new Roadmaps.GanttChart(@visibleMilestones, @options)
|
36
|
+
@template = HandlebarsTemplates['houston/roadmaps/roadmap/history']
|
37
|
+
super
|
38
|
+
|
39
|
+
render: ->
|
40
|
+
@$el.html @template
|
41
|
+
commits: @commits
|
42
|
+
|
43
|
+
$form = @$el.find('form')
|
44
|
+
$form.css(bottom: 42) if App.meta('env') is 'development'
|
45
|
+
|
46
|
+
setTop = ->
|
47
|
+
roadmapBottom = $('#roadmap').position().top + $('#roadmap').height() - 10
|
48
|
+
$form.css(top: roadmapBottom)
|
49
|
+
setTop()
|
50
|
+
$(window).resize(setTop)
|
51
|
+
addResizeListener $('#roadmap')[0], setTop
|
52
|
+
|
53
|
+
@$el.find(':radio').first().prop('checked', true)
|
54
|
+
@roadmap.render()
|
55
|
+
@
|
56
|
+
|
57
|
+
changeCommit: (e)->
|
58
|
+
$radio = $(e.target)
|
59
|
+
$commit = $radio.closest('.roadmap-commit')
|
60
|
+
$commit.prevAll().andSelf().addClass('roadmap-commit-reverted')
|
61
|
+
$commit.nextAll().removeClass('roadmap-commit-reverted')
|
62
|
+
@commitId = +$radio.val()
|
63
|
+
@updateRoadmap()
|
64
|
+
|
65
|
+
updateRoadmap: ->
|
66
|
+
milestones = @milestones[@commitId]
|
67
|
+
@visibleMilestones.reset milestones, parse: true
|