From 53112b2917e6bd83cd2befae36909e7d3b22b7ce Mon Sep 17 00:00:00 2001 From: Karel Picman Date: Tue, 19 Dec 2017 14:52:53 +0100 Subject: [PATCH 1/6] alias_method_chain is deprecated --- init.rb | 7 +++--- .../projects_helper_patch.rb | 22 +++++++------------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/init.rb b/init.rb index 8248f92..ceefa2f 100644 --- a/init.rb +++ b/init.rb @@ -15,13 +15,12 @@ end require 'redmine_custom_workflows/hooks' +require File.dirname(__FILE__) + '/lib/redmine_custom_workflows/projects_helper_patch' + Rails.application.config.to_prepare do unless Project.include?(RedmineCustomWorkflows::ProjectPatch) Project.send(:include, RedmineCustomWorkflows::ProjectPatch) end - unless ProjectsHelper.include?(RedmineCustomWorkflows::ProjectsHelperPatch) - ProjectsHelper.send(:include, RedmineCustomWorkflows::ProjectsHelperPatch) - end unless Attachment.include?(RedmineCustomWorkflows::AttachmentPatch) Attachment.send(:include, RedmineCustomWorkflows::AttachmentPatch) end @@ -52,4 +51,4 @@ Rails.application.config.to_prepare do unless ActionView::Base.include?(RedmineCustomWorkflows::Helper) ActionView::Base.send(:include, RedmineCustomWorkflows::Helper) end -end \ No newline at end of file +end diff --git a/lib/redmine_custom_workflows/projects_helper_patch.rb b/lib/redmine_custom_workflows/projects_helper_patch.rb index 458e54f..af8f4b6 100644 --- a/lib/redmine_custom_workflows/projects_helper_patch.rb +++ b/lib/redmine_custom_workflows/projects_helper_patch.rb @@ -1,20 +1,14 @@ module RedmineCustomWorkflows module ProjectsHelperPatch - def self.included(base) - base.send(:include, InstanceMethods) - base.class_eval do - alias_method_chain :project_settings_tabs, :custom_workflows - end + def project_settings_tabs + tabs = super + tabs << {:name => 'custom_workflows', :action => :manage_project_workflow, :partial => 'projects/settings/custom_workflow', + :label => :label_custom_workflow_plural} if User.current.allowed_to?(:manage_project_workflow, @project) + tabs end - module InstanceMethods - def project_settings_tabs_with_custom_workflows - tabs = project_settings_tabs_without_custom_workflows - tabs << {:name => 'custom_workflows', :action => :manage_project_workflow, :partial => 'projects/settings/custom_workflow', - :label => :label_custom_workflow_plural} if User.current.allowed_to?(:manage_project_workflow, @project) - tabs - end - end end -end \ No newline at end of file +end + +ProjectsHelper.send(:prepend, RedmineCustomWorkflows::ProjectsHelperPatch) From ce493be7712e7fe046733d5865509f6e166acb7d Mon Sep 17 00:00:00 2001 From: Karel Picman Date: Tue, 19 Dec 2017 15:07:46 +0100 Subject: [PATCH 2/6] #88 admin menu --- init.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/init.rb b/init.rb index ceefa2f..88f186b 100644 --- a/init.rb +++ b/init.rb @@ -8,7 +8,8 @@ Redmine::Plugin.register :redmine_custom_workflows do url 'http://www.redmine.org/plugins/custom-workflows' menu :admin_menu, :custom_workflows, {:controller => 'custom_workflows', :action => 'index'}, - :if => Proc.new { User.current.admin? }, :caption => :label_custom_workflow_plural + :if => Proc.new { User.current.admin? }, :caption => :label_custom_workflow_plural, + :html => {:class => 'icon icon-workflows'} permission :manage_project_workflow, {}, :require => :member end From e5daba9fe7ffe50f2039a7a24d45a5d7f6896a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Fri, 12 Oct 2018 07:56:21 +0200 Subject: [PATCH 3/6] Wrong file name for Brasilian localisation --- config/locales/{pt-br.yml => pt-BR.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config/locales/{pt-br.yml => pt-BR.yml} (100%) diff --git a/config/locales/pt-br.yml b/config/locales/pt-BR.yml similarity index 100% rename from config/locales/pt-br.yml rename to config/locales/pt-BR.yml From 7aadd331ca70accb924234fe8f1f537648666b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 19 Dec 2018 13:36:47 +0100 Subject: [PATCH 4/6] Czech localisation --- config/locales/cs.yml | 104 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 config/locales/cs.yml diff --git a/config/locales/cs.yml b/config/locales/cs.yml new file mode 100644 index 0000000..d6e3ad4 --- /dev/null +++ b/config/locales/cs.yml @@ -0,0 +1,104 @@ +cs: + project_module_custom_workflows_module: Uživatelské procesy + permission_manage_project_workflow: Spravovat uživatelské procesy + + label_custom_workflow: Uživatelský proces + label_custom_workflow_plural: Uživatelské procesy + label_custom_workflow_new: Vytvořit uživatelský proces + label_workflow_scripts: Skript procesu + label_enabled_projects: Povoleno pro projekt(y) + label_custom_workflow_export: Export + label_custom_workflow_import: Importovat proces + label_save_workflows: Uložení sledovaných objektů + label_destroy_workflows: Smazání sledovaných objektů + label_add_workflows: Přidání sledovaných objektů do sezanmu + label_remove_workflows: Odstranění sledovaných objektů za seznamu + + button_import: Import + button_custom_workflow_activate: Aktivovat + button_custom_workflow_deactivate: Deaktivovat + + field_after_save: Skript spuštěný po uložení sledovaného objektu + field_before_save: Skript spuštěný před uložením sledovaného objektu + field_after_destroy: Skript spuštěný po smazání sledovaného objektu + field_before_destroy: Skript spuštěný před smazáním sledovaného objektu + field_after_add: Skript spuštěný po přidání sledovaného objektu do seznamu + field_before_add: Skript spuštěný před přidáním sledovaného objektu do seznamu + field_after_remove: Skript spuštěný po odstranění sledovaného objektu ze seznamu + field_before_remove: Skript spuštěný před odstraněním sledovaného objektu ze seznamu + field_shared_code: Sdílený kód + field_observable: Sledovaný objekt + field_is_enabled: Povoleno + field_enabled_for_all_projects: Povoleno pro všechny projekty + field_custom_workflow_author: Autorův e-mail + field_custom_workflow_file: Select the XML file previously exported process + field_custom_workflow_active: Aktivní + field_custom_workflow: + script: Skript + + notice_successful_import: Uživatelský proces byl úspěšně naimportován + notice_successful_status_change: Status byl úspěšně změněn + error_failed_import: Chyba při importu uživatelského procesu (Neznámý formát? Podívejte se do logu.) + + activerecord: + errors: + messages: + invalid_script: "obsahuje chyby: %{error}" + custom_workflow_error: Chyba uživatelského procesu (kontaktujte administrátora) + new_status_invalid: "změna z '%{old_status}' na '%{new_status}' není povolena" + scripts_absent: Musí být definován alespoň jeden skript + + text_select_project_custom_workflows: Vyberte uživatelský skript projektu + text_custom_workflow_before_save_note: "Zde můžete měnit vlastnosti úkolu. Ve skriptu nevytvářejte ani neměňte + související úkoly. Pro ukončení skriptu chybou použijte: `raise WorkflowError, 'Zpráva uživateli'`." + text_custom_workflow_after_save_note: Zde můžete aktualizovat nebo vytvářet souvissející úkoly. Mějte na paměti, že + tento skript bude také vykonán pro nově vytvořené úkoly. Takže nezapomeňte udělat vhodné kontroly pro zabránění + rekurzivnímu volání. + text_custom_workflow_issue_code_note: Skripty jsou vykonávány v rámci objektu úkolu stejně jako volání `before_save` + a `after_save` funkcí. Takže lze použít přímo vlastností úkolů. Proměnné (@variable) jsou rovněž dostupné a lze jich + použít. + text_custom_workflow_shared_code_note: Tento kód bude spuštěn pře jakýmkoli jiným procesem a může obsahovat sdílený + kód, např. funkce a třídy, které jsou potřeba v jiných procesech + text_custom_workflow_user_code_note: Skripty jsou vykonávány v rámci objektu uživatel, když se objekt mění (maže). + Můžete přímo použít metody a vlastnosti objektu. + text_custom_workflow_group_code_note: Skripty jsou vykonávány v rámci objektu skupina, když se objekt mění (maže). + Můžete přímo použít metody a vlastnosti objektu. + text_custom_workflow_group_users_code_note: Tyto skripty jsou vykonávány, když je uživatel přidán nebo odebrán ze + skupiny. Pro přístup k objektům použijte proměnné @user a @group. + text_custom_workflow_attachment_code_note: Skripty jsou vykonávány v rámci objektu příloha, když se tento objekt mění + (maže se). Můžete přímo použít metody a vlastnosti objektu. Mějte na paměti, že se to týká všech typů příloh + (u úkolů, dokumentů, wiki stránek atd.), takže byste měli zkontrolovat proměnnou 'container_type' pro určení, + o jakou přílohu se jedná. + text_custom_workflow_issue_attachments_code_note: Tento skripty se vykonávají když je příloha přidána nebo odebrába + z úkolu. Můžete použít proměnné @issue a @attachment pro přístup k těmto objektům ve skriptu. + text_custom_workflow_project_code_note: SSkripty jsou vykonávány v rámci objektu projekt, když se objekt mění (maže). + Můžete přímo použít metody a vlastnosti objektu. + text_custom_workflow_project_attachments_code_note: Tyto skripty jsou vykonávány, když se přidává nebo se maže soubor + u projektu. Můžete použít proměnné @project a @attachment pro přístup k těmto objektům ve skriptu. + text_custom_workflow_wiki_content_code_note: Tyto kripty jsou vykonávány v rámci objektu Wiki, když se mění nebo se + maže. Můžete přímo použít metody a vlastnosti objektu. + text_custom_workflow_wiki_page_attachments_code_note: Tyto skripty jsou vykonávány, když se přidává nebo se maže + příloha u wiki stránky. Můžete použít proměnné @page a @attachment pro přístup k těmto objektům ve skriptu. + text_custom_workflow_time_entry_code_note: Skripty jsou vykonávány v rámci objektu časový záznam, kdyže se mění nebo + se maže. Můžete přímo použít metody a vlastnosti objektu. + text_custom_workflow_version_code_note: Skripty jsou vykonávány v rámci objektu verze, když se mění nebo se maže. + Můžete přímo použít metody a vlastnosti objektu. + + text_no_enabled_projects: Žádné projekty + text_custom_workflow_author: Bude zahrnuto do exportovaného XML + text_custom_workflow_disabled: zakázáno administrátorem + text_custom_workflow_is_for_all: povoleno pro všechny projekty + + custom_workflow_observable_shared: + custom_workflow_observable_issue: Úkol + custom_workflow_observable_issue_attachments: Přílohy úkolů + custom_workflow_observable_group: Skupina + custom_workflow_observable_user: Uživatel + custom_workflow_observable_attachment: Příloha + custom_workflow_observable_project: Projekt + custom_workflow_observable_project_attachments: Soubory + custom_workflow_observable_wiki_content: Wiki + custom_workflow_observable_wiki_page_attachments: Přílohy na wiki + custom_workflow_observable_group_users: Uživatelé skupin + custom_workflow_observable_time_entry: Časový záznam + custom_workflow_observable_version: Verze From 3f11d9eec5e1f6f6cdf30795a5445f2a16bf0d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Pi=C4=8Dman?= Date: Wed, 19 Dec 2018 13:37:12 +0100 Subject: [PATCH 5/6] Compatibility with Redmine 4 --- Gemfile | 4 + .../custom_workflows_controller.rb | 68 +++++++++-- app/models/custom_workflow.rb | 2 +- app/views/custom_workflows/_form.html.erb | 108 +++++++++--------- app/views/custom_workflows/index.html.erb | 10 +- app/views/layouts/_collapsible.html.erb | 6 - .../settings/_custom_workflow.html.erb | 2 +- assets/javascripts/tab_override.js | 9 +- config/routes.rb | 1 + .../20110915084858_create_custom_workflows.rb | 7 +- .../20120601054047_alter_custom_workflows.rb | 4 +- ...054557_create_custom_workflows_projects.rb | 7 +- ...hange_custom_workflows_description_type.rb | 4 +- ...5222_add_after_save_to_custom_workflows.rb | 2 +- ...5252_add_is_for_all_to_custom_workflows.rb | 7 +- ...ake_after_save_and_before_save_nullable.rb | 4 +- ...50522134437_set_position_field_nullable.rb | 4 +- ...thor_and_timestamps_to_custom_workflows.rb | 2 +- .../20150526132244_create_example_workflow.rb | 2 +- ...40_add_active_field_to_custom_workflows.rb | 2 +- ...dd_observable_field_to_custom_workflows.rb | 2 +- ...ional_script_fields_to_custom_workflows.rb | 2 +- ...e_and_after_destroy_to_custom_workflows.rb | 2 +- init.rb | 2 + lib/redmine_custom_workflows/mailer_patch.rb | 2 +- 25 files changed, 155 insertions(+), 110 deletions(-) create mode 100644 Gemfile delete mode 100644 app/views/layouts/_collapsible.html.erb diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..13946ec --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem 'acts_as_list' +gem 'activemodel-serializers-xml' \ No newline at end of file diff --git a/app/controllers/custom_workflows_controller.rb b/app/controllers/custom_workflows_controller.rb index 592f56a..e17bd6d 100644 --- a/app/controllers/custom_workflows_controller.rb +++ b/app/controllers/custom_workflows_controller.rb @@ -1,8 +1,32 @@ class CustomWorkflowsController < ApplicationController layout 'admin' - before_filter :require_admin - before_filter :find_workflow, :only => [:show, :edit, :update, :destroy, :export, :change_status] + before_action :require_admin + before_action :find_workflow, only: [:show, :edit, :update, :destroy, :export, :change_status, :reorder] + + def reorder + from = @workflow.position + to = params[:custom_workflow][:position].to_i + CustomWorkflow.transaction do + CustomWorkflow.find_each do |wf| + if wf.position == from + wf.update_attribute :position, to + elsif wf.position >= to && wf.position < from + # Move up + wf.update_attribute :position, wf.position + 1 + elsif wf.position <= to && wf.position > from + # Move down + wf.update_attribute :position, wf.position - 1 + end + end + end + respond_to do |format| + format.html + format.js { + render inline: "location.replace('#{custom_workflows_path}');" + } + end + end def index @workflows = CustomWorkflow.includes(:projects).all @@ -52,14 +76,30 @@ class CustomWorkflowsController < ApplicationController end def create - @workflow = CustomWorkflow.new(params[:custom_workflow]) + @workflow = CustomWorkflow.new + @workflow.before_save = params[:custom_workflow][:before_save] + @workflow.after_save = params[:custom_workflow][:after_save] + @workflow.name = params[:custom_workflow][:name] + @workflow.description = params[:custom_workflow][:description] + @workflow.position = CustomWorkflow.count + 1 + @workflow.is_for_all = params[:custom_workflow][:is_for_all].present? + @workflow.author = params[:custom_workflow][:author] + @workflow.active = params[:custom_workflow][:active] + @workflow.observable = params[:custom_workflow][:observable] + @workflow.shared_code = params[:custom_workflow][:shared_code] + @workflow.before_add = params[:custom_workflow][:before_add] + @workflow.after_add = params[:custom_workflow][:after_add] + @workflow.before_remove = params[:custom_workflow][:before_remove] + @workflow.after_remove = params[:custom_workflow][:after_remove] + @workflow.before_destroy = params[:custom_workflow][:before_destroy] + @workflow.after_destroy = params[:custom_workflow][:after_destroy] respond_to do |format| if params.has_key?(:commit) && @workflow.save flash[:notice] = l(:notice_successful_create) cookies[:custom_workflows_author] = @workflow.author format.html { redirect_to(custom_workflows_path) } else - format.html { render :action => "new" } + format.html { render action: :new } end end end @@ -70,26 +110,38 @@ class CustomWorkflowsController < ApplicationController flash[:notice] = l(:notice_successful_status_change) format.html { redirect_to(custom_workflows_path) } else - format.html { render :action => :edit } + format.html { render action: :edit } end end end def update respond_to do |format| - @workflow.assign_attributes(params[:custom_workflow]) + @workflow.before_save = params[:custom_workflow][:before_save] + @workflow.after_save = params[:custom_workflow][:after_save] + @workflow.name = params[:custom_workflow][:name] + @workflow.description = params[:custom_workflow][:description] + @workflow.is_for_all = params[:custom_workflow][:is_for_all].present? + @workflow.author = params[:custom_workflow][:author] + @workflow.active = params[:custom_workflow][:active] + @workflow.shared_code = params[:custom_workflow][:shared_code] + @workflow.before_add = params[:custom_workflow][:before_add] + @workflow.after_add = params[:custom_workflow][:after_add] + @workflow.before_remove = params[:custom_workflow][:before_remove] + @workflow.after_remove = params[:custom_workflow][:after_remove] + @workflow.before_destroy = params[:custom_workflow][:before_destroy] + @workflow.after_destroy = params[:custom_workflow][:after_destroy] if params.has_key?(:commit) && @workflow.save flash[:notice] = l(:notice_successful_update) format.html { redirect_to(custom_workflows_path) } else - format.html { render :action => :edit } + format.html { render action: :edit } end end end def destroy @workflow.destroy - respond_to do |format| flash[:notice] = l(:notice_successful_delete) format.html { redirect_to(custom_workflows_path) } diff --git a/app/models/custom_workflow.rb b/app/models/custom_workflow.rb index 52c1586..45383a1 100644 --- a/app/models/custom_workflow.rb +++ b/app/models/custom_workflow.rb @@ -14,7 +14,6 @@ class CustomWorkflow < ActiveRecord::Base COLLECTION_OBSERVABLES = [:group_users, :issue_attachments, :project_attachments, :wiki_page_attachments] SINGLE_OBSERVABLES = [:issue, :user, :group, :attachment, :project, :wiki_content, :time_entry, :version] - attr_protected :id has_and_belongs_to_many :projects acts_as_list @@ -105,6 +104,7 @@ class CustomWorkflow < ActiveRecord::Base def validate_syntax_for(object, event) object.instance_eval(read_attribute(event)) if respond_to?(event) && read_attribute(event) rescue WorkflowError => e + errors.add event, :invalid_script, :error => e rescue Exception => e errors.add event, :invalid_script, :error => e end diff --git a/app/views/custom_workflows/_form.html.erb b/app/views/custom_workflows/_form.html.erb index 6c8b84a..3ee7cfe 100644 --- a/app/views/custom_workflows/_form.html.erb +++ b/app/views/custom_workflows/_form.html.erb @@ -9,7 +9,7 @@ CustomWorkflow::OBSERVABLES.collect {|o| [l("custom_workflow_observable_#{o}"), o]}, {}, :onchange => 'this.form.submit()', :disabled => !@workflow.new_record? %>

-

<%= f.text_area :description, :cols => 40, :rows => 5 %>

+

<%= f.text_area :description, cols: 40, rows: 5 , class: 'wiki-edit' %>

<% if @workflow.has_projects_association? %>

<%= f.check_box :is_for_all, :onclick => "checkAndDisable('custom_workflow_enabled_projects', this.checked);", :label => :field_enabled_for_all_projects %>

<% end %> @@ -44,69 +44,73 @@ <% when :shared %> <%= f.text_area :shared_code, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> <% when *CustomWorkflow::COLLECTION_OBSERVABLES %> - <%= render :layout => 'layouts/collapsible', - :locals => { - :collapsed => (not (@workflow.before_add.present? or @workflow.after_add.present? or @workflow.errors[:base].present?)), - :label => l(:label_add_workflows)} do %> -
-
- <%= f.text_area :before_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' %> + <% collapsed = (not (@workflow.before_add.present? or @workflow.after_add.present? or @workflow.errors[:base].present?)) %> + + <% collapsed = (not (@workflow.before_remove.present? or @workflow.after_remove.present?)) %> + <% when *CustomWorkflow::SINGLE_OBSERVABLES %> - <%= render :layout => 'layouts/collapsible', - :locals => { - :collapsed => (not (@workflow.before_save.present? or @workflow.after_save.present? or @workflow.errors[:base].present?)), - :label => l(:label_save_workflows)} do %> -
-
- <%= f.text_area :before_save, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> - <% if observable == :issue %> - <%= l(:text_custom_workflow_before_save_note) %> - <% end %> -
-
- <%= f.text_area :after_save, :cols => 40, :rows => 20, :wrap => 'off', :class => 'custom_workflow_script' %> - <% if observable == :issue %> - <%= l(:text_custom_workflow_after_save_note) %> - <% end %> + <% collapsed = (not (@workflow.before_save.present? or @workflow.after_save.present? or @workflow.errors[:base].present?)) %> + + <% collapsed = (not (@workflow.before_destroy.present? or @workflow.after_destroy.present?)) %> + <% end %> -