mirror of
https://github.com/anteo/redmine_custom_workflows.git
synced 2026-01-26 00:04:20 +00:00
Redmine look & feel
This commit is contained in:
parent
640f3aa077
commit
3f901f6bbb
@ -1,7 +1,7 @@
|
|||||||
Custom Workflows plug-in
|
Custom Workflows plug-in
|
||||||
========================
|
========================
|
||||||
|
|
||||||
The current version of Redmine CustomWorkflows is **1.0.2** [](https://travis-ci.org/anteo/redmine_custom_workflows)
|
The current version of Redmine CustomWorkflows is **1.0.3 devel** [](https://travis-ci.org/anteo/redmine_custom_workflows)
|
||||||
|
|
||||||
This plug-in provides a great functionality for those who is familiar with the Ruby language.
|
This plug-in provides a great functionality for those who is familiar with the Ruby language.
|
||||||
It allows to customize workflow by defining own rules for issues processing. It's possible:
|
It allows to customize workflow by defining own rules for issues processing. It's possible:
|
||||||
|
|||||||
@ -99,23 +99,9 @@ class CustomWorkflowsController < ApplicationController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
@workflow = CustomWorkflow.new
|
@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.position = CustomWorkflow.count + 1
|
||||||
@workflow.is_for_all = params[:custom_workflow][:is_for_all] == '1'
|
|
||||||
@workflow.author = params[:custom_workflow][:author]
|
|
||||||
@workflow.active = params[:custom_workflow][:active]
|
|
||||||
@workflow.observable = params[:custom_workflow][:observable]
|
@workflow.observable = params[:custom_workflow][:observable]
|
||||||
@workflow.shared_code = params[:custom_workflow][:shared_code]
|
update_from_params
|
||||||
@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]
|
|
||||||
@workflow.project_ids = params[:custom_workflow][:project_ids]
|
|
||||||
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)
|
||||||
@ -140,21 +126,7 @@ class CustomWorkflowsController < ApplicationController
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
@workflow.before_save = params[:custom_workflow][:before_save]
|
update_from_params
|
||||||
@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] == '1'
|
|
||||||
@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]
|
|
||||||
@workflow.project_ids = params[:custom_workflow][:project_ids]
|
|
||||||
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) }
|
||||||
@ -180,4 +152,22 @@ class CustomWorkflowsController < ApplicationController
|
|||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_from_params
|
||||||
|
@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] == '1'
|
||||||
|
@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]
|
||||||
|
@workflow.project_ids = params[:custom_workflow][:project_ids]
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -31,11 +31,11 @@ class CustomWorkflow < ActiveRecord::Base
|
|||||||
acts_as_list
|
acts_as_list
|
||||||
|
|
||||||
validates_presence_of :name
|
validates_presence_of :name
|
||||||
validates_uniqueness_of :name, :case_sensitive => false
|
validates_uniqueness_of :name, case_sensitive: false
|
||||||
validates_format_of :author, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
|
validates_format_of :author, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, allow_blank: true
|
||||||
validate :validate_syntax, :validate_scripts_presence, :if => Proc.new {|workflow| workflow.respond_to?(:observable) and workflow.active?}
|
validate :validate_syntax, :validate_scripts_presence, if: Proc.new { |workflow| workflow.respond_to?(:observable) and workflow.active? }
|
||||||
|
|
||||||
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 #{reflect_on_association(:projects).join_table} WHERE project_id=? AND custom_workflow_id=id)",
|
where("is_for_all=? OR EXISTS (SELECT * FROM #{reflect_on_association(:projects).join_table} WHERE project_id=? AND custom_workflow_id=id)",
|
||||||
true, project.id)
|
true, project.id)
|
||||||
@ -43,11 +43,11 @@ class CustomWorkflow < ActiveRecord::Base
|
|||||||
|
|
||||||
def self.import_from_xml(xml)
|
def self.import_from_xml(xml)
|
||||||
attributes = Hash.from_xml(xml).values.first
|
attributes = Hash.from_xml(xml).values.first
|
||||||
attributes.delete('exported_at')
|
attributes.delete 'exported_at'
|
||||||
attributes.delete('plugin_version')
|
attributes.delete 'plugin_version'
|
||||||
attributes.delete('ruby_version')
|
attributes.delete 'ruby_version'
|
||||||
attributes.delete('rails_version')
|
attributes.delete 'rails_version'
|
||||||
CustomWorkflow.new(attributes)
|
CustomWorkflow.new attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.log_message(str, object)
|
def self.log_message(str, object)
|
||||||
|
|||||||
@ -1,22 +1,45 @@
|
|||||||
|
<%
|
||||||
|
# encoding: utf-8
|
||||||
|
#
|
||||||
|
# Redmine plugin for Custom Workflows
|
||||||
|
#
|
||||||
|
# Copyright © 2015-19 Anton Argirov
|
||||||
|
# Copyright © 2019-20 Karel Pičman <karel.picman@kontron.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
%>
|
||||||
|
|
||||||
<div class="splitcontent">
|
<div class="splitcontent">
|
||||||
<div class="splitcontentleft">
|
<div class="splitcontentleft">
|
||||||
<div class="box tabular">
|
<div class="box tabular">
|
||||||
<p><%= f.text_field :name, :required => true, :size => 50 %></p>
|
<p><%= f.text_field :name, required: true %></p>
|
||||||
<p><%= f.text_field :author, :size => 50, :label => :field_custom_workflow_author %>
|
<p><%= f.text_field :author, label: :field_custom_workflow_author %>
|
||||||
<em class="info"><%= l(:text_custom_workflow_author) %></em>
|
<em class="info"><%= l(:text_custom_workflow_author) %></em>
|
||||||
</p>
|
</p>
|
||||||
<p><%= f.select :observable,
|
<p><%= f.select :observable,
|
||||||
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 , class: 'wiki-edit' %></p>
|
<p><%= f.text_area :description, class: 'wiki-edit' %></p>
|
||||||
<% if @workflow.has_projects_association? %>
|
<% if @workflow.has_projects_association? %>
|
||||||
<p>
|
<p>
|
||||||
<%= f.check_box :is_for_all, onclick: "checkAndDisable('custom_workflow_enabled_projects', this.checked);",
|
<%= f.check_box :is_for_all, onclick: "checkAndDisable('custom_workflow_enabled_projects', this.checked);",
|
||||||
label: :field_enabled_for_all_projects %>
|
label: :field_enabled_for_all_projects %>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p><%= f.check_box :active, :label => :field_custom_workflow_active %></p>
|
<p><%= f.check_box :active, label: l(:field_active) %></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% if @workflow.has_projects_association? %>
|
<% if @workflow.has_projects_association? %>
|
||||||
@ -28,102 +51,94 @@
|
|||||||
<%= l(:label_project_plural) %>
|
<%= l(:label_project_plural) %>
|
||||||
</legend>
|
</legend>
|
||||||
<%= render_project_nested_lists(Project.visible.active) do |p| %>
|
<%= render_project_nested_lists(Project.visible.active) do |p| %>
|
||||||
<%= content_tag('label',
|
<%= content_tag 'label',
|
||||||
check_box_tag('custom_workflow[project_ids][]', p.id,
|
check_box_tag('custom_workflow[project_ids][]', p.id,
|
||||||
@workflow.project_ids.include?(p.id) || @workflow.is_for_all?, id: nil,
|
@workflow.project_ids.include?(p.id) || @workflow.is_for_all?, id: nil,
|
||||||
:disabled => @workflow.is_for_all?) + ' ' + h(p), class: 'block') %>
|
disabled: @workflow.is_for_all?) + ' ' + h(p), class: 'block' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= hidden_field_tag('custom_workflow[project_ids][]', '', id: nil) %>
|
<%= hidden_field_tag 'custom_workflow[project_ids][]', '', id: nil %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="clear: left;"></div>
|
<div id="custom_workflow_scripts" class="box tabular">
|
||||||
|
<fieldset>
|
||||||
<fieldset class="box">
|
<legend><%= l(:label_workflow_scripts) %></legend>
|
||||||
<legend><%= l(:label_workflow_scripts) %></legend>
|
<% observable = @workflow.observable.to_sym %>
|
||||||
<% observable = @workflow.observable.to_sym %>
|
<div class="custom-workflow-info">
|
||||||
<p>
|
<em class="info"><%= l("text_custom_workflow_#{observable}_code_note") %></em>
|
||||||
<em class="info"><%= l("text_custom_workflow_#{observable}_code_note") %></em>
|
</div>
|
||||||
</p>
|
<% case observable %>
|
||||||
<% case observable %>
|
<% 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 %>
|
<% collapsed = !(@workflow.before_add.present? || @workflow.after_add.present? || @workflow.errors[:base].present?) %>
|
||||||
<% collapsed = (not (@workflow.before_add.present? or @workflow.after_add.present? or @workflow.errors[:base].present?)) %>
|
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
||||||
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
<legend onclick="toggleFieldset(this);" class="icon icon-collapsed"><%= l(:label_add_workflows) %></legend>
|
||||||
<legend onclick="toggleFieldset(this);"><%= l(:label_add_workflows) %></legend>
|
<div class="<%= collapsed ? 'custom-workflow-hidden' : '' %>">
|
||||||
<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>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
<% collapsed = !(@workflow.before_remove.present? || @workflow.after_remove.present?) %>
|
||||||
<% collapsed = (not (@workflow.before_remove.present? or @workflow.after_remove.present?)) %>
|
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
||||||
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
<legend onclick="toggleFieldset(this);" class="icon icon-collapsed"><%= l(:label_remove_workflows) %></legend>
|
||||||
<legend onclick="toggleFieldset(this);"><%= l(:label_remove_workflows) %></legend>
|
<div class="<%= collapsed ? 'custom-workflow-hidden' : '' %>">
|
||||||
<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>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
<% when *CustomWorkflow::SINGLE_OBSERVABLES %>
|
||||||
<% when *CustomWorkflow::SINGLE_OBSERVABLES %>
|
<% collapsed = (not (@workflow.before_save.present? or @workflow.after_save.present? or @workflow.errors[:base].present?)) %>
|
||||||
<% collapsed = (not (@workflow.before_save.present? or @workflow.after_save.present? or @workflow.errors[:base].present?)) %>
|
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
||||||
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
<legend onclick="toggleFieldset(this);" class="icon icon-collapsed"><%= l(:label_save_workflows) %></legend>
|
||||||
<legend onclick="toggleFieldset(this);"><%= l(:label_save_workflows) %></legend>
|
<div class="<%= collapsed ? 'custom-workflow-hidden' : '' %>">
|
||||||
<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>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
<% collapsed = !(@workflow.before_destroy.present? || @workflow.after_destroy.present?) %>
|
||||||
<% collapsed = (not (@workflow.before_destroy.present? or @workflow.after_destroy.present?)) %>
|
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
||||||
<fieldset class="collapsible <%= collapsed ? 'collapsed' : '' %>">
|
<legend onclick="toggleFieldset(this);" class="icon icon-collapsed"><%= l(:label_destroy_workflows) %></legend>
|
||||||
<legend onclick="toggleFieldset(this);"><%= l(:label_destroy_workflows) %></legend>
|
<div class="<%= collapsed ? 'custom-workflow-hidden' : '' %>">
|
||||||
<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>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
<% end %>
|
||||||
<% end %>
|
</fieldset>
|
||||||
</fieldset>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
$('.custom_workflow_script').taboverride(2, true);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<%= wikitoolbar_for :custom_workflow_description %>
|
<%= wikitoolbar_for :custom_workflow_description %>
|
||||||
|
|
||||||
<% content_for :header_tags do %>
|
|
||||||
<%= javascript_include_tag 'tab_override', plugin: 'redmine_custom_workflows' %>
|
|
||||||
<% end %>
|
|
||||||
@ -1,10 +1,33 @@
|
|||||||
|
<%
|
||||||
|
# encoding: utf-8
|
||||||
|
#
|
||||||
|
# Redmine plugin for Custom Workflows
|
||||||
|
#
|
||||||
|
# Copyright © 2015-19 Anton Argirov
|
||||||
|
# Copyright © 2019-20 Karel Pičman <karel.picman@kontron.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
%>
|
||||||
|
|
||||||
<h2><%= link_to l(:label_custom_workflow_plural), custom_workflows_path %> » <%= @workflow %></h2>
|
<h2><%= link_to l(:label_custom_workflow_plural), custom_workflows_path %> » <%= @workflow %></h2>
|
||||||
|
|
||||||
<%= error_messages_for 'workflow' %>
|
<%= error_messages_for 'workflow' %>
|
||||||
|
|
||||||
<%= labelled_form_for @workflow do |f| %>
|
<%= labelled_form_for @workflow do |f| %>
|
||||||
<%= render :partial => 'form', :locals => {:f => f} %>
|
<%= render partial: 'form', locals: { f: f } %>
|
||||||
<%= submit_tag l(:button_save) %>
|
<%= submit_tag l(:button_save) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% html_title(l(:label_custom_workflow_plural), @workflow, l(:label_administration)) -%>
|
<% html_title l(:label_custom_workflow_plural), @workflow, l(:label_administration) %>
|
||||||
|
|||||||
@ -1,85 +1,94 @@
|
|||||||
<% html_title(l(:label_custom_workflow_plural)) -%>
|
<%
|
||||||
|
# encoding: utf-8
|
||||||
|
#
|
||||||
|
# Redmine plugin for Custom Workflows
|
||||||
|
#
|
||||||
|
# Copyright © 2015-19 Anton Argirov
|
||||||
|
# Copyright © 2019-20 Karel Pičman <karel.picman@kontron.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
%>
|
||||||
|
|
||||||
|
<% html_title l(:label_custom_workflow_plural) %>
|
||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
<%= link_to l(:label_custom_workflow_import), '#', :class => 'icon icon-import', :onclick => "showModal('import-dialog', '450px'); return false;" %>
|
<%= link_to l(:label_custom_workflow_new), new_custom_workflow_path, class: 'icon icon-add' %>
|
||||||
<%= link_to l(:label_custom_workflow_new), new_custom_workflow_path, :class => 'icon icon-add' %>
|
<%= actions_dropdown do %>
|
||||||
|
<%= link_to l(:label_custom_workflow_import), '#', class: 'icon icon-move',
|
||||||
|
onclick: "showModal('import-dialog', '450px'); return false;" %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2><%=l(:label_custom_workflow_plural)%></h2>
|
<h2><%= l(:label_custom_workflow_plural) %></h2>
|
||||||
|
|
||||||
<div class="autoscroll">
|
<div class="autoscroll">
|
||||||
<% if @workflows.any? %>
|
<% if @workflows.any? %>
|
||||||
<table class="custom-workflows list">
|
<table class="custom-workflows list" data-hascontextmenu="true">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><%= l(:field_name) %></th>
|
<th><%= l(:field_name) %></th>
|
||||||
<th><%= l(:field_description) %></th>
|
<th><%= l(:field_observable) %></th>
|
||||||
<th><%= l(:field_observable) %></th>
|
<th><%= l(:field_author) %></th>
|
||||||
<th><%= l(:field_author) %></th>
|
<th></th>
|
||||||
<th><%= l(:label_project_plural) %></th>
|
</tr>
|
||||||
<th><%= l(:button_sort) %></th>
|
</thead>
|
||||||
<th></th>
|
<tbody>
|
||||||
</tr>
|
<% @workflows.each do |workflow| %>
|
||||||
</thead>
|
<tr class="<%= cycle('odd', 'even') %> <%= 'disabled' unless workflow.active? %>">
|
||||||
<tbody>
|
<td class="name"><%= link_to workflow.name, edit_custom_workflow_path(workflow) %></td>
|
||||||
<% @workflows.each do |workflow| %>
|
<td class="observable"><%= l("custom_workflow_observable_#{workflow.observable}") %></td>
|
||||||
<tr class="<%= cycle("odd", "even") %> <%= 'disabled' unless workflow.active? %>">
|
<td class="author"><%= mail_to workflow.author if workflow.author.present? %></td>
|
||||||
<td class="name"><%= link_to(workflow.name, edit_custom_workflow_path(workflow)) %></td>
|
<td class="buttons">
|
||||||
<td class="description"><%= textilizable(workflow.description) %></td>
|
<%= reorder_handle workflow, url: url_for(action: 'reorder', id: workflow) %>
|
||||||
<td class="observable"><%= l("custom_workflow_observable_#{workflow.observable}") %></td>
|
<% if workflow.active? %>
|
||||||
<td class="author"><%= mail_to workflow.author if workflow.author.present? %></td>
|
<%= link_to l(:button_custom_workflow_deactivate), custom_workflow_status_path(workflow, active: false),
|
||||||
<td>
|
class: 'icon icon-lock', method: :post %>
|
||||||
<% if not workflow.has_projects_association? %>
|
<% else %>
|
||||||
-
|
<%= link_to l(:button_activate), custom_workflow_status_path(workflow, active: true),
|
||||||
<% elsif workflow.is_for_all? %>
|
class: 'icon icon-unlock', method: :post %>
|
||||||
<%= l(:field_enabled_for_all_projects) %>
|
<% end %>
|
||||||
<% elsif workflow.projects.empty? %>
|
<%= link_to l(:label_custom_workflow_export), export_custom_workflow_path(workflow),
|
||||||
<%= l(:text_no_enabled_projects) %>
|
class: 'icon icon-download', method: :get %>
|
||||||
<% else %>
|
<%= link_to l(:button_delete), workflow, class: 'icon icon-del', data: { confirm: l(:text_are_you_sure) },
|
||||||
<%= workflow.projects.map(&:name).join(", ") %>
|
confirm: l(:text_are_you_sure), method: :delete %>
|
||||||
<% end %>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
<td align="center" nowrap>
|
<% end %>
|
||||||
<%= reorder_handle(workflow, url: url_for(action: 'reorder', id: workflow) ) %>
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
<td class="buttons">
|
|
||||||
<div class="icon"></div>
|
|
||||||
<% if workflow.active? %>
|
|
||||||
<%= link_to(l(:button_custom_workflow_deactivate), custom_workflow_status_path(workflow, active: false), class: 'icon icon-lock', method: :post) %>
|
|
||||||
<% else %>
|
|
||||||
<%= link_to(l(:button_custom_workflow_activate), custom_workflow_status_path(workflow, active: true), class: 'icon icon-unlock', method: :post) %>
|
|
||||||
<% end %>
|
|
||||||
<br/>
|
|
||||||
<%= link_to(l(:label_custom_workflow_export), export_custom_workflow_path(workflow), class: 'icon icon-export', method: :get) %>
|
|
||||||
<br/>
|
|
||||||
<%= link_to(l(:button_delete), workflow, class: 'icon icon-del', data: { confirm: l(:text_are_you_sure) }, confirm: l(:text_are_you_sure), method: :delete) %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="import-dialog" class="custom-workflow-hidden">
|
||||||
<div id="import-dialog" style="display: none">
|
|
||||||
<h3 class="title"><%= l(:label_custom_workflow_import) %></h3>
|
<h3 class="title"><%= l(:label_custom_workflow_import) %></h3>
|
||||||
<%= form_tag import_custom_workflow_path, :multipart => true do %>
|
<%= form_tag import_custom_workflow_path, :multipart => true do %>
|
||||||
<p>
|
<p>
|
||||||
<%= l(:field_custom_workflow_file) %>:
|
<%= l(:field_custom_workflow_file) %>:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<%= file_field_tag 'file', :accept => 'application/xml' %>
|
<%= file_field_tag 'file', accept: 'application/xml' %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="buttons">
|
<p class="buttons">
|
||||||
<%= submit_tag l(:button_import), :name => nil, :onclick => "hideModal(this);" %>
|
<%= submit_tag l(:button_import), name: nil, onclick: 'hideModal(this);' %>
|
||||||
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
|
<%= submit_tag l(:button_cancel), name: nil, onclick: 'hideModal(this);', type: 'button' %>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= javascript_tag do %>
|
<%= javascript_tag do %>
|
||||||
$(function() { $("table.custom-workflows tbody").positionedItems(); });
|
$(function() {
|
||||||
|
$("table.custom-workflows tbody").positionedItems();
|
||||||
|
});
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@ -1,10 +1,33 @@
|
|||||||
|
<%
|
||||||
|
# encoding: utf-8
|
||||||
|
#
|
||||||
|
# Redmine plugin for Custom Workflows
|
||||||
|
#
|
||||||
|
# Copyright © 2015-19 Anton Argirov
|
||||||
|
# Copyright © 2019-20 Karel Pičman <karel.picman@kontron.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
%>
|
||||||
|
|
||||||
<h2><%= link_to l(:label_custom_workflow_plural), custom_workflows_path %> » <%= l(:label_custom_workflow_new) %></h2>
|
<h2><%= link_to l(:label_custom_workflow_plural), custom_workflows_path %> » <%= l(:label_custom_workflow_new) %></h2>
|
||||||
|
|
||||||
<%= error_messages_for 'workflow' %>
|
<%= error_messages_for 'workflow' %>
|
||||||
|
|
||||||
<%= labelled_form_for @workflow do |f| %>
|
<%= labelled_form_for @workflow do |f| %>
|
||||||
<%= render :partial => 'form', :locals => {:f => f} %>
|
<%= render partial: 'form', locals: { f: f } %>
|
||||||
<%= submit_tag l(:button_create) %>
|
<%= submit_tag l(:button_create) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% html_title(l(:label_custom_workflow_plural), l(:label_custom_workflow_new), l(:label_administration)) -%>
|
<% html_title l(:label_custom_workflow_plural), l(:label_custom_workflow_new), l(:label_administration) %>
|
||||||
|
|||||||
@ -1,3 +1,26 @@
|
|||||||
|
<%
|
||||||
|
# encoding: utf-8
|
||||||
|
#
|
||||||
|
# Redmine plugin for Custom Workflows
|
||||||
|
#
|
||||||
|
# Copyright © 2015-19 Anton Argirov
|
||||||
|
# Copyright © 2019-20 Karel Pičman <karel.picman@kontron.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
%>
|
||||||
|
|
||||||
<%= form_for @project do %>
|
<%= 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][]', '' %>
|
||||||
@ -18,7 +41,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</label>
|
</label>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="<%= 'disabled' unless w.active? %>"><em><%= textilizable(w.description) %></em></dd>
|
<dd class="<%= 'disabled' unless w.active? %>"><em><%= textilizable w.description %></em></dd>
|
||||||
<% end %>
|
<% end %>
|
||||||
</dl>
|
</dl>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 247 B |
Binary file not shown.
|
Before Width: | Height: | Size: 259 B |
@ -1,353 +0,0 @@
|
|||||||
/* encoding: utf-8
|
|
||||||
*
|
|
||||||
* Redmine plugin for Custom Workflows
|
|
||||||
*
|
|
||||||
* Copyright © 2015-19 Anton Argirov
|
|
||||||
* Copyright © 2019-20 Karel Pičman <karel.picman@kontron.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function($) {
|
|
||||||
$.fn.taboverride = function(tabSize, autoIndent) {
|
|
||||||
this.each(function() {
|
|
||||||
$(this).data('taboverride', new TabOverride(this, tabSize, autoIndent));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function TabOverride(element, tabSize, autoIndent) {
|
|
||||||
let ta = document.createElement('textarea');
|
|
||||||
ta.value = '\n';
|
|
||||||
|
|
||||||
this.newline = ta.value;
|
|
||||||
this.newlineLen = this.newline.length;
|
|
||||||
this.autoIndent = autoIndent;
|
|
||||||
this.inWhitespace = false;
|
|
||||||
this.element = element;
|
|
||||||
this.setTabSize(tabSize);
|
|
||||||
|
|
||||||
$(element).on('keypress', $.proxy(this.overrideKeyPress, this));
|
|
||||||
$(element).on('keydown', $.proxy(this.overrideKeyDown, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
TabOverride.prototype = {
|
|
||||||
/**
|
|
||||||
* Returns the current tab size. 0 represents the tab character.
|
|
||||||
*
|
|
||||||
* @return {Number} the size (length) of the tab string or 0 for the tab character
|
|
||||||
*
|
|
||||||
* @name getTabSize
|
|
||||||
* @function
|
|
||||||
*/
|
|
||||||
getTabSize:function () {
|
|
||||||
return this.aTab === '\t' ? 0 : this.aTab.length;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the tab size for all elements that have Tab Override enabled.
|
|
||||||
* 0 represents the tab character.
|
|
||||||
*
|
|
||||||
* @param {Number} size the tab size (default = 0)
|
|
||||||
*
|
|
||||||
* @name setTabSize
|
|
||||||
* @function
|
|
||||||
*/
|
|
||||||
setTabSize:function (size) {
|
|
||||||
if (!size) { // size is 0 or not specified (or falsy)
|
|
||||||
this.aTab = '\t';
|
|
||||||
} else if (typeof size === 'number' && size > 0) {
|
|
||||||
this.aTab = '';
|
|
||||||
for (let i = 0; i < size; i += 1) {
|
|
||||||
this.aTab += ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevents the default action for the keyPress event when tab or enter are
|
|
||||||
* pressed. Opera (and Firefox) also fire a keypress event when the tab or
|
|
||||||
* enter key is pressed. Opera requires that the default action be prevented
|
|
||||||
* on this event or the textarea will lose focus.
|
|
||||||
*
|
|
||||||
* @param {Event} e the event object
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
overrideKeyPress:function (e) {
|
|
||||||
let key = e.keyCode;
|
|
||||||
if ((key === 9 || (key === 13 && this.autoIndent && !this.inWhitespace)) && !e.ctrlKey && !e.altKey) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts / removes tabs and newlines on the keyDown event for the tab or enter key.
|
|
||||||
*
|
|
||||||
* @param {Event} e the event object
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
overrideKeyDown:function (e) {
|
|
||||||
let key = e.keyCode, // the key code for the key that was pressed
|
|
||||||
tab, // the string representing a tab
|
|
||||||
tabLen, // the length of a tab
|
|
||||||
text, // initial text in the textarea
|
|
||||||
range, // the IE TextRange object
|
|
||||||
tempRange, // used to calculate selection start and end positions in IE
|
|
||||||
preNewlines, // the number of newline character sequences before the selection start (for IE)
|
|
||||||
selNewlines, // the number of newline character sequences within the selection (for IE)
|
|
||||||
initScrollTop, // initial scrollTop value used to fix scrolling in Firefox
|
|
||||||
selStart, // the selection start position
|
|
||||||
selEnd, // the selection end position
|
|
||||||
sel, // the selected text
|
|
||||||
startLine, // for multi-line selections, the first character position of the first line
|
|
||||||
endLine, // for multi-line selections, the last character position of the last line
|
|
||||||
numTabs, // the number of tabs inserted / removed in the selection
|
|
||||||
startTab, // if a tab was removed from the start of the first line
|
|
||||||
preTab, // if a tab was removed before the start of the selection
|
|
||||||
whitespace, // the whitespace at the beginning of the first selected line
|
|
||||||
whitespaceLen; // the length of the whitespace at the beginning of the first selected line
|
|
||||||
|
|
||||||
// don't do any unnecessary work
|
|
||||||
if ((key !== 9 && (key !== 13 || !this.autoIndent)) || e.ctrlKey || e.altKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize variables used for tab and enter keys
|
|
||||||
this.inWhitespace = false; // this will be set to true if enter is pressed in the leading whitespace
|
|
||||||
text = this.element.value;
|
|
||||||
|
|
||||||
// this is really just for Firefox, but will be used by all browsers that support
|
|
||||||
// selectionStart and selectionEnd - whenever the textarea value property is reset,
|
|
||||||
// Firefox scrolls back to the top - this is used to set it back to the original value
|
|
||||||
// scrollTop is nonstandard, but supported by all modern browsers
|
|
||||||
initScrollTop = this.element.scrollTop;
|
|
||||||
|
|
||||||
// get the text selection
|
|
||||||
// prefer the nonstandard document.selection way since it allows for
|
|
||||||
// automatic scrolling to the cursor via the range.select() method
|
|
||||||
if (document.selection) { // IE
|
|
||||||
range = document.selection.createRange();
|
|
||||||
sel = range.text;
|
|
||||||
tempRange = range.duplicate();
|
|
||||||
tempRange.moveToElementText(this.element);
|
|
||||||
tempRange.setEndPoint('EndToEnd', range);
|
|
||||||
selEnd = tempRange.text.length;
|
|
||||||
selStart = selEnd - sel.length;
|
|
||||||
|
|
||||||
// whenever the value of the textarea is changed, the range needs to be reset
|
|
||||||
// IE <9 (and Opera) use both \r and \n for newlines - this adds an extra character
|
|
||||||
// that needs to be accounted for when doing position calculations with ranges
|
|
||||||
// these values are used to offset the selection start and end positions
|
|
||||||
if (this.newlineLen > 1) {
|
|
||||||
preNewlines = text.slice(0, selStart).split(this.newline).length - 1;
|
|
||||||
selNewlines = sel.split(this.newline).length - 1;
|
|
||||||
} else {
|
|
||||||
preNewlines = selNewlines = 0;
|
|
||||||
}
|
|
||||||
} else if (typeof this.element.selectionStart !== 'undefined') {
|
|
||||||
selStart = this.element.selectionStart;
|
|
||||||
selEnd = this.element.selectionEnd;
|
|
||||||
sel = text.slice(selStart, selEnd);
|
|
||||||
} else {
|
|
||||||
return; // cannot access textarea selection - do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// tab key - insert / remove tab
|
|
||||||
if (key === 9) {
|
|
||||||
// initialize tab variables
|
|
||||||
tab = this.aTab;
|
|
||||||
tabLen = tab.length;
|
|
||||||
numTabs = 0;
|
|
||||||
startTab = 0;
|
|
||||||
preTab = 0;
|
|
||||||
|
|
||||||
// multi-line selection
|
|
||||||
if (selStart !== selEnd && sel.indexOf('\n') !== -1) {
|
|
||||||
if (text.charAt(selEnd - 1) === '\n') {
|
|
||||||
selEnd = selEnd - this.newlineLen;
|
|
||||||
sel = text.slice(selStart, selEnd);
|
|
||||||
}
|
|
||||||
// for multiple lines, only insert / remove tabs from the beginning of each line
|
|
||||||
|
|
||||||
// find the start of the first selected line
|
|
||||||
if (selStart === 0 || text.charAt(selStart - 1) === '\n') {
|
|
||||||
// the selection starts at the beginning of a line
|
|
||||||
startLine = selStart;
|
|
||||||
} else {
|
|
||||||
// the selection starts after the beginning of a line
|
|
||||||
// set startLine to the beginning of the first partially selected line
|
|
||||||
// subtract 1 from selStart in case the cursor is at the newline character,
|
|
||||||
// for instance, if the very end of the previous line was selected
|
|
||||||
// add 1 to get the next character after the newline
|
|
||||||
// if there is none before the selection, lastIndexOf returns -1
|
|
||||||
// when 1 is added to that it becomes 0 and the first character is used
|
|
||||||
startLine = text.lastIndexOf('\n', selStart - 1) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the end of the last selected line
|
|
||||||
if (selEnd === text.length || text.charAt(selEnd) === '\n') {
|
|
||||||
// the selection ends at the end of a line
|
|
||||||
endLine = selEnd;
|
|
||||||
} else {
|
|
||||||
// the selection ends before the end of a line
|
|
||||||
// set endLine to the end of the last partially selected line
|
|
||||||
endLine = text.indexOf('\n', selEnd);
|
|
||||||
if (endLine === -1) {
|
|
||||||
endLine = text.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if the shift key was pressed, remove tabs instead of inserting them
|
|
||||||
if (e.shiftKey) {
|
|
||||||
if (text.slice(startLine).indexOf(tab) === 0) {
|
|
||||||
// is this tab part of the selection?
|
|
||||||
if (startLine === selStart) {
|
|
||||||
// it is, remove it
|
|
||||||
sel = sel.slice(tabLen);
|
|
||||||
} else {
|
|
||||||
// the tab comes before the selection
|
|
||||||
preTab = tabLen;
|
|
||||||
}
|
|
||||||
startTab = tabLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.element.value = text.slice(0, startLine) + text.slice(startLine + preTab, selStart) +
|
|
||||||
sel.replace(new RegExp('\n' + tab, 'g'), function () {
|
|
||||||
numTabs += 1;
|
|
||||||
return '\n';
|
|
||||||
}) + text.slice(selEnd);
|
|
||||||
|
|
||||||
// set start and end points
|
|
||||||
if (range) { // IE
|
|
||||||
// setting end first makes calculations easier
|
|
||||||
range.collapse();
|
|
||||||
range.moveEnd('character', selEnd - startTab - (numTabs * tabLen) - selNewlines - preNewlines);
|
|
||||||
range.moveStart('character', selStart - preTab - preNewlines);
|
|
||||||
range.select();
|
|
||||||
} else {
|
|
||||||
// set start first for Opera
|
|
||||||
this.element.selectionStart = selStart - preTab; // preTab is 0 or tabLen
|
|
||||||
// move the selection end over by the total number of tabs removed
|
|
||||||
this.element.selectionEnd = selEnd - startTab - (numTabs * tabLen);
|
|
||||||
}
|
|
||||||
} else { // no shift key
|
|
||||||
numTabs = 1; // for the first tab
|
|
||||||
// insert tabs at the beginning of each line of the selection
|
|
||||||
this.element.value = text.slice(0, startLine) + tab + text.slice(startLine, selStart) +
|
|
||||||
sel.replace(/\n/g, function () {
|
|
||||||
numTabs += 1;
|
|
||||||
return '\n' + tab;
|
|
||||||
}) + text.slice(selEnd);
|
|
||||||
|
|
||||||
// set start and end points
|
|
||||||
if (range) { // IE
|
|
||||||
range.collapse();
|
|
||||||
range.moveEnd('character', selEnd + (numTabs * tabLen) - selNewlines - preNewlines);
|
|
||||||
range.moveStart('character', selStart + tabLen - preNewlines);
|
|
||||||
range.select();
|
|
||||||
} else {
|
|
||||||
// the selection start is always moved by 1 character
|
|
||||||
this.element.selectionStart = selStart + (selStart == startLine ? 0 : tabLen);
|
|
||||||
// move the selection end over by the total number of tabs inserted
|
|
||||||
this.element.selectionEnd = selEnd + (numTabs * tabLen);
|
|
||||||
this.element.scrollTop = initScrollTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // single line selection
|
|
||||||
// if the shift key was pressed, remove a tab instead of inserting one
|
|
||||||
if (e.shiftKey) {
|
|
||||||
// if the character before the selection is a tab, remove it
|
|
||||||
if (text.slice(selStart - tabLen).indexOf(tab) === 0) {
|
|
||||||
this.element.value = text.slice(0, selStart - tabLen) + text.slice(selStart);
|
|
||||||
|
|
||||||
// set start and end points
|
|
||||||
if (range) { // IE
|
|
||||||
// collapses range and moves it by -1 tab
|
|
||||||
range.move('character', selStart - tabLen - preNewlines);
|
|
||||||
range.select();
|
|
||||||
} else {
|
|
||||||
this.element.selectionEnd = this.element.selectionStart = selStart - tabLen;
|
|
||||||
this.element.scrollTop = initScrollTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // no shift key - insert a tab
|
|
||||||
if (range) { // IE
|
|
||||||
range.text = tab;
|
|
||||||
range.select();
|
|
||||||
} else {
|
|
||||||
this.element.value = text.slice(0, selStart) + tab + text.slice(selEnd);
|
|
||||||
this.element.selectionEnd = this.element.selectionStart = selStart + tabLen;
|
|
||||||
this.element.scrollTop = initScrollTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (this.autoIndent) { // Enter key
|
|
||||||
// insert a newline and copy the whitespace from the beginning of the line
|
|
||||||
// find the start of the first selected line
|
|
||||||
if (selStart === 0 || text.charAt(selStart - 1) === '\n') {
|
|
||||||
// the selection starts at the beginning of a line
|
|
||||||
// do nothing special
|
|
||||||
this.inWhitespace = true;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// see explanation under "multi-line selection" above
|
|
||||||
startLine = text.lastIndexOf('\n', selStart - 1) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the end of the first selected line
|
|
||||||
endLine = text.indexOf('\n', selStart);
|
|
||||||
|
|
||||||
// if no newline is found, set endLine to the end of the text
|
|
||||||
if (endLine === -1) {
|
|
||||||
endLine = text.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the whitespace at the beginning of the first selected line (spaces and tabs only)
|
|
||||||
whitespace = text.slice(startLine, endLine).match(/^[ \t]*/)[0];
|
|
||||||
whitespaceLen = whitespace.length;
|
|
||||||
|
|
||||||
// the cursor (selStart) is in the whitespace at beginning of the line
|
|
||||||
// do nothing special
|
|
||||||
if (selStart < startLine + whitespaceLen) {
|
|
||||||
this.inWhitespace = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (range) { // IE
|
|
||||||
// insert the newline and whitespace
|
|
||||||
range.text = '\n' + whitespace;
|
|
||||||
range.select();
|
|
||||||
} else {
|
|
||||||
// insert the newline and whitespace
|
|
||||||
this.element.value = text.slice(0, selStart) + '\n' + whitespace + text.slice(selEnd);
|
|
||||||
// Opera uses \r\n for a newline, instead of \n,
|
|
||||||
// so use newlineLen instead of a hard-coded value
|
|
||||||
this.element.selectionEnd = this.element.selectionStart = selStart + this.newlineLen + whitespaceLen;
|
|
||||||
this.element.scrollTop = initScrollTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
})(jQuery);
|
|
||||||
|
|
||||||
function checkAndDisable(id, checked) {
|
|
||||||
if (checked) {
|
|
||||||
$('#' + id).find('input[type=checkbox]').attr('checked', true).attr('disabled', true);
|
|
||||||
} else {
|
|
||||||
$('#' + id).find('input[type=checkbox]').removeAttr('checked').removeAttr('disabled');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -23,44 +23,27 @@
|
|||||||
color: silver;
|
color: silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.list.custom-workflows td {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.list.custom-workflows td.description {
|
|
||||||
text-align: left;
|
|
||||||
width: 40%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.list.custom-workflows td.buttons {
|
|
||||||
white-space: normal;
|
|
||||||
width: 10%;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.list.custom-workflows tr.disabled {
|
table.list.custom-workflows tr.disabled {
|
||||||
color: silver;
|
color: silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom_workflow_description, #custom_workflow_name {
|
|
||||||
width: 98%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom_workflow_script {
|
|
||||||
width: 98%;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#custom_workflow_enabled_projects ul.root {
|
#custom_workflow_enabled_projects ul.root {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Icons */
|
.custom-workflow-hidden {
|
||||||
.icon-import {
|
display: none;
|
||||||
background-image: url(../images/export.png);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-export {
|
.custom-workflow-info {
|
||||||
background-image: url(../images/import.png);
|
text-align: justify;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#custom_workflow_scripts label {
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 0;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
@ -27,7 +27,6 @@ cs:
|
|||||||
label_custom_workflow_plural: Uživatelské procesy
|
label_custom_workflow_plural: Uživatelské procesy
|
||||||
label_custom_workflow_new: Vytvořit uživatelský proces
|
label_custom_workflow_new: Vytvořit uživatelský proces
|
||||||
label_workflow_scripts: Skript procesu
|
label_workflow_scripts: Skript procesu
|
||||||
label_enabled_projects: Povoleno pro projekt(y)
|
|
||||||
label_custom_workflow_export: Export
|
label_custom_workflow_export: Export
|
||||||
label_custom_workflow_import: Importovat proces
|
label_custom_workflow_import: Importovat proces
|
||||||
label_save_workflows: Uložení sledovaných objektů
|
label_save_workflows: Uložení sledovaných objektů
|
||||||
@ -35,8 +34,6 @@ cs:
|
|||||||
label_add_workflows: Přidání sledovaných objektů do sezanmu
|
label_add_workflows: Přidání sledovaných objektů do sezanmu
|
||||||
label_remove_workflows: Odstranění sledovaných objektů za seznamu
|
label_remove_workflows: Odstranění sledovaných objektů za seznamu
|
||||||
|
|
||||||
button_import: Import
|
|
||||||
button_custom_workflow_activate: Aktivovat
|
|
||||||
button_custom_workflow_deactivate: Deaktivovat
|
button_custom_workflow_deactivate: Deaktivovat
|
||||||
|
|
||||||
field_after_save: Skript spuštěný po uložení sledovaného objektu
|
field_after_save: Skript spuštěný po uložení sledovaného objektu
|
||||||
@ -49,11 +46,9 @@ cs:
|
|||||||
field_before_remove: Skript spuštěný před odstraněním 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_shared_code: Sdílený kód
|
||||||
field_observable: Sledovaný objekt
|
field_observable: Sledovaný objekt
|
||||||
field_is_enabled: Povoleno
|
|
||||||
field_enabled_for_all_projects: Povoleno pro všechny projekty
|
field_enabled_for_all_projects: Povoleno pro všechny projekty
|
||||||
field_custom_workflow_author: Autorův e-mail
|
field_custom_workflow_author: Autorův e-mail
|
||||||
field_custom_workflow_file: Select the XML file previously exported process
|
field_custom_workflow_file: Select the XML file previously exported process
|
||||||
field_custom_workflow_active: Aktivní
|
|
||||||
field_custom_workflow:
|
field_custom_workflow:
|
||||||
script: Skript
|
script: Skript
|
||||||
|
|
||||||
@ -70,8 +65,8 @@ cs:
|
|||||||
scripts_absent: Musí být definován alespoň jeden skript
|
scripts_absent: Musí být definován alespoň jeden skript
|
||||||
|
|
||||||
text_select_project_custom_workflows: Vyberte uživatelský skript projektu
|
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
|
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'`."
|
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
|
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í
|
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í.
|
rekurzivnímu volání.
|
||||||
|
|||||||
@ -20,87 +20,101 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
en:
|
en:
|
||||||
project_module_custom_workflows_module: "Custom workflows"
|
project_module_custom_workflows_module: Custom workflows
|
||||||
permission_manage_project_workflow: "Manage project custom workflows"
|
permission_manage_project_workflow: Manage project custom workflows
|
||||||
|
|
||||||
label_custom_workflow: "Custom workflows"
|
label_custom_workflow: Custom workflow
|
||||||
label_custom_workflow_plural: "Custom workflows"
|
label_custom_workflow_plural: Custom workflows
|
||||||
label_custom_workflow_new: "Create a custom workflow"
|
label_custom_workflow_new: Create a custom workflow
|
||||||
label_workflow_scripts: "Workflow scripts"
|
label_workflow_scripts: Workflow scripts
|
||||||
label_enabled_projects: "Enabled for project(s)"
|
label_custom_workflow_export: Export
|
||||||
label_custom_workflow_export: "Export"
|
label_custom_workflow_import: Import workflow
|
||||||
label_custom_workflow_import: "Import workflow"
|
label_save_workflows: Saving observable objects
|
||||||
label_save_workflows: "Saving observable objects"
|
label_destroy_workflows: Destroying observable objects
|
||||||
label_destroy_workflows: "Destroying observable objects"
|
label_add_workflows: Adding observable objects to collection
|
||||||
label_add_workflows: "Adding observable objects to collection"
|
label_remove_workflows: Removing observable objects from collection
|
||||||
label_remove_workflows: "Removing observable objects from collection"
|
|
||||||
|
|
||||||
button_import: "Import"
|
button_custom_workflow_deactivate: Deactivate
|
||||||
button_custom_workflow_activate: "Activate"
|
|
||||||
button_custom_workflow_deactivate: "Deactivate"
|
|
||||||
|
|
||||||
field_after_save: "Workflow script executable after saving observable object"
|
field_after_save: Workflow script executable after saving observable object
|
||||||
field_before_save: "Workflow script executable before saving observable object"
|
field_before_save: Workflow script executable before saving observable object
|
||||||
field_after_destroy: "Workflow script executable after destroying observable object"
|
field_after_destroy: Workflow script executable after destroying observable object
|
||||||
field_before_destroy: "Workflow script executable before destroying observable object"
|
field_before_destroy: Workflow script executable before destroying observable object
|
||||||
field_after_add: "Workflow script executable after adding observable object to collection"
|
field_after_add: Workflow script executable after adding observable object to collection
|
||||||
field_before_add: "Workflow script executable before adding observable object to collection"
|
field_before_add: Workflow script executable before adding observable object to collection
|
||||||
field_after_remove: "Workflow script executable after removing observable object from collection"
|
field_after_remove: Workflow script executable after removing observable object from collection
|
||||||
field_before_remove: "Workflow script executable before removing observable object from collection"
|
field_before_remove: Workflow script executable before removing observable object from collection
|
||||||
field_shared_code: "Shared code"
|
field_shared_code: Shared code
|
||||||
field_observable: "Observable object"
|
field_observable: Observable object
|
||||||
field_is_enabled: "Enabled"
|
field_enabled_for_all_projects: Enabled for all projects
|
||||||
field_enabled_for_all_projects: "Enabled for all projects"
|
field_custom_workflow_author: Author's e-mail
|
||||||
field_custom_workflow_author: "Author's e-mail"
|
field_custom_workflow_file: Select the XML file previously exported process
|
||||||
field_custom_workflow_file: "Select the XML file previously exported process"
|
|
||||||
field_custom_workflow_active: "Active"
|
|
||||||
field_custom_workflow:
|
field_custom_workflow:
|
||||||
script: "Workflow script"
|
script: Workflow script
|
||||||
|
|
||||||
notice_successful_import: "Custom workflow has successfully imported"
|
notice_successful_import: Custom workflow has successfully imported
|
||||||
notice_successful_status_change: "Status has successfully changed"
|
notice_successful_status_change: Status has successfully changed
|
||||||
error_failed_import: "Error importing custom workflow (unknown format? please see log)"
|
error_failed_import: Error importing custom workflow (unknown format? please see log)
|
||||||
|
|
||||||
activerecord:
|
activerecord:
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
invalid_script: "contains error: %{error}"
|
invalid_script: "contains error: %{error}"
|
||||||
custom_workflow_error: "Custom workflow error (please contact administrator)"
|
custom_workflow_error: Custom workflow error (Please contact an administrator)
|
||||||
new_status_invalid: "transition from '%{old_status}' to '%{new_status}' is prohibited"
|
new_status_invalid: "transition from '%{old_status}' to '%{new_status}' is prohibited"
|
||||||
scripts_absent: "At least one script should be defined"
|
scripts_absent: At least one script should be defined
|
||||||
|
|
||||||
text_select_project_custom_workflows: Select project custom workflows
|
text_select_project_custom_workflows: Select project custom workflows
|
||||||
text_custom_workflow_before_save_note: You can change properties of the issues here. Do not create or update related issues in this script. To finish with error, use raise WorkflowError, "Message to user".
|
text_custom_workflow_before_save_note: You can change properties of the issues here. Do not create or update related
|
||||||
text_custom_workflow_after_save_note: You can update or create related issues here. Note that this script will be also executed for the newly created issues. So make appropriate checks to prevent infinite recursion.
|
issues in this script. To finish with error, use `raise WorkflowError, 'Message to user'`.
|
||||||
text_custom_workflow_issue_code_note: Scripts are executed in the context of Issue object like ordinary before_save and after_save callbacks. So use methods and properties of the issue directly (or through "self"). Instance variables (@variable) are also allowed and may be used if needed.
|
text_custom_workflow_after_save_note: You can update or create related issues here. Note that this script will be
|
||||||
text_custom_workflow_shared_code_note: This code will run before any other workflow and may contain shared code, e.g. functions and classes needed by other workflows
|
also executed for the newly created issues. So make appropriate checks to prevent infinite recursion.
|
||||||
text_custom_workflow_user_code_note: Scripts are executed in the context of User object when user object changes (destroys). Use methods and properties of the user directly (or through "self")
|
|
||||||
text_custom_workflow_group_code_note: Scripts are executed in the context of Group object when group object changes (destroys). Use methods and properties of the group directly (or through "self")
|
text_custom_workflow_issue_code_note: Scripts are executed in the context of Issue object like ordinary
|
||||||
text_custom_workflow_group_users_code_note: These scripts are executed when user being added to group/removed from group. Use variables @user and @group to access appropriate objects in your scripts.
|
before_save and after_save callbacks. So use methods and properties of the issue directly (or through `self`).
|
||||||
text_custom_workflow_attachment_code_note: Scripts are executed in the context of Attachment object when attachment object changes (destroys). Use methods and properties of the attachment object directly (or through "self"). Note that these scripts will affect all attachment types (issue, document, wiki pages and etc), so you should check 'container_type' field additionally in your script or select specific "... Attachments" observable object.
|
Instance variables (@variable) are also allowed and may be used if needed.
|
||||||
text_custom_workflow_issue_attachments_code_note: These scripts are executed when attachment being added to issue/removed from issue. Use variables @issue and @attachment to access appropriate objects in your scripts.
|
text_custom_workflow_shared_code_note: This code will run before any other workflow and may contain shared code,
|
||||||
text_custom_workflow_project_code_note: Scripts are executed in the context of Project object when project object changes (destroys). Use methods and properties of the project directly (or through "self")
|
e.g. functions and classes needed by other workflows
|
||||||
text_custom_workflow_project_attachments_code_note: These scripts are executed when a file being added to project/removed from project. Use variables @project and @attachment to access appropriate objects in your scripts.
|
text_custom_workflow_user_code_note: Scripts are executed in the context of User object when user object changes
|
||||||
text_custom_workflow_wiki_content_code_note: Scripts are executed in the context of Wiki Content object when project object changes (destroys). Use methods and properties of the project directly (or through "self")
|
(destroys). Use methods and properties of the user directly (or through `self`)
|
||||||
text_custom_workflow_wiki_page_attachments_code_note: These scripts are executed when a file being added to wiki page/removed from wiki page. Use variables @page and @attachment to access appropriate objects in your scripts.
|
text_custom_workflow_group_code_note: Scripts are executed in the context of Group object when group object changes
|
||||||
text_custom_workflow_time_entry_code_note: Scripts are executed in the context of TimeEntry object when time enty object changes (destroys). Use methods and properties of the time entry directly (or through "self")
|
(destroys). Use methods and properties of the group directly (or through `self`)
|
||||||
text_custom_workflow_version_code_note: Scripts are executed in the context of Version object when version object changes (destroys). Use methods and properties of the version directly (or through "self")
|
text_custom_workflow_group_users_code_note: These scripts are executed when user being added to group/removed from
|
||||||
|
group. Use variables @user and @group to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_attachment_code_note: Scripts are executed in the context of Attachment object when attachment
|
||||||
|
object changes (destroys). Use methods and properties of the attachment object directly (or through `self`). Note that
|
||||||
|
these scripts will affect all attachment types (issue, document, wiki pages and etc), so you should check
|
||||||
|
'container_type' field additionally in your script or select specific '... Attachments' observable object.
|
||||||
|
text_custom_workflow_issue_attachments_code_note: These scripts are executed when attachment being added to
|
||||||
|
issue/removed from issue. Use variables @issue and @attachment to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_project_code_note: Scripts are executed in the context of Project object when project object
|
||||||
|
changes (destroys). Use methods and properties of the project directly (or through `self`)
|
||||||
|
text_custom_workflow_project_attachments_code_note: These scripts are executed when a file being added to
|
||||||
|
project/removed from project. Use variables @project and @attachment to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_wiki_content_code_note: Scripts are executed in the context of Wiki Content object when project
|
||||||
|
object changes (destroys). Use methods and properties of the project directly (or through `self`)
|
||||||
|
text_custom_workflow_wiki_page_attachments_code_note: These scripts are executed when a file being added to wiki
|
||||||
|
page/removed from wiki page. Use variables @page and @attachment to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_time_entry_code_note: Scripts are executed in the context of TimeEntry object when time enty
|
||||||
|
object changes (destroys). Use methods and properties of the time entry directly (or through `self`)
|
||||||
|
text_custom_workflow_version_code_note: Scripts are executed in the context of Version object when version object
|
||||||
|
changes (destroys). Use methods and properties of the version directly (or through `self`)
|
||||||
|
|
||||||
text_no_enabled_projects: No projects
|
text_no_enabled_projects: No projects
|
||||||
text_custom_workflow_author: Will be included in exported XML
|
text_custom_workflow_author: Will be included in exported XML
|
||||||
text_custom_workflow_disabled: disabled by admin
|
text_custom_workflow_disabled: disabled by admin
|
||||||
text_custom_workflow_is_for_all: enabled for all projects
|
text_custom_workflow_is_for_all: enabled for all projects
|
||||||
|
|
||||||
custom_workflow_observable_shared: "<shared code>"
|
custom_workflow_observable_shared: <shared code>
|
||||||
custom_workflow_observable_issue: "Issue"
|
custom_workflow_observable_issue: Issue
|
||||||
custom_workflow_observable_issue_attachments: "Issue Attachments"
|
custom_workflow_observable_issue_attachments: Issue Attachments
|
||||||
custom_workflow_observable_group: "Group"
|
custom_workflow_observable_group: Group
|
||||||
custom_workflow_observable_user: "User"
|
custom_workflow_observable_user: User
|
||||||
custom_workflow_observable_attachment: "Attachment"
|
custom_workflow_observable_attachment: Attachment
|
||||||
custom_workflow_observable_project: "Project"
|
custom_workflow_observable_project: Project
|
||||||
custom_workflow_observable_project_attachments: "Project Attachments / Files"
|
custom_workflow_observable_project_attachments: Project Attachments / Files
|
||||||
custom_workflow_observable_wiki_content: "Wiki Content"
|
custom_workflow_observable_wiki_content: Wiki Content
|
||||||
custom_workflow_observable_wiki_page_attachments: "Wiki Page Attachments"
|
custom_workflow_observable_wiki_page_attachments: Wiki Page Attachments
|
||||||
custom_workflow_observable_group_users: "Group Users"
|
custom_workflow_observable_group_users: Group Users
|
||||||
custom_workflow_observable_time_entry: "Time Entry"
|
custom_workflow_observable_time_entry: Time Entry
|
||||||
custom_workflow_observable_version: "Version"
|
custom_workflow_observable_version: Version
|
||||||
|
|||||||
@ -20,63 +20,101 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
pt-BR:
|
pt-BR:
|
||||||
project_module_custom_workflows_module: "Fluxo de Trabalho Personalizado"
|
project_module_custom_workflows_module: Fluxo de Trabalho Personalizado
|
||||||
permission_manage_project_workflow: "Gerenciar fluxos de trabalho personalizados de projeto"
|
permission_manage_project_workflow: Gerenciar fluxos de trabalho personalizados de projeto
|
||||||
|
|
||||||
label_custom_workflow: "Fluxo de Trabalho personalizado"
|
label_custom_workflow: Fluxo de Trabalho personalizado
|
||||||
label_custom_workflow_plural: "Fluxos de Trabalho personalizados"
|
label_custom_workflow_plural: Fluxos de Trabalho personalizados
|
||||||
label_custom_workflow_new: "Criar um fluxo de trabalho personalizado"
|
label_custom_workflow_new: Criar um fluxo de trabalho personalizado
|
||||||
label_workflow_scripts: "Scripts de fluxo de trabalho"
|
label_workflow_scripts: Scripts de fluxo de trabalho
|
||||||
label_enabled_projects: "Habilitado para o(s) projeto(s)"
|
label_custom_workflow_export: Exportar
|
||||||
label_custom_workflow_export: "Exportar"
|
label_custom_workflow_import: Importar fluxo de trabalho
|
||||||
label_custom_workflow_import: "Importar fluxo de trabalho"
|
label_save_workflows: Saving observable objects
|
||||||
|
label_destroy_workflows: Destroying observable objects
|
||||||
|
label_add_workflows: Adding observable objects to collection
|
||||||
|
label_remove_workflows: Removing observable objects from collection
|
||||||
|
|
||||||
button_import: "Importar"
|
button_custom_workflow_deactivate: Desativar
|
||||||
button_custom_workflow_activate: "Ativar"
|
|
||||||
button_custom_workflow_deactivate: "Desativar"
|
|
||||||
|
|
||||||
field_after_save: "Workflow script executable after saving observable object"
|
field_after_save: Workflow script executable after saving observable object
|
||||||
field_before_save: "Workflow script executable before saving observable object"
|
field_before_save: Workflow script executable before saving observable object
|
||||||
field_after_add: "Workflow script executable after adding observable object to collection"
|
field_after_destroy: Workflow script executable after destroying observable object
|
||||||
field_before_add: "Workflow script executable before adding observable object to collection"
|
field_before_destroy: Workflow script executable before destroying observable object
|
||||||
field_after_remove: "Workflow script executable after removing observable object from collection"
|
field_after_add: Workflow script executable after adding observable object to collection
|
||||||
field_before_remove: "Workflow script executable before removing observable object from collection"
|
field_before_add: Workflow script executable before adding observable object to collection
|
||||||
field_shared_code: "Shared code"
|
field_after_remove: Workflow script executable after removing observable object from collection
|
||||||
field_observable: "Observable object"
|
field_before_remove: Workflow script executable before removing observable object from collection
|
||||||
field_is_enabled: "Ativado"
|
field_shared_code: Shared code
|
||||||
field_enabled_for_all_projects: "Ativado para todos os projetos"
|
field_observable: Observable object
|
||||||
field_custom_workflow_author: "E-mail do autor"
|
field_enabled_for_all_projects: Ativado para todos os projetos
|
||||||
field_custom_workflow_file: "Selecione o arquivo XML exportado anteriormente"
|
field_custom_workflow_author: E-mail do autor
|
||||||
field_custom_workflow_active: "Ativo"
|
field_custom_workflow_file: Selecione o arquivo XML exportado anteriormente
|
||||||
field_custom_workflow:
|
field_custom_workflow:
|
||||||
script: "Script do Fluxo de Trabalho"
|
script: Script do Fluxo de Trabalho
|
||||||
|
|
||||||
notice_successful_import: "Fluxo de Trabalho Personalizado foi importado com sucesso"
|
notice_successful_import: Fluxo de Trabalho Personalizado foi importado com sucesso
|
||||||
notice_successful_status_change: "Situação foi alterada com sucesso"
|
notice_successful_status_change: Situação foi alterada com sucesso
|
||||||
error_failed_import: "Erro ao importar o fluxo de trabalho customizado (Formato desconhecido? Por favor verifique o log)"
|
error_failed_import: Erro ao importar o fluxo de trabalho customizado (Formato desconhecido? Por favor verifique o log)
|
||||||
|
|
||||||
activerecord:
|
activerecord:
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
invalid_script: "contém erro: %{error}"
|
invalid_script: "contém erro: %{error}"
|
||||||
custom_workflow_error: "Erro no fluxo de trabalho customizado (por favor contate o administrador)"
|
custom_workflow_error: Erro no fluxo de trabalho customizado (Por favor contate o administrador)
|
||||||
new_status_invalid: "Transição de '%{old_status}' para '%{new_status}' é proibida"
|
new_status_invalid: "Transição de '%{old_status}' para '%{new_status}' é proibida"
|
||||||
|
scripts_absent: At least one script should be defined
|
||||||
|
|
||||||
text_select_project_custom_workflows: Selecione o projeto para os fluxos de trabalho
|
text_select_project_custom_workflows: Selecione o projeto para os fluxos de trabalho
|
||||||
text_custom_workflow_before_save_note: Você pode alterar as propriedades das tarefas aqui. Não crie ou atualize tarefas relacionadas neste script. Para terminar com o erro, utilize a exceção WorkflowError, "Mensagem para o usuário".
|
text_custom_workflow_before_save_note: Você pode alterar as propriedades das tarefas aqui. Não crie ou atualize
|
||||||
text_custom_workflow_after_save_note: Você pode atualizar ou criar tarefas relacionadas aqui. Note que esse script também será executado para as tarefas criadas recentemente. Então, faça as verificações adequadas para evitar que entre em recursividade infinita.
|
tarefas relacionadas neste script. Para terminar com o erro, utilize a `raise WorkflowError, 'Mensagem para o usuário'`.
|
||||||
text_custom_workflow_issue_code_note: Ambos os scripts são executados no contexto da tarefa pelas chamadas before_save com retornos para a chamada after_save. Portanto, use métodos e propriedades da tarefa diretamente (ou através de "self"). Variáveis de instância (@variable) também são permitidos e podem ser utilizados, se necessário.
|
text_custom_workflow_after_save_note: Você pode atualizar ou criar tarefas relacionadas aqui. Note que esse script
|
||||||
text_custom_workflow_shared_code_note: This code will run before any other workflow and may contain shared code, e.g. functions and classes needed by other workflows.
|
também será executado para as tarefas criadas recentemente. Então, faça as verificações adequadas para evitar que
|
||||||
text_custom_workflow_user_code_note: Both scripts are executed in the context of the user object when user object changes. Use methods and properties of the user directly (or through "self")
|
entre em recursividade infinita.
|
||||||
text_custom_workflow_group_code_note: Both scripts are executed in the context of the group object when group object changes. Use methods and properties of the group directly (or through "self")
|
text_custom_workflow_issue_code_note: Ambos os scripts são executados no contexto da tarefa pelas chamadas before_save
|
||||||
text_custom_workflow_group_users_code_note: These scripts are executed when user being added to group/removed from group. Use variables @user and @group to access appropriate objects in your scripts.
|
com retornos para a chamada after_save. Portanto, use métodos e propriedades da tarefa diretamente
|
||||||
|
(ou através de "self"). Variáveis de instância (@variable) também são permitidos e podem ser utilizados, se necessário.
|
||||||
|
text_custom_workflow_shared_code_note: This code will run before any other workflow and may contain shared code,
|
||||||
|
e.g. functions and classes needed by other workflows.
|
||||||
|
text_custom_workflow_user_code_note: Both scripts are executed in the context of the user object when user object
|
||||||
|
changes. Use methods and properties of the user directly (or through `self`)
|
||||||
|
text_custom_workflow_group_code_note: Both scripts are executed in the context of the group object when group object
|
||||||
|
changes. Use methods and properties of the group directly (or through `self`)
|
||||||
|
text_custom_workflow_group_users_code_note: These scripts are executed when user being added to group/removed from
|
||||||
|
group. Use variables @user and @group to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_attachment_code_note: Scripts are executed in the context of Attachment object when attachment
|
||||||
|
object changes (destroys). Use methods and properties of the attachment object directly (or through `self`). Note that
|
||||||
|
these scripts will affect all attachment types (issue, document, wiki pages and etc), so you should check
|
||||||
|
'container_type' field additionally in your script or select specific '... Attachments' observable object.
|
||||||
|
text_custom_workflow_issue_attachments_code_note: These scripts are executed when attachment being added to
|
||||||
|
issue/removed from issue. Use variables @issue and @attachment to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_project_code_note: Scripts are executed in the context of Project object when project object
|
||||||
|
changes (destroys). Use methods and properties of the project directly (or through `self`)
|
||||||
|
text_custom_workflow_project_attachments_code_note: These scripts are executed when a file being added to
|
||||||
|
project/removed from project. Use variables @project and @attachment to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_wiki_content_code_note: Scripts are executed in the context of Wiki Content object when project
|
||||||
|
object changes (destroys). Use methods and properties of the project directly (or through `self`)
|
||||||
|
text_custom_workflow_wiki_page_attachments_code_note: These scripts are executed when a file being added to wiki
|
||||||
|
page/removed from wiki page. Use variables @page and @attachment to access appropriate objects in your scripts.
|
||||||
|
text_custom_workflow_time_entry_code_note: Scripts are executed in the context of TimeEntry object when time enty
|
||||||
|
object changes (destroys). Use methods and properties of the time entry directly (or through `self`)
|
||||||
|
text_custom_workflow_version_code_note: Scripts are executed in the context of Version object when version object
|
||||||
|
changes (destroys). Use methods and properties of the version directly (or through `self`)
|
||||||
|
|
||||||
text_no_enabled_projects: Não há projeto
|
text_no_enabled_projects: Não há projeto
|
||||||
text_custom_workflow_author: Será incluído no XML exportado
|
text_custom_workflow_author: Será incluído no XML exportado
|
||||||
text_custom_workflow_disabled: desabilitado por admin
|
text_custom_workflow_disabled: desabilitado por admin
|
||||||
text_custom_workflow_is_for_all: Ativado para todos os projetos
|
text_custom_workflow_is_for_all: Ativado para todos os projetos
|
||||||
|
|
||||||
custom_workflow_observable_shared: "<shared code>"
|
custom_workflow_observable_shared: <shared code>
|
||||||
custom_workflow_observable_issue: "Issue"
|
custom_workflow_observable_issue: Issue
|
||||||
custom_workflow_observable_group: "Group"
|
custom_workflow_observable_issue_attachments: Issue Attachments
|
||||||
custom_workflow_observable_user: "User"
|
custom_workflow_observable_group: Group
|
||||||
custom_workflow_observable_group_users: "Group Users"
|
custom_workflow_observable_user: User
|
||||||
|
custom_workflow_observable_attachment: Attachment
|
||||||
|
custom_workflow_observable_project: Project
|
||||||
|
custom_workflow_observable_project_attachments: Project Attachments / Files
|
||||||
|
custom_workflow_observable_wiki_content: Wiki Content
|
||||||
|
custom_workflow_observable_wiki_page_attachments: Wiki Page Attachments
|
||||||
|
custom_workflow_observable_group_users: Group Users
|
||||||
|
custom_workflow_observable_time_entry: Time Entry
|
||||||
|
custom_workflow_observable_version: Version
|
||||||
|
|||||||
@ -20,87 +20,101 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
ru:
|
ru:
|
||||||
project_module_custom_workflows_module: "Пользовательские рабочие процессы"
|
project_module_custom_workflows_module: Пользовательские рабочие процессы
|
||||||
permission_manage_project_workflow: "Управление пользовательскими рабочими процессами в проекте"
|
permission_manage_project_workflow: Управление пользовательскими рабочими процессами в проекте
|
||||||
|
|
||||||
label_custom_workflow: "Пользовательский рабочий процесс"
|
label_custom_workflow: Пользовательский рабочий процесс
|
||||||
label_custom_workflow_plural: "Пользовательские рабочие процессы"
|
label_custom_workflow_plural: Пользовательские рабочие процессы
|
||||||
label_custom_workflow_new: "Новый процесс"
|
label_custom_workflow_new: Новый процесс
|
||||||
label_workflow_scripts: "Сценарии"
|
label_workflow_scripts: Сценарии
|
||||||
label_enabled_projects: "Разрешен в проектах"
|
label_custom_workflow_export: Экспорт
|
||||||
label_custom_workflow_export: "Экспорт"
|
label_custom_workflow_import: Импорт процесса
|
||||||
label_custom_workflow_import: "Импорт процесса"
|
label_save_workflows: Сохранение наблюдаемых объектов
|
||||||
label_save_workflows: "Сохранение наблюдаемых объектов"
|
label_destroy_workflows: Уничтожение наблюдаемых объектов
|
||||||
label_destroy_workflows: "Уничтожение наблюдаемых объектов"
|
label_add_workflows: Добавление наблюдаемых объектов в коллекцию
|
||||||
label_add_workflows: "Добавление наблюдаемых объектов в коллекцию"
|
label_remove_workflows: Удаление наблюдаемых объектов из коллекции
|
||||||
label_remove_workflows: "Удаление наблюдаемых объектов из коллекции"
|
|
||||||
|
|
||||||
button_import: "Импортировать"
|
button_custom_workflow_deactivate: Деактивировать
|
||||||
button_custom_workflow_activate: "Активировать"
|
|
||||||
button_custom_workflow_deactivate: "Деактивировать"
|
|
||||||
|
|
||||||
field_after_save: "Сценарий выполняемый после сохранения наблюдаемого объекта"
|
field_after_save: Сценарий выполняемый после сохранения наблюдаемого объекта
|
||||||
field_before_save: "Сценарий выполняемый перед сохранением наблюдаемого объекта"
|
field_before_save: Сценарий выполняемый перед сохранением наблюдаемого объекта
|
||||||
field_after_destroy: "Сценарий выполняемый после уничтожения наблюдаемого объекта"
|
field_after_destroy: Сценарий выполняемый после уничтожения наблюдаемого объекта
|
||||||
field_before_destroy: "Сценарий выполняемый перед уничтожением наблюдаемого объекта"
|
field_before_destroy: Сценарий выполняемый перед уничтожением наблюдаемого объекта
|
||||||
field_after_add: "Сценарий выполняемый после добавления наблюдаемого объекта в коллекцию"
|
field_after_add: Сценарий выполняемый после добавления наблюдаемого объекта в коллекцию
|
||||||
field_before_add: "Сценарий выполняемый перед добавлением наблюдаемого объекта в коллекцию"
|
field_before_add: Сценарий выполняемый перед добавлением наблюдаемого объекта в коллекцию
|
||||||
field_after_remove: "Сценарий выполняемый после удаления наблюдаемого объекта из коллекции"
|
field_after_remove: Сценарий выполняемый после удаления наблюдаемого объекта из коллекции
|
||||||
field_before_remove: "Сценарий выполняемый перед удалением наблюдаемого объекта из коллекции"
|
field_before_remove: Сценарий выполняемый перед удалением наблюдаемого объекта из коллекции
|
||||||
field_shared_code: "Общий код"
|
field_shared_code: Общий код
|
||||||
field_observable: "Наблюдаемый объект"
|
field_observable: Наблюдаемый объект
|
||||||
field_is_enabled: "Разрешено"
|
field_enabled_for_all_projects: Разрешен для всех проектов
|
||||||
field_enabled_for_all_projects: "Разрешен для всех проектов"
|
field_custom_workflow_author: E-Mail адрес автора
|
||||||
field_custom_workflow_author: "E-Mail адрес автора"
|
field_custom_workflow_file: Выберите XML файл ранее экспортированного процесса
|
||||||
field_custom_workflow_file: "Выберите XML файл ранее экспортированного процесса"
|
|
||||||
field_custom_workflow_active: "Активен"
|
|
||||||
field_custom_workflow:
|
field_custom_workflow:
|
||||||
script: "Сценарий"
|
script: Сценарий
|
||||||
|
|
||||||
notice_successful_import: "Рабочий процесс успешно импортирован"
|
notice_successful_import: Рабочий процесс успешно импортирован
|
||||||
notice_successful_status_change: "Статус успешно изменен"
|
notice_successful_status_change: Статус успешно изменен
|
||||||
error_failed_import: "Ошибка импорта рабочего процесса (неверный формат? смотри журнал)"
|
error_failed_import: Ошибка импорта рабочего процесса (неверный формат? смотри журнал)
|
||||||
|
|
||||||
activerecord:
|
activerecord:
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
invalid_script: "содержит ошибку: %{error}"
|
invalid_script: "содержит ошибку: %{error}"
|
||||||
custom_workflow_error: "Ошибка в сценарии рабочего процесса (обратитесь к администратору)"
|
custom_workflow_error: Ошибка в сценарии рабочего процесса (Обратитесь к администратору)
|
||||||
new_status_invalid: "- переход от '%{old_status}' к '%{new_status}' невозможен"
|
new_status_invalid: "- переход от '%{old_status}' к '%{new_status}' невозможен"
|
||||||
scripts_absent: "Хотя бы один скрипт должен быть определен"
|
scripts_absent: Хотя бы один скрипт должен быть определен
|
||||||
|
|
||||||
text_select_project_custom_workflows: Выберите процессы для данного проекта
|
text_select_project_custom_workflows: Выберите процессы для данного проекта
|
||||||
text_custom_workflow_before_save_note: Здесь вы можете изменять свойства задачи. Не создавайте и не обновляйте связанные задачи в этом сценарии. Чтобы завершить сценарий с произвольной ошибкой, используйте raise WorkflowError, "Message to user".
|
text_custom_workflow_before_save_note: Здесь вы можете изменять свойства задачи. Не создавайте и не обновляйте
|
||||||
text_custom_workflow_after_save_note: Вы можете обновлять и создавать задачи (в том числе и связанные задачи) здесь. Обратите внимание, что данный сценарий будет также выполняться и для вновь создаваемых задач. Поэтому используйте дополнительные проверки, чтобы избежать бесконечной рекурсии.
|
связанные задачи в этом сценарии. Чтобы завершить сценарий с произвольной ошибкой, используйте `raise WorkflowError, 'Message to user'`.
|
||||||
text_custom_workflow_issue_code_note: Эти сценарии исполняются в контексте задачи, как и обычные обратные вызовы before_save и after_save. Поэтому используйте методы и свойства задачи (Issue) напрямую или через ключевое слово self.
|
text_custom_workflow_after_save_note: Вы можете обновлять и создавать задачи (в том числе и связанные задачи) здесь.
|
||||||
text_custom_workflow_shared_code_note: Этот код будет исполняться перед любым другим процессом и может содержать общий код, например, функции и классы, необходимые для работы других процессов.
|
Обратите внимание, что данный сценарий будет также выполняться и для вновь создаваемых задач. Поэтому используйте
|
||||||
text_custom_workflow_user_code_note: Эти сценарии исполняются в контексте объекта пользователя когда объект пользователя изменяется (удаляется). Используйте методы и свойства объекта пользователя (User) напрямую или через ключевое слово self.
|
дополнительные проверки, чтобы избежать бесконечной рекурсии.
|
||||||
text_custom_workflow_group_code_note: Эти сценарии исполняются в контексте объекта группы когда объект группы изменяется (удаляется). Используйте методы и свойства объекта группы (Group) напрямую или через ключевое слово self.
|
text_custom_workflow_issue_code_note: Эти сценарии исполняются в контексте задачи, как и обычные обратные вызовы
|
||||||
text_custom_workflow_group_users_code_note: Эти сценарии выполняются когда пользователь добавляется в группу/удаляется из группы. Используйте переменные @user и @group для доступа к соответствующим объектам из Ваших сценариев.
|
before_save и after_save. Поэтому используйте методы и свойства задачи (Issue) напрямую или через ключевое слово
|
||||||
text_custom_workflow_attachment_code_note: Эти сценарии исполняются в контексте объекта вложения когда объект вложения изменяется (удаляется). Используйте методы и свойства объекта вложения (Attachment) напрямую или через ключевое слово self. Обратите внимание на то, что данные сценарии выполняются при сохранении (удалении) вложения любого типа (задача, документ, страница Wiki и т.д.), поэтому следует дополнительно проверять в коде поле container_type либо в качестве наблюдаемого объекта выбрать конкретный тип вложения.
|
self.
|
||||||
text_custom_workflow_issue_attachments_code_note: Эти сценарии выполняются когда вложение прикладывается к задаче/удаляется из задачи. Используйте переменные @issue и @attachment для доступа к соответствующим объектам из Ваших сценариев.
|
text_custom_workflow_shared_code_note: Этот код будет исполняться перед любым другим процессом и может содержать общий
|
||||||
text_custom_workflow_project_code_note: Эти сценарии исполняются в контексте объекта проекта когда объект проекта изменяется (удаляется). Используйте методы и свойства объекта группы (Project) напрямую или через ключевое слово self.
|
код, например, функции и классы, необходимые для работы других процессов.
|
||||||
text_custom_workflow_project_attachments_code_note: Эти сценарии выполняются когда файл загружается в проект/удаляется из проекта. Используйте переменные @project и @attachment для доступа к соответствующим объектам из Ваших сценариев.
|
text_custom_workflow_user_code_note: Эти сценарии исполняются в контексте объекта пользователя когда объект
|
||||||
text_custom_workflow_wiki_content_code_note: Эти сценарии исполняются в контексте объекта Wiki содержания когда объект Wiki содержания изменяется (удаляется). Используйте методы и свойства объекта содержания Wiki (WikiContent) напрямую или через ключевое слово self.
|
пользователя изменяется (удаляется). Используйте методы и свойства объекта пользователя (User) напрямую или через ключевое слово `self`.
|
||||||
text_custom_workflow_wiki_page_attachments_code_note: Эти сценарии выполняются когда файл загружается на Wiki страницу/удаляется с Wiki страницы. Используйте переменные @page и @attachment для доступа к соответствующим объектам из Ваших сценариев.
|
text_custom_workflow_group_code_note: Эти сценарии исполняются в контексте объекта группы когда объект группы
|
||||||
text_custom_workflow_time_entry_code_note: Эти сценарии исполняются в контексте объекта затраченного времени когда объект изменяется (удаляется). Используйте методы и свойства объекта затраченного времени (TimeEntry) напрямую или через ключевое слово self.
|
изменяется (удаляется). Используйте методы и свойства объекта группы (Group) напрямую или через ключевое слово `self`.
|
||||||
text_custom_workflow_version_code_note: Эти сценарии исполняются в контексте объекта версии когда объект изменяется (удаляется). Используйте методы и свойства объекта версии (Version) напрямую или через ключевое слово self.
|
text_custom_workflow_group_users_code_note: Эти сценарии выполняются когда пользователь добавляется в группу/удаляется
|
||||||
|
из группы. Используйте переменные @user и @group для доступа к соответствующим объектам из Ваших сценариев.
|
||||||
|
text_custom_workflow_attachment_code_note: Эти сценарии исполняются в контексте объекта вложения когда объект вложения
|
||||||
|
изменяется (удаляется). Используйте методы и свойства объекта вложения (Attachment) напрямую или через ключевое
|
||||||
|
слово self. Обратите внимание на то, что данные сценарии выполняются при сохранении (удалении) вложения любого типа
|
||||||
|
(задача, документ, страница Wiki и т.д.), поэтому следует дополнительно проверять в коде поле container_type либо в качестве наблюдаемого объекта выбрать конкретный тип вложения.
|
||||||
|
text_custom_workflow_issue_attachments_code_note: Эти сценарии выполняются когда вложение прикладывается
|
||||||
|
к задаче/удаляется из задачи. Используйте переменные @issue и @attachment для доступа к соответствующим объектам из Ваших сценариев.
|
||||||
|
text_custom_workflow_project_code_note: Эти сценарии исполняются в контексте объекта проекта когда объект проекта
|
||||||
|
изменяется (удаляется). Используйте методы и свойства объекта группы (Project) напрямую или через ключевое слово `self`.
|
||||||
|
text_custom_workflow_project_attachments_code_note: Эти сценарии выполняются когда файл загружается в проект/удаляется
|
||||||
|
из проекта. Используйте переменные @project и @attachment для доступа к соответствующим объектам из Ваших сценариев.
|
||||||
|
text_custom_workflow_wiki_content_code_note: Эти сценарии исполняются в контексте объекта Wiki содержания когда объект
|
||||||
|
Wiki содержания изменяется (удаляется). Используйте методы и свойства объекта содержания Wiki (WikiContent) напрямую или через ключевое слово self.
|
||||||
|
text_custom_workflow_wiki_page_attachments_code_note: Эти сценарии выполняются когда файл загружается на Wiki
|
||||||
|
страницу/удаляется с Wiki страницы. Используйте переменные @page и @attachment для доступа к соответствующим объектам из Ваших сценариев.
|
||||||
|
text_custom_workflow_time_entry_code_note: Эти сценарии исполняются в контексте объекта затраченного времени когда
|
||||||
|
объект изменяется (удаляется). Используйте методы и свойства объекта затраченного времени (TimeEntry) напрямую или через ключевое слово self.
|
||||||
|
text_custom_workflow_version_code_note: Эти сценарии исполняются в контексте объекта версии когда объект изменяется
|
||||||
|
(удаляется). Используйте методы и свойства объекта версии (Version) напрямую или через ключевое слово `self`.
|
||||||
|
|
||||||
text_no_enabled_projects: Нет проектов
|
text_no_enabled_projects: Нет проектов
|
||||||
text_custom_workflow_author: Будет использован в XML файле при экспорте
|
text_custom_workflow_author: Будет использован в XML файле при экспорте
|
||||||
text_custom_workflow_disabled: отключен администратором
|
text_custom_workflow_disabled: отключен администратором
|
||||||
text_custom_workflow_is_for_all: разрешен для всех проектов
|
text_custom_workflow_is_for_all: разрешен для всех проектов
|
||||||
|
|
||||||
custom_workflow_observable_shared: "<общий код>"
|
custom_workflow_observable_shared: <общий код>
|
||||||
custom_workflow_observable_issue: "Задача"
|
custom_workflow_observable_issue: Задача
|
||||||
custom_workflow_observable_issue_attachments: "Вложения задач"
|
custom_workflow_observable_issue_attachments: Вложения задач
|
||||||
custom_workflow_observable_group: "Группа"
|
custom_workflow_observable_group: Группа
|
||||||
custom_workflow_observable_user: "Пользователь"
|
custom_workflow_observable_user: Пользователь
|
||||||
custom_workflow_observable_attachment: "Вложение"
|
custom_workflow_observable_attachment: Вложение
|
||||||
custom_workflow_observable_project: "Проект"
|
custom_workflow_observable_project: Проект
|
||||||
custom_workflow_observable_project_attachments: "Вложения проекта / Файлы"
|
custom_workflow_observable_project_attachments: Вложения проекта / Файлы
|
||||||
custom_workflow_observable_wiki_content: "Содержание Wiki"
|
custom_workflow_observable_wiki_content: Содержание Wiki
|
||||||
custom_workflow_observable_wiki_page_attachments: "Вложения страниц Wiki"
|
custom_workflow_observable_wiki_page_attachments: Вложения страниц Wiki
|
||||||
custom_workflow_observable_group_users: "Пользователи группы"
|
custom_workflow_observable_group_users: Пользователи группы
|
||||||
custom_workflow_observable_time_entry: "Затраченное время"
|
custom_workflow_observable_time_entry: Затраченное время
|
||||||
custom_workflow_observable_version: "Версия"
|
custom_workflow_observable_version: Версия
|
||||||
|
|||||||
@ -28,9 +28,10 @@ RedmineApp::Application.routes.draw do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
post '/custom_workflows/import', :to => 'custom_workflows#import', :as => 'import_custom_workflow'
|
post '/custom_workflows/import', to: 'custom_workflows#import', as: 'import_custom_workflow'
|
||||||
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'
|
put '/custom_workflows/:id/reorder', to: 'custom_workflows#reorder'
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,12 +22,12 @@
|
|||||||
class CreateCustomWorkflows < ActiveRecord::Migration[4.2]
|
class CreateCustomWorkflows < ActiveRecord::Migration[4.2]
|
||||||
|
|
||||||
def change
|
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
|
||||||
t.boolean :is_enabled
|
t.boolean :is_enabled
|
||||||
end
|
end
|
||||||
add_index :custom_workflows, [:project_id], :unique => true
|
add_index :custom_workflows, [:project_id], unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -24,9 +24,9 @@ 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
|
||||||
add_column :custom_workflows, :name, :string, :null => false, :default => ''
|
add_column :custom_workflows, :name, :string, null: false, default: ''
|
||||||
add_column :custom_workflows, :description, :string, :null => false, :default => ''
|
add_column :custom_workflows, :description, :string, null: false, default: ''
|
||||||
add_column :custom_workflows, :position, :integer, :null => false, :default => 1
|
add_column :custom_workflows, :position, :integer, null: false, default: 1
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
class CreateCustomWorkflowsProjects < ActiveRecord::Migration[4.2]
|
class CreateCustomWorkflowsProjects < ActiveRecord::Migration[4.2]
|
||||||
|
|
||||||
def change
|
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
|
||||||
end
|
end
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
class ChangeCustomWorkflowsDescriptionType < ActiveRecord::Migration[4.2]
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -23,8 +23,8 @@ class AddAfterSaveToCustomWorkflows < ActiveRecord::Migration[4.2]
|
|||||||
|
|
||||||
def up
|
def 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
|
||||||
add_column :custom_workflows, :after_save, :text, :null => true, :after => :before_save
|
add_column :custom_workflows, :after_save, :text, null: true, after: :before_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def down
|
def down
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
class AddIsForAllToCustomWorkflows < ActiveRecord::Migration[4.2]
|
class AddIsForAllToCustomWorkflows < ActiveRecord::Migration[4.2]
|
||||||
|
|
||||||
def change
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,8 +22,8 @@
|
|||||||
class MakeAfterSaveAndBeforeSaveNullable < ActiveRecord::Migration[4.2]
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
class SetPositionFieldNullable < ActiveRecord::Migration[4.2]
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
class AddAuthorAndTimestampsToCustomWorkflows < ActiveRecord::Migration[4.2]
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
class AddActiveFieldToCustomWorkflows < ActiveRecord::Migration[4.2]
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
class AddObservableFieldToCustomWorkflows < ActiveRecord::Migration[4.2]
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,11 +22,11 @@
|
|||||||
class AddAdditionalScriptFieldsToCustomWorkflows < ActiveRecord::Migration[4.2]
|
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
|
||||||
add_column :custom_workflows, :after_add, :text, :null => true
|
add_column :custom_workflows, :after_add, :text, null: true
|
||||||
add_column :custom_workflows, :before_remove, :text, :null => true
|
add_column :custom_workflows, :before_remove, :text, null: true
|
||||||
add_column :custom_workflows, :after_remove, :text, :null => true
|
add_column :custom_workflows, :after_remove, :text, null: true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,8 +22,8 @@
|
|||||||
class AddBeforeAndAfterDestroyToCustomWorkflows < ActiveRecord::Migration[4.2]
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
2
init.rb
2
init.rb
@ -36,7 +36,7 @@ Redmine::Plugin.register :redmine_custom_workflows do
|
|||||||
|
|
||||||
requires_redmine version_or_higher: '4.1.0'
|
requires_redmine version_or_higher: '4.1.0'
|
||||||
|
|
||||||
permission :manage_project_workflow, {}, :require => :member
|
permission :manage_project_workflow, {}, require: :member
|
||||||
end
|
end
|
||||||
|
|
||||||
unless Redmine::Plugin.installed?(:easy_extensions)
|
unless Redmine::Plugin.installed?(:easy_extensions)
|
||||||
|
|||||||
@ -24,19 +24,11 @@ module RedmineCustomWorkflows
|
|||||||
|
|
||||||
class Hooks < Redmine::Hook::ViewListener
|
class Hooks < Redmine::Hook::ViewListener
|
||||||
|
|
||||||
def view_layouts_base_html_head(context)
|
def view_layouts_base_html_head(context={})
|
||||||
return if defined?(EasyExtensions)
|
return unless context[:controller].class.name.match?(/^(CustomWorkflows|Projects)/)
|
||||||
"\n".html_safe + stylesheet_link_tag('custom_workflows.css', plugin: :redmine_custom_workflows)
|
"\n".html_safe + stylesheet_link_tag('custom_workflows.css', plugin: :redmine_custom_workflows)
|
||||||
end
|
end
|
||||||
|
|
||||||
def easy_extensions_javascripts_hook(context={})
|
|
||||||
context[:template].require_asset('tab_override.js')
|
|
||||||
end
|
|
||||||
|
|
||||||
def easy_extensions_stylesheets_hook(context={})
|
|
||||||
context[:template].require_asset('custom_workflows.css')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -36,8 +36,8 @@ module RedmineCustomWorkflows
|
|||||||
def before_save_custom_workflows
|
def before_save_custom_workflows
|
||||||
@attachment = self
|
@attachment = self
|
||||||
@saved_attributes = attributes.dup
|
@saved_attributes = attributes.dup
|
||||||
CustomWorkflow.run_shared_code(self)
|
CustomWorkflow.run_shared_code self
|
||||||
CustomWorkflow.run_custom_workflows(:attachment, self, :before_save)
|
CustomWorkflow.run_custom_workflows :attachment, self, :before_save
|
||||||
throw :abort if errors.any?
|
throw :abort if errors.any?
|
||||||
errors.empty? && (@saved_attributes == attributes || valid?)
|
errors.empty? && (@saved_attributes == attributes || valid?)
|
||||||
ensure
|
ensure
|
||||||
@ -45,15 +45,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:attachment, self, :after_save)
|
CustomWorkflow.run_custom_workflows :attachment, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:attachment, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :attachment, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:attachment, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :attachment, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -32,10 +32,10 @@ module RedmineCustomWorkflows
|
|||||||
after_destroy :after_destroy_custom_workflows
|
after_destroy :after_destroy_custom_workflows
|
||||||
|
|
||||||
def self.users_callback(event, group, user)
|
def self.users_callback(event, group, user)
|
||||||
group.instance_variable_set(:@group, group)
|
group.instance_variable_set :@group, group
|
||||||
group.instance_variable_set(:@user, user)
|
group.instance_variable_set :@user, user
|
||||||
CustomWorkflow.run_shared_code(group) if event.to_s.starts_with? 'before_'
|
CustomWorkflow.run_shared_code(group) if event.to_s.starts_with? 'before_'
|
||||||
CustomWorkflow.run_custom_workflows(:group_users, group, event)
|
CustomWorkflow.run_custom_workflows :group_users, group, event
|
||||||
end
|
end
|
||||||
[:before_add, :before_remove, :after_add, :after_remove].each do |observable|
|
[:before_add, :before_remove, :after_add, :after_remove].each do |observable|
|
||||||
send("#{observable}_for_users") << if Rails::VERSION::MAJOR >= 4
|
send("#{observable}_for_users") << if Rails::VERSION::MAJOR >= 4
|
||||||
@ -50,8 +50,8 @@ module RedmineCustomWorkflows
|
|||||||
def before_save_custom_workflows
|
def before_save_custom_workflows
|
||||||
@group = self
|
@group = self
|
||||||
@saved_attributes = attributes.dup
|
@saved_attributes = attributes.dup
|
||||||
CustomWorkflow.run_shared_code(self)
|
CustomWorkflow.run_shared_code self
|
||||||
CustomWorkflow.run_custom_workflows(:group, self, :before_save)
|
CustomWorkflow.run_custom_workflows :group, self, :before_save
|
||||||
throw :abort if errors.any?
|
throw :abort if errors.any?
|
||||||
errors.empty? && (@saved_attributes == attributes || valid?)
|
errors.empty? && (@saved_attributes == attributes || valid?)
|
||||||
ensure
|
ensure
|
||||||
@ -59,15 +59,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:group, self, :after_save)
|
CustomWorkflow.run_custom_workflows :group, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:group, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :group, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:group, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :group, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -33,10 +33,10 @@ module RedmineCustomWorkflows
|
|||||||
validate :validate_status
|
validate :validate_status
|
||||||
|
|
||||||
def self.attachments_callback(event, issue, attachment)
|
def self.attachments_callback(event, issue, attachment)
|
||||||
issue.instance_variable_set(:@issue, issue)
|
issue.instance_variable_set :@issue, issue
|
||||||
issue.instance_variable_set(:@attachment, attachment)
|
issue.instance_variable_set :@attachment, attachment
|
||||||
CustomWorkflow.run_shared_code(issue) if event.to_s.starts_with? 'before_'
|
CustomWorkflow.run_shared_code(issue) if event.to_s.starts_with? 'before_'
|
||||||
CustomWorkflow.run_custom_workflows(:issue_attachments, issue, event)
|
CustomWorkflow.run_custom_workflows :issue_attachments, issue, event
|
||||||
end
|
end
|
||||||
|
|
||||||
[:before_add, :before_remove, :after_add, :after_remove].each do |observable|
|
[:before_add, :before_remove, :after_add, :after_remove].each do |observable|
|
||||||
@ -57,15 +57,15 @@ module RedmineCustomWorkflows
|
|||||||
status_new = IssueStatus.find_by_id(status_id)
|
status_new = IssueStatus.find_by_id(status_id)
|
||||||
|
|
||||||
errors.add :status, :new_status_invalid,
|
errors.add :status, :new_status_invalid,
|
||||||
:old_status => status_was && status_was.name,
|
old_status: status_was && status_was.name,
|
||||||
:new_status => status_new && status_new.name
|
new_status: status_new && status_new.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_save_custom_workflows
|
def before_save_custom_workflows
|
||||||
@issue = self
|
@issue = self
|
||||||
@saved_attributes = attributes.dup
|
@saved_attributes = attributes.dup
|
||||||
CustomWorkflow.run_shared_code(self)
|
CustomWorkflow.run_shared_code self
|
||||||
CustomWorkflow.run_custom_workflows(:issue, self, :before_save)
|
CustomWorkflow.run_custom_workflows :issue, self, :before_save
|
||||||
throw :abort if errors.any?
|
throw :abort if errors.any?
|
||||||
errors.empty? && (@saved_attributes == attributes || valid?)
|
errors.empty? && (@saved_attributes == attributes || valid?)
|
||||||
ensure
|
ensure
|
||||||
@ -73,15 +73,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:issue, self, :after_save)
|
CustomWorkflow.run_custom_workflows :issue, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:issue, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :issue, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:issue, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :issue, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -27,7 +27,7 @@ module RedmineCustomWorkflows
|
|||||||
def self.included(base)
|
def self.included(base)
|
||||||
base.class_eval do
|
base.class_eval do
|
||||||
has_and_belongs_to_many :custom_workflows
|
has_and_belongs_to_many :custom_workflows
|
||||||
safe_attributes :custom_workflow_ids, :if =>
|
safe_attributes :custom_workflow_ids, if:
|
||||||
lambda { |project, user| project.new_record? || user.allowed_to?(:manage_project_workflow, project) }
|
lambda { |project, user| project.new_record? || user.allowed_to?(:manage_project_workflow, project) }
|
||||||
|
|
||||||
before_save :before_save_custom_workflows
|
before_save :before_save_custom_workflows
|
||||||
@ -51,8 +51,8 @@ module RedmineCustomWorkflows
|
|||||||
def before_save_custom_workflows
|
def before_save_custom_workflows
|
||||||
@project = self
|
@project = self
|
||||||
@saved_attributes = attributes.dup
|
@saved_attributes = attributes.dup
|
||||||
CustomWorkflow.run_shared_code(self)
|
CustomWorkflow.run_shared_code self
|
||||||
CustomWorkflow.run_custom_workflows(:project, self, :before_save)
|
CustomWorkflow.run_custom_workflows :project, self, :before_save
|
||||||
throw :abort if errors.any?
|
throw :abort if errors.any?
|
||||||
errors.empty? && (@saved_attributes == attributes || valid?)
|
errors.empty? && (@saved_attributes == attributes || valid?)
|
||||||
ensure
|
ensure
|
||||||
@ -60,15 +60,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:project, self, :after_save)
|
CustomWorkflow.run_custom_workflows :project, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:project, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :project, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:project, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :project, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -45,15 +45,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:time_entry, self, :after_save)
|
CustomWorkflow.run_custom_workflows :time_entry, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:time_entry, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :time_entry, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:time_entry, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :time_entry, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -36,8 +36,8 @@ module RedmineCustomWorkflows
|
|||||||
def before_save_custom_workflows
|
def before_save_custom_workflows
|
||||||
@user = self
|
@user = self
|
||||||
@saved_attributes = attributes.dup
|
@saved_attributes = attributes.dup
|
||||||
CustomWorkflow.run_shared_code(self)
|
CustomWorkflow.run_shared_code self
|
||||||
CustomWorkflow.run_custom_workflows(:user, self, :before_save)
|
CustomWorkflow.run_custom_workflows :user, self, :before_save
|
||||||
throw :abort if errors.any?
|
throw :abort if errors.any?
|
||||||
errors.empty? && (@saved_attributes == attributes || valid?)
|
errors.empty? && (@saved_attributes == attributes || valid?)
|
||||||
ensure
|
ensure
|
||||||
@ -45,15 +45,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:user, self, :after_save)
|
CustomWorkflow.run_custom_workflows :user, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:user, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :user, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:user, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :user, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -36,8 +36,8 @@ module RedmineCustomWorkflows
|
|||||||
def before_save_custom_workflows
|
def before_save_custom_workflows
|
||||||
@version = self
|
@version = self
|
||||||
@saved_attributes = attributes.dup
|
@saved_attributes = attributes.dup
|
||||||
CustomWorkflow.run_shared_code(self)
|
CustomWorkflow.run_shared_code self
|
||||||
CustomWorkflow.run_custom_workflows(:version, self, :before_save)
|
CustomWorkflow.run_custom_workflows :version, self, :before_save
|
||||||
throw :abort if errors.any?
|
throw :abort if errors.any?
|
||||||
errors.empty? && (@saved_attributes == attributes || valid?)
|
errors.empty? && (@saved_attributes == attributes || valid?)
|
||||||
ensure
|
ensure
|
||||||
@ -45,15 +45,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:version, self, :after_save)
|
CustomWorkflow.run_custom_workflows :version, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:version, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :version, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:version, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :version, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -36,8 +36,8 @@ module RedmineCustomWorkflows
|
|||||||
def before_save_custom_workflows
|
def before_save_custom_workflows
|
||||||
@content = self
|
@content = self
|
||||||
@saved_attributes = attributes.dup
|
@saved_attributes = attributes.dup
|
||||||
CustomWorkflow.run_shared_code(self)
|
CustomWorkflow.run_shared_code self
|
||||||
CustomWorkflow.run_custom_workflows(:wiki_content, self, :before_save)
|
CustomWorkflow.run_custom_workflows :wiki_content, self, :before_save
|
||||||
throw :abort if errors.any?
|
throw :abort if errors.any?
|
||||||
errors.empty? && (@saved_attributes == attributes || valid?)
|
errors.empty? && (@saved_attributes == attributes || valid?)
|
||||||
ensure
|
ensure
|
||||||
@ -45,15 +45,15 @@ module RedmineCustomWorkflows
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_save_custom_workflows
|
def after_save_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:wiki_content, self, :after_save)
|
CustomWorkflow.run_custom_workflows :wiki_content, self, :after_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_destroy_custom_workflows
|
def before_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:wiki_content, self, :before_destroy)
|
CustomWorkflow.run_custom_workflows :wiki_content, self, :before_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_destroy_custom_workflows
|
def after_destroy_custom_workflows
|
||||||
CustomWorkflow.run_custom_workflows(:wiki_content, self, :after_destroy)
|
CustomWorkflow.run_custom_workflows :wiki_content, self, :after_destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -27,10 +27,10 @@ module RedmineCustomWorkflows
|
|||||||
def self.included(base)
|
def self.included(base)
|
||||||
base.class_eval do
|
base.class_eval do
|
||||||
def self.attachments_callback(event, page, attachment)
|
def self.attachments_callback(event, page, attachment)
|
||||||
page.instance_variable_set(:@page, page)
|
page.instance_variable_set :@page, page
|
||||||
page.instance_variable_set(:@attachment, attachment)
|
page.instance_variable_set :@attachment, attachment
|
||||||
CustomWorkflow.run_shared_code(page) if event.to_s.starts_with? 'before_'
|
CustomWorkflow.run_shared_code(page) if event.to_s.starts_with? 'before_'
|
||||||
CustomWorkflow.run_custom_workflows(:wiki_page_attachments, page, event)
|
CustomWorkflow.run_custom_workflows :wiki_page_attachments, page, event
|
||||||
end
|
end
|
||||||
|
|
||||||
[:before_add, :before_remove, :after_add, :after_remove].each do |observable|
|
[:before_add, :before_remove, :after_add, :after_remove].each do |observable|
|
||||||
|
|||||||
@ -28,8 +28,8 @@ clone()
|
|||||||
# Exit if the cloning fails
|
# Exit if the cloning fails
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
rm -rf $PATH_TO_REDMINE
|
rm -rf ${PATH_TO_REDMINE}
|
||||||
git clone -b $REDMINE_GIT_TAG --depth=100 --quiet $REDMINE_GIT_REPO $PATH_TO_REDMINE
|
git clone -b ${REDMINE_GIT_TAG} --depth=100 --quiet ${REDMINE_GIT_REPO} ${PATH_TO_REDMINE}
|
||||||
}
|
}
|
||||||
|
|
||||||
test()
|
test()
|
||||||
@ -37,7 +37,7 @@ test()
|
|||||||
# Exit if a test fails
|
# Exit if a test fails
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
cd $PATH_TO_REDMINE
|
cd ${PATH_TO_REDMINE}
|
||||||
|
|
||||||
# Run tests within application
|
# Run tests within application
|
||||||
bundle exec rake redmine:plugins:test:units NAME=redmine_custom_workflows RAILS_ENV=test
|
bundle exec rake redmine:plugins:test:units NAME=redmine_custom_workflows RAILS_ENV=test
|
||||||
@ -49,7 +49,7 @@ uninstall()
|
|||||||
# Exit if the migration fails
|
# Exit if the migration fails
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
cd $PATH_TO_REDMINE
|
cd ${PATH_TO_REDMINE}
|
||||||
|
|
||||||
# clean up database
|
# clean up database
|
||||||
bundle exec rake redmine:plugins:migrate NAME=redmine_custom_workflows VERSION=0 RAILS_ENV=test
|
bundle exec rake redmine:plugins:migrate NAME=redmine_custom_workflows VERSION=0 RAILS_ENV=test
|
||||||
@ -61,14 +61,14 @@ install()
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# cd to redmine folder
|
# cd to redmine folder
|
||||||
cd $PATH_TO_REDMINE
|
cd ${PATH_TO_REDMINE}
|
||||||
echo current directory is `pwd`
|
echo current directory is `pwd`
|
||||||
|
|
||||||
# Create a link to the Custom Workflows plugin
|
# Create a link to the Custom Workflows plugin
|
||||||
ln -sf $PATH_TO_CUSTOM_WORKFLOWS plugins/redmine_custom_workflows
|
ln -sf ${PATH_TO_CUSTOM_WORKFLOWS} plugins/redmine_custom_workflows
|
||||||
|
|
||||||
# Copy database.yml
|
# Copy database.yml
|
||||||
cp $WORKSPACE/database.yml config/
|
cp ${WORKSPACE}/database.yml config/
|
||||||
|
|
||||||
# Install gems
|
# Install gems
|
||||||
# Not ideal, but at present Travis-CI will not install with xapian enabled:
|
# Not ideal, but at present Travis-CI will not install with xapian enabled:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user