Plugin: how to add button on issue list?
Added by Stéphane CHÂTEAU over 5 years ago
Hi everybody.
I'm currently develop a plugin suite for a french company that add a geometry (spatial database) to issues.
This first plugin works fine.
The second one add a infos and button on issue details to be able to send issue ID to a QGis plugin via WebSocket to be able to say to QGis to display the geometry.
It's works fine too.
The init.rb:
require 'redmine' Rails.logger.info 'Plugin d’affichage du statut de la présence d’une géométrie pour Redmine' # This is the important line. # It requires the file in lib/geometry_status/view_hook_listeners.rb require_dependency 'geometry_status/view_hook_listeners' Redmine::Plugin.register :geometry_status do name 'Geometry Status plugin' author 'xxxxxx' description 'Ceci est le plugin pour l’intégration du status de la géométrie dans Redmine' version '1.0.0' # Requires the redmine geometry plugin requires_redmine_plugin :geometry, :version_or_higher => '1.0.0' end
view_hook_listeners.rb:
module GeometryStatus # Voir : http://www.redmine.org/projects/redmine/wiki/Hooks class Hooks < Redmine::Hook::ViewListener def view_layouts_base_html_head(context) stylesheet_link_tag("plugin", :plugin => 'geometry_status') + javascript_include_tag('plugin', :plugin => 'geometry_status') end # rewrite select for trackers on issue form // view_issues_show_details_bottom def view_issues_show_details_bottom(context={}) issue = context[:issue] project = context[:project] html_return = '' if project != nil && project.id == 24 && issue != nil # Afficher tous les custom fields : #================================== # html_return = "<hr>" # CustomField.all.each do |custom| # html_return += "<br/>custom id=#{custom.id} / name=#{custom.name}" # custom.possible_values.each do |value| # html_return += "<br/> => #{value}" # end # end # return html_return # id == 24 => project.name == "Base des défauts" pointe = Pointes.where(issue_id: issue.id) if pointe.first != nil # La géométrie a été trouvée html_button_click = "onClick=\"call_qgis('#{issue.id}|#{pointe.first.pointe}')\"" html_button = "<button class=\"geometry_status_button\" #{html_button_click}>" + image_tag('geometry.png', :plugin => 'geometry_status', :title => "La FT #{issue.id} a une géométrie\nCliquez sur le bouton pour l'ouvrir dans le plugin Redmine sous QGis", :align => "center") + "</button>" html_return = "<hr><p>#{html_button}<strong class=\"geometry_status_centered_text\">Géométrie</strong><div class=\"wiki\"><p>La FT a une géométrie => WKT = #{pointe.first.pointe}</p></div>" else # La géométrie n'a pas été trouvée html_button_click = "onClick=\"call_qgis('#{issue.id}|')\"" value = CustomField.select('id, name, possible_values').where(name: 'Portée du Défaut').first if value # Obligé de mettre dans "#{xxxxxx}" sinon la comparaison ne fonctionne pas ! portee_du_defaut = "#{issue.custom_value_for(value.id)}" if portee_du_defaut == "Général" html_button = "<button class=\"geometry_status_button\" #{html_button_click}>" + image_tag('geometry_none.png', :plugin => 'geometry_status', :title => "La FT #{issue.id} n'a pas de géométrie\nCliquez sur le bouton pour l'ouvrir dans le plugin Redmine sous QGis", :align => "center") + "</button>" html_return = "<hr><p>#{html_button}<strong class=\"geometry_status_centered_text\">Géométrie</strong><div class=\"wiki\"><p>La FT générale ne contient pas de géométrie</p></div>" elsif portee_du_defaut == "Local" html_button = "<button class=\"geometry_status_button\" #{html_button_click}>" + image_tag('geometry_gray.png', :plugin => 'geometry_status', :title => "La FT #{issue.id} n'a pas de géométrie mais elle devrait en avoir une !\nCliquez sur le bouton pour l'ouvrir dans le plugin Redmine sous QGis", :align => "center") + "</button>" html_return = "<hr><p>#{html_button}<strong class=\"geometry_status_centered_text\">Géométrie</strong><div class=\"wiki\"><p>La FT locale ne contient pas de géométrie mais elle devrait en avoir une !</p></div>" else html_return = "<hr><p><strong class=\"geometry_status_centered_text\">Géométrie</strong><div class=\"wiki\"><p>La FT ne contient pas de géométrie. <strong class=\"geometry_unknown_portee_default\">Attention, la portée du défaut '#{portee_du_defaut}' est inconnue !</strong></p></div>" end end end end html_return end end end
The websocket is implemented into the plugin.js.
All of this is working fine.
Now, I would like to add a global button on issue list page to be able to send all displayed (and filtered) issue's ID to the QGis plugin.
I try to use hooks:
view_layouts_base_body_top
view_layouts_base_content
view_layouts_base_body_bottom
view_projects_show_right
But none of them is placed where I want: at the top of the list, behind the apply/clear filters line.
And another problem is: i have not the issue's ids list into the context passsed into the view hooks.
I'm sure there is another way (may be by controller hooks?) but I don't know how to use it.
I hope some peaple here can show me the way to do these expected things.
Thanks for all,
Kind regards,
Stéphane.
Replies (2)
RE: Plugin: how to add button on issue list? - Added by kumar abhinav over 5 years ago
Use 'view_issues_index_bottom' hook.
It renders at the bottom of issue list page but you can use js to move your element around as desired.
The hook is present in app/views/issues/index.html.erb.
The hook also provides the list of issues in @issues.
RE: Plugin: how to add button on issue list? - Added by Stéphane CHÂTEAU over 5 years ago
Wonderfull, thanks a lot !!!!!!!!
In my javascript I have add:
function geometry_status_move_geometry_button() { // Move list_geometry_button (if exist) in the correct place var eltDestination = document.getElementById('query_form_with_buttons'); if (eltDestination != null) { var allSelect = eltDestination.getElementsByClassName("buttons"); if (allSelect.length > 1) { eltDestination = allSelect[allSelect.length - 1] if (eltDestination != null) { var eltSource = document.getElementById('id_list_geometry_button'); if (eltSource != null) { eltDestination.appendChild(eltSource); } } } } } $(document).ready(function() { geometry_status_move_geometry_button(); });
It do the job. Just some think that take me a lot of time to understand:
Moving the element where I put it => it seem to be is into a <form> and so clicking on button make the page reload making WenbSocket.send never call.
I shoud modify my js script like :
function call_qgis(evt, issues_ids_and_wtk) { // Very important! // If not these lines, clicking on button after moving it into a form will send the form and // force the page to be reloaded. evt = evt || window.event; evt.preventDefault(); try { if ("WebSocket" in window) { var bConnected = false; // Let us open a web socket ws = new WebSocket("wss://localhost:8025/xxxxxxxx"); ws.onopen = function() { bConnected = true; // Web Socket is connected, send data using send() var jsonArr = []; issues_ids_and_wtk.split(",").forEach(function (item) { array_ids_wkf = item.split("|"); if (array_ids_wkf.length == 2) { jsonArr.push({ issue_id: array_ids_wkf[0], wkt: array_ids_wkf[1]}); } }); ws.send(JSON.stringify(jsonArr)); }; ws.onmessage = function (evt) { if (evt.data != "OK") { alert("Error return by QGis plugin:\n" + evt.data); } ws.close(); }; ws.onclose = function(evt) { // websocket is closed. if (!bConnected) { alert("Not working, server is offline\n"); // Pour Chrome activer : chrome://flags/#allow-insecure-localhost } }; window.onbeforeunload = function(event) { ws.close(); }; } else { // The browser doesn't support WebSocket alert("WebSocket NOT supported by your Browser!\n"); } } catch(error) { alert(error); } }