@@ -0,0 +1,9 | |||
|
1 | <h3 class="title"><%=l(:label_version_new)%></h3> | |
|
2 | ||
|
3 | <% labelled_remote_form_for @version, :url => project_versions_path(@project) do |f| %> | |
|
4 | <%= render :partial => 'versions/form', :locals => { :f => f } %> | |
|
5 | <p class="buttons"> | |
|
6 | <%= submit_tag l(:button_create), :name => nil %> | |
|
7 | <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %> | |
|
8 | </p> | |
|
9 | <% end %> |
@@ -1,189 +1,205 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | class VersionsController < ApplicationController |
|
19 | 19 | menu_item :roadmap |
|
20 | 20 | model_object Version |
|
21 | 21 | before_filter :find_model_object, :except => [:index, :new, :create, :close_completed] |
|
22 | 22 | before_filter :find_project_from_association, :except => [:index, :new, :create, :close_completed] |
|
23 | 23 | before_filter :find_project, :only => [:index, :new, :create, :close_completed] |
|
24 | 24 | before_filter :authorize |
|
25 | 25 | |
|
26 | 26 | accept_api_auth :index, :create, :update, :destroy |
|
27 | 27 | |
|
28 | 28 | helper :custom_fields |
|
29 | 29 | helper :projects |
|
30 | 30 | |
|
31 | 31 | def index |
|
32 | 32 | respond_to do |format| |
|
33 | 33 | format.html { |
|
34 | 34 | @trackers = @project.trackers.find(:all, :order => 'position') |
|
35 | 35 | retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) |
|
36 | 36 | @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') |
|
37 | 37 | project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id] |
|
38 | 38 | |
|
39 | 39 | @versions = @project.shared_versions || [] |
|
40 | 40 | @versions += @project.rolled_up_versions.visible if @with_subprojects |
|
41 | 41 | @versions = @versions.uniq.sort |
|
42 | 42 | unless params[:completed] |
|
43 | 43 | @completed_versions = @versions.select {|version| version.closed? || version.completed? } |
|
44 | 44 | @versions -= @completed_versions |
|
45 | 45 | end |
|
46 | 46 | |
|
47 | 47 | @issues_by_version = {} |
|
48 | 48 | unless @selected_tracker_ids.empty? |
|
49 | 49 | @versions.each do |version| |
|
50 | 50 | issues = version.fixed_issues.visible.find(:all, |
|
51 | 51 | :include => [:project, :status, :tracker, :priority], |
|
52 | 52 | :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids}, |
|
53 | 53 | :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") |
|
54 | 54 | @issues_by_version[version] = issues |
|
55 | 55 | end |
|
56 | 56 | end |
|
57 | 57 | @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} |
|
58 | 58 | } |
|
59 | 59 | format.api { |
|
60 | 60 | @versions = @project.shared_versions.all |
|
61 | 61 | } |
|
62 | 62 | end |
|
63 | 63 | end |
|
64 | 64 | |
|
65 | 65 | def show |
|
66 | 66 | respond_to do |format| |
|
67 | 67 | format.html { |
|
68 | 68 | @issues = @version.fixed_issues.visible.find(:all, |
|
69 | 69 | :include => [:status, :tracker, :priority], |
|
70 | 70 | :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") |
|
71 | 71 | } |
|
72 | 72 | format.api |
|
73 | 73 | end |
|
74 | 74 | end |
|
75 | 75 | |
|
76 | 76 | def new |
|
77 | 77 | @version = @project.versions.build(params[:version]) |
|
78 | ||
|
79 | respond_to do |format| | |
|
80 | format.html | |
|
81 | format.js do | |
|
82 | render :update do |page| | |
|
83 | page.replace_html 'ajax-modal', :partial => 'versions/new_modal' | |
|
84 | page << "showModal('ajax-modal', '600px');" | |
|
85 | page << "Form.Element.focus('version_name');" | |
|
86 | end | |
|
87 | end | |
|
88 | end | |
|
78 | 89 | end |
|
79 | 90 | |
|
80 | 91 | def create |
|
81 | 92 | @version = @project.versions.build |
|
82 | 93 | if params[:version] |
|
83 | 94 | attributes = params[:version].dup |
|
84 | 95 | attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) |
|
85 | 96 | @version.attributes = attributes |
|
86 | 97 | end |
|
87 | 98 | |
|
88 | 99 | if request.post? |
|
89 | 100 | if @version.save |
|
90 | 101 | respond_to do |format| |
|
91 | 102 | format.html do |
|
92 | 103 | flash[:notice] = l(:notice_successful_create) |
|
93 | 104 | redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project |
|
94 | 105 | end |
|
95 | 106 | format.js do |
|
107 | render(:update) {|page| | |
|
108 | page << 'hideModal();' | |
|
96 | 109 | # IE doesn't support the replace_html rjs method for select box options |
|
97 |
|
|
|
110 | page.replace "issue_fixed_version_id", | |
|
98 | 111 | content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]') |
|
99 | 112 | } |
|
100 | 113 | end |
|
101 | 114 | format.api do |
|
102 | 115 | render :action => 'show', :status => :created, :location => version_url(@version) |
|
103 | 116 | end |
|
104 | 117 | end |
|
105 | 118 | else |
|
106 | 119 | respond_to do |format| |
|
107 | 120 | format.html { render :action => 'new' } |
|
108 | 121 | format.js do |
|
109 | render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) } | |
|
122 | render :update do |page| | |
|
123 | page.replace_html 'ajax-modal', :partial => 'versions/new_modal' | |
|
124 | page << "Form.Element.focus('version_name');" | |
|
125 | end | |
|
110 | 126 | end |
|
111 | 127 | format.api { render_validation_errors(@version) } |
|
112 | 128 | end |
|
113 | 129 | end |
|
114 | 130 | end |
|
115 | 131 | end |
|
116 | 132 | |
|
117 | 133 | def edit |
|
118 | 134 | end |
|
119 | 135 | |
|
120 | 136 | def update |
|
121 | 137 | if request.put? && params[:version] |
|
122 | 138 | attributes = params[:version].dup |
|
123 | 139 | attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) |
|
124 | 140 | if @version.update_attributes(attributes) |
|
125 | 141 | respond_to do |format| |
|
126 | 142 | format.html { |
|
127 | 143 | flash[:notice] = l(:notice_successful_update) |
|
128 | 144 | redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project |
|
129 | 145 | } |
|
130 | 146 | format.api { head :ok } |
|
131 | 147 | end |
|
132 | 148 | else |
|
133 | 149 | respond_to do |format| |
|
134 | 150 | format.html { render :action => 'edit' } |
|
135 | 151 | format.api { render_validation_errors(@version) } |
|
136 | 152 | end |
|
137 | 153 | end |
|
138 | 154 | end |
|
139 | 155 | end |
|
140 | 156 | |
|
141 | 157 | def close_completed |
|
142 | 158 | if request.put? |
|
143 | 159 | @project.close_completed_versions |
|
144 | 160 | end |
|
145 | 161 | redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project |
|
146 | 162 | end |
|
147 | 163 | |
|
148 | 164 | verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } |
|
149 | 165 | def destroy |
|
150 | 166 | if @version.fixed_issues.empty? |
|
151 | 167 | @version.destroy |
|
152 | 168 | respond_to do |format| |
|
153 | 169 | format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project } |
|
154 | 170 | format.api { head :ok } |
|
155 | 171 | end |
|
156 | 172 | else |
|
157 | 173 | respond_to do |format| |
|
158 | 174 | format.html { |
|
159 | 175 | flash[:error] = l(:notice_unable_delete_version) |
|
160 | 176 | redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project |
|
161 | 177 | } |
|
162 | 178 | format.api { head :unprocessable_entity } |
|
163 | 179 | end |
|
164 | 180 | end |
|
165 | 181 | end |
|
166 | 182 | |
|
167 | 183 | def status_by |
|
168 | 184 | respond_to do |format| |
|
169 | 185 | format.html { render :action => 'show' } |
|
170 | 186 | format.js { render(:update) {|page| page.replace_html 'status_by', render_issue_status_by(@version, params[:status_by])} } |
|
171 | 187 | end |
|
172 | 188 | end |
|
173 | 189 | |
|
174 | 190 | private |
|
175 | 191 | def find_project |
|
176 | 192 | @project = Project.find(params[:project_id]) |
|
177 | 193 | rescue ActiveRecord::RecordNotFound |
|
178 | 194 | render_404 |
|
179 | 195 | end |
|
180 | 196 | |
|
181 | 197 | def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil) |
|
182 | 198 | if ids = params[:tracker_ids] |
|
183 | 199 | @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } |
|
184 | 200 | else |
|
185 | 201 | @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s } |
|
186 | 202 | end |
|
187 | 203 | end |
|
188 | 204 | |
|
189 | 205 | end |
@@ -1,69 +1,67 | |||
|
1 | 1 | <% labelled_fields_for :issue, @issue do |f| %> |
|
2 | 2 | |
|
3 | 3 | <div class="splitcontentleft"> |
|
4 | 4 | <% if @issue.safe_attribute? 'status_id' %> |
|
5 | 5 | <p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p> |
|
6 | 6 | <% else %> |
|
7 | 7 | <p><label><%= l(:field_status) %></label> <%= h(@issue.status.name) %></p> |
|
8 | 8 | <% end %> |
|
9 | 9 | |
|
10 | 10 | <% if @issue.safe_attribute? 'priority_id' %> |
|
11 | 11 | <p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %></p> |
|
12 | 12 | <% end %> |
|
13 | 13 | |
|
14 | 14 | <% if @issue.safe_attribute? 'assigned_to_id' %> |
|
15 | 15 | <p><%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true %></p> |
|
16 | 16 | <% end %> |
|
17 | 17 | |
|
18 | 18 | <% if @issue.safe_attribute?('category_id') && @issue.project.issue_categories.any? %> |
|
19 | 19 | <p><%= f.select :category_id, (@issue.project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> |
|
20 | 20 | <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), |
|
21 | 21 | l(:label_issue_category_new), |
|
22 | 22 | 'issue_category[name]', |
|
23 | 23 | {:controller => 'issue_categories', :action => 'create', :project_id => @issue.project}, |
|
24 | 24 | :title => l(:label_issue_category_new), |
|
25 | 25 | :tabindex => 199) if User.current.allowed_to?(:manage_categories, @issue.project) %></p> |
|
26 | 26 | <% end %> |
|
27 | 27 | |
|
28 | 28 | <% if @issue.safe_attribute?('fixed_version_id') && @issue.assignable_versions.any? %> |
|
29 | 29 | <p><%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %> |
|
30 |
<%= |
|
|
31 | l(:label_version_new), | |
|
32 | 'version[name]', | |
|
33 | {:controller => 'versions', :action => 'create', :project_id => @issue.project}, | |
|
30 | <%= link_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), | |
|
31 | {:url => new_project_version_path(@issue.project), :method => 'get'}, | |
|
34 | 32 |
|
|
35 | 33 |
|
|
36 | 34 | </p> |
|
37 | 35 | <% end %> |
|
38 | 36 | </div> |
|
39 | 37 | |
|
40 | 38 | <div class="splitcontentright"> |
|
41 | 39 | <% if @issue.safe_attribute? 'parent_issue_id' %> |
|
42 | 40 | <p id="parent_issue"><%= f.text_field :parent_issue_id, :size => 10 %></p> |
|
43 | 41 | <div id="parent_issue_candidates" class="autocomplete"></div> |
|
44 | 42 | <%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @issue.project) }')" %> |
|
45 | 43 | <% end %> |
|
46 | 44 | |
|
47 | 45 | <% if @issue.safe_attribute? 'start_date' %> |
|
48 | 46 | <p><%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_start_date') if @issue.leaf? %></p> |
|
49 | 47 | <% end %> |
|
50 | 48 | |
|
51 | 49 | <% if @issue.safe_attribute? 'due_date' %> |
|
52 | 50 | <p><%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_due_date') if @issue.leaf? %></p> |
|
53 | 51 | <% end %> |
|
54 | 52 | |
|
55 | 53 | <% if @issue.safe_attribute? 'estimated_hours' %> |
|
56 | 54 | <p><%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf? %> <%= l(:field_hours) %></p> |
|
57 | 55 | <% end %> |
|
58 | 56 | |
|
59 | 57 | <% if @issue.safe_attribute?('done_ratio') && @issue.leaf? && Issue.use_field_for_done_ratio? %> |
|
60 | 58 | <p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p> |
|
61 | 59 | <% end %> |
|
62 | 60 | </div> |
|
63 | 61 | |
|
64 | 62 | <div style="clear:both;"> </div> |
|
65 | 63 | <% if @issue.safe_attribute? 'custom_field_values' %> |
|
66 | 64 | <%= render :partial => 'issues/form_custom_fields' %> |
|
67 | 65 | <% end %> |
|
68 | 66 | |
|
69 | 67 | <% end %> |
@@ -1,517 +1,522 | |||
|
1 | 1 | /* Redmine - project management software |
|
2 | 2 | Copyright (C) 2006-2012 Jean-Philippe Lang */ |
|
3 | 3 | |
|
4 | 4 | function checkAll (id, checked) { |
|
5 | 5 | var els = Element.descendants(id); |
|
6 | 6 | for (var i = 0; i < els.length; i++) { |
|
7 | 7 | if (els[i].disabled==false) { |
|
8 | 8 | els[i].checked = checked; |
|
9 | 9 | } |
|
10 | 10 | } |
|
11 | 11 | } |
|
12 | 12 | |
|
13 | 13 | function toggleCheckboxesBySelector(selector) { |
|
14 | 14 | boxes = $$(selector); |
|
15 | 15 | var all_checked = true; |
|
16 | 16 | for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } } |
|
17 | 17 | for (i = 0; i < boxes.length; i++) { boxes[i].checked = !all_checked; } |
|
18 | 18 | } |
|
19 | 19 | |
|
20 | 20 | function setCheckboxesBySelector(checked, selector) { |
|
21 | 21 | var boxes = $$(selector); |
|
22 | 22 | boxes.each(function(ele) { |
|
23 | 23 | ele.checked = checked; |
|
24 | 24 | }); |
|
25 | 25 | } |
|
26 | 26 | |
|
27 | 27 | function showAndScrollTo(id, focus) { |
|
28 | 28 | Element.show(id); |
|
29 | 29 | if (focus!=null) { Form.Element.focus(focus); } |
|
30 | 30 | Element.scrollTo(id); |
|
31 | 31 | } |
|
32 | 32 | |
|
33 | 33 | function toggleRowGroup(el) { |
|
34 | 34 | var tr = Element.up(el, 'tr'); |
|
35 | 35 | var n = Element.next(tr); |
|
36 | 36 | tr.toggleClassName('open'); |
|
37 | 37 | while (n != undefined && !n.hasClassName('group')) { |
|
38 | 38 | Element.toggle(n); |
|
39 | 39 | n = Element.next(n); |
|
40 | 40 | } |
|
41 | 41 | } |
|
42 | 42 | |
|
43 | 43 | function collapseAllRowGroups(el) { |
|
44 | 44 | var tbody = Element.up(el, 'tbody'); |
|
45 | 45 | tbody.childElements('tr').each(function(tr) { |
|
46 | 46 | if (tr.hasClassName('group')) { |
|
47 | 47 | tr.removeClassName('open'); |
|
48 | 48 | } else { |
|
49 | 49 | tr.hide(); |
|
50 | 50 | } |
|
51 | 51 | }) |
|
52 | 52 | } |
|
53 | 53 | |
|
54 | 54 | function expandAllRowGroups(el) { |
|
55 | 55 | var tbody = Element.up(el, 'tbody'); |
|
56 | 56 | tbody.childElements('tr').each(function(tr) { |
|
57 | 57 | if (tr.hasClassName('group')) { |
|
58 | 58 | tr.addClassName('open'); |
|
59 | 59 | } else { |
|
60 | 60 | tr.show(); |
|
61 | 61 | } |
|
62 | 62 | }) |
|
63 | 63 | } |
|
64 | 64 | |
|
65 | 65 | function toggleAllRowGroups(el) { |
|
66 | 66 | var tr = Element.up(el, 'tr'); |
|
67 | 67 | if (tr.hasClassName('open')) { |
|
68 | 68 | collapseAllRowGroups(el); |
|
69 | 69 | } else { |
|
70 | 70 | expandAllRowGroups(el); |
|
71 | 71 | } |
|
72 | 72 | } |
|
73 | 73 | |
|
74 | 74 | function toggleFieldset(el) { |
|
75 | 75 | var fieldset = Element.up(el, 'fieldset'); |
|
76 | 76 | fieldset.toggleClassName('collapsed'); |
|
77 | 77 | Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2}); |
|
78 | 78 | } |
|
79 | 79 | |
|
80 | 80 | function hideFieldset(el) { |
|
81 | 81 | var fieldset = Element.up(el, 'fieldset'); |
|
82 | 82 | fieldset.toggleClassName('collapsed'); |
|
83 | 83 | fieldset.down('div').hide(); |
|
84 | 84 | } |
|
85 | 85 | |
|
86 | 86 | function add_filter() { |
|
87 | 87 | select = $('add_filter_select'); |
|
88 | 88 | field = select.value |
|
89 | 89 | Element.show('tr_' + field); |
|
90 | 90 | check_box = $('cb_' + field); |
|
91 | 91 | check_box.checked = true; |
|
92 | 92 | toggle_filter(field); |
|
93 | 93 | select.selectedIndex = 0; |
|
94 | 94 | |
|
95 | 95 | for (i=0; i<select.options.length; i++) { |
|
96 | 96 | if (select.options[i].value == field) { |
|
97 | 97 | select.options[i].disabled = true; |
|
98 | 98 | } |
|
99 | 99 | } |
|
100 | 100 | } |
|
101 | 101 | |
|
102 | 102 | function toggle_filter(field) { |
|
103 | 103 | check_box = $('cb_' + field); |
|
104 | 104 | if (check_box.checked) { |
|
105 | 105 | Element.show("operators_" + field); |
|
106 | 106 | Form.Element.enable("operators_" + field); |
|
107 | 107 | toggle_operator(field); |
|
108 | 108 | } else { |
|
109 | 109 | Element.hide("operators_" + field); |
|
110 | 110 | Form.Element.disable("operators_" + field); |
|
111 | 111 | enableValues(field, []); |
|
112 | 112 | } |
|
113 | 113 | } |
|
114 | 114 | |
|
115 | 115 | function enableValues(field, indexes) { |
|
116 | 116 | var f = $$(".values_" + field); |
|
117 | 117 | for(var i=0;i<f.length;i++) { |
|
118 | 118 | if (indexes.include(i)) { |
|
119 | 119 | Form.Element.enable(f[i]); |
|
120 | 120 | f[i].up('span').show(); |
|
121 | 121 | } else { |
|
122 | 122 | f[i].value = ''; |
|
123 | 123 | Form.Element.disable(f[i]); |
|
124 | 124 | f[i].up('span').hide(); |
|
125 | 125 | } |
|
126 | 126 | } |
|
127 | 127 | if (indexes.length > 0) { |
|
128 | 128 | Element.show("div_values_" + field); |
|
129 | 129 | } else { |
|
130 | 130 | Element.hide("div_values_" + field); |
|
131 | 131 | } |
|
132 | 132 | } |
|
133 | 133 | |
|
134 | 134 | function toggle_operator(field) { |
|
135 | 135 | operator = $("operators_" + field); |
|
136 | 136 | switch (operator.value) { |
|
137 | 137 | case "!*": |
|
138 | 138 | case "*": |
|
139 | 139 | case "t": |
|
140 | 140 | case "w": |
|
141 | 141 | case "o": |
|
142 | 142 | case "c": |
|
143 | 143 | enableValues(field, []); |
|
144 | 144 | break; |
|
145 | 145 | case "><": |
|
146 | 146 | enableValues(field, [0,1]); |
|
147 | 147 | break; |
|
148 | 148 | case "<t+": |
|
149 | 149 | case ">t+": |
|
150 | 150 | case "t+": |
|
151 | 151 | case ">t-": |
|
152 | 152 | case "<t-": |
|
153 | 153 | case "t-": |
|
154 | 154 | enableValues(field, [2]); |
|
155 | 155 | break; |
|
156 | 156 | default: |
|
157 | 157 | enableValues(field, [0]); |
|
158 | 158 | break; |
|
159 | 159 | } |
|
160 | 160 | } |
|
161 | 161 | |
|
162 | 162 | function toggle_multi_select(el) { |
|
163 | 163 | var select = $(el); |
|
164 | 164 | if (select.multiple == true) { |
|
165 | 165 | select.multiple = false; |
|
166 | 166 | } else { |
|
167 | 167 | select.multiple = true; |
|
168 | 168 | } |
|
169 | 169 | } |
|
170 | 170 | |
|
171 | 171 | function submit_query_form(id) { |
|
172 | 172 | selectAllOptions("selected_columns"); |
|
173 | 173 | $(id).submit(); |
|
174 | 174 | } |
|
175 | 175 | |
|
176 | 176 | function apply_filters_observer() { |
|
177 | 177 | $$("#query_form input[type=text]").invoke("observe", "keypress", function(e){ |
|
178 | 178 | if(e.keyCode == Event.KEY_RETURN) { |
|
179 | 179 | submit_query_form("query_form"); |
|
180 | 180 | } |
|
181 | 181 | }); |
|
182 | 182 | } |
|
183 | 183 | |
|
184 | 184 | var fileFieldCount = 1; |
|
185 | 185 | |
|
186 | 186 | function addFileField() { |
|
187 | 187 | var fields = $('attachments_fields'); |
|
188 | 188 | if (fields.childElements().length >= 10) return false; |
|
189 | 189 | fileFieldCount++; |
|
190 | 190 | var s = new Element('span'); |
|
191 | 191 | s.update(fields.down('span').innerHTML); |
|
192 | 192 | s.down('input.file').name = "attachments[" + fileFieldCount + "][file]"; |
|
193 | 193 | s.down('input.description').name = "attachments[" + fileFieldCount + "][description]"; |
|
194 | 194 | fields.appendChild(s); |
|
195 | 195 | } |
|
196 | 196 | |
|
197 | 197 | function removeFileField(el) { |
|
198 | 198 | var fields = $('attachments_fields'); |
|
199 | 199 | var s = Element.up(el, 'span'); |
|
200 | 200 | if (fields.childElements().length > 1) { |
|
201 | 201 | s.remove(); |
|
202 | 202 | } else { |
|
203 | 203 | s.update(s.innerHTML); |
|
204 | 204 | } |
|
205 | 205 | } |
|
206 | 206 | |
|
207 | 207 | function checkFileSize(el, maxSize, message) { |
|
208 | 208 | var files = el.files; |
|
209 | 209 | if (files) { |
|
210 | 210 | for (var i=0; i<files.length; i++) { |
|
211 | 211 | if (files[i].size > maxSize) { |
|
212 | 212 | alert(message); |
|
213 | 213 | el.value = ""; |
|
214 | 214 | } |
|
215 | 215 | } |
|
216 | 216 | } |
|
217 | 217 | } |
|
218 | 218 | |
|
219 | 219 | function showTab(name) { |
|
220 | 220 | var f = $$('div#content .tab-content'); |
|
221 | 221 | for(var i=0; i<f.length; i++){ |
|
222 | 222 | Element.hide(f[i]); |
|
223 | 223 | } |
|
224 | 224 | var f = $$('div.tabs a'); |
|
225 | 225 | for(var i=0; i<f.length; i++){ |
|
226 | 226 | Element.removeClassName(f[i], "selected"); |
|
227 | 227 | } |
|
228 | 228 | Element.show('tab-content-' + name); |
|
229 | 229 | Element.addClassName('tab-' + name, "selected"); |
|
230 | 230 | return false; |
|
231 | 231 | } |
|
232 | 232 | |
|
233 | 233 | function moveTabRight(el) { |
|
234 | 234 | var lis = Element.up(el, 'div.tabs').down('ul').childElements(); |
|
235 | 235 | var tabsWidth = 0; |
|
236 | 236 | var i; |
|
237 | 237 | for (i=0; i<lis.length; i++) { |
|
238 | 238 | if (lis[i].visible()) { |
|
239 | 239 | tabsWidth += lis[i].getWidth() + 6; |
|
240 | 240 | } |
|
241 | 241 | } |
|
242 | 242 | if (tabsWidth < Element.up(el, 'div.tabs').getWidth() - 60) { |
|
243 | 243 | return; |
|
244 | 244 | } |
|
245 | 245 | i=0; |
|
246 | 246 | while (i<lis.length && !lis[i].visible()) { |
|
247 | 247 | i++; |
|
248 | 248 | } |
|
249 | 249 | lis[i].hide(); |
|
250 | 250 | } |
|
251 | 251 | |
|
252 | 252 | function moveTabLeft(el) { |
|
253 | 253 | var lis = Element.up(el, 'div.tabs').down('ul').childElements(); |
|
254 | 254 | var i = 0; |
|
255 | 255 | while (i<lis.length && !lis[i].visible()) { |
|
256 | 256 | i++; |
|
257 | 257 | } |
|
258 | 258 | if (i>0) { |
|
259 | 259 | lis[i-1].show(); |
|
260 | 260 | } |
|
261 | 261 | } |
|
262 | 262 | |
|
263 | 263 | function displayTabsButtons() { |
|
264 | 264 | var lis; |
|
265 | 265 | var tabsWidth = 0; |
|
266 | 266 | var i; |
|
267 | 267 | $$('div.tabs').each(function(el) { |
|
268 | 268 | lis = el.down('ul').childElements(); |
|
269 | 269 | for (i=0; i<lis.length; i++) { |
|
270 | 270 | if (lis[i].visible()) { |
|
271 | 271 | tabsWidth += lis[i].getWidth() + 6; |
|
272 | 272 | } |
|
273 | 273 | } |
|
274 | 274 | if ((tabsWidth < el.getWidth() - 60) && (lis[0].visible())) { |
|
275 | 275 | el.down('div.tabs-buttons').hide(); |
|
276 | 276 | } else { |
|
277 | 277 | el.down('div.tabs-buttons').show(); |
|
278 | 278 | } |
|
279 | 279 | }); |
|
280 | 280 | } |
|
281 | 281 | |
|
282 | 282 | function setPredecessorFieldsVisibility() { |
|
283 | 283 | relationType = $('relation_relation_type'); |
|
284 | 284 | if (relationType && (relationType.value == "precedes" || relationType.value == "follows")) { |
|
285 | 285 | Element.show('predecessor_fields'); |
|
286 | 286 | } else { |
|
287 | 287 | Element.hide('predecessor_fields'); |
|
288 | 288 | } |
|
289 | 289 | } |
|
290 | 290 | |
|
291 | 291 | function promptToRemote(text, param, url) { |
|
292 | 292 | value = prompt(text + ':'); |
|
293 | 293 | if (value) { |
|
294 | 294 | new Ajax.Request(url + '?' + param + '=' + encodeURIComponent(value), {asynchronous:true, evalScripts:true}); |
|
295 | 295 | return false; |
|
296 | 296 | } |
|
297 | 297 | } |
|
298 | 298 | |
|
299 | 299 | function showModal(id, width) { |
|
300 | 300 | el = $(id); |
|
301 | 301 | if (el == undefined || el.visible()) {return;} |
|
302 | 302 | var h = $$('body')[0].getHeight(); |
|
303 | 303 | var d = document.createElement("div"); |
|
304 | 304 | d.id = 'modalbg'; |
|
305 | 305 | $('main').appendChild(d); |
|
306 | 306 | $('modalbg').setStyle({ width: '100%', height: h + 'px' }); |
|
307 | 307 | $('modalbg').show(); |
|
308 | 308 | |
|
309 | 309 | var pageWidth = document.viewport.getWidth(); |
|
310 | 310 | if (width) { |
|
311 | 311 | el.setStyle({'width': width}); |
|
312 | 312 | } |
|
313 | 313 | el.setStyle({'left': (((pageWidth - el.getWidth())/2 *100) / pageWidth) + '%'}); |
|
314 | 314 | el.addClassName('modal'); |
|
315 | 315 | el.show(); |
|
316 | 316 | |
|
317 | 317 | var submit = el.down("input[type=submit]"); |
|
318 | 318 | if (submit) { |
|
319 | 319 | submit.focus(); |
|
320 | 320 | } |
|
321 | 321 | } |
|
322 | 322 | |
|
323 | 323 | function hideModal(el) { |
|
324 | var modal = Element.up(el, 'div.modal'); | |
|
324 | var modal; | |
|
325 | if (el) { | |
|
326 | modal = Element.up(el, 'div.modal'); | |
|
327 | } else { | |
|
328 | modal = $('ajax-modal'); | |
|
329 | } | |
|
325 | 330 | if (modal) { |
|
326 | 331 | modal.hide(); |
|
327 | 332 | } |
|
328 | 333 | var bg = $('modalbg'); |
|
329 | 334 | if (bg) { |
|
330 | 335 | bg.remove(); |
|
331 | 336 | } |
|
332 | 337 | } |
|
333 | 338 | |
|
334 | 339 | function collapseScmEntry(id) { |
|
335 | 340 | var els = document.getElementsByClassName(id, 'browser'); |
|
336 | 341 | for (var i = 0; i < els.length; i++) { |
|
337 | 342 | if (els[i].hasClassName('open')) { |
|
338 | 343 | collapseScmEntry(els[i].id); |
|
339 | 344 | } |
|
340 | 345 | Element.hide(els[i]); |
|
341 | 346 | } |
|
342 | 347 | $(id).removeClassName('open'); |
|
343 | 348 | } |
|
344 | 349 | |
|
345 | 350 | function expandScmEntry(id) { |
|
346 | 351 | var els = document.getElementsByClassName(id, 'browser'); |
|
347 | 352 | for (var i = 0; i < els.length; i++) { |
|
348 | 353 | Element.show(els[i]); |
|
349 | 354 | if (els[i].hasClassName('loaded') && !els[i].hasClassName('collapsed')) { |
|
350 | 355 | expandScmEntry(els[i].id); |
|
351 | 356 | } |
|
352 | 357 | } |
|
353 | 358 | $(id).addClassName('open'); |
|
354 | 359 | } |
|
355 | 360 | |
|
356 | 361 | function scmEntryClick(id) { |
|
357 | 362 | el = $(id); |
|
358 | 363 | if (el.hasClassName('open')) { |
|
359 | 364 | collapseScmEntry(id); |
|
360 | 365 | el.addClassName('collapsed'); |
|
361 | 366 | return false; |
|
362 | 367 | } else if (el.hasClassName('loaded')) { |
|
363 | 368 | expandScmEntry(id); |
|
364 | 369 | el.removeClassName('collapsed'); |
|
365 | 370 | return false; |
|
366 | 371 | } |
|
367 | 372 | if (el.hasClassName('loading')) { |
|
368 | 373 | return false; |
|
369 | 374 | } |
|
370 | 375 | el.addClassName('loading'); |
|
371 | 376 | return true; |
|
372 | 377 | } |
|
373 | 378 | |
|
374 | 379 | function scmEntryLoaded(id) { |
|
375 | 380 | Element.addClassName(id, 'open'); |
|
376 | 381 | Element.addClassName(id, 'loaded'); |
|
377 | 382 | Element.removeClassName(id, 'loading'); |
|
378 | 383 | } |
|
379 | 384 | |
|
380 | 385 | function randomKey(size) { |
|
381 | 386 | var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); |
|
382 | 387 | var key = ''; |
|
383 | 388 | for (i = 0; i < size; i++) { |
|
384 | 389 | key += chars[Math.floor(Math.random() * chars.length)]; |
|
385 | 390 | } |
|
386 | 391 | return key; |
|
387 | 392 | } |
|
388 | 393 | |
|
389 | 394 | function observeParentIssueField(url) { |
|
390 | 395 | new Ajax.Autocompleter('issue_parent_issue_id', |
|
391 | 396 | 'parent_issue_candidates', |
|
392 | 397 | url, |
|
393 | 398 | { minChars: 3, |
|
394 | 399 | frequency: 0.5, |
|
395 | 400 | paramName: 'q', |
|
396 | 401 | method: 'get', |
|
397 | 402 | updateElement: function(value) { |
|
398 | 403 | document.getElementById('issue_parent_issue_id').value = value.id; |
|
399 | 404 | }}); |
|
400 | 405 | } |
|
401 | 406 | |
|
402 | 407 | function observeRelatedIssueField(url) { |
|
403 | 408 | new Ajax.Autocompleter('relation_issue_to_id', |
|
404 | 409 | 'related_issue_candidates', |
|
405 | 410 | url, |
|
406 | 411 | { minChars: 3, |
|
407 | 412 | frequency: 0.5, |
|
408 | 413 | paramName: 'q', |
|
409 | 414 | method: 'get', |
|
410 | 415 | updateElement: function(value) { |
|
411 | 416 | document.getElementById('relation_issue_to_id').value = value.id; |
|
412 | 417 | }, |
|
413 | 418 | parameters: 'scope=all' |
|
414 | 419 | }); |
|
415 | 420 | } |
|
416 | 421 | |
|
417 | 422 | function setVisible(id, visible) { |
|
418 | 423 | var el = $(id); |
|
419 | 424 | if (el) {if (visible) {el.show();} else {el.hide();}} |
|
420 | 425 | } |
|
421 | 426 | |
|
422 | 427 | function observeProjectModules() { |
|
423 | 428 | var f = function() { |
|
424 | 429 | /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */ |
|
425 | 430 | var c = ($('project_enabled_module_names_issue_tracking').checked == true); |
|
426 | 431 | setVisible('project_trackers', c); |
|
427 | 432 | setVisible('project_issue_custom_fields', c); |
|
428 | 433 | }; |
|
429 | 434 | |
|
430 | 435 | Event.observe(window, 'load', f); |
|
431 | 436 | Event.observe('project_enabled_module_names_issue_tracking', 'change', f); |
|
432 | 437 | } |
|
433 | 438 | |
|
434 | 439 | /* |
|
435 | 440 | * Class used to warn user when leaving a page with unsaved textarea |
|
436 | 441 | * Author: mathias.fischer@berlinonline.de |
|
437 | 442 | */ |
|
438 | 443 | |
|
439 | 444 | var WarnLeavingUnsaved = Class.create({ |
|
440 | 445 | observedForms: false, |
|
441 | 446 | observedElements: false, |
|
442 | 447 | changedForms: false, |
|
443 | 448 | message: null, |
|
444 | 449 | |
|
445 | 450 | initialize: function(message){ |
|
446 | 451 | this.observedForms = $$('form'); |
|
447 | 452 | this.observedElements = $$('textarea'); |
|
448 | 453 | this.message = message; |
|
449 | 454 | |
|
450 | 455 | this.observedElements.each(this.observeChange.bind(this)); |
|
451 | 456 | this.observedForms.each(this.submitAction.bind(this)); |
|
452 | 457 | |
|
453 | 458 | window.onbeforeunload = this.unload.bind(this); |
|
454 | 459 | }, |
|
455 | 460 | |
|
456 | 461 | unload: function(){ |
|
457 | 462 | this.observedElements.each(function(el) {el.blur();}) |
|
458 | 463 | if(this.changedForms) |
|
459 | 464 | return this.message; |
|
460 | 465 | }, |
|
461 | 466 | |
|
462 | 467 | setChanged: function(){ |
|
463 | 468 | this.changedForms = true; |
|
464 | 469 | }, |
|
465 | 470 | |
|
466 | 471 | setUnchanged: function(){ |
|
467 | 472 | this.changedForms = false; |
|
468 | 473 | }, |
|
469 | 474 | |
|
470 | 475 | observeChange: function(element){ |
|
471 | 476 | element.observe('change',this.setChanged.bindAsEventListener(this)); |
|
472 | 477 | }, |
|
473 | 478 | |
|
474 | 479 | submitAction: function(element){ |
|
475 | 480 | element.observe('submit',this.setUnchanged.bindAsEventListener(this)); |
|
476 | 481 | } |
|
477 | 482 | }); |
|
478 | 483 | |
|
479 | 484 | /* |
|
480 | 485 | * 1 - registers a callback which copies the csrf token into the |
|
481 | 486 | * X-CSRF-Token header with each ajax request. Necessary to |
|
482 | 487 | * work with rails applications which have fixed |
|
483 | 488 | * CVE-2011-0447 |
|
484 | 489 | * 2 - shows and hides ajax indicator |
|
485 | 490 | */ |
|
486 | 491 | Ajax.Responders.register({ |
|
487 | 492 | onCreate: function(request){ |
|
488 | 493 | var csrf_meta_tag = $$('meta[name=csrf-token]')[0]; |
|
489 | 494 | |
|
490 | 495 | if (csrf_meta_tag) { |
|
491 | 496 | var header = 'X-CSRF-Token', |
|
492 | 497 | token = csrf_meta_tag.readAttribute('content'); |
|
493 | 498 | |
|
494 | 499 | if (!request.options.requestHeaders) { |
|
495 | 500 | request.options.requestHeaders = {}; |
|
496 | 501 | } |
|
497 | 502 | request.options.requestHeaders[header] = token; |
|
498 | 503 | } |
|
499 | 504 | |
|
500 | 505 | if ($('ajax-indicator') && Ajax.activeRequestCount > 0) { |
|
501 | 506 | Element.show('ajax-indicator'); |
|
502 | 507 | } |
|
503 | 508 | }, |
|
504 | 509 | onComplete: function(){ |
|
505 | 510 | if ($('ajax-indicator') && Ajax.activeRequestCount == 0) { |
|
506 | 511 | Element.hide('ajax-indicator'); |
|
507 | 512 | } |
|
508 | 513 | } |
|
509 | 514 | }); |
|
510 | 515 | |
|
511 | 516 | function hideOnLoad() { |
|
512 | 517 | $$('.hol').each(function(el) { |
|
513 | 518 | el.hide(); |
|
514 | 519 | }); |
|
515 | 520 | } |
|
516 | 521 | |
|
517 | 522 | Event.observe(window, 'load', hideOnLoad); |
@@ -1,187 +1,211 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../test_helper', __FILE__) |
|
19 | 19 | require 'versions_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class VersionsController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class VersionsControllerTest < ActionController::TestCase |
|
25 | 25 | fixtures :projects, :versions, :issues, :users, :roles, :members, :member_roles, :enabled_modules, :issue_statuses |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = VersionsController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | 34 | def test_index |
|
35 | 35 | get :index, :project_id => 1 |
|
36 | 36 | assert_response :success |
|
37 | 37 | assert_template 'index' |
|
38 | 38 | assert_not_nil assigns(:versions) |
|
39 | 39 | # Version with no date set appears |
|
40 | 40 | assert assigns(:versions).include?(Version.find(3)) |
|
41 | 41 | # Completed version doesn't appear |
|
42 | 42 | assert !assigns(:versions).include?(Version.find(1)) |
|
43 | 43 | # Context menu on issues |
|
44 | 44 | assert_select "script", :text => Regexp.new(Regexp.escape("new ContextMenu('/issues/context_menu')")) |
|
45 | 45 | # Links to versions anchors |
|
46 | 46 | assert_tag 'a', :attributes => {:href => '#2.0'}, |
|
47 | 47 | :ancestor => {:tag => 'div', :attributes => {:id => 'sidebar'}} |
|
48 | 48 | # Links to completed versions in the sidebar |
|
49 | 49 | assert_tag 'a', :attributes => {:href => '/versions/1'}, |
|
50 | 50 | :ancestor => {:tag => 'div', :attributes => {:id => 'sidebar'}} |
|
51 | 51 | end |
|
52 | 52 | |
|
53 | 53 | def test_index_with_completed_versions |
|
54 | 54 | get :index, :project_id => 1, :completed => 1 |
|
55 | 55 | assert_response :success |
|
56 | 56 | assert_template 'index' |
|
57 | 57 | assert_not_nil assigns(:versions) |
|
58 | 58 | # Version with no date set appears |
|
59 | 59 | assert assigns(:versions).include?(Version.find(3)) |
|
60 | 60 | # Completed version appears |
|
61 | 61 | assert assigns(:versions).include?(Version.find(1)) |
|
62 | 62 | end |
|
63 | 63 | |
|
64 | 64 | def test_index_with_tracker_ids |
|
65 | 65 | get :index, :project_id => 1, :tracker_ids => [1, 3] |
|
66 | 66 | assert_response :success |
|
67 | 67 | assert_template 'index' |
|
68 | 68 | assert_not_nil assigns(:issues_by_version) |
|
69 | 69 | assert_nil assigns(:issues_by_version).values.flatten.detect {|issue| issue.tracker_id == 2} |
|
70 | 70 | end |
|
71 | 71 | |
|
72 | 72 | def test_index_showing_subprojects_versions |
|
73 | 73 | @subproject_version = Version.generate!(:project => Project.find(3)) |
|
74 | 74 | get :index, :project_id => 1, :with_subprojects => 1 |
|
75 | 75 | assert_response :success |
|
76 | 76 | assert_template 'index' |
|
77 | 77 | assert_not_nil assigns(:versions) |
|
78 | 78 | |
|
79 | 79 | assert assigns(:versions).include?(Version.find(4)), "Shared version not found" |
|
80 | 80 | assert assigns(:versions).include?(@subproject_version), "Subproject version not found" |
|
81 | 81 | end |
|
82 | 82 | |
|
83 | 83 | def test_show |
|
84 | 84 | get :show, :id => 2 |
|
85 | 85 | assert_response :success |
|
86 | 86 | assert_template 'show' |
|
87 | 87 | assert_not_nil assigns(:version) |
|
88 | 88 | |
|
89 | 89 | assert_tag :tag => 'h2', :content => /1.0/ |
|
90 | 90 | end |
|
91 | 91 | |
|
92 | 92 | def test_new |
|
93 | 93 | @request.session[:user_id] = 2 |
|
94 | 94 | get :new, :project_id => '1' |
|
95 | 95 | assert_response :success |
|
96 | 96 | assert_template 'new' |
|
97 | 97 | end |
|
98 | 98 | |
|
99 | def test_new_from_issue_form | |
|
100 | @request.session[:user_id] = 2 | |
|
101 | xhr :get, :new, :project_id => '1' | |
|
102 | assert_response :success | |
|
103 | assert_select_rjs :replace_html, "ajax-modal" do | |
|
104 | assert_select "form[action=/projects/ecookbook/versions]" | |
|
105 | assert_select "input#version_name" | |
|
106 | end | |
|
107 | end | |
|
108 | ||
|
99 | 109 | def test_create |
|
100 | 110 | @request.session[:user_id] = 2 # manager |
|
101 | 111 | assert_difference 'Version.count' do |
|
102 | 112 | post :create, :project_id => '1', :version => {:name => 'test_add_version'} |
|
103 | 113 | end |
|
104 | 114 | assert_redirected_to '/projects/ecookbook/settings/versions' |
|
105 | 115 | version = Version.find_by_name('test_add_version') |
|
106 | 116 | assert_not_nil version |
|
107 | 117 | assert_equal 1, version.project_id |
|
108 | 118 | end |
|
109 | 119 | |
|
110 | 120 | def test_create_from_issue_form |
|
111 |
@request.session[:user_id] = 2 |
|
|
121 | @request.session[:user_id] = 2 | |
|
112 | 122 | assert_difference 'Version.count' do |
|
113 | 123 | xhr :post, :create, :project_id => '1', :version => {:name => 'test_add_version_from_issue_form'} |
|
114 | 124 | end |
|
115 | assert_response :success | |
|
116 | assert_select_rjs :replace, 'issue_fixed_version_id' | |
|
117 | 125 | version = Version.find_by_name('test_add_version_from_issue_form') |
|
118 | 126 | assert_not_nil version |
|
119 | 127 | assert_equal 1, version.project_id |
|
128 | ||
|
129 | assert_response :success | |
|
130 | assert_select_rjs :replace, 'issue_fixed_version_id' do | |
|
131 | assert_select "option[value=#{version.id}][selected=selected]" | |
|
132 | end | |
|
133 | end | |
|
134 | ||
|
135 | def test_create_from_issue_form_with_failure | |
|
136 | @request.session[:user_id] = 2 | |
|
137 | assert_no_difference 'Version.count' do | |
|
138 | xhr :post, :create, :project_id => '1', :version => {:name => ''} | |
|
139 | end | |
|
140 | assert_response :success | |
|
141 | assert_select_rjs :replace_html, "ajax-modal" do | |
|
142 | assert_select "div#errorExplanation" | |
|
143 | end | |
|
120 | 144 | end |
|
121 | 145 | |
|
122 | 146 | def test_get_edit |
|
123 | 147 | @request.session[:user_id] = 2 |
|
124 | 148 | get :edit, :id => 2 |
|
125 | 149 | assert_response :success |
|
126 | 150 | assert_template 'edit' |
|
127 | 151 | end |
|
128 | 152 | |
|
129 | 153 | def test_close_completed |
|
130 | 154 | Version.update_all("status = 'open'") |
|
131 | 155 | @request.session[:user_id] = 2 |
|
132 | 156 | put :close_completed, :project_id => 'ecookbook' |
|
133 | 157 | assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' |
|
134 | 158 | assert_not_nil Version.find_by_status('closed') |
|
135 | 159 | end |
|
136 | 160 | |
|
137 | 161 | def test_post_update |
|
138 | 162 | @request.session[:user_id] = 2 |
|
139 | 163 | put :update, :id => 2, |
|
140 | 164 | :version => { :name => 'New version name', |
|
141 | 165 | :effective_date => Date.today.strftime("%Y-%m-%d")} |
|
142 | 166 | assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' |
|
143 | 167 | version = Version.find(2) |
|
144 | 168 | assert_equal 'New version name', version.name |
|
145 | 169 | assert_equal Date.today, version.effective_date |
|
146 | 170 | end |
|
147 | 171 | |
|
148 | 172 | def test_post_update_with_validation_failure |
|
149 | 173 | @request.session[:user_id] = 2 |
|
150 | 174 | put :update, :id => 2, |
|
151 | 175 | :version => { :name => '', |
|
152 | 176 | :effective_date => Date.today.strftime("%Y-%m-%d")} |
|
153 | 177 | assert_response :success |
|
154 | 178 | assert_template 'edit' |
|
155 | 179 | end |
|
156 | 180 | |
|
157 | 181 | def test_destroy |
|
158 | 182 | @request.session[:user_id] = 2 |
|
159 | 183 | assert_difference 'Version.count', -1 do |
|
160 | 184 | delete :destroy, :id => 3 |
|
161 | 185 | end |
|
162 | 186 | assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' |
|
163 | 187 | assert_nil Version.find_by_id(3) |
|
164 | 188 | end |
|
165 | 189 | |
|
166 | 190 | def test_destroy_version_in_use_should_fail |
|
167 | 191 | @request.session[:user_id] = 2 |
|
168 | 192 | assert_no_difference 'Version.count' do |
|
169 | 193 | delete :destroy, :id => 2 |
|
170 | 194 | end |
|
171 | 195 | assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' |
|
172 | 196 | assert flash[:error].match(/Unable to delete version/) |
|
173 | 197 | assert Version.find_by_id(2) |
|
174 | 198 | end |
|
175 | 199 | |
|
176 | 200 | def test_issue_status_by |
|
177 | 201 | xhr :get, :status_by, :id => 2 |
|
178 | 202 | assert_response :success |
|
179 | 203 | assert_template '_issue_counts' |
|
180 | 204 | end |
|
181 | 205 | |
|
182 | 206 | def test_issue_status_by_status |
|
183 | 207 | xhr :get, :status_by, :id => 2, :status_by => 'status' |
|
184 | 208 | assert_response :success |
|
185 | 209 | assert_template '_issue_counts' |
|
186 | 210 | end |
|
187 | 211 | end |
General Comments 0
You need to be logged in to leave comments.
Login now