Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support to Redmine 6.x and timetracking additions #60

Merged
merged 9 commits into from
Dec 28, 2024
15 changes: 11 additions & 4 deletions app/controllers/kanban_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
class KanbanController < ApplicationController
unloadable
if Redmine::VERSION::MAJOR < 4 || (Redmine::VERSION::MAJOR == 4 && Redmine::VERSION::MINOR < 1)
unloadable
end
before_action :global_authorize
#
# Display kanban board
Expand Down Expand Up @@ -261,7 +263,7 @@ def index
# Hide user without issues
if Constants::DISPLAY_USER_WITHOUT_ISSUES != 1 then
remove_user_without_issues
end
end
end

private
Expand All @@ -277,6 +279,7 @@ def discard_session
# Store session
#
def store_params_to_session

session_hash = {}
session_hash["updated_within"] = @updated_within
session_hash["done_within"] = @done_within
Expand All @@ -287,7 +290,7 @@ def store_params_to_session
session_hash["project_all"] = @project_all
session_hash["version_id"] = @version_id
session_hash["open_versions"] = @open_versions
session_hash["status_fields"] = @status_fields
session_hash["status_fields"] = @status_fields.to_json
session_hash["wip_max"] = @wip_max
session_hash["card_size"] = @card_size
session_hash["show_ancestors"] = @show_ancestors
Expand Down Expand Up @@ -365,7 +368,11 @@ def restore_params_from_session

# Selected statuses
if !session_hash.blank? && params[:status_fields].blank?
@status_fields = session_hash["status_fields"]
if !session_hash["status_fields"].blank?
@status_fields = JSON.parse( session_hash["status_fields"])
else
@status_fields = ""
end
else
@status_fields = params[:status_fields]
end
Expand Down
13 changes: 6 additions & 7 deletions app/models/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ class Constants < ActiveRecord::Base
# Limit selection strategy
# 0: No Limit
# 1: Limited by `SELECT_LIMIT` value
SELECT_LIMIT_STRATEGY = 1;
SELECT_LIMIT_STRATEGY = 0;
# Max number of selections
SELECT_LIMIT = 250

# Days since upadated date
# Please choose "1" "3" "7" "14" "31" "62" "93" "unspecified"
DEFAULT_VALUE_UPDATED_WITHIN = "31"
DEFAULT_VALUE_UPDATED_WITHIN = "62"

# Days since closed date
# Please choose "1" "3" "7" "14" "31" "62" "93" "unspecified"
Expand Down Expand Up @@ -57,11 +57,11 @@ class Constants < ActiveRecord::Base
# Display comment dialog when issue was dropped
# 0: Not display
# 1: Display
DISPLAY_COMMENT_DIALOG_WHEN_DROP = 1
DISPLAY_COMMENT_DIALOG_WHEN_DROP = 0

# Default Card Size
# Please choose "normal_days_left" "normal_estimated_hours" "small"
DEFAULT_CARD_SIZE = "normal_days_left"
DEFAULT_CARD_SIZE = "normal_estimated_hours"

# Default High Priority issue id
# Default is 3 to back compatibility
Expand All @@ -71,10 +71,9 @@ class Constants < ActiveRecord::Base
# Default Normal Priority issue id
# Default is 2 to back compatibility
# All issues == DEFAULT_HIGH_ DEFAULT_NORMAL_PRIORITY_ISSUE_ID will be seen as normal priority issues
DEFAULT_NORMAL_PRIORITY_ISSUE_ID = 2

DEFAULT_NORMAL_PRIORITY_ISSUE_ID = 4
# Default Show ancestors
# 0: Not display
# 1: Display
DEFAULT_SHOW_ANCESTORS = "1"
DEFAULT_SHOW_ANCESTORS = "1"
end
32 changes: 28 additions & 4 deletions app/views/kanban/_normal_card_spent_hours.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,37 @@
<% if issue.priority_id >= Constants::DEFAULT_HIGH_PRIORITY_ISSUE_ID then %> my-issue-card-high-priority <% elsif issue.priority_id == Constants::DEFAULT_NORMAL_PRIORITY_ISSUE_ID %> my-issue-card <% else %> my-issue-card-low-priority <% end %>">
<div style="float: right; font-size: smaller"><%= issue.project.name %></div>
<p><input type="checkbox" name="ids[]" value="<%= issue.id %>"> <%= issue.tracker.name %> #<%= issue.id %></p>

<% if @show_ancestors == "1" then %>
<%= render_issue_ancestors(issue) %>
<% end %>
<p><a href="./issues/<%= issue.id %>"><%= issue.subject %></a></p>
<hr>
<!-- Spent hours -->
<div style="float: right; font-size: smaller"><%= (issue.spent_hours || 0.0) %><%= I18n.t(:kanban_hours_abbreviation) %></div>
<!-- User name -->
<p id="user_name_issue-<%= issue.id %>"><% if issue.assigned_to != nil %><%= issue.assigned_to.name %><% else %>Not assigned<% end %></p>

<!-- Details container -->
<div style="display: flex; justify-content: space-between; align-items: center; font-size: smaller;">
<!-- Assignee -->
<p id="user_name_issue-<%= issue.id %>" style="margin: 0;">
<% if issue.assigned_to.present? %>
<%= issue.assigned_to.name %>
<% else %>
Not assigned
<% end %>
</p>

<!-- Hours details -->
<div>
<!-- Spent time -->
<div style="display: flex; align-items: center;">
<%= (issue.spent_hours || 0.0) %><%= I18n.t(:kanban_hours_abbreviation) %>
<%= link_to new_time_entry_path(issue_id: issue.id), class: 'icon-only icon-time', title: l(:label_spent_time) do %>
<i class="icon-time" style="margin-left: 5px;"></i>
<% end %>
</div>
<!-- Planned hours -->
<div>
(<%= (issue.estimated_hours || 0.0) %><%= I18n.t(:kanban_hours_abbreviation) %>)
</div>
</div>
</div>
</div>
23 changes: 14 additions & 9 deletions app/views/kanban/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
<!-- Javascript -->


<%= stylesheet_link_tag 'context_menu' %>
<%= javascript_include_tag 'context_menu' %>


<%= javascript_include_tag "jquery.floatThead", :plugin => "kanban" %>
<%= javascript_include_tag "hotkeys", :plugin => "kanban" %>
<%= javascript_include_tag "kanban", :plugin => "kanban" %>
<script>
var login_user_id = "<%= @current_user.id %>";
var label_recent_history_is_here = "<%= I18n.t(:kanban_label_recent_history_is_here) %>";
var label_add_notes = "<%= I18n.t(:kanban_label_add_notes) %>";
var option_display_comment_dialog_when_drop = "<%= Constants::DISPLAY_COMMENT_DIALOG_WHEN_DROP %>";
window.onload = function(){
$(window).scrollTop(<%= params[:scroll_top] %>);
window.onload = function(){
$(window).scrollTop(<%= params[:scroll_top] %>);
}

</script>
<script src="./javascripts/context_menu.js"></script>
<%= javascript_include_tag "jquery.floatThead", :plugin => "kanban" %>
<%= javascript_include_tag "hotkeys", :plugin => "kanban" %>
<%= javascript_include_tag "kanban", :plugin => "kanban" %>

<!-- CSS -->
<link rel="stylesheet" media="screen" href="./stylesheets/context_menu.css">
<%= stylesheet_link_tag 'kanban', :plugin => 'kanban' %>
<div class="contextual">
<% if @project_id.blank? != true then %>
Expand Down Expand Up @@ -199,14 +205,13 @@
</table>
</div>
</fieldset>
<!-- This is the part that opens and closes -->
<!-- This is the part that opens and closes -->
<fieldset id="lower_filters" class="collapsible collapsed">
<legend class="icon icon-collapsed" onclick="toggleFieldset(this);"><%= I18n.t(:kanban_label_fields) %></legend>
<div style="display: none;">
<table>
<tr>
<td>
<!-- checkboxes for status fields -->
<% @issue_statuses.each_with_index do |status,index| %>
<% if @status_fields_array.include?(status.id) then flag = true else flag = false end %>
<div style="float: left;">
Expand Down
46 changes: 20 additions & 26 deletions assets/javascripts/jquery.floatThead.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/** @preserve jQuery.floatThead 2.2.0 - https://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2019 Misha Koryak **/
/** @preserve jQuery.floatThead 2.2.5 - https://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2023 Misha Koryak **/
// @license MIT

/* @author Misha Koryak
* @projectDescription position:fixed on steroids. Lock a table header in place while scrolling.
*
* Dependencies:
* jquery 1.9.0 + [required] OR jquery 1.7.0 + jquery UI core
* jquery 1.9.0+ [required] OR jquery 1.7.0+ jquery UI core
*
* https://mkoryak.github.io/floatThead/
*
* Tested on FF13+, Chrome 21+, IE8, IE9, IE10, IE11
* Tested on FF13+, Chrome 21+, IE9, IE10, IE11, EDGE
*/
(function( $ ) {
/**
Expand Down Expand Up @@ -106,7 +106,6 @@

var globalCanObserveMutations = typeof MutationObserver !== 'undefined';


//browser stuff
var ieVersion = function(){for(var a=3,b=document.createElement("b"),c=b.all||[];a = 1+a,b.innerHTML="<!--[if gt IE "+ a +"]><i><![endif]-->",c[0];);return 4<a?a:document.documentMode}();
var isFF = /Gecko\//.test(navigator.userAgent);
Expand All @@ -120,11 +119,11 @@
//safari 7 (and perhaps others) reports table width to be parent container's width if max-width is set on table. see: https://github.com/mkoryak/floatThead/issues/108
var isTableWidthBug = function(){
if(isWebkit) {
var $test = $('<div>').css('width', 0).append(
var $test = $('<div>').css('width', '0').append(
$('<table>').css('max-width', '100%').append(
$('<tr>').append(
$('<th>').append(
$('<div>').css('min-width', 100).text('X')
$('<div>').css('min-width', '100px').text('X')
)
)
)
Expand Down Expand Up @@ -195,7 +194,6 @@
return $(parent);
}


function debug(str){
window && window.console && window.console.error && window.console.error("jQuery.floatThead: " + str);
}
Expand Down Expand Up @@ -350,8 +348,6 @@

var useAbsolutePositioning = null;



if (opts.position === 'auto') {
useAbsolutePositioning = null;
} else if (opts.position === 'fixed') {
Expand All @@ -373,8 +369,8 @@

var $fthGrp = $('<fthfoot>').css({
'display': 'table-footer-group',
'border-spacing': 0,
'height': 0,
'border-spacing': '0',
'height': '0',
'border-collapse': 'collapse',
'visibility': 'hidden'
});
Expand All @@ -393,8 +389,8 @@
var colSelector = existingColGroup ? "col:visible" : "col";
var $fthRow = $('<fthtr>').css({ //created unstyled elements (used for sizing the table because chrome can't read <col> width)
'display': 'table-row',
'border-spacing': 0,
'height': 0,
'border-spacing': '0',
'height': '0',
'border-collapse': 'collapse'
});
var $floatContainer = $('<div>').css(opts.floatContainerCss).attr('aria-hidden', 'true');
Expand Down Expand Up @@ -436,7 +432,7 @@
floatTableHidden = true;
}

$floatTable.addClass(opts.floatTableClass).css({'margin': 0, 'border-bottom-width': 0}); //must have no margins or you won't be able to click on things under floating table
$floatTable.addClass(opts.floatTableClass).css({'margin': '0', 'border-bottom-width': '0'}); //must have no margins or you won't be able to click on things under floating table

if(useAbsolutePositioning){
var makeRelative = function($container, alwaysWrap){
Expand Down Expand Up @@ -468,11 +464,10 @@
$table.before($floatContainer);
}


$floatContainer.css({
position: useAbsolutePositioning ? 'absolute' : 'fixed',
marginTop: 0,
top: useAbsolutePositioning ? 0 : 'auto',
marginTop: '0',
top: useAbsolutePositioning ? '0' : 'auto',
zIndex: opts.zIndex,
willChange: 'transform'
});
Expand Down Expand Up @@ -504,7 +499,6 @@
$sizerCells.outerHeight(headerHeight);
}


function setFloatWidth(){
var tw = tableWidth($table, $fthCells, true);
var $container = responsive ? $responsiveContainer : $scrollContainer;
Expand Down Expand Up @@ -544,14 +538,16 @@
$sizerRow.empty();
for(var x = 0; x < count; x++){
var cell = document.createElement('th');
cell.setAttribute('aria-label', opts.ariaLabel($table, $headerColumns.eq(x), x));
var span = document.createElement('span');
span.setAttribute('aria-label', opts.ariaLabel($table, $headerColumns.eq(x), x));
cell.appendChild(span);
cell.className = 'floatThead-col';
$sizerRow[0].appendChild(cell);
cols.push('<col/>');
psuedo.push(
$('<fthtd>').css({
'display': 'table-cell',
'height': 0,
'height': '0',
'width': 'auto'
})
);
Expand Down Expand Up @@ -795,7 +791,7 @@
triggerFloatEvent(false);
} else if(scrollingContainerTop - tableContainerGap > tableHeight - floatContainerHeight){
// scrolled past table but there is space in the container under it..
top = tableHeight - floatContainerHeight - scrollingContainerTop - tableContainerGap;
top = tableHeight - floatContainerHeight - scrollingContainerTop + tableContainerGap;
} else {
top = wrappedContainer ? tableTopGap : scrollingContainerTop;
//headers stop at the top of the viewport
Expand Down Expand Up @@ -869,8 +865,8 @@
'-ms-transform' : transform,
'-o-transform' : transform,
'transform' : transform,
'top': 0,
'left': 0,
'top': '0',
'left': '0',
};
$floatContainer.css(cssObj);
}
Expand Down Expand Up @@ -996,7 +992,6 @@
}
////// end printing stuff


if(locked){ //internal scrolling
if(useAbsolutePositioning){
$scrollContainer.on(eventName('scroll'), containerScrollEvent);
Expand Down Expand Up @@ -1027,7 +1022,6 @@
$window.on(eventName('tabsactivate'), reflowEvent); // same thing for jqueryui
}


if (canObserveMutations) {
var mutationElement = null;
if(util.isFunction(opts.autoReflow)){
Expand Down Expand Up @@ -1126,4 +1120,4 @@
$ = require('jquery');
}
return $;
})());
})());
10 changes: 8 additions & 2 deletions assets/javascripts/kanban.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
$(function() {

// Redraw table header
$('#upper_filters').on('click',function(){
$('#kanban_table').floatThead('reflow')
Expand All @@ -16,14 +17,19 @@ $(function() {
$('#sidebar').css({"cssText" : "padding : 0 8px 0px 8px !important"});

// Floating table header
$('#kanban_table').floatThead({zIndex: 39});
$('#kanban_table').floatThead({
responsiveContainer: function($table) {
return $table.closest('#content'); // Use the right container
},
zIndex: 39
});
//Moved from beginning of file so that float table loads after sidebar.
//Placing it here, after the sidebar fixes an issue with Kanban Board overflowing to end of page until reflow.

// Initial message when no note
var initial_string = "<table class=\"my-journal-table\"><tr><td>" + label_recent_history_is_here + "</td></tr></table>"
$('#sidebar').html(initial_string);

let timeout;
// When mouse over
$('[id^=issue-]').hover(function() {
var card = $(this);
Expand Down
9 changes: 9 additions & 0 deletions assets/stylesheets/kanban.css
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,12 @@
.context-menu-selection p {
color:rgb(184, 224, 244);
}

#kanban_table {
width: 100%;
table-layout: auto;
}

.floatThead-container {
width: 100% !important;
}