diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb index 9b9b87cc9f..4db7edce4d 100644 --- a/app/models/issue_query.rb +++ b/app/models/issue_query.rb @@ -73,10 +73,20 @@ class IssueQuery < Query options[:draw_progress_line] = (arg == '1' ? '1' : nil) end + def draw_selected_columns + r = options[:draw_selected_columns] + r == '1' + end + + def draw_selected_columns=(arg) + options[:draw_selected_columns] = (arg == '1' ? '1' : nil) + end + def build_from_params(params, defaults={}) super self.draw_relations = params[:draw_relations] || (params[:query] && params[:query][:draw_relations]) || options[:draw_relations] self.draw_progress_line = params[:draw_progress_line] || (params[:query] && params[:query][:draw_progress_line]) || options[:draw_progress_line] + self.draw_selected_columns = params[:draw_selected_columns] || (params[:query] && params[:query][:draw_selected_columns]) || options[:draw_progress_line] self end diff --git a/app/views/gantts/show.html.erb b/app/views/gantts/show.html.erb index 90f6a85fa6..e82d65980d 100644 --- a/app/views/gantts/show.html.erb +++ b/app/views/gantts/show.html.erb @@ -24,6 +24,20 @@
+ + | +|||
- - | +<% @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 %> + | +<% end %> +
<%
style = ""
@@ -371,10 +421,11 @@
<%= 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);
- $("#draw_progress_line").change(drawGanttHandler);
+ drawSelectedColumns();
+ $("#draw_relations, #draw_progress_line, #draw_selected_columns").change(drawGanttHandler);
});
$(window).resize(function() {
drawGanttHandler();
diff --git a/app/views/queries/_form.html.erb b/app/views/queries/_form.html.erb
index f424e103cd..ff94e58c69 100644
--- a/app/views/queries/_form.html.erb
+++ b/app/views/queries/_form.html.erb
@@ -22,12 +22,12 @@
<% end %>
-<% unless params[:gantt] %>
<%= content_tag 'fieldset', :id => 'columns' do %>
<%= render_query_columns_selection(query) %>
<% end %>
-<% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 36d2099c8b..233047db61 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1032,6 +1032,7 @@ en:
label_font_proportional: Proportional font
label_last_notes: Last notes
label_nothing_to_preview: Nothing to preview
+ label_gantt_selected_columns: Selected columns
button_login: Login
button_submit: Submit
diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb
index 312a3133a4..d69b4936ea 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]
+
# Some utility methods for the PDF export
# @private
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 2e71178b0f..60f02b298c 100644
--- a/public/javascripts/gantt.js
+++ b/public/javascripts/gantt.js
@@ -161,6 +161,36 @@ function drawGanttProgressLines() {
}
}
+function drawSelectedColumns(){
+ if ($("#draw_selected_columns").prop('checked')) {
+ 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();
+ });
+ });
+ }
+ }else{
+ $('td.gantt_selected_column').each(function (i) {
+ $(this).hide();
+ });
+ }
+}
+
function drawGanttHandler() {
var folder = document.getElementById('gantt_draw_area');
if(draw_gantt != null)
@@ -168,6 +198,7 @@ function drawGanttHandler() {
else
draw_gantt = Raphael(folder);
setDrawArea();
+ drawSelectedColumns();
if ($("#draw_progress_line").prop('checked'))
drawGanttProgressLines();
if ($("#draw_relations").prop('checked'))
@@ -195,3 +226,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 19fb90f586..79a88da086 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -1193,13 +1193,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/functional/queries_controller_test.rb b/test/functional/queries_controller_test.rb
index 9b094ab979..af53805aa9 100644
--- a/test/functional/queries_controller_test.rb
+++ b/test/functional/queries_controller_test.rb
@@ -293,7 +293,8 @@ class QueriesControllerTest < Redmine::ControllerTest
:query => {
:name => "test_create_from_gantt",
:draw_relations => '1',
- :draw_progress_line => '1'
+ :draw_progress_line => '1',
+ :draw_selected_columns => '1'
}
}
assert_response 302
@@ -302,6 +303,7 @@ class QueriesControllerTest < Redmine::ControllerTest
assert_redirected_to "/issues/gantt?query_id=#{query.id}"
assert_equal true, query.draw_relations
assert_equal true, query.draw_progress_line
+ assert_equal true, query.draw_selected_columns
end
def test_create_project_query_from_gantt
@@ -319,7 +321,8 @@ class QueriesControllerTest < Redmine::ControllerTest
:query => {
:name => "test_create_from_gantt",
:draw_relations => '0',
- :draw_progress_line => '0'
+ :draw_progress_line => '0',
+ :draw_selected_columns => '0'
}
}
assert_response 302
@@ -328,6 +331,7 @@ class QueriesControllerTest < Redmine::ControllerTest
assert_redirected_to "/projects/ecookbook/issues/gantt?query_id=#{query.id}"
assert_equal false, query.draw_relations
assert_equal false, query.draw_progress_line
+ assert_equal false, query.draw_selected_columns
end
def test_create_project_public_query_should_force_private_without_manage_public_queries_permission
diff --git a/test/unit/lib/redmine/helpers/gantt_test.rb b/test/unit/lib/redmine/helpers/gantt_test.rb
index 351f9c0376..478c5ba1da 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)
@@ -432,6 +444,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)
<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, :class => (User.current.admin? ? '' : 'disable-unless-private') %> -<% unless params[:gantt] %> <% else %> - <% end %> + |