commit 94bb6e67f675a7554aad26ee2ae866fcf0f9393d Author: Hugo Zilliox Date: Wed Aug 2 17:27:52 2017 +0200 Initialization diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cd2df41 --- /dev/null +++ b/LICENSE @@ -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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9b2263e --- /dev/null +++ b/README.md @@ -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 \ No newline at end of file diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 0000000..6bce2f5 --- /dev/null +++ b/README.rdoc @@ -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 diff --git a/assets/javascripts/issue_dynamic_edit.js b/assets/javascripts/issue_dynamic_edit.js new file mode 100644 index 0000000..3c4ea9a --- /dev/null +++ b/assets/javascripts/issue_dynamic_edit.js @@ -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(' '); + ticketData = ''; + ticketData += ''; + ticketData += '' + _ISSUE_ID + ''; + ticketData += '<' + field_name + '>'+ field_value +''; + ticketData += ''; + 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(' '); + 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'); + } + }); \ No newline at end of file diff --git a/assets/stylesheets/issue_dynamic_edit.css b/assets/stylesheets/issue_dynamic_edit.css new file mode 100644 index 0000000..bcfe308 --- /dev/null +++ b/assets/stylesheets/issue_dynamic_edit.css @@ -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; +} \ No newline at end of file diff --git a/init.rb b/init.rb new file mode 100644 index 0000000..8d10425 --- /dev/null +++ b/init.rb @@ -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 diff --git a/lib/details_issue_hooks.rb b/lib/details_issue_hooks.rb new file mode 100644 index 0000000..339c124 --- /dev/null +++ b/lib/details_issue_hooks.rb @@ -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 << "" + end + assignables = project.assignable_users + if (!assignables.empty?) + o << "" + end + + priorities = IssuePriority.all + if(!priorities.empty?) + o << "" + end + end + end + + o << "" + return o + end + end + +end