Merge branch 'devel-1.0.0' into master

This commit is contained in:
Karel Picman 2018-12-19 14:40:06 +01:00 committed by GitHub
commit 0bc5179686
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 275 additions and 132 deletions

4
Gemfile Normal file
View File

@ -0,0 +1,4 @@
source 'https://rubygems.org'
gem 'acts_as_list'
gem 'activemodel-serializers-xml'

View File

@ -1,8 +1,32 @@
class CustomWorkflowsController < ApplicationController class CustomWorkflowsController < ApplicationController
layout 'admin' layout 'admin'
before_filter :require_admin before_action :require_admin
before_filter :find_workflow, :only => [:show, :edit, :update, :destroy, :export, :change_status] before_action :find_workflow, only: [:show, :edit, :update, :destroy, :export, :change_status, :reorder]
def reorder
from = @workflow.position
to = params[:custom_workflow][:position].to_i
CustomWorkflow.transaction do
CustomWorkflow.find_each do |wf|
if wf.position == from
wf.update_attribute :position, to
elsif wf.position >= to && wf.position < from
# Move up
wf.update_attribute :position, wf.position + 1
elsif wf.position <= to && wf.position > from
# Move down
wf.update_attribute :position, wf.position - 1
end
end
end
respond_to do |format|
format.html
format.js {
render inline: "location.replace('#{custom_workflows_path}');"
}
end
end
def index def index
@workflows = CustomWorkflow.includes(:projects).all @workflows = CustomWorkflow.includes(:projects).all
@ -52,14 +76,30 @@ class CustomWorkflowsController < ApplicationController
end end
def create def create
@workflow = CustomWorkflow.new(params[:custom_workflow]) @workflow = CustomWorkflow.new
@workflow.before_save = params[:custom_workflow][:before_save]
@workflow.after_save = params[:custom_workflow][:after_save]
@workflow.name = params[:custom_workflow][:name]
@workflow.description = params[:custom_workflow][:description]
@workflow.position = CustomWorkflow.count + 1
@workflow.is_for_all = params[:custom_workflow][:is_for_all].present?
@workflow.author = params[:custom_workflow][:author]
@workflow.active = params[:custom_workflow][:active]
@workflow.observable = params[:custom_workflow][:observable]
@workflow.shared_code = params[:custom_workflow][:shared_code]
@workflow.before_add = params[:custom_workflow][:before_add]
@workflow.after_add = params[:custom_workflow][:after_add]
@workflow.before_remove = params[:custom_workflow][:before_remove]
@workflow.after_remove = params[:custom_workflow][:after_remove]
@workflow.before_destroy = params[:custom_workflow][:before_destroy]
@workflow.after_destroy = params[:custom_workflow][:after_destroy]
respond_to do |format| respond_to do |format|
if params.has_key?(:commit) && @workflow.save if params.has_key?(:commit) && @workflow.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
cookies[:custom_workflows_author] = @workflow.author cookies[:custom_workflows_author] = @workflow.author
format.html { redirect_to(custom_workflows_path) } format.html { redirect_to(custom_workflows_path) }
else else
format.html { render :action => "new" } format.html { render action: :new }
end end
end end
end end
@ -70,26 +110,38 @@ class CustomWorkflowsController < ApplicationController
flash[:notice] = l(:notice_successful_status_change) flash[:notice] = l(:notice_successful_status_change)
format.html { redirect_to(custom_workflows_path) } format.html { redirect_to(custom_workflows_path) }
else else
format.html { render :action => :edit } format.html { render action: :edit }
end end
end end
end end
def update def update
respond_to do |format| respond_to do |format|
@workflow.assign_attributes(params[:custom_workflow]) @workflow.before_save = params[:custom_workflow][:before_save]
@workflow.after_save = params[:custom_workflow][:after_save]
@workflow.name = params[:custom_workflow][:name]
@workflow.description = params[:custom_workflow][:description]
@workflow.is_for_all = params[:custom_workflow][:is_for_all].present?
@workflow.author = params[:custom_workflow][:author]
@workflow.active = params[:custom_workflow][:active]
@workflow.shared_code = params[:custom_workflow][:shared_code]
@workflow.before_add = params[:custom_workflow][:before_add]
@workflow.after_add = params[:custom_workflow][:after_add]
@workflow.before_remove = params[:custom_workflow][:before_remove]
@workflow.after_remove = params[:custom_workflow][:after_remove]
@workflow.before_destroy = params[:custom_workflow][:before_destroy]
@workflow.after_destroy = params[:custom_workflow][:after_destroy]
if params.has_key?(:commit) && @workflow.save if params.has_key?(:commit) && @workflow.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
format.html { redirect_to(custom_workflows_path) } format.html { redirect_to(custom_workflows_path) }
else else
format.html { render :action => :edit } format.html { render action: :edit }
end end
end end
end end
def destroy def destroy
@workflow.destroy @workflow.destroy
respond_to do |format| respond_to do |format|
flash[:notice] = l(:notice_successful_delete) flash[:notice] = l(:notice_successful_delete)
format.html { redirect_to(custom_workflows_path) } format.html { redirect_to(custom_workflows_path) }

View File

@ -14,7 +14,6 @@ class CustomWorkflow < ActiveRecord::Base
COLLECTION_OBSERVABLES = [:group_users, :issue_attachments, :project_attachments, :wiki_page_attachments] COLLECTION_OBSERVABLES = [:group_users, :issue_attachments, :project_attachments, :wiki_page_attachments]
SINGLE_OBSERVABLES = [:issue, :user, :group, :attachment, :project, :wiki_content, :time_entry, :version] SINGLE_OBSERVABLES = [:issue, :user, :group, :attachment, :project, :wiki_content, :time_entry, :version]
attr_protected :id
has_and_belongs_to_many :projects has_and_belongs_to_many :projects
acts_as_list acts_as_list
@ -33,7 +32,8 @@ class CustomWorkflow < ActiveRecord::Base
scope :active, lambda { where(:active => true) } scope :active, lambda { where(:active => true) }
scope :for_project, (lambda do |project| scope :for_project, (lambda do |project|
where("is_for_all OR EXISTS (SELECT * FROM #{projects_join_table} WHERE project_id=? AND custom_workflow_id=id)", project.id) where("is_for_all=? OR EXISTS (SELECT * FROM #{projects_join_table} WHERE project_id=? AND custom_workflow_id=id)",
1, project.id)
end) end)
scope :observing, lambda { |observable| where(:observable => observable) } scope :observing, lambda { |observable| where(:observable => observable) }
@ -104,7 +104,7 @@ class CustomWorkflow < ActiveRecord::Base
def validate_syntax_for(object, event) def validate_syntax_for(object, event)
object.instance_eval(read_attribute(event)) if respond_to?(event) && read_attribute(event) object.instance_eval(read_attribute(event)) if respond_to?(event) && read_attribute(event)
rescue WorkflowError => e rescue WorkflowError => _
rescue Exception => e rescue Exception => e
errors.add event, :invalid_script, :error => e errors.add event, :invalid_script, :error => e
end end

View File

@ -9,7 +9,7 @@
CustomWorkflow::OBSERVABLES.collect {|o| [l("custom_workflow_observable_#{o}"), o]}, {}, CustomWorkflow::OBSERVABLES.collect {|o| [l("custom_workflow_observable_#{o}"), o]}, {},
:onchange => 'this.form.submit()', :onchange => 'this.form.submit()',
:disabled => !@workflow.new_record? %></p> :disabled => !@workflow.new_record? %></p>
<p><%= f.text_area :description, :cols => 40, :rows => 5 %></p> <p><%= f.text_area :description, cols: 40, rows: 5 , class: 'wiki-edit' %></p>
<% if @workflow.has_projects_association? %> <% if @workflow.has_projects_association? %>
<p><%= f.check_box :is_for_all, :onclick => "checkAndDisable('custom_workflow_enabled_projects', this.checked);", :label => :field_enabled_for_all_projects %></p> <p><%= f.check_box :is_for_all, :onclick => "checkAndDisable('custom_workflow_enabled_projects', this.checked);", :label => :field_enabled_for_all_projects %></p>
<% end %> <% end %>
@ -44,69 +44,73 @@
<% when :shared %> <% when :shared %>
<%= f.text_area :shared_code, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :shared_code, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
<% when *CustomWorkflow::COLLECTION_OBSERVABLES %> <% when *CustomWorkflow::COLLECTION_OBSERVABLES %>
<%= render :layout => 'layouts/collapsible', <% collapsed = (not (@workflow.before_add.present? or @workflow.after_add.present? or @workflow.errors[:base].present?)) %>
:locals => { <fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
:collapsed => (not (@workflow.before_add.present? or @workflow.after_add.present? or @workflow.errors[:base].present?)), <legend onclick="toggleFieldset(this);"><%= l(:label_add_workflows) %></legend>
:label => l(:label_add_workflows)} do %> <div style="<%= collapsed ? 'display: none' : '' %>">
<div class="splitcontent"> <div class="splitcontent">
<div class="splitcontentleft"> <div class="splitcontentleft">
<%= f.text_area :before_add, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :before_add, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<%= f.text_area :after_add, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :after_add, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
</div>
</div> </div>
</div> </div>
<% end %> </fieldset>
<%= render :layout => 'layouts/collapsible', <% collapsed = (not (@workflow.before_remove.present? or @workflow.after_remove.present?)) %>
:locals => { <fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
:collapsed => (not (@workflow.before_remove.present? or @workflow.after_remove.present?)), <legend onclick="toggleFieldset(this);"><%= l(:label_remove_workflows) %></legend>
:label => l(:label_remove_workflows)} do %> <div style="<%= collapsed ? 'display: none' : '' %>">
<div class="splitcontent"> <div class="splitcontent">
<div class="splitcontentleft"> <div class="splitcontentleft">
<%= f.text_area :before_remove, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :before_remove, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<%= f.text_area :after_remove, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :after_remove, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
</div>
</div> </div>
</div> </div>
<% end %> </fieldset>
<% when *CustomWorkflow::SINGLE_OBSERVABLES %> <% when *CustomWorkflow::SINGLE_OBSERVABLES %>
<%= render :layout => 'layouts/collapsible', <% collapsed = (not (@workflow.before_save.present? or @workflow.after_save.present? or @workflow.errors[:base].present?)) %>
:locals => { <fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
:collapsed => (not (@workflow.before_save.present? or @workflow.after_save.present? or @workflow.errors[:base].present?)), <legend onclick="toggleFieldset(this);"><%= l(:label_save_workflows) %></legend>
:label => l(:label_save_workflows)} do %> <div style="<%= collapsed ? 'display: none' : '' %>">
<div class="splitcontent"> <div class="splitcontent">
<div class="splitcontentleft"> <div class="splitcontentleft">
<%= f.text_area :before_save, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :before_save, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
<% if observable == :issue %> <% if observable == :issue %>
<em class="info"><%= l(:text_custom_workflow_before_save_note) %></em> <em class="info"><%= l(:text_custom_workflow_before_save_note) %></em>
<% end %> <% end %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<%= f.text_area :after_save, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :after_save, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
<% if observable == :issue %> <% if observable == :issue %>
<em class="info"><%= l(:text_custom_workflow_after_save_note) %></em> <em class="info"><%= l(:text_custom_workflow_after_save_note) %></em>
<% end %> <% end %>
</div>
</div> </div>
</div> </div>
<% end %> </fieldset>
<%= render :layout => 'layouts/collapsible', <% collapsed = (not (@workflow.before_destroy.present? or @workflow.after_destroy.present?)) %>
:locals => { <fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
:collapsed => (not (@workflow.before_destroy.present? or @workflow.after_destroy.present?)), <legend onclick="toggleFieldset(this);"><%= l(:label_destroy_workflows) %></legend>
:label => l(:label_destroy_workflows)} do %> <div style="<%= collapsed ? 'display: none' : '' %>">
<div class="splitcontent"> <div class="splitcontent">
<div class="splitcontentleft"> <div class="splitcontentleft">
<%= f.text_area :before_destroy, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :before_destroy, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<%= f.text_area :after_destroy, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <%= f.text_area :after_destroy, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %>
</div>
</div> </div>
</div> </div>
<% end %> </fieldset>
<% end %> <% end %>
</fieldset> </fieldset>
<script type="text/javascript"> <script>
jQuery('.custom_workflow_script').taboverride(2, true); jQuery('.custom_workflow_script').taboverride(2, true);
function checkAndDisable(id, checked) { function checkAndDisable(id, checked) {
if (checked) { if (checked) {

View File

@ -38,7 +38,9 @@
<%= workflow.projects.map(&:name).join(", ") %> <%= workflow.projects.map(&:name).join(", ") %>
<% end %> <% end %>
</td> </td>
<td align="center" nowrap><%= reorder_links("custom_workflow", {:action => 'update', :id => workflow, :commit => true}) %></td> <td align="center" nowrap>
<%= reorder_handle(workflow, url: url_for(action: 'reorder', id: workflow) ) %>
</td>
<td class="buttons"> <td class="buttons">
<% if workflow.active? %> <% if workflow.active? %>
<%= link_to(l(:button_custom_workflow_deactivate), custom_workflow_status_path(workflow, :active => false), :class => 'icon icon-inactive', :method => :post) %> <%= link_to(l(:button_custom_workflow_deactivate), custom_workflow_status_path(workflow, :active => false), :class => 'icon icon-inactive', :method => :post) %>
@ -74,3 +76,7 @@
</p> </p>
<% end %> <% end %>
</div> </div>
<%= javascript_tag do %>
$(function() { $("table.custom-workflows tbody").positionedItems(); });
<% end %>

View File

@ -1,6 +0,0 @@
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
<legend onclick="toggleFieldset(this);"><%= label %></legend>
<div style="<%= collapsed ? 'display: none' : '' %>">
<%= yield %>
</div>
</fieldset>

View File

@ -1,4 +1,4 @@
<%= form_for @project do |f| %> <%= form_for @project do %>
<%= hidden_field_tag :tab, 'custom_workflow' %> <%= hidden_field_tag :tab, 'custom_workflow' %>
<%= hidden_field_tag 'project[custom_workflow_ids][]', '' %> <%= hidden_field_tag 'project[custom_workflow_ids][]', '' %>
<fieldset> <fieldset>

View File

@ -6,7 +6,7 @@
}; };
function TabOverride(element, tabSize, autoIndent) { function TabOverride(element, tabSize, autoIndent) {
var ta = document.createElement('textarea'); let ta = document.createElement('textarea');
ta.value = '\n'; ta.value = '\n';
this.newline = ta.value; this.newline = ta.value;
@ -43,12 +43,11 @@
* @function * @function
*/ */
setTabSize:function (size) { setTabSize:function (size) {
var i;
if (!size) { // size is 0 or not specified (or falsy) if (!size) { // size is 0 or not specified (or falsy)
this.aTab = '\t'; this.aTab = '\t';
} else if (typeof size === 'number' && size > 0) { } else if (typeof size === 'number' && size > 0) {
this.aTab = ''; this.aTab = '';
for (i = 0; i < size; i += 1) { for (let i = 0; i < size; i += 1) {
this.aTab += ' '; this.aTab += ' ';
} }
} }
@ -64,7 +63,7 @@
* @private * @private
*/ */
overrideKeyPress:function (e) { overrideKeyPress:function (e) {
var key = e.keyCode; let key = e.keyCode;
if ((key === 9 || (key === 13 && this.autoIndent && !this.inWhitespace)) && !e.ctrlKey && !e.altKey) { if ((key === 9 || (key === 13 && this.autoIndent && !this.inWhitespace)) && !e.ctrlKey && !e.altKey) {
e.preventDefault(); e.preventDefault();
} }
@ -78,7 +77,7 @@
* @private * @private
*/ */
overrideKeyDown:function (e) { overrideKeyDown:function (e) {
var key = e.keyCode, // the key code for the key that was pressed let key = e.keyCode, // the key code for the key that was pressed
tab, // the string representing a tab tab, // the string representing a tab
tabLen, // the length of a tab tabLen, // the length of a tab
text, // initial text in the textarea text, // initial text in the textarea

104
config/locales/cs.yml Normal file
View File

@ -0,0 +1,104 @@
cs:
project_module_custom_workflows_module: Uživatelské procesy
permission_manage_project_workflow: Spravovat uživatelské procesy
label_custom_workflow: Uživatelský proces
label_custom_workflow_plural: Uživatelské procesy
label_custom_workflow_new: Vytvořit uživatelský proces
label_workflow_scripts: Skript procesu
label_enabled_projects: Povoleno pro projekt(y)
label_custom_workflow_export: Export
label_custom_workflow_import: Importovat proces
label_save_workflows: Uložení sledovaných objektů
label_destroy_workflows: Smazání sledovaných objektů
label_add_workflows: Přidání sledovaných objektů do sezanmu
label_remove_workflows: Odstranění sledovaných objektů za seznamu
button_import: Import
button_custom_workflow_activate: Aktivovat
button_custom_workflow_deactivate: Deaktivovat
field_after_save: Skript spuštěný po uložení sledovaného objektu
field_before_save: Skript spuštěný před uložením sledovaného objektu
field_after_destroy: Skript spuštěný po smazání sledovaného objektu
field_before_destroy: Skript spuštěný před smazáním sledovaného objektu
field_after_add: Skript spuštěný po přidání sledovaného objektu do seznamu
field_before_add: Skript spuštěný před přidáním sledovaného objektu do seznamu
field_after_remove: Skript spuštěný po odstranění sledovaného objektu ze seznamu
field_before_remove: Skript spuštěný před odstraněním sledovaného objektu ze seznamu
field_shared_code: Sdílený kód
field_observable: Sledovaný objekt
field_is_enabled: Povoleno
field_enabled_for_all_projects: Povoleno pro všechny projekty
field_custom_workflow_author: Autorův e-mail
field_custom_workflow_file: Select the XML file previously exported process
field_custom_workflow_active: Aktivní
field_custom_workflow:
script: Skript
notice_successful_import: Uživatelský proces byl úspěšně naimportován
notice_successful_status_change: Status byl úspěšně změněn
error_failed_import: Chyba při importu uživatelského procesu (Neznámý formát? Podívejte se do logu.)
activerecord:
errors:
messages:
invalid_script: "obsahuje chyby: %{error}"
custom_workflow_error: Chyba uživatelského procesu (kontaktujte administrátora)
new_status_invalid: "změna z '%{old_status}' na '%{new_status}' není povolena"
scripts_absent: Musí být definován alespoň jeden skript
text_select_project_custom_workflows: Vyberte uživatelský skript projektu
text_custom_workflow_before_save_note: "Zde můžete měnit vlastnosti úkolu. Ve skriptu nevytvářejte ani neměňte
související úkoly. Pro ukončení skriptu chybou použijte: `raise WorkflowError, 'Zpráva uživateli'`."
text_custom_workflow_after_save_note: Zde můžete aktualizovat nebo vytvářet souvissející úkoly. Mějte na paměti, že
tento skript bude také vykonán pro nově vytvořené úkoly. Takže nezapomeňte udělat vhodné kontroly pro zabránění
rekurzivnímu volání.
text_custom_workflow_issue_code_note: Skripty jsou vykonávány v rámci objektu úkolu stejně jako volání `before_save`
a `after_save` funkcí. Takže lze použít přímo vlastností úkolů. Proměnné (@variable) jsou rovněž dostupné a lze jich
použít.
text_custom_workflow_shared_code_note: Tento kód bude spuštěn pře jakýmkoli jiným procesem a může obsahovat sdílený
kód, např. funkce a třídy, které jsou potřeba v jiných procesech
text_custom_workflow_user_code_note: Skripty jsou vykonávány v rámci objektu uživatel, když se objekt mění (maže).
Můžete přímo použít metody a vlastnosti objektu.
text_custom_workflow_group_code_note: Skripty jsou vykonávány v rámci objektu skupina, když se objekt mění (maže).
Můžete přímo použít metody a vlastnosti objektu.
text_custom_workflow_group_users_code_note: Tyto skripty jsou vykonávány, když je uživatel přidán nebo odebrán ze
skupiny. Pro přístup k objektům použijte proměnné @user a @group.
text_custom_workflow_attachment_code_note: Skripty jsou vykonávány v rámci objektu příloha, když se tento objekt mění
(maže se). Můžete přímo použít metody a vlastnosti objektu. Mějte na paměti, že se to týká všech typů příloh
(u úkolů, dokumentů, wiki stránek atd.), takže byste měli zkontrolovat proměnnou 'container_type' pro určení,
o jakou přílohu se jedná.
text_custom_workflow_issue_attachments_code_note: Tento skripty se vykonávají když je příloha přidána nebo odebrába
z úkolu. Můžete použít proměnné @issue a @attachment pro přístup k těmto objektům ve skriptu.
text_custom_workflow_project_code_note: SSkripty jsou vykonávány v rámci objektu projekt, když se objekt mění (maže).
Můžete přímo použít metody a vlastnosti objektu.
text_custom_workflow_project_attachments_code_note: Tyto skripty jsou vykonávány, když se přidává nebo se maže soubor
u projektu. Můžete použít proměnné @project a @attachment pro přístup k těmto objektům ve skriptu.
text_custom_workflow_wiki_content_code_note: Tyto kripty jsou vykonávány v rámci objektu Wiki, když se mění nebo se
maže. Můžete přímo použít metody a vlastnosti objektu.
text_custom_workflow_wiki_page_attachments_code_note: Tyto skripty jsou vykonávány, když se přidává nebo se maže
příloha u wiki stránky. Můžete použít proměnné @page a @attachment pro přístup k těmto objektům ve skriptu.
text_custom_workflow_time_entry_code_note: Skripty jsou vykonávány v rámci objektu časový záznam, kdyže se mění nebo
se maže. Můžete přímo použít metody a vlastnosti objektu.
text_custom_workflow_version_code_note: Skripty jsou vykonávány v rámci objektu verze, když se mění nebo se maže.
Můžete přímo použít metody a vlastnosti objektu.
text_no_enabled_projects: Žádné projekty
text_custom_workflow_author: Bude zahrnuto do exportovaného XML
text_custom_workflow_disabled: zakázáno administrátorem
text_custom_workflow_is_for_all: povoleno pro všechny projekty
custom_workflow_observable_shared: <sdílený kód>
custom_workflow_observable_issue: Úkol
custom_workflow_observable_issue_attachments: Přílohy úkolů
custom_workflow_observable_group: Skupina
custom_workflow_observable_user: Uživatel
custom_workflow_observable_attachment: Příloha
custom_workflow_observable_project: Projekt
custom_workflow_observable_project_attachments: Soubory
custom_workflow_observable_wiki_content: Wiki
custom_workflow_observable_wiki_page_attachments: Přílohy na wiki
custom_workflow_observable_group_users: Uživatelé skupin
custom_workflow_observable_time_entry: Časový záznam
custom_workflow_observable_version: Verze

View File

@ -4,4 +4,5 @@ RedmineApp::Application.routes.draw do
post '/custom_workflows/:id', :to => 'custom_workflows#update' post '/custom_workflows/:id', :to => 'custom_workflows#update'
get '/custom_workflows/:id/export', :to => 'custom_workflows#export', :as => 'export_custom_workflow' get '/custom_workflows/:id/export', :to => 'custom_workflows#export', :as => 'export_custom_workflow'
post '/custom_workflows/:id/change_status', :to => 'custom_workflows#change_status', :as => 'custom_workflow_status' post '/custom_workflows/:id/change_status', :to => 'custom_workflows#change_status', :as => 'custom_workflow_status'
put '/custom_workflows/:id/reorder', :to => 'custom_workflows#reorder'
end end

View File

@ -1,5 +1,5 @@
class CreateCustomWorkflows < ActiveRecord::Migration class CreateCustomWorkflows < ActiveRecord::Migration[4.2]
def self.up def change
create_table :custom_workflows, :force => true do |t| create_table :custom_workflows, :force => true do |t|
t.references :project t.references :project
t.text :script, :null => true, :default => nil t.text :script, :null => true, :default => nil
@ -8,7 +8,4 @@ class CreateCustomWorkflows < ActiveRecord::Migration
add_index :custom_workflows, [:project_id], :unique => true add_index :custom_workflows, [:project_id], :unique => true
end end
def self.down
drop_table :custom_workflows
end
end end

View File

@ -1,4 +1,4 @@
class AlterCustomWorkflows < ActiveRecord::Migration class AlterCustomWorkflows < ActiveRecord::Migration[4.2]
def self.up def self.up
remove_column :custom_workflows, :project_id remove_column :custom_workflows, :project_id
remove_column :custom_workflows, :is_enabled remove_column :custom_workflows, :is_enabled
@ -7,6 +7,4 @@ class AlterCustomWorkflows < ActiveRecord::Migration
add_column :custom_workflows, :position, :integer, :null => false, :default => 1 add_column :custom_workflows, :position, :integer, :null => false, :default => 1
end end
def self.down
end
end end

View File

@ -1,5 +1,5 @@
class CreateCustomWorkflowsProjects < ActiveRecord::Migration class CreateCustomWorkflowsProjects < ActiveRecord::Migration[4.2]
def self.up def change
create_table :custom_workflows_projects, :force => true, :id => false do |t| create_table :custom_workflows_projects, :force => true, :id => false do |t|
t.references :project t.references :project
t.references :custom_workflow t.references :custom_workflow
@ -8,7 +8,4 @@ class CreateCustomWorkflowsProjects < ActiveRecord::Migration
add_index :custom_workflows_projects, [:custom_workflow_id] add_index :custom_workflows_projects, [:custom_workflow_id]
end end
def self.down
drop_table :custom_workflows_projects
end
end end

View File

@ -1,8 +1,6 @@
class ChangeCustomWorkflowsDescriptionType < ActiveRecord::Migration class ChangeCustomWorkflowsDescriptionType < ActiveRecord::Migration[4.2]
def self.up def self.up
change_column :custom_workflows, :description, :text, :null => true, :default => nil change_column :custom_workflows, :description, :text, :null => true, :default => nil
end end
def self.down
end
end end

View File

@ -1,4 +1,4 @@
class AddAfterSaveToCustomWorkflows < ActiveRecord::Migration class AddAfterSaveToCustomWorkflows < ActiveRecord::Migration[4.2]
def self.up def self.up
rename_column :custom_workflows, :script, :before_save rename_column :custom_workflows, :script, :before_save
change_column :custom_workflows, :before_save, :text, :null => true change_column :custom_workflows, :before_save, :text, :null => true

View File

@ -1,8 +1,5 @@
class AddIsForAllToCustomWorkflows < ActiveRecord::Migration class AddIsForAllToCustomWorkflows < ActiveRecord::Migration[4.2]
def self.up def change
add_column :custom_workflows, :is_for_all, :boolean, :null => false, :default => false add_column :custom_workflows, :is_for_all, :boolean, :null => false, :default => false
end end
def self.down
remove_column :custom_workflows, :is_for_all
end
end end

View File

@ -1,8 +1,6 @@
class MakeAfterSaveAndBeforeSaveNullable < ActiveRecord::Migration class MakeAfterSaveAndBeforeSaveNullable < ActiveRecord::Migration[4.2]
def up def up
change_column :custom_workflows, :before_save, :text, :null => true, :default => nil change_column :custom_workflows, :before_save, :text, :null => true, :default => nil
change_column :custom_workflows, :after_save, :text, :null => true, :default => nil change_column :custom_workflows, :after_save, :text, :null => true, :default => nil
end end
def down
end
end end

View File

@ -1,7 +1,5 @@
class SetPositionFieldNullable < ActiveRecord::Migration class SetPositionFieldNullable < ActiveRecord::Migration[4.2]
def up def up
change_column :custom_workflows, :position, :integer, :null => true change_column :custom_workflows, :position, :integer, :null => true
end end
def down
end
end end

View File

@ -1,4 +1,4 @@
class AddAuthorAndTimestampsToCustomWorkflows < ActiveRecord::Migration class AddAuthorAndTimestampsToCustomWorkflows < ActiveRecord::Migration[4.2]
def change def change
add_column :custom_workflows, :author, :string, :null => true add_column :custom_workflows, :author, :string, :null => true
add_timestamps :custom_workflows add_timestamps :custom_workflows

View File

@ -1,4 +1,4 @@
class CreateExampleWorkflow < ActiveRecord::Migration class CreateExampleWorkflow < ActiveRecord::Migration[4.2]
def self.up def self.up
CustomWorkflow.reset_column_information CustomWorkflow.reset_column_information
old = CustomWorkflow.where(:name => 'Duration/Done Ratio/Status correlation').first old = CustomWorkflow.where(:name => 'Duration/Done Ratio/Status correlation').first

View File

@ -1,4 +1,4 @@
class AddActiveFieldToCustomWorkflows < ActiveRecord::Migration class AddActiveFieldToCustomWorkflows < ActiveRecord::Migration[4.2]
def change def change
add_column :custom_workflows, :active, :boolean, :null => false, :default => true add_column :custom_workflows, :active, :boolean, :null => false, :default => true
end end

View File

@ -1,4 +1,4 @@
class AddObservableFieldToCustomWorkflows < ActiveRecord::Migration class AddObservableFieldToCustomWorkflows < ActiveRecord::Migration[4.2]
def change def change
add_column :custom_workflows, :observable, :string, :null => false, :default => 'issue' add_column :custom_workflows, :observable, :string, :null => false, :default => 'issue'
end end

View File

@ -1,4 +1,4 @@
class AddAdditionalScriptFieldsToCustomWorkflows < ActiveRecord::Migration class AddAdditionalScriptFieldsToCustomWorkflows < ActiveRecord::Migration[4.2]
def change def change
add_column :custom_workflows, :shared_code, :text, :null => true add_column :custom_workflows, :shared_code, :text, :null => true
add_column :custom_workflows, :before_add, :text, :null => true add_column :custom_workflows, :before_add, :text, :null => true

View File

@ -1,4 +1,4 @@
class AddBeforeAndAfterDestroyToCustomWorkflows < ActiveRecord::Migration class AddBeforeAndAfterDestroyToCustomWorkflows < ActiveRecord::Migration[4.2]
def change def change
add_column :custom_workflows, :before_destroy, :text, :null => true add_column :custom_workflows, :before_destroy, :text, :null => true
add_column :custom_workflows, :after_destroy, :text, :null => true add_column :custom_workflows, :after_destroy, :text, :null => true

10
init.rb
View File

@ -7,21 +7,23 @@ Redmine::Plugin.register :redmine_custom_workflows do
version '0.1.6' version '0.1.6'
url 'http://www.redmine.org/plugins/custom-workflows' url 'http://www.redmine.org/plugins/custom-workflows'
requires_redmine version_or_higher: '4.0.0'
menu :admin_menu, :custom_workflows, {:controller => 'custom_workflows', :action => 'index'}, menu :admin_menu, :custom_workflows, {:controller => 'custom_workflows', :action => 'index'},
:if => Proc.new { User.current.admin? }, :caption => :label_custom_workflow_plural, :html => {:class => 'icon'} :if => Proc.new { User.current.admin? }, :caption => :label_custom_workflow_plural,
:html => {:class => 'icon icon-workflows'}
permission :manage_project_workflow, {}, :require => :member permission :manage_project_workflow, {}, :require => :member
end end
require 'redmine_custom_workflows/hooks' require 'redmine_custom_workflows/hooks'
require File.dirname(__FILE__) + '/lib/redmine_custom_workflows/projects_helper_patch'
Rails.application.config.to_prepare do Rails.application.config.to_prepare do
unless Project.include?(RedmineCustomWorkflows::ProjectPatch) unless Project.include?(RedmineCustomWorkflows::ProjectPatch)
Project.send(:include, RedmineCustomWorkflows::ProjectPatch) Project.send(:include, RedmineCustomWorkflows::ProjectPatch)
end end
unless ProjectsHelper.include?(RedmineCustomWorkflows::ProjectsHelperPatch)
ProjectsHelper.send(:include, RedmineCustomWorkflows::ProjectsHelperPatch)
end
unless Attachment.include?(RedmineCustomWorkflows::AttachmentPatch) unless Attachment.include?(RedmineCustomWorkflows::AttachmentPatch)
Attachment.send(:include, RedmineCustomWorkflows::AttachmentPatch) Attachment.send(:include, RedmineCustomWorkflows::AttachmentPatch)
end end

View File

@ -8,7 +8,7 @@ module RedmineCustomWorkflows
end end
module InstanceMethods module InstanceMethods
def custom_email(headers={}) def self.deliver_custom_email(headers={})
user = headers.delete :user user = headers.delete :user
headers[:to] = user.mail if user headers[:to] = user.mail if user
text_body = headers.delete :text_body text_body = headers.delete :text_body
@ -27,7 +27,7 @@ module RedmineCustomWorkflows
format.html { render template_name } unless Setting.plain_text_mail? format.html { render template_name } unless Setting.plain_text_mail?
end end
else else
raise 'Nor :text_body, :html_body or :template_name specified' raise 'Not :text_body, :html_body or :template_name specified'
end end
end end
end end

View File

@ -1,20 +1,14 @@
module RedmineCustomWorkflows module RedmineCustomWorkflows
module ProjectsHelperPatch module ProjectsHelperPatch
def self.included(base) def project_settings_tabs
base.send(:include, InstanceMethods) tabs = super
base.class_eval do tabs << {:name => 'custom_workflows', :action => :manage_project_workflow, :partial => 'projects/settings/custom_workflow',
alias_method_chain :project_settings_tabs, :custom_workflows :label => :label_custom_workflow_plural} if User.current.allowed_to?(:manage_project_workflow, @project)
end tabs
end end
module InstanceMethods
def project_settings_tabs_with_custom_workflows
tabs = project_settings_tabs_without_custom_workflows
tabs << {:name => 'custom_workflows', :action => :manage_project_workflow, :partial => 'projects/settings/custom_workflow',
:label => :label_custom_workflow_plural} if User.current.allowed_to?(:manage_project_workflow, @project)
tabs
end
end
end end
end end
ProjectsHelper.send(:prepend, RedmineCustomWorkflows::ProjectsHelperPatch)