Initialization
This commit is contained in:
commit
94bb6e67f6
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Hugo Zilliox
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# redmine_issue_dynamic_edit
|
||||||
|
|
||||||
|
Add new dropdowns elements on detailed issue page to dynamically update issue's status, assignee and priority directly in the details block of the issue
|
||||||
|
You have to enable Redmine REST API
|
||||||
4
README.rdoc
Normal file
4
README.rdoc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
= redmine_issue_dynamic_edit
|
||||||
|
|
||||||
|
Add new dropdowns elements on detailed issue page to dynamically update issue's status, assignee and priority directly in the details block of the issue
|
||||||
|
You have to enable Redmine REST API
|
||||||
84
assets/javascripts/issue_dynamic_edit.js
Normal file
84
assets/javascripts/issue_dynamic_edit.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
var cssId = 'fontAwesome';
|
||||||
|
if (!document.getElementById(cssId))
|
||||||
|
{
|
||||||
|
var head = document.getElementsByTagName('head')[0];
|
||||||
|
var link = document.createElement('link');
|
||||||
|
link.id = cssId;
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.type = 'text/css';
|
||||||
|
link.href = 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css';
|
||||||
|
link.media = 'all';
|
||||||
|
head.appendChild(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($('#statusListDropdown').length > 0) {
|
||||||
|
var htmlCopy = $('#statusListDropdown').get(0).outerHTML;
|
||||||
|
$('#statusListDropdown').remove();
|
||||||
|
$('.details .attributes .status.attribute .value').html(htmlCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($('#usersListDropdown').length > 0) {
|
||||||
|
var htmlCopy = $('#usersListDropdown').get(0).outerHTML;
|
||||||
|
$('#usersListDropdown').remove();
|
||||||
|
$('.details .attributes .assigned-to.attribute .value').html(htmlCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($('#prioritiesListDropdown').length > 0) {
|
||||||
|
var htmlCopy = $('#prioritiesListDropdown').get(0).outerHTML;
|
||||||
|
$('#prioritiesListDropdown').remove();
|
||||||
|
$('.details .attributes .priority.attribute .value').html(htmlCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDataIssue(field_name, field_value, cssClass) {
|
||||||
|
$('.details .attributes .' + cssClass + '.attribute .value').append(' <i class="fa fa-refresh fa-spin fa-fw"></i>');
|
||||||
|
ticketData = '<?xml version="1.0" encoding="UTF-8"?>';
|
||||||
|
ticketData += '<issue>';
|
||||||
|
ticketData += '<id>' + _ISSUE_ID + '</id>';
|
||||||
|
ticketData += '<' + field_name + '>'+ field_value +'</' + field_name + '>';
|
||||||
|
ticketData += '</issue>';
|
||||||
|
jQuery.ajax({
|
||||||
|
type: 'PUT',
|
||||||
|
url: '/issues/' + _ISSUE_ID + '.xml',
|
||||||
|
crossDomain: true,
|
||||||
|
async: false,
|
||||||
|
contentType: "application/xml",
|
||||||
|
data: ticketData,
|
||||||
|
beforeSend: function(xhr) {
|
||||||
|
xhr.setRequestHeader("X-Redmine-API-Key", _USER_API_KEY);
|
||||||
|
},
|
||||||
|
success: function(msg) {
|
||||||
|
setTimeout(function(){
|
||||||
|
$('.details .attributes .' + cssClass + '.attribute .value i.fa-spin').remove();
|
||||||
|
$('.details .attributes .' + cssClass + '.attribute .value').append(' <i class="fa fa-check"></i>');
|
||||||
|
setTimeout(function(){
|
||||||
|
$('.details .attributes .' + cssClass + '.attribute .value i.fa-check').remove();
|
||||||
|
}, 2000);
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
error: function(xhr, msg, error) {}
|
||||||
|
});
|
||||||
|
} /* end function updateDataIssue */
|
||||||
|
|
||||||
|
var domSelectStatus = $('body').find('#statusListDropdown select');
|
||||||
|
domSelectStatus.on('change', function(e){
|
||||||
|
updateDataIssue('status_id', domSelectStatus.val(), 'status');
|
||||||
|
}); /* end on change domSelectStatus */
|
||||||
|
|
||||||
|
var domSelectPriorities = $('body').find('#prioritiesListDropdown select');
|
||||||
|
domSelectPriorities.on('change', function(e){
|
||||||
|
updateDataIssue('priority_id', domSelectPriorities.val(), 'priority');
|
||||||
|
}); /* end on change domSelectPriorities */
|
||||||
|
|
||||||
|
var domSelectUsers = $('body').find('#usersListDropdown select');
|
||||||
|
domSelectUsers.on('change', function(e){
|
||||||
|
updateDataIssue('assigned_to_id', domSelectUsers.val(), 'assigned-to');
|
||||||
|
}); /* end on change domSelectUsers */
|
||||||
|
|
||||||
|
$('.details .attributes .attribute .value').on({
|
||||||
|
mouseenter: function () {
|
||||||
|
$(this).find('.fa-pencil').removeClass('fa-pencil').addClass('fa-angle-down');
|
||||||
|
},
|
||||||
|
mouseleave: function () {
|
||||||
|
$(this).find('.fa-angle-down').removeClass('fa-angle-down').addClass('fa-pencil');
|
||||||
|
}
|
||||||
|
});
|
||||||
31
assets/stylesheets/issue_dynamic_edit.css
Normal file
31
assets/stylesheets/issue_dynamic_edit.css
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.value .dynamicEditSelect select {
|
||||||
|
border-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
|
font-size: inherit;
|
||||||
|
color: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value:hover .dynamicEditSelect select {
|
||||||
|
border-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value .dynamicEditSelect {
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value .dynamicEditSelect i.dropdown {
|
||||||
|
position:absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
12
init.rb
Normal file
12
init.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
require 'redmine'
|
||||||
|
|
||||||
|
require 'details_issue_hooks'
|
||||||
|
|
||||||
|
Redmine::Plugin.register :redmine_issue_dynamic_edit do
|
||||||
|
name 'Redmine Dynamic edit Issue plugin'
|
||||||
|
author 'Hugo Zilliox'
|
||||||
|
description 'Allows users to dynamically update issue\'s status, assignee and priority in detailed view using REST API'
|
||||||
|
version '0.1.0'
|
||||||
|
url 'https://github.com/ilogeek/redmine_issue_dynamic_edit'
|
||||||
|
author_url 'https://hzilliox.fr'
|
||||||
|
end
|
||||||
76
lib/details_issue_hooks.rb
Normal file
76
lib/details_issue_hooks.rb
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
class DetailsIssueHooks < Redmine::Hook::ViewListener
|
||||||
|
|
||||||
|
def protect_against_forgery?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def view_layouts_base_html_head(context)
|
||||||
|
stylesheet_link_tag('issue_dynamic_edit.css', :plugin => :redmine_issue_dynamic_edit)
|
||||||
|
end
|
||||||
|
|
||||||
|
def view_layouts_base_body_bottom(context)
|
||||||
|
javascript_include_tag('issue_dynamic_edit.js', :plugin => :redmine_issue_dynamic_edit)
|
||||||
|
end
|
||||||
|
|
||||||
|
def view_issues_show_details_bottom(context = { })
|
||||||
|
project = context[:project]
|
||||||
|
request = context[:request]
|
||||||
|
issue_id = request.path_parameters[:id]
|
||||||
|
back = request.env['HTTP_REFERER']
|
||||||
|
|
||||||
|
if (issue_id)
|
||||||
|
issue = Issue.find(issue_id)
|
||||||
|
if (issue)
|
||||||
|
if (User.current.allowed_to?(:edit_issues, project))
|
||||||
|
o = ''
|
||||||
|
statuses = issue.new_statuses_allowed_to(User.current)
|
||||||
|
if (!statuses.empty?)
|
||||||
|
o << "<span class='dynamicEditSelect' id='statusListDropdown'><select data-issue='#{issue_id}'>"
|
||||||
|
statuses.each do |s|
|
||||||
|
if (s != issue.status)
|
||||||
|
o << "<option value='#{s.id}'>#{s.name}</option>"
|
||||||
|
else
|
||||||
|
o << "<option value='#{s.id}' selected>#{s.name}</option>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
o << "</select><i class=\"fa fa-pencil fa-fw dropdown\" aria-hidden=\"true\"></i></span>"
|
||||||
|
end
|
||||||
|
assignables = project.assignable_users
|
||||||
|
if (!assignables.empty?)
|
||||||
|
o << "<span class='dynamicEditSelect' id='usersListDropdown'><select data-issue='#{issue_id}'>"
|
||||||
|
assignables.each do |u|
|
||||||
|
if (u != issue.assigned_to)
|
||||||
|
o << "<option value='#{u.id}'>#{u.name}</option>"
|
||||||
|
else
|
||||||
|
o << "<option value='#{u.id}' selected>#{u.name}</option>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
o << "</select><i class=\"fa fa-pencil fa-fw dropdown\" aria-hidden=\"true\"></i></span>"
|
||||||
|
end
|
||||||
|
|
||||||
|
priorities = IssuePriority.all
|
||||||
|
if(!priorities.empty?)
|
||||||
|
o << "<span class='dynamicEditSelect' id='prioritiesListDropdown'><select data-issue='#{issue_id}'>"
|
||||||
|
priorities.each do |p|
|
||||||
|
if (p != issue.priority)
|
||||||
|
o << "<option value='#{p.id}'>#{p.name}</option>"
|
||||||
|
else
|
||||||
|
o << "<option value='#{p.id}' selected>#{p.name}</option>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
o << "</select><i class=\"fa fa-pencil fa-fw dropdown\" aria-hidden=\"true\"></i></span>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
o << "<script>"
|
||||||
|
|
||||||
|
o << " var _ISSUE_ID = \"#{issue_id}\";"
|
||||||
|
o << " var _USER_API_KEY = \"#{User.current.api_key}\";"
|
||||||
|
|
||||||
|
o << "</script>"
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
Loading…
x
Reference in New Issue
Block a user