mirror of
https://github.com/dolphin-emu/redmine_issue_templates.git
synced 2026-01-31 01:15:19 +01:00
Initial commit.
This commit is contained in:
27
README.rdoc
Normal file
27
README.rdoc
Normal file
@@ -0,0 +1,27 @@
|
||||
= Redmine Issue Templates Plugin
|
||||
|
||||
Plugin to generate and use issue templates to assist issue creation.
|
||||
|
||||
=== Plugin installation
|
||||
|
||||
1. Copy the plugin directory into the vendor/plugins directory.
|
||||
2. Do migration task. (e.g. rake db:migrate_plugins RAILS_ENV=production)
|
||||
2. (Re)Start Redmine.
|
||||
|
||||
=== Note
|
||||
|
||||
This plugin aims to assist contributor's feedback by using template if the
|
||||
project has some format for issues.
|
||||
|
||||
=== Repository
|
||||
|
||||
* https://bitbucket.org/akiko_pusu/redmine_issue_templates
|
||||
|
||||
=== WebPage
|
||||
|
||||
* http://www.r-labs.org/projects/issue-template (Project Page)
|
||||
|
||||
|
||||
=== License
|
||||
|
||||
This software is licensed under the GNU GPL v2. See COPYRIGHT and COPYING for details.
|
||||
113
app/controllers/issue_templates_controller.rb
Normal file
113
app/controllers/issue_templates_controller.rb
Normal file
@@ -0,0 +1,113 @@
|
||||
class IssueTemplatesController < ApplicationController
|
||||
unloadable
|
||||
layout 'base'
|
||||
helper :sort
|
||||
include SortHelper
|
||||
include IssueTemplatesHelper
|
||||
helper :issues
|
||||
include IssuesHelper
|
||||
|
||||
before_filter :find_object, :only => [:show, :edit, :destroy]
|
||||
before_filter :find_user, :find_project, :authorize, :except => [ :preview ]
|
||||
before_filter :find_tracker, :only => [:set_pulldown]
|
||||
|
||||
def index
|
||||
sort_init "id", 'desc'
|
||||
sort_update ["id", "name", "tracker_id", "author_id", "updated_on", "enabled"]
|
||||
@issue_templates = IssueTemplate.find(:all,
|
||||
:conditions => ['project_id = ?', @project.id], :order => sort_clause)
|
||||
|
||||
render :template => 'issue_templates/index.html.erb', :layout => !request.xhr?
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def new
|
||||
# create empty instance
|
||||
@issue_template = IssueTemplate.new(:author => @user, :project => @project,
|
||||
:tracker => @tracker)
|
||||
if request.post?
|
||||
# Case post, set attributes passed as parameters.
|
||||
@issue_template.attributes = params[:issue_template]
|
||||
if @issue_template.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to :action => "show", :id => @issue_template.id, :project_id => @project
|
||||
end
|
||||
# In case failed to save, redirect to show.
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
if request.post?
|
||||
@issue_template.attributes = params[:issue_template]
|
||||
if @issue_template.save
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to :action => "show", :id => @issue_template.id, :project_id => @project
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if request.post?
|
||||
if @issue_template.destroy
|
||||
flash[:notice] = l(:notice_successful_delete)
|
||||
redirect_to :action => "index", :project_id => @project
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# load template description
|
||||
def load
|
||||
@issue_template = IssueTemplate.find(params[:issue_template])
|
||||
render :text => @issue_template.to_json
|
||||
end
|
||||
|
||||
# update pulldown
|
||||
def set_pulldown
|
||||
issue_templates = IssueTemplate.find(:all,
|
||||
:conditions => ['project_id = ? AND tracker_id = ? AND enabled = ?',
|
||||
@project.id, params[:issue_tracker_id], true])
|
||||
@grouped_options = []
|
||||
group = []
|
||||
tmpls = issue_templates
|
||||
if tmpls.size > 0
|
||||
tmpls.each { |x| group.push([x.title, x.id]) }
|
||||
@grouped_options.push([@tracker.name, group])
|
||||
end
|
||||
render :action => "issue_templates/_template_pulldown", :layout => false
|
||||
end
|
||||
|
||||
# preview
|
||||
def preview
|
||||
@text = (params[:issue_template] ? params[:issue_template][:description] : nil)
|
||||
@issue_template = IssueTemplate.find(params[:id]) if params[:id]
|
||||
render :partial => 'common/preview'
|
||||
end
|
||||
|
||||
private
|
||||
def find_user
|
||||
@user = User.current
|
||||
end
|
||||
|
||||
def find_tracker
|
||||
@tracker = Tracker.find(params[:issue_tracker_id])
|
||||
end
|
||||
|
||||
def find_object
|
||||
@issue_template = IssueTemplate.find(params[:id])
|
||||
@project = @issue_template.project
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
|
||||
def find_project
|
||||
begin
|
||||
@project = Project.find(params[:project_id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
35
app/controllers/issue_templates_settings_controller.rb
Normal file
35
app/controllers/issue_templates_settings_controller.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
class IssueTemplatesSettingsController < ApplicationController
|
||||
unloadable
|
||||
before_filter :find_project, :find_user
|
||||
before_filter :authorize, :except => [ :show_help, :preview ]
|
||||
|
||||
def edit
|
||||
if (params[:settings] != nil)
|
||||
@issue_templates_setting = IssueTemplateSetting.find_or_create(@project.id)
|
||||
@issue_templates_setting.attributes = params[:settings]
|
||||
@issue_templates_setting.save!
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to :controller => 'projects',
|
||||
:action => "settings", :id => @project, :tab => 'issue_templates'
|
||||
end
|
||||
end
|
||||
|
||||
def preview
|
||||
@text = params[:settings][:help_message]
|
||||
render :partial => 'common/preview'
|
||||
end
|
||||
|
||||
private
|
||||
def find_user
|
||||
@user = User.current
|
||||
end
|
||||
|
||||
def find_project
|
||||
begin
|
||||
@project = Project.find(params[:project_id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
2
app/helpers/issue_template_settings_helper.rb
Normal file
2
app/helpers/issue_template_settings_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
||||
module IssueTemplateSettingsHelper
|
||||
end
|
||||
14
app/helpers/issue_templates_helper.rb
Normal file
14
app/helpers/issue_templates_helper.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module IssueTemplatesHelper
|
||||
def grouped_array(trackers, project_id)
|
||||
array = []
|
||||
trackers.each {|tracker|
|
||||
group = []
|
||||
tmpls = IssueTemplate.find(:all,
|
||||
:conditions => ['tracker_id = ? AND project_id = ?',
|
||||
item.id, project_id])
|
||||
tmpls.each { |x| group.push([x.id, x.title]) }
|
||||
array.push([tracker.name, group])
|
||||
}
|
||||
return array
|
||||
end
|
||||
end
|
||||
12
app/models/issue_template.rb
Normal file
12
app/models/issue_template.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class IssueTemplate < ActiveRecord::Base
|
||||
unloadable
|
||||
belongs_to :project
|
||||
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
||||
belongs_to :tracker
|
||||
validates_presence_of :project, :title, :description, :tracker
|
||||
validates_uniqueness_of :title, :scope => :project_id
|
||||
|
||||
def enabled?
|
||||
self.enabled == true
|
||||
end
|
||||
end
|
||||
24
app/models/issue_template_setting.rb
Normal file
24
app/models/issue_template_setting.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
class IssueTemplateSetting < ActiveRecord::Base
|
||||
unloadable
|
||||
belongs_to :project
|
||||
|
||||
validates_uniqueness_of :project_id
|
||||
validates_presence_of :project_id
|
||||
|
||||
def self.find_or_create(project_id)
|
||||
setting = IssueTemplateSetting.find(:first, :conditions => ['project_id = ?', project_id])
|
||||
unless setting
|
||||
setting = IssueTemplateSetting.new
|
||||
setting.project_id = project_id
|
||||
setting.save!
|
||||
end
|
||||
return setting
|
||||
end
|
||||
|
||||
def enable_help?
|
||||
if self.enabled == true && !self.help_message.blank?
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
21
app/views/issue_templates/_form.html.erb
Normal file
21
app/views/issue_templates/_form.html.erb
Normal file
@@ -0,0 +1,21 @@
|
||||
<%= error_messages_for 'issue_template' %>
|
||||
<div class="box tabular">
|
||||
<p><%= f.text_field :title, :required => true, :size => 100, :label => l(:field_title) %> </p>
|
||||
<p><%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true,:label => l(:label_tracker) %></p>
|
||||
<p>
|
||||
<%= f.text_area :description,:cols => 78, :rows => 12,
|
||||
:required => true,
|
||||
:label => l(:template_description), :style => "overflow:auto;" %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.text_area :note,:cols => 70, :rows => 3,
|
||||
:required => false,
|
||||
:label => l(:issue_template_note), :style => "overflow:auto;" %>
|
||||
</p>
|
||||
<p><%= f.check_box :enabled, :label => l(:label_enabled) %> <%= l(:label_enabled_help_message) %></p>
|
||||
</div>
|
||||
|
||||
<%= wikitoolbar_for 'issue_template_description' %>
|
||||
|
||||
|
||||
|
||||
48
app/views/issue_templates/_issue_select_form.rhtml
Normal file
48
app/views/issue_templates/_issue_select_form.rhtml
Normal file
@@ -0,0 +1,48 @@
|
||||
<% return '' unless @project.module_enabled? :issue_templates %>
|
||||
<%
|
||||
# TODO: This code should be moved from vire template.
|
||||
@setting = IssueTemplateSetting.find_or_create(@project.id)
|
||||
grouprd_options = []
|
||||
|
||||
# default set templates of first tracker
|
||||
tracker = @project.trackers[0]
|
||||
group = []
|
||||
tmpls = IssueTemplate.find(:all,
|
||||
:conditions => ['tracker_id = ? AND project_id = ? AND enabled = ?',
|
||||
tracker.id, @project.id, true])
|
||||
if tmpls.size > 0
|
||||
tmpls.each { |x| group.push([x.title, x.id]) }
|
||||
grouprd_options.push([tracker.name, group])
|
||||
end
|
||||
%>
|
||||
|
||||
<div id="template_area" style="margin-top: 4pt;">
|
||||
<label><%=h l(:issue_template)%></label>
|
||||
<select id="issue_template" include_blank="true" length="150" name="issue_template">
|
||||
<option value="">---</option>
|
||||
<%= grouped_options_for_select(grouprd_options) %>
|
||||
</select>
|
||||
|
||||
<% if @setting.enable_help? == true %>
|
||||
<a class="icon icon-help" href="#" title="<%= l(:about_template_help_message) %>"
|
||||
onclick="checkExpand('template_help_content');">
|
||||
<%= l(:label_help_message) %></a>
|
||||
<br/>
|
||||
<% end %>
|
||||
<div class="template_help box" id="template_help_content" style="display: none;"><%= textilizable @setting.help_message %>
|
||||
<div id="template_help_hide"><a href="#" onClick="checkExpand('template_help_content');" title="<%= l(:close_help) %>">[x]</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
|
||||
token = '<%= form_authenticity_token %>';
|
||||
load_url = '<%= url_for(:controller => 'issue_templates',
|
||||
:action => 'load', :project_id => @project) %>';
|
||||
pulldown_url = '<%= url_for(:controller => 'issue_templates',
|
||||
:action => 'set_pulldown', :project_id => @project) %>';
|
||||
document.observe("dom:loaded", function() {
|
||||
Event.observe('issue_tracker_id', 'change', function(e){ set_pulldown(e, pulldown_url, token); },false );
|
||||
Event.observe('issue_template', 'change', function(e){ load_template(e, load_url, token); },false);
|
||||
});
|
||||
</script>
|
||||
3
app/views/issue_templates/_template_pulldown.rhtml
Normal file
3
app/views/issue_templates/_template_pulldown.rhtml
Normal file
@@ -0,0 +1,3 @@
|
||||
<option value="">---</option>
|
||||
<%= grouped_options_for_select(@grouped_options) %>
|
||||
|
||||
36
app/views/issue_templates/index.html.erb
Normal file
36
app/views/issue_templates/index.html.erb
Normal file
@@ -0,0 +1,36 @@
|
||||
<div class="contextual">
|
||||
<%= link_to_if_authorized(l(:label_new),
|
||||
{:controller => 'issue_templates', :action => 'new', :project_id => @project},
|
||||
:class => 'icon icon-add',:onclick => 'Element.show("add-template"); return false;') %>
|
||||
</div>
|
||||
|
||||
<% if @notice -%>
|
||||
<div class="flash notice"><%= @notice -%></div>
|
||||
<% end -%>
|
||||
|
||||
<table class="list issues">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= sort_header_tag 'id', :caption => '#' %></th>
|
||||
<th><%= sort_header_tag 'title', :caption => l(:field_title) %></th>
|
||||
<th><%= sort_header_tag 'tracker_id', :caption => l(:field_tracker) %></th>
|
||||
<th><%= sort_header_tag 'author_id', :caption => l(:field_author) %></th>
|
||||
<th><%= sort_header_tag 'updated_on', :caption => l(:field_updated_on) %></th>
|
||||
<th><%= sort_header_tag 'enabled', :caption => l(:label_enabled) %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @issue_templates.each do |issue_template| %>
|
||||
<tr class="<%= cycle("odd", "even") %> issue_template issue">
|
||||
<td colspan="2"><%= issue_template.id %></td>
|
||||
<td colspan="2"><%= link_to h(issue_template.title), :controller => 'issue_templates',
|
||||
:action => 'show', :id => issue_template.id, :project_id => @project %></td>
|
||||
<td colspan="2"><%=h issue_template.tracker.name %></td>
|
||||
<td colspan="2"><%=h issue_template.author %></td>
|
||||
<td colspan="2"><%= format_time(issue_template.updated_on)%> </td>
|
||||
<td colspan="2"><%= image_tag('true.png') if issue_template.enabled? %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
22
app/views/issue_templates/new.html.erb
Normal file
22
app/views/issue_templates/new.html.erb
Normal file
@@ -0,0 +1,22 @@
|
||||
<h2><%=h "#{l(:issue_templates)} / #{l(:button_add)}" %></h2>
|
||||
<div class="box">
|
||||
<%= error_messages_for 'issue_template' %>
|
||||
<% labelled_tabular_form_for :issue_template, @issue_template,
|
||||
:url => { :controller => 'issue_templates', :action => 'new', :project_id => @project },
|
||||
:html => { :id => 'issue_template-form',
|
||||
:class => nil, :multipart => false } do |f| %>
|
||||
<%= render :partial => 'form', :locals => { :f => f } %>
|
||||
<%= submit_tag l(:button_apply) %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to_remote l(:label_preview),
|
||||
{ :url => { :controller => 'issue_templates', :action => 'preview', :id => @issue_template },
|
||||
:method => 'post',
|
||||
:update => 'preview',
|
||||
:with => "Form.serialize('issue_template-form')"
|
||||
}, :accesskey => accesskey(:preview) %> |
|
||||
<%= link_to l(:button_cancel), {:action => 'index'}, :confirm => l(:text_are_you_sure) %>
|
||||
<div id="preview" class="wiki"></div>
|
||||
|
||||
</div>
|
||||
|
||||
59
app/views/issue_templates/show.html.erb
Normal file
59
app/views/issue_templates/show.html.erb
Normal file
@@ -0,0 +1,59 @@
|
||||
<div class="contextual">
|
||||
<%= link_to_if_authorized l(:button_edit),
|
||||
{:controller => 'issue_templates', :action => 'edit', :id => @issue_template,
|
||||
:project_id => @project},
|
||||
:class => 'icon icon-edit',
|
||||
:accesskey => accesskey(:edit),
|
||||
:onclick => 'Element.show("edit-issue_template"); return false;' %>
|
||||
<%= link_to_if_authorized l(:button_delete),
|
||||
{:controller => 'issue_templates', :action => 'destroy',
|
||||
:id => @issue_template, :project_id => @project},
|
||||
:confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
|
||||
</div>
|
||||
|
||||
<h2><%= l(:issue_templates) %>: #<%= @issue_template.id %> <%= avatar(@issue_template.author, :size => "24") %></h2>
|
||||
|
||||
<% if authorize_for('issue_templates', 'edit') %>
|
||||
<div id="edit-issue_template" style="display:none;">
|
||||
<% labelled_tabular_form_for :issue_template, @issue_template, :url => { :controller => 'issue_templates', :action => 'edit', :project_id => @project, :id => @issue_template },
|
||||
:html => { :id => 'issue_template-form',
|
||||
:class => nil,
|
||||
:multipart => false } do |f| %>
|
||||
<%= render :partial => 'form', :locals => { :f => f } %>
|
||||
<%= submit_tag l(:button_edit) %>
|
||||
<% end %>
|
||||
<%= link_to_remote l(:label_preview),
|
||||
{ :url => { :controller => 'issue_templates', :action => 'preview', :id => @issue_template },
|
||||
:method => 'post',
|
||||
:update => 'preview',
|
||||
:with => "Form.serialize('issue_template-form')"
|
||||
}, :accesskey => accesskey(:preview) %> |
|
||||
<%= link_to l(:button_cancel), {:action => 'index'}, :onclick => 'Element.hide("edit-issue_template"); return false;' %>
|
||||
<div id="preview" class="wiki"></div>
|
||||
<hr/>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
<div class="box tabular">
|
||||
<p>
|
||||
<label><%= l(:field_title) %></label>
|
||||
<%= h @issue_template.title %>
|
||||
</p>
|
||||
<p><label><%= l(:label_tracker) %></label>
|
||||
<%= h @issue_template.tracker.name %>
|
||||
</p>
|
||||
<p><label><%= l(:field_author) %></label>
|
||||
<%= @issue_template.author %> (<%= @issue_template.updated_on %>)</p>
|
||||
|
||||
<p>
|
||||
<label for="issue_template_description"><%= l(:template_description) %></label>
|
||||
<%= textilizable(@issue_template.description) %>
|
||||
</p>
|
||||
<p><label><%= l(:issue_template_note) %></label>
|
||||
<%= @issue_template.note.blank? ? l(:label_none) : @issue_template.note %>
|
||||
</p>
|
||||
<p><label><%= l(:label_enabled) %></label>
|
||||
<%= @issue_template.enabled? ? l(:label_enabled) : l(:label_disabled) %>
|
||||
</p>
|
||||
</div>
|
||||
34
app/views/issue_templates_settings/_show.html.erb
Normal file
34
app/views/issue_templates_settings/_show.html.erb
Normal file
@@ -0,0 +1,34 @@
|
||||
<div id="issue_templates_settings">
|
||||
<%
|
||||
@issue_templates_setting = IssueTemplateSetting.find_or_create(@project.id)
|
||||
%>
|
||||
<p><%= l(:about_help_message) %></p>
|
||||
<% labelled_tabular_form_for :settings, @issue_templates_setting,
|
||||
:url => {:controller => 'issue_templates_settings',
|
||||
:action => 'edit', :project_id => @project, :tab => 'issue_templates',
|
||||
:setting_id => @issue_templates_setting.id},
|
||||
:html => {:id => 'issue_templates_settings' } do |f| %>
|
||||
<%= error_messages_for 'issue_templates_setting' %>
|
||||
<div class="box">
|
||||
<p><%= f.check_box :enabled, :label => l(:field_enabled) %></p>
|
||||
<p><label><%=l(:label_help_message)%></label>
|
||||
<%=content_tag(:label, l(:label_help_message)) %>
|
||||
<%=text_area_tag 'settings[help_message]', @issue_templates_setting['help_message'], :size =>"50x5",
|
||||
:class => 'wiki-edit' ,:required => true %><br/>
|
||||
<%= wikitoolbar_for "settings_help_message" %>
|
||||
<%= link_to_remote l(:label_preview),
|
||||
{ :url => { :controller => 'issue_templates_settings',
|
||||
:action => 'preview', :project_id => @project},
|
||||
:method => 'post',
|
||||
:id => 'help_preview',
|
||||
:update => 'template_help_preview',
|
||||
:with => "Form.serialize('issue_templates_settings')",
|
||||
:complete => "Element.scrollTo('template_help_preview')"
|
||||
}, :accesskey => accesskey(:preview) %>
|
||||
<div id="template_help_preview" class="wiki"></div>
|
||||
|
||||
</div>
|
||||
<%= submit_tag l(:button_update) %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
BIN
assets/images/issue_templates.png
Normal file
BIN
assets/images/issue_templates.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 425 B |
44
assets/javascripts/issue_templates.js
Normal file
44
assets/javascripts/issue_templates.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
function checkExpand(ch) {
|
||||
var obj=document.all && document.all(ch) || document.getElementById && document.getElementById(ch);
|
||||
if(obj && obj.style) obj.style.display=
|
||||
"none" == obj.style.display ?"" : "none"
|
||||
}
|
||||
|
||||
// Change Location of pulldown.
|
||||
document.observe("dom:loaded", function() {
|
||||
new Insertion.After($('issue_tracker_id'), $('template_area'));
|
||||
//ConnectedSelect(['issue_tracker_id','issue_template']);
|
||||
});
|
||||
|
||||
|
||||
function load_template(evt, target_url, token) {
|
||||
if (evt.target.value != "") {
|
||||
new Ajax.Request(target_url,
|
||||
{asynchronous:true, evalScripts:true,
|
||||
onComplete:function(request){
|
||||
eval("var template = " + request.responseText);
|
||||
$('issue_description').value = template.description
|
||||
$('issue_subject').value = template.title
|
||||
},
|
||||
parameters:'issue_template=' + encodeURIComponent(evt.target.value)
|
||||
+ '&authenticity_token=' + encodeURIComponent(token)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function set_pulldown(evt, target_url, token) {
|
||||
new Ajax.Request(target_url,
|
||||
{ asynchronous:true, evalScripts:true,
|
||||
onComplete:function(request){
|
||||
Element.update('issue_template', request.responseText);
|
||||
},
|
||||
parameters:'issue_tracker_id=' + encodeURIComponent(evt.target.value)
|
||||
+ '&authenticity_token=' + encodeURIComponent(token)
|
||||
}
|
||||
);
|
||||
}
|
||||
73
assets/stylesheets/issue_templates.css
Normal file
73
assets/stylesheets/issue_templates.css
Normal file
@@ -0,0 +1,73 @@
|
||||
#main-menu a.issue-templates.selected {
|
||||
background-image: url(../images/issue_templates.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 3px center;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
#main-menu a.issue-templates.selected:hover {
|
||||
background-image: url(../images/issue_templates.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 3px center;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
#main-menu a.issue-templates {
|
||||
background-image: url(../images/issue_templates.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 3px center;
|
||||
color: transparent;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
#main-menu a.issue-templates:hover {
|
||||
background-image: url(../images/issue_templates.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 3px center;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
#template_help_message {
|
||||
}
|
||||
|
||||
#template_area {
|
||||
}
|
||||
|
||||
.template_help {
|
||||
display: block;
|
||||
border: solid #BBB 1px;
|
||||
background-color: #F0F0F0;
|
||||
padding: 1em;
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#template_help_content {
|
||||
position:relative;
|
||||
text-align: left;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
#template_help_content p{
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
div.template_help div#template_help_hide {
|
||||
display:block;
|
||||
position:absolute;
|
||||
bottom:5px;
|
||||
right:10px;
|
||||
font-size:smaller;
|
||||
background:none;
|
||||
color:#000;
|
||||
filter: alpha(opacity=30);
|
||||
-moz-opacity: 0.3;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
div.template_help div#template_help_hide:hover {
|
||||
filter: alpha(opacity=80);
|
||||
-moz-opacity: 0.8;
|
||||
opacity: 0.8;
|
||||
}
|
||||
14
config/locales/en.yml
Normal file
14
config/locales/en.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
# English strings go here for Rails i18n
|
||||
en:
|
||||
issue_templates: Templates
|
||||
issue_template: Issue template
|
||||
issue_template_note: note
|
||||
label_enabled: Enable
|
||||
label_disabled: Disable
|
||||
template_description: Template description
|
||||
label_help_meessage: About templates
|
||||
label_show_help_message: Show help message when create/update issues.
|
||||
about_help_message: Each project can customize help message for templates.
|
||||
close_help: Close help message.
|
||||
about_template_help_message: You can see the instruction of issue templates on this project.
|
||||
label_enabled_help_message: Checkbox to activate (enabled) to this template. If you hope to save this template as draft, turn this checkbox off.
|
||||
14
config/locales/ja.yml
Normal file
14
config/locales/ja.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
ja:
|
||||
issue_templates: テンプレート
|
||||
issue_template: チケットテンプレート
|
||||
issue_template_note: メモ
|
||||
label_enabled: "有効"
|
||||
label_disabled: "無効"
|
||||
template_description: "テンプレートの本文"
|
||||
label_help_message: "テンプレートについて"
|
||||
label_show_help_message: "ヘルプメッセージを有効にする"
|
||||
field_enabled: "ヘルプメッセージを有効にする"
|
||||
about_help_message: "プロジェクト毎にテンプレートに関するヘルプを設定できます。"
|
||||
close_help: "ヘルプメッセージを閉じます。"
|
||||
about_template_help_message: "プロジェクト毎のテンプレートに関するヘルプを表示します。"
|
||||
label_enabled_help_message: "有効にチェックを入れると、選択できるようになります。ドラフト状態の場合は、チェックを外して下さい。"
|
||||
7
config/routes.rb
Normal file
7
config/routes.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
# Routes
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.connect 'projects/:project_id/issue_templates/:action', :controller => 'issue_templates'
|
||||
map.connect 'projects/:project_id/issue_templates/:action/:id', :controller => 'issue_templates', :action => 'edit'
|
||||
map.connect 'projects/:project_id/issue_templates_settings/:action',
|
||||
:controller => 'issue_templates_settings'
|
||||
end
|
||||
25
db/migrate/0001_create_issue_templates.rb
Normal file
25
db/migrate/0001_create_issue_templates.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
class CreateIssueTemplates < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :issue_templates do |t|
|
||||
t.column :title, :string, :null => false
|
||||
t.column :project_id, :integer
|
||||
t.column :tracker_id, :integer, :null => false
|
||||
t.column :author_id, :integer, :null => false
|
||||
t.column :note, :string
|
||||
t.column :description, :text
|
||||
t.column :enabled, :boolean
|
||||
t.column :created_on, :timestamp
|
||||
t.column :updated_on, :timestamp
|
||||
end
|
||||
add_index :issue_templates, :author_id
|
||||
add_index :issue_templates, :project_id
|
||||
add_index :issue_templates, :tracker_id
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :issue_templates
|
||||
remove_index :issue_templates, :author_id
|
||||
remove_index :issue_templates, :project_id
|
||||
remove_index :issue_templates, :tracker_id
|
||||
end
|
||||
end
|
||||
17
db/migrate/0002_create_issue_template_settings.rb
Normal file
17
db/migrate/0002_create_issue_template_settings.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
class CreateIssueTemplateSettings < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :issue_template_settings do |t|
|
||||
|
||||
t.column :project_id, :integer
|
||||
|
||||
t.column :help_message, :text
|
||||
|
||||
t.column :enabled, :boolean
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :issue_template_settings
|
||||
end
|
||||
end
|
||||
35
init.rb
Normal file
35
init.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
require 'redmine'
|
||||
require 'issue_templates_issues_hook'
|
||||
require 'issue_templates_projects_helper_patch'
|
||||
|
||||
Redmine::Plugin.register :redmine_issue_templates do
|
||||
name 'Redmine Issue Templates plugin'
|
||||
author 'Akiko Takano'
|
||||
description 'This is a plugin for Redmine'
|
||||
version '0.0.1'
|
||||
author_url 'http://twitter.com/akiko_pusu'
|
||||
requires_redmine :version_or_higher => '1.2.0'
|
||||
|
||||
project_module :issue_templates do
|
||||
permission :edit_issue_templates, {:issue_templates => [:new, :edit, :destroy]}
|
||||
permission :show_issue_templates, {:issue_templates => [:index, :show, :load, :set_pulldown]}
|
||||
permission :manage_issue_templates,
|
||||
{:issue_templates_settings => [:show, :edit]}, :require => :member
|
||||
end
|
||||
|
||||
menu :project_menu, :issue_templates, { :controller => 'issue_templates',
|
||||
:action => 'index' }, :caption => :issue_templates,
|
||||
:param => :project_id,
|
||||
:last => true
|
||||
|
||||
end
|
||||
|
||||
require 'dispatcher'
|
||||
Dispatcher.to_prepare :redmine_issue_templates do
|
||||
require_dependency 'projects_helper'
|
||||
unless ProjectsHelper.included_modules.include? IssueTemplatesProjectsHelperPatch
|
||||
ProjectsHelper.send(:include, IssueTemplatesProjectsHelperPatch)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
2
lang/en.yml
Normal file
2
lang/en.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
# English strings go here
|
||||
my_label: "My label"
|
||||
17
lib/issue_templates_issues_hook.rb
Normal file
17
lib/issue_templates_issues_hook.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
# To change this template, choose Tools | Templates
|
||||
# and open the template in the editor.
|
||||
|
||||
class IssueTemplatesIssuesHook < Redmine::Hook::ViewListener
|
||||
include IssuesHelper
|
||||
|
||||
def view_layouts_base_html_head(context = {})
|
||||
o = stylesheet_link_tag('issue_templates', :plugin => 'redmine_issue_templates')
|
||||
if context[:controller].class.name == 'IssuesController' and
|
||||
context[:controller].action_name != 'index'
|
||||
o << javascript_include_tag('issue_templates', :plugin => 'redmine_issue_templates')
|
||||
end
|
||||
return o
|
||||
end
|
||||
|
||||
render_on :view_issues_form_details_top, :partial => 'issue_templates/issue_select_form'
|
||||
end
|
||||
28
lib/issue_templates_projects_helper_patch.rb
Normal file
28
lib/issue_templates_projects_helper_patch.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
# To change this template, choose Tools | Templates
|
||||
# and open the template in the editor.
|
||||
require_dependency 'projects_helper'
|
||||
|
||||
module IssueTemplatesProjectsHelperPatch
|
||||
def self.included base # :nodoc:
|
||||
base.send :include, ProjectsHelperMethodsIssueTemplates
|
||||
base.class_eval do
|
||||
alias_method_chain :project_settings_tabs, :issue_templates
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ProjectsHelperMethodsIssueTemplates
|
||||
def project_settings_tabs_with_issue_templates
|
||||
tabs = project_settings_tabs_without_issue_templates
|
||||
action = {:name => 'issue_templates',
|
||||
:controller => 'issue_templates_settings',
|
||||
:action => :show,
|
||||
:partial => 'issue_templates_settings/show', :label => :issue_templates}
|
||||
tabs << action if User.current.allowed_to?(action, @project)
|
||||
tabs
|
||||
end
|
||||
end
|
||||
|
||||
ProjectsHelper.send(:include, IssueTemplatesProjectsHelperPatch)
|
||||
|
||||
|
||||
19
test/fixtures/issue_template_settings.yml
vendored
Normal file
19
test/fixtures/issue_template_settings.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
|
||||
project_id: 1
|
||||
|
||||
help_message: MyText
|
||||
|
||||
enabled: true
|
||||
|
||||
two:
|
||||
id: 2
|
||||
|
||||
project_id: 1
|
||||
|
||||
help_message: MyText
|
||||
|
||||
enabled: false
|
||||
|
||||
53
test/fixtures/issue_templates.yml
vendored
Normal file
53
test/fixtures/issue_templates.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
|
||||
project_id: 1
|
||||
|
||||
tracker_id: 1
|
||||
|
||||
author_id: 1
|
||||
|
||||
title: title1
|
||||
|
||||
description: description1
|
||||
|
||||
note: note1
|
||||
|
||||
enabled: 1
|
||||
|
||||
|
||||
two:
|
||||
id: 2
|
||||
|
||||
project_id: 1
|
||||
|
||||
tracker_id: 3
|
||||
|
||||
author_id: 1
|
||||
|
||||
title: titel2
|
||||
|
||||
description: description2
|
||||
|
||||
note: note2
|
||||
|
||||
enabled: 0
|
||||
|
||||
three:
|
||||
id: 3
|
||||
|
||||
project_id: 1
|
||||
|
||||
tracker_id: 2
|
||||
|
||||
author_id: 1
|
||||
|
||||
title: titel3
|
||||
|
||||
description: description3
|
||||
|
||||
note: note3
|
||||
|
||||
enabled: 1
|
||||
|
||||
104
test/functional/issue_templates_controller_test.rb
Normal file
104
test/functional/issue_templates_controller_test.rb
Normal file
@@ -0,0 +1,104 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class IssueTemplatesControllerTest < ActionController::TestCase
|
||||
fixtures :projects, :users, :roles, :members, :enabled_modules, :issue_templates
|
||||
def setup
|
||||
@controller = IssueTemplatesController.new
|
||||
@request = ActionController::TestRequest.new
|
||||
@request.session[:user_id] = 1
|
||||
@response = ActionController::TestResponse.new
|
||||
@request.env["HTTP_REFERER"] = '/'
|
||||
# Enabled Template module
|
||||
@project = Project.find(1)
|
||||
@project.enabled_modules << EnabledModule.new(:name => 'issue_templates')
|
||||
@project.save!
|
||||
end
|
||||
|
||||
context "new" do
|
||||
setup do
|
||||
|
||||
end
|
||||
|
||||
should "should get index" do
|
||||
get :index, :project_id => 1
|
||||
assert_response :success
|
||||
assert_template 'index'
|
||||
assert_not_nil assigns(:issue_templates)
|
||||
end
|
||||
|
||||
should "return new template instance when request is get" do
|
||||
get :new, :project_id => 1, :author_id => User.current.id
|
||||
assert_response :success
|
||||
|
||||
template = assigns(:issue_template)
|
||||
assert_not_nil template
|
||||
assert template.title.blank?
|
||||
assert template.description.blank?
|
||||
assert template.note.blank?
|
||||
assert template.tracker.blank?
|
||||
assert_equal(1, template.author.id)
|
||||
assert_equal(1, template.project.id)
|
||||
end
|
||||
|
||||
# do post
|
||||
should "insert new template record when request is post" do
|
||||
count = IssueTemplate.find(:all).length
|
||||
post :new, :issue_template => {:title => "newtitle", :note => "note",
|
||||
:description => "description", :tracker_id => 1, :enabled => 1,
|
||||
:author_id => 1 }, :project_id => 1
|
||||
|
||||
template = IssueTemplate.first(:order => 'id DESC')
|
||||
assert_response :redirect # show
|
||||
|
||||
assert_equal(count + 1, IssueTemplate.find(:all).length)
|
||||
|
||||
assert_not_nil template
|
||||
assert_equal("newtitle", template.title)
|
||||
assert_equal("note", template.note)
|
||||
assert_equal("description", template.description)
|
||||
assert_equal(1, template.project.id)
|
||||
assert_equal(1, template.tracker.id)
|
||||
assert_equal(1, template.author.id)
|
||||
end
|
||||
|
||||
# fail check
|
||||
should "not be able to save if title is empty" do
|
||||
count = IssueTemplate.find(:all).length
|
||||
|
||||
# when title blank, validation bloks to save.
|
||||
post :new, :issue_template => {:title => "", :note => "note",
|
||||
:description => "description", :tracker_id => 1, :enabled => 1,
|
||||
:author_id => 1 }, :project_id => 1
|
||||
|
||||
assert_response :success
|
||||
assert_equal(count, IssueTemplate.find(:all).length)
|
||||
end
|
||||
|
||||
should "should preview template" do
|
||||
get :preview, {:issue_template => {:description=> "h1. Test data."}}
|
||||
assert_template "common/_preview.html.erb"
|
||||
assert_select 'h1', /Test data\./, "#{@response.body}"
|
||||
end
|
||||
|
||||
should "should edit template when request is post" do
|
||||
post :edit, :id => 2,
|
||||
:issue_template => { :description => 'Update Test template2' },
|
||||
:project_id => 1
|
||||
project = Project.find 1
|
||||
assert_response :redirect # show
|
||||
issue_template = IssueTemplate.find(2)
|
||||
assert_redirected_to :controller => 'issue_templates',
|
||||
:action => "show", :id => issue_template.id, :project_id => project
|
||||
assert_equal 'Update Test template2', issue_template.description
|
||||
end
|
||||
|
||||
should "should destroy template when request is delete" do
|
||||
post :destroy, :id => 1, :project_id => 1
|
||||
project = Project.find 1
|
||||
assert_redirected_to :controller => 'issue_templates',
|
||||
:action => "index", :project_id => project
|
||||
assert_raise(ActiveRecord::RecordNotFound) {IssueTemplate.find(1)}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
60
test/functional/issue_templates_setting_controller_test.rb
Normal file
60
test/functional/issue_templates_setting_controller_test.rb
Normal file
@@ -0,0 +1,60 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class IssuteTemplatesSettingControllerTest < ActionController::TestCase
|
||||
fixtures :projects,
|
||||
:users,
|
||||
:roles,
|
||||
:members,
|
||||
:member_roles,
|
||||
:enabled_modules,
|
||||
:issue_templates
|
||||
|
||||
def setup
|
||||
@controller = IssueTemplatesSettingsController.new
|
||||
@response = ActionController::TestResponse.new
|
||||
# Enabled Template module
|
||||
#EnabledModule.generate! :project_id => 1, :name => 'issue_templates'
|
||||
enabled_module = EnabledModule.new
|
||||
enabled_module.project_id = 1
|
||||
enabled_module.name = 'issue_templates'
|
||||
enabled_module.save
|
||||
end
|
||||
|
||||
context "#update" do
|
||||
|
||||
context "by member" do
|
||||
setup do
|
||||
@request.session[:user_id] = 2
|
||||
end
|
||||
|
||||
context "without permission" do
|
||||
should "403 post" do
|
||||
project = Project.find 1
|
||||
post :edit, :project_id => project,
|
||||
:settings => { :enabled => "1", :help_message => "Hoo"},
|
||||
:setting_id => 1, :tab => "issue_templates"
|
||||
assert_response 403
|
||||
end
|
||||
end
|
||||
|
||||
context "with permission" do
|
||||
setup do
|
||||
Role.find(1).add_permission! :manage_issue_templates
|
||||
end
|
||||
|
||||
should "should redirect post" do
|
||||
project = Project.find 1
|
||||
post :edit, :project_id => project,
|
||||
:settings => { :enabled => "1", :help_message => "Hoo"},
|
||||
:setting_id => 1, :tab => "issue_templates"
|
||||
assert_response :redirect
|
||||
|
||||
assert_redirected_to :controller => 'projects',
|
||||
:action => "settings", :id => project, :tab => 'issue_templates'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
5
test/test_helper.rb
Normal file
5
test/test_helper.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
# Load the normal Rails helper
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
|
||||
|
||||
# Ensure that we are using the temporary fixture path
|
||||
Engines::Testing.set_fixture_path
|
||||
29
test/unit/issue_template_setting_test.rb
Normal file
29
test/unit/issue_template_setting_test.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class IssueTemplateSettingTest < ActiveSupport::TestCase
|
||||
fixtures :issue_template_settings
|
||||
|
||||
def setup
|
||||
@issue_template_setting = IssueTemplateSetting.find(1)
|
||||
end
|
||||
|
||||
def test_truth
|
||||
assert_kind_of IssueTemplateSetting, @issue_template_setting
|
||||
end
|
||||
|
||||
def test_help_message_enabled
|
||||
assert_equal(true, @issue_template_setting.enabled)
|
||||
assert_equal(false, !@issue_template_setting.enabled)
|
||||
end
|
||||
|
||||
def test_duplicate_project_setting
|
||||
templ = IssueTemplateSetting.find_or_create(3)
|
||||
templ.attributes = {:enabled => true, :help_message => 'Help!'}
|
||||
assert templ.save!, 'Failed to save.'
|
||||
|
||||
# test which has the same proect id
|
||||
templ2 = IssueTemplateSetting.new
|
||||
templ2.attributes = {:project_id => 1, :enabled => true, :help_message => 'Help!'}
|
||||
assert !templ2.save, 'Dupricate project should be denied.'
|
||||
end
|
||||
end
|
||||
23
test/unit/issue_template_test.rb
Normal file
23
test/unit/issue_template_test.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class IssueTemplateTest < ActiveSupport::TestCase
|
||||
fixtures :issue_templates
|
||||
|
||||
def setup
|
||||
@issue_template = IssueTemplate.find(1)
|
||||
end
|
||||
|
||||
def test_truth
|
||||
assert_kind_of IssueTemplate, @issue_template
|
||||
end
|
||||
|
||||
def test_template_enabled
|
||||
@issue_template.enabled = true
|
||||
@issue_template.save!
|
||||
assert_equal true, @issue_template.enabled?, @issue_template.enabled?
|
||||
|
||||
@issue_template.enabled = false
|
||||
@issue_template.save!
|
||||
assert_equal false, @issue_template.enabled?, @issue_template.enabled?
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user