Project

General

Profile

Feature #27672 » 0001~0003.patch

Mizuki ISHIKAWA, 2018-11-09 09:22

View differences:

app/models/issue_query.rb
73 73
    options[:draw_progress_line] = (arg == '1' ? '1' : nil)
74 74
  end
75 75

  
76
  def draw_selected_columns
77
    r = options[:draw_selected_columns]
78
    r == '1'
79
  end
80

  
81
  def draw_selected_columns=(arg)
82
    options[:draw_selected_columns] = (arg == '1' ? '1' : nil)
83
  end
84

  
76 85
  def build_from_params(params, defaults={})
77 86
    super
78 87
    self.draw_relations = params[:draw_relations] || (params[:query] && params[:query][:draw_relations]) || options[:draw_relations]
79 88
    self.draw_progress_line = params[:draw_progress_line] || (params[:query] && params[:query][:draw_progress_line]) || options[:draw_progress_line]
89
    self.draw_selected_columns = params[:draw_selected_columns] || (params[:query] && params[:query][:draw_selected_columns]) || options[:draw_progress_line]
80 90
    self
81 91
  end
82 92

  
app/views/gantts/show.html.erb
24 24
    <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
25 25
    <div style="display: none;">
26 26
      <table>
27
        <tr>
28
          <td>
29
            <fieldset>
30
              <legend>
31
                <%= l(:field_column_names) %>
32
              </legend>
33
              <label for="draw_selected_columns">
34
                <%= check_box 'query', 'draw_selected_columns', :id => 'draw_selected_columns' %>
35
                  <%= l(:label_display) %>
36
              </label>
37
              <%= render_query_columns_selection(@query) %>
38
            </fieldset>
39
          </td>
40
        </tr>
27 41
        <tr>
28 42
          <td>
29 43
            <fieldset>
......
71 85
                       :class => 'icon icon-checked' %>
72 86
  <%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 },
73 87
              :class => 'icon icon-reload' %>
74
  <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
75
    <%= link_to_function l(:button_save),
76
                         "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }').submit();",
77
                         :class => 'icon icon-save' %>
88
  <% if @query.new_record? %>
89
    <% if User.current.allowed_to?(:save_queries, @project, :global => true) %>
90
      <%= link_to_function l(:button_save),
91
                           "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }').submit();",
92
                           :class => 'icon icon-save' %>
93
    <% end %>
94
  <% else %>
95
    <% if @query.editable_by?(User.current) %>
96
      <%= link_to l(:button_edit), edit_query_path(@query, :gantt => 1), :class => 'icon icon-edit' %>
97
      <%= delete_link query_path(@query, :gantt => 1) %>
98
    <% end %>
78 99
  <% end %>
79 100
<% if !@query.new_record? && @query.editable_by?(User.current) %>
80 101
  <%= link_to l(:button_edit), edit_query_path(@query, :gantt => 1), :class => 'icon icon-edit' %>
......
92 113

  
93 114
  subject_width = 330
94 115
  header_height = 18
116
  selected_column_width = 50
95 117

  
96 118
  headers_height = header_height
97 119
  show_weeks = false
......
157 179
    <% end %>
158 180
  <% end %>
159 181
</td>
160

  
161
<td>
182
<% @query.columns.each do |column| %>
183
  <% next if Redmine::Helpers::Gantt::UNAVAILABLE_COLUMNS.include?(column.name) %>
184
  <td style="width:<%= selected_column_width %>px; padding:0px;" class="gantt_<%= column.name %>_column gantt_selected_column" id="<%= column.name %>">
185
    <%
186
      style = "position:relative;"
187
      style += "height: #{t_height + 24}px;"
188
      style += "width: #{selected_column_width + 1}px;"
189
    %>
190
    <%= content_tag(:div, :style => style, :class => "gantt_#{column.name}_container") do %>
191
      <%
192
        style = "width: #{selected_column_width}px;"
193
        style += "height: #{t_height}px;"
194
        style += 'border-left: 0px;'
195
        style += 'overflow: hidden;'
196
      %>
197
      <%= content_tag(:div, '', :style => style, :class => "gantt_hdr") %>
198
      <%
199
        style = "width: #{selected_column_width}px;"
200
        style += "height: #{headers_height}px;"
201
        style += 'background: #eee;'
202
        style += 'border-left: 0px !important;'
203
      %>
204
      <%= content_tag(:div, content_tag(:p, column.caption, :class => 'gantt_hdr_selected_column_name'), :style => style, :class => "gantt_hdr") %>
205
      <%= content_tag(:div, :class => "gantt_#{column.name} gantt_selected_column_content") do %>
206
        <%= @gantt.selected_column_content({:column => column, :top => headers_height + 8, :zoom => zoom, :g_width => g_width}).html_safe %>
207
      <% end %>
208
    <% end %>
209
  </td>
210
<% end %>
211
<td style='padding: 0px;'>
162 212
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;" id="gantt_area">
163 213
<%
164 214
  style  = ""
......
371 421
<%= javascript_tag do %>
372 422
  var issue_relation_type = <%= raw Redmine::Helpers::Gantt::DRAW_TYPES.to_json %>;
373 423
  $(function() {
424
    disable_unavailable_columns('<%= Redmine::Helpers::Gantt::UNAVAILABLE_COLUMNS.map{|column| column.to_s }.join(',') %>'.split(','));
374 425
    drawGanttHandler();
375 426
    resizableSubjectColumn();
376
    $("#draw_relations").change(drawGanttHandler);
377
    $("#draw_progress_line").change(drawGanttHandler);
427
    drawSelectedColumns();
428
    $("#draw_relations, #draw_progress_line, #draw_selected_columns").change(drawGanttHandler);
378 429
  });
379 430
  $(window).resize(function() {
380 431
    drawGanttHandler();
app/views/queries/_form.html.erb
22 22
<p><label for="query_is_for_all"><%=l(:field_is_for_all)%></label>
23 23
<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, :class => (User.current.admin? ? '' : 'disable-unless-private') %></p>
24 24

  
25
<% unless params[:gantt] %>
26 25
<fieldset id="options"><legend><%= l(:label_options) %></legend>
27 26
<p><label for="query_default_columns"><%=l(:label_default_columns)%></label>
28 27
<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns',
29 28
      :data => {:disables => "#columns, .block_columns input"} %></p>
30 29

  
30
<% unless params[:gantt] %>
31 31
<p><label for="query_group_by"><%= l(:field_group_by) %></label>
32 32
<%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p>
33 33

  
......
36 36

  
37 37
<p><label><%= l(:label_total_plural) %></label>
38 38
<%= available_totalable_columns_tags(@query) %></p>
39
</fieldset>
40 39
<% else %>
41
<fieldset id="options"><legend><%= l(:label_options) %></legend>
42 40
  <p><label><%= l(:button_show) %></label>
43 41
  <label class="inline"><%= check_box_tag "query[draw_relations]", "1", @query.draw_relations %> <%= l(:label_related_issues) %></label>
44 42
  <label class="inline"><%= check_box_tag "query[draw_progress_line]", "1", @query.draw_progress_line %> <%= l(:label_gantt_progress_line) %></label>
43
  <label class="inline"><%= check_box_tag "query[draw_selected_columns]", "1", @query.draw_selected_columns %> <%= l(:label_gantt_selected_columns) %></label>
45 44
  </p>
46
</fieldset>
47 45
<% end %>
46
</fieldset>
48 47
</div>
49 48

  
50 49
<fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend>
......
70 69
</fieldset>
71 70
<% end %>
72 71

  
73
<% unless params[:gantt] %>
74 72
<%= content_tag 'fieldset', :id => 'columns' do %>
75 73
<legend><%= l(:field_column_names) %></legend>
76 74
<%= render_query_columns_selection(query) %>
77 75
<% end %>
78
<% end %>
79 76

  
80 77
</div>
81 78

  
config/locales/en.yml
1032 1032
  label_font_proportional: Proportional font
1033 1033
  label_last_notes: Last notes
1034 1034
  label_nothing_to_preview: Nothing to preview
1035
  label_gantt_selected_columns: Selected columns
1035 1036

  
1036 1037
  button_login: Login
1037 1038
  button_submit: Submit
lib/redmine/helpers/gantt.rb
32 32
        IssueRelation::TYPE_PRECEDES => { :landscape_margin => 20, :color => '#628FEA' }
33 33
      }.freeze
34 34

  
35
      UNAVAILABLE_COLUMNS = [:id, :subject]
36

  
35 37
      # Some utility methods for the PDF export
36 38
      # @private
37 39
      class PDF
......
76 78
        @date_to = (@date_from >> @months) - 1
77 79
        @subjects = ''
78 80
        @lines = ''
81
        @columns = {}
79 82
        @number_of_rows = nil
80 83
        @truncated = false
81 84
        if options.has_key?(:max_rows)
......
135 138
        @lines
136 139
      end
137 140

  
141
      # Renders the selected column of the Gantt chart, the right side of subjects.
142
      def selected_column_content(options={})
143
        render(options.merge(:only => :selected_columns)) unless @columns.has_key?(options[:column].name)
144
        @columns[options[:column].name]
145
      end
146

  
138 147
      # Returns issues that will be rendered
139 148
      def issues
140 149
        @issues ||= @query.issues(
......
196 205
                   :indent_increment => 20, :render => :subject,
197 206
                   :format => :html}.merge(options)
198 207
        indent = options[:indent] || 4
199
        @subjects = '' unless options[:only] == :lines
200
        @lines = '' unless options[:only] == :subjects
208
        @subjects = '' unless options[:only] == :lines || options[:only] == :selected_columns
209
        @lines = '' unless options[:only] == :subjects || options[:only] == :selected_columns
210
        @columns[options[:column].name] = '' if options[:only] == :selected_columns && @columns.has_key?(options[:column]) == false
201 211
        @number_of_rows = 0
202 212
        begin
203 213
          Project.project_tree(projects) do |project, level|
......
207 217
        rescue MaxLinesLimitReached
208 218
          @truncated = true
209 219
        end
210
        @subjects_rendered = true unless options[:only] == :lines
211
        @lines_rendered = true unless options[:only] == :subjects
220
        @subjects_rendered = true unless options[:only] == :lines || options[:only] == :selected_columns
221
        @lines_rendered = true unless options[:only] == :subjects || options[:only] == :selected_columns
212 222
        render_end(options)
213 223
      end
214 224

  
......
254 264

  
255 265
      def render_object_row(object, options)
256 266
        class_name = object.class.name.downcase
257
        send("subject_for_#{class_name}", object, options) unless options[:only] == :lines
258
        send("line_for_#{class_name}", object, options) unless options[:only] == :subjects
267
        send("subject_for_#{class_name}", object, options) unless options[:only] == :lines || options[:only] == :selected_columns
268
        send("line_for_#{class_name}", object, options) unless options[:only] == :subjects || options[:only] == :selected_columns
269
        column_content_for_issue(object, options) if options[:only] == :selected_columns && options[:column].present? && object.is_a?(Issue)
259 270
        options[:top] += options[:top_increment]
260 271
        @number_of_rows += 1
261 272
        if @max_rows && @number_of_rows >= @max_rows
......
323 334
        end
324 335
      end
325 336

  
337
      def column_content_for_issue(issue, options)
338
        if options[:format] == :html
339
          style = "position: absolute;top: #{options[:top]}px; font-size: 0.8em;"
340
          content = view.content_tag(:div, view.column_content(options[:column], issue), :style => style, :class => "issue_#{options[:column].name}", :id => "#{options[:column].name}_issue_#{issue.id}")
341
          @columns[options[:column].name] << content if @columns.has_key?(options[:column].name)
342
          content
343
        end
344
      end
345

  
326 346
      def subject(label, options, object=nil)
327 347
        send "#{options[:format]}_subject", options, label, object
328 348
      end
public/javascripts/gantt.js
161 161
  }
162 162
}
163 163

  
164
function drawSelectedColumns(){
165
  if ($("#draw_selected_columns").prop('checked')) {
166
    if(isMobile()) {
167
      $('td.gantt_selected_column').each(function(i) {
168
        $(this).hide();
169
      });
170
    }else{
171
      $('#content').addClass("gantt_content");
172
      $('td.gantt_selected_column').each(function() {
173
        $(this).show();
174
        var column_name = $(this).attr('id');
175
        $(this).resizable({
176
          alsoResize: `.gantt_${column_name}_container, .gantt_${column_name}_container > .gantt_hdr`,
177
          minWidth: 20,
178
          handles: "e",
179
          create: function( event, ui ) {
180
            $(".ui-resizable-e").css("cursor","ew-resize");
181
          }
182
        }).on('resize', function (e) {
183
            e.stopPropagation();
184
        });
185
      });
186
    }
187
  }else{
188
    $('td.gantt_selected_column').each(function (i) {
189
      $(this).hide();
190
    });
191
  }
192
}
193

  
164 194
function drawGanttHandler() {
165 195
  var folder = document.getElementById('gantt_draw_area');
166 196
  if(draw_gantt != null)
......
168 198
  else
169 199
    draw_gantt = Raphael(folder);
170 200
  setDrawArea();
201
  drawSelectedColumns();
171 202
  if ($("#draw_progress_line").prop('checked'))
172 203
    drawGanttProgressLines();
173 204
  if ($("#draw_relations").prop('checked'))
......
195 226
    $('td.gantt_subjects_column').resizable('enable');
196 227
  };
197 228
}
229

  
230
function disable_unavailable_columns(unavailable_columns){
231
  $.each(unavailable_columns, function(index, value) {
232
    $('#available_c, #selected_c').children("[value='" + value + "']").prop('disabled', true);
233
  });
234
}
public/stylesheets/application.css
1193 1193

  
1194 1194
.gantt_hdr.nwday {background-color:#f1f1f1; color:#999;}
1195 1195

  
1196
.gantt_subjects { font-size: 0.8em; }
1197
.gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; }
1196
.gantt_subjects, .gantt_selected_column_content.gantt_hdr { font-size: 0.8em; }
1197
.gantt_subjects div, .gantt_selected_column_content div {
1198
  line-height: 16px;
1199
  height: 16px;
1200
  white-space: nowrap;
1201
  text-overflow: ellipsis;
1202
  overflow: hidden !important;
1203
  width: 100%;
1204
}
1198 1205
.gantt_subjects div.issue-subject:hover { background-color:#ffffdd; }
1206
.gantt_selected_column_content { padding-left: 3px; padding-right: 3px;}
1199 1207

  
1200 1208
.gantt_subjects .issue-subject img.icon-gravatar {
1201 1209
  margin: 2px 5px 0px 2px;
1202 1210
}
1211
.gantt_hdr_selected_column_name {
1212
  padding-top: 15px;
1213
  font-size: 0.8em;
1214
  white-space: nowrap;
1215
  text-overflow: ellipsis;
1216
  overflow: hidden;
1217
}
1218
.gantt_content {
1219
  overflow: scroll;
1220
}
1203 1221

  
1204 1222
.task {
1205 1223
  position: absolute;
test/functional/queries_controller_test.rb
293 293
          :query => {
294 294
            :name => "test_create_from_gantt",
295 295
            :draw_relations => '1',
296
            :draw_progress_line => '1'
296
            :draw_progress_line => '1',
297
            :draw_selected_columns => '1'
297 298
          }
298 299
        }
299 300
      assert_response 302
......
302 303
    assert_redirected_to "/issues/gantt?query_id=#{query.id}"
303 304
    assert_equal true, query.draw_relations
304 305
    assert_equal true, query.draw_progress_line
306
    assert_equal true, query.draw_selected_columns
305 307
  end
306 308

  
307 309
  def test_create_project_query_from_gantt
......
319 321
          :query => {
320 322
            :name => "test_create_from_gantt",
321 323
            :draw_relations => '0',
322
            :draw_progress_line => '0'
324
            :draw_progress_line => '0',
325
            :draw_selected_columns => '0'
323 326
          }
324 327
        }
325 328
      assert_response 302
......
328 331
    assert_redirected_to "/projects/ecookbook/issues/gantt?query_id=#{query.id}"
329 332
    assert_equal false, query.draw_relations
330 333
    assert_equal false, query.draw_progress_line
334
    assert_equal false, query.draw_selected_columns
331 335
  end
332 336

  
333 337
  def test_create_project_public_query_should_force_private_without_manage_public_queries_permission
test/unit/lib/redmine/helpers/gantt_test.rb
23 23

  
24 24
  include ProjectsHelper
25 25
  include IssuesHelper
26
  include QueriesHelper
26 27
  include ERB::Util
27 28
  include Rails.application.routes.url_helpers
28 29

  
......
237 238
    assert_select "div.tooltip", /#{@issue.subject}/
238 239
  end
239 240

  
241
  test "#selected_column_content" do
242
    create_gantt
243
    issue = Issue.generate!
244
    @gantt.query.column_names = [:assigned_to]
245
    issue.update(:assigned_to_id => issue.assignable_users.first.id)
246
    @project.issues << issue
247
    # :column => assigned_to
248
    @output_buffer = @gantt.selected_column_content({ :column => @gantt.query.columns.last })
249
    assert_select "div.issue_assigned_to#assigned_to_issue_#{issue.id}"
250
  end
251

  
240 252
  test "#subject_for_project" do
241 253
    create_gantt
242 254
    @output_buffer = @gantt.subject_for_project(@project, :format => :html)
......
432 444
    assert_select "div.label", :text => 'line'
433 445
  end
434 446

  
447
  test "#column_content_for_issue" do
448
    create_gantt
449
    @gantt.query.column_names = [:assigned_to]
450
    issue = Issue.generate!
451
    issue.update(:assigned_to_id => issue.assignable_users.first.id)
452
    @project.issues << issue
453
    # :column => assigned_to
454
    options = { :column => @gantt.query.columns.last, :top => 64, :format => :html }
455
    @output_buffer = @gantt.column_content_for_issue(issue, options)
456

  
457
    assert_select "div.issue_assigned_to#assigned_to_issue_#{issue.id}"
458
    assert_includes @output_buffer, column_content(options[:column], issue)
459
  end
460

  
435 461
  def test_sort_issues_no_date
436 462
    project = Project.generate!
437 463
    issue1 = Issue.generate!(:subject => "test", :project => project)
(6-6/14)