From 44751403168acece5b03ba5b2a711d989a4b93cb Mon Sep 17 00:00:00 2001 From: ishikawa Date: Wed, 31 Jan 2018 09:26:34 +0900 Subject: [PATCH 1/2] Show selected columns on gantt --- app/views/gantts/show.html.erb | 44 +++++++++++++++++++++++++++-- lib/redmine/helpers/gantt.rb | 32 +++++++++++++++++---- public/javascripts/gantt.js | 31 ++++++++++++++++++++ public/stylesheets/application.css | 22 +++++++++++++-- test/unit/lib/redmine/helpers/gantt_test.rb | 26 +++++++++++++++++ 5 files changed, 145 insertions(+), 10 deletions(-) diff --git a/app/views/gantts/show.html.erb b/app/views/gantts/show.html.erb index 6e5651fae..6a5b6b641 100644 --- a/app/views/gantts/show.html.erb +++ b/app/views/gantts/show.html.erb @@ -28,6 +28,16 @@ <%= l(:label_options) %>
+ + + - - +<% end %> +
+
+ + <%= l(:field_column_names) %> + + <%= render_query_columns_selection(@query) %> +
+
@@ -92,6 +102,7 @@ subject_width = 330 header_height = 18 + selected_column_width = 50 headers_height = header_height show_weeks = false @@ -157,8 +168,36 @@ <% end %> <% end %>
+<% @query.columns.each do |column| %> + <% next if Redmine::Helpers::Gantt::UNAVAILABLE_COLUMNS.include?(column.name) %> + + <% + style = "position:relative;" + style += "height: #{t_height + 24}px;" + style += "width: #{selected_column_width + 1}px;" + %> + <%= content_tag(:div, :style => style, :class => "gantt_#{column.name}_container") do %> + <% + style = "width: #{selected_column_width}px;" + style += "height: #{t_height}px;" + style += 'border-left: 0px;' + style += 'overflow: hidden;' + %> + <%= content_tag(:div, '', :style => style, :class => "gantt_hdr") %> + <% + style = "width: #{selected_column_width}px;" + style += "height: #{headers_height}px;" + style += 'background: #eee;' + style += 'border-left: 0px !important;' + %> + <%= content_tag(:div, content_tag(:p, column.caption, :class => 'gantt_hdr_selected_column_name'), :style => style, :class => "gantt_hdr") %> + <%= content_tag(:div, :class => "gantt_#{column.name} gantt_selected_column_content") do %> + <%= @gantt.selected_column_content({:column => column, :top => headers_height + 8, :zoom => zoom, :g_width => g_width}).html_safe %> + <% end %> + <% end %> +
<% style = "" @@ -371,6 +410,7 @@ <%= javascript_tag do %> var issue_relation_type = <%= raw Redmine::Helpers::Gantt::DRAW_TYPES.to_json %>; $(function() { + disable_unavailable_columns('<%= Redmine::Helpers::Gantt::UNAVAILABLE_COLUMNS.map{|column| column.to_s }.join(',') %>'.split(',')); drawGanttHandler(); resizableSubjectColumn(); $("#draw_relations").change(drawGanttHandler); diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb index c0b1f3148..02d72e9a6 100644 --- a/lib/redmine/helpers/gantt.rb +++ b/lib/redmine/helpers/gantt.rb @@ -32,6 +32,8 @@ module Redmine IssueRelation::TYPE_PRECEDES => { :landscape_margin => 20, :color => '#628FEA' } }.freeze + UNAVAILABLE_COLUMNS = [:id, :subject] + # :nodoc: # Some utility methods for the PDF export class PDF @@ -76,6 +78,7 @@ module Redmine @date_to = (@date_from >> @months) - 1 @subjects = '' @lines = '' + @columns = {} @number_of_rows = nil @truncated = false if options.has_key?(:max_rows) @@ -135,6 +138,12 @@ module Redmine @lines end + # Renders the selected column of the Gantt chart, the right side of subjects. + def selected_column_content(options={}) + render(options.merge(:only => :selected_columns)) unless @columns.has_key?(options[:column].name) + @columns[options[:column].name] + end + # Returns issues that will be rendered def issues @issues ||= @query.issues( @@ -196,8 +205,9 @@ module Redmine :indent_increment => 20, :render => :subject, :format => :html}.merge(options) indent = options[:indent] || 4 - @subjects = '' unless options[:only] == :lines - @lines = '' unless options[:only] == :subjects + @subjects = '' unless options[:only] == :lines || options[:only] == :selected_columns + @lines = '' unless options[:only] == :subjects || options[:only] == :selected_columns + @columns[options[:column].name] = '' if options[:only] == :selected_columns && @columns.has_key?(options[:column]) == false @number_of_rows = 0 begin Project.project_tree(projects) do |project, level| @@ -207,8 +217,8 @@ module Redmine rescue MaxLinesLimitReached @truncated = true end - @subjects_rendered = true unless options[:only] == :lines - @lines_rendered = true unless options[:only] == :subjects + @subjects_rendered = true unless options[:only] == :lines || options[:only] == :selected_columns + @lines_rendered = true unless options[:only] == :subjects || options[:only] == :selected_columns render_end(options) end @@ -254,8 +264,9 @@ module Redmine def render_object_row(object, options) class_name = object.class.name.downcase - send("subject_for_#{class_name}", object, options) unless options[:only] == :lines - send("line_for_#{class_name}", object, options) unless options[:only] == :subjects + send("subject_for_#{class_name}", object, options) unless options[:only] == :lines || options[:only] == :selected_columns + send("line_for_#{class_name}", object, options) unless options[:only] == :subjects || options[:only] == :selected_columns + column_content_for_issue(object, options) if options[:only] == :selected_columns && options[:column].present? && object.is_a?(Issue) options[:top] += options[:top_increment] @number_of_rows += 1 if @max_rows && @number_of_rows >= @max_rows @@ -323,6 +334,15 @@ module Redmine end end + def column_content_for_issue(issue, options) + if options[:format] == :html + style = "position: absolute;top: #{options[:top]}px; font-size: 0.8em;" + 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}") + @columns[options[:column].name] << content if @columns.has_key?(options[:column].name) + content + end + end + def subject(label, options, object=nil) send "#{options[:format]}_subject", options, label, object end diff --git a/public/javascripts/gantt.js b/public/javascripts/gantt.js index 2e71178b0..17a192970 100644 --- a/public/javascripts/gantt.js +++ b/public/javascripts/gantt.js @@ -161,6 +161,30 @@ function drawGanttProgressLines() { } } +function drawSelectedColumns(){ + if(isMobile()) { + $('td.gantt_selected_column').each(function(i) { + $(this).hide(); + }); + }else{ + $('#content').addClass("gantt_content"); + $('td.gantt_selected_column').each(function() { + $(this).show(); + var column_name = $(this).attr('id'); + $(this).resizable({ + alsoResize: `.gantt_${column_name}_container, .gantt_${column_name}_container > .gantt_hdr`, + minWidth: 20, + handles: "e", + create: function( event, ui ) { + $(".ui-resizable-e").css("cursor","ew-resize"); + } + }).on('resize', function (e) { + e.stopPropagation(); + }); + }); + } +} + function drawGanttHandler() { var folder = document.getElementById('gantt_draw_area'); if(draw_gantt != null) @@ -168,6 +192,7 @@ function drawGanttHandler() { else draw_gantt = Raphael(folder); setDrawArea(); + drawSelectedColumns(); if ($("#draw_progress_line").prop('checked')) drawGanttProgressLines(); if ($("#draw_relations").prop('checked')) @@ -195,3 +220,9 @@ function resizableSubjectColumn(){ $('td.gantt_subjects_column').resizable('enable'); }; } + +function disable_unavailable_columns(unavailable_columns){ + $.each(unavailable_columns, function(index, value) { + $('#available_c, #selected_c').children("[value='" + value + "']").prop('disabled', true); + }); +} diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 48bcbf9bc..4593a9a0d 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -1169,13 +1169,31 @@ div.wiki img {vertical-align:middle; max-width:100%;} .gantt_hdr.nwday {background-color:#f1f1f1; color:#999;} -.gantt_subjects { font-size: 0.8em; } -.gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } +.gantt_subjects, .gantt_selected_column_content.gantt_hdr { font-size: 0.8em; } +.gantt_subjects div, .gantt_selected_column_content div { + line-height: 16px; + height: 16px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden !important; + width: 100%; +} .gantt_subjects div.issue-subject:hover { background-color:#ffffdd; } +.gantt_selected_column_content { padding-left: 3px; padding-right: 3px;} .gantt_subjects .issue-subject img.icon-gravatar { margin: 2px 5px 0px 2px; } +.gantt_hdr_selected_column_name { + padding-top: 15px; + font-size: 0.8em; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} +.gantt_content { + overflow: scroll; +} .task { position: absolute; diff --git a/test/unit/lib/redmine/helpers/gantt_test.rb b/test/unit/lib/redmine/helpers/gantt_test.rb index 1dd825d2c..a05967b76 100644 --- a/test/unit/lib/redmine/helpers/gantt_test.rb +++ b/test/unit/lib/redmine/helpers/gantt_test.rb @@ -23,6 +23,7 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest include ProjectsHelper include IssuesHelper + include QueriesHelper include ERB::Util include Rails.application.routes.url_helpers @@ -237,6 +238,17 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest assert_select "div.tooltip", /#{@issue.subject}/ end + test "#selected_column_content" do + create_gantt + issue = Issue.generate! + @gantt.query.column_names = [:assigned_to] + issue.update(:assigned_to_id => issue.assignable_users.first.id) + @project.issues << issue + # :column => assigned_to + @output_buffer = @gantt.selected_column_content({ :column => @gantt.query.columns.last }) + assert_select "div.issue_assigned_to#assigned_to_issue_#{issue.id}" + end + test "#subject_for_project" do create_gantt @output_buffer = @gantt.subject_for_project(@project, :format => :html) @@ -418,6 +430,20 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest assert_select "div.label", :text => 'line' end + test "#column_content_for_issue" do + create_gantt + @gantt.query.column_names = [:assigned_to] + issue = Issue.generate! + issue.update(:assigned_to_id => issue.assignable_users.first.id) + @project.issues << issue + # :column => assigned_to + options = { :column => @gantt.query.columns.last, :top => 64, :format => :html } + @output_buffer = @gantt.column_content_for_issue(issue, options) + + assert_select "div.issue_assigned_to#assigned_to_issue_#{issue.id}" + assert_includes @output_buffer, column_content(options[:column], issue) + end + def test_sort_issues_no_date project = Project.generate! issue1 = Issue.generate!(:subject => "test", :project => project) -- 2.14.3 (Apple Git-98)