diff --git a/app/components/automations/index_component.rb b/app/components/automations/index_component.rb
new file mode 100644
index 00000000000..e5494ea9bfa
--- /dev/null
+++ b/app/components/automations/index_component.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Automations
+ class IndexComponent < ::TableComponent
+ columns :name, :triggers, :conditions, :actions, :sort
+
+ def headers
+ [
+ ["name", { caption: Automation.human_attribute_name(:name) }],
+ ["triggers", { caption: I18n.t("automations.triggers.name") }],
+ ["conditions", { caption: I18n.t("automations.conditions") }],
+ ["actions", { caption: I18n.t("automations.actions.name") }],
+ ["sort", { caption: I18n.t(:label_sort) }]
+ ]
+ end
+
+ def sortable?
+ false
+ end
+
+ def inline_create_link
+ link_to new_automation_path,
+ aria: { label: t("automations.new") },
+ class: "wp-inline-create--add-link",
+ title: t("automations.new") do
+ helpers.op_icon("icon icon-add")
+ end
+ end
+ end
+end
diff --git a/app/components/automations/row_component.rb b/app/components/automations/row_component.rb
new file mode 100644
index 00000000000..7dc948ac4ce
--- /dev/null
+++ b/app/components/automations/row_component.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+module Automations
+ class RowComponent < ::RowComponent
+ def automation
+ row
+ end
+
+ def name
+ link_to automation.name, edit_automation_path(automation)
+ end
+
+ def triggers
+ automation.triggers.map do |trigger|
+ case trigger
+ when Automations::Triggers::Manual
+ I18n.t("automations.triggers.manual.label")
+ else
+ trigger.type.demodulize
+ end
+ end.join(", ")
+ end
+
+ def conditions
+ automation.conditions.map(&:human_name).join(", ")
+ end
+
+ def actions
+ automation.actions.map(&:human_name).join(", ")
+ end
+
+ def sort
+ helpers.reorder_links("automation", { action: "update", id: automation }, method: :put)
+ end
+
+ def button_links
+ [
+ edit_link,
+ delete_link
+ ]
+ end
+
+ def edit_link
+ link_to(
+ helpers.op_icon("icon icon-edit"),
+ helpers.edit_automation_path(automation),
+ title: t(:button_edit)
+ )
+ end
+
+ def delete_link
+ link_to(
+ helpers.op_icon("icon icon-delete"),
+ helpers.automation_path(automation),
+ data: {
+ turbo_method: :delete,
+ turbo_confirm: I18n.t(:text_are_you_sure)
+ },
+ title: t(:button_delete)
+ )
+ end
+ end
+end
diff --git a/app/components/custom_actions/row_component.rb b/app/components/custom_actions/row_component.rb
deleted file mode 100644
index 2f3f065f605..00000000000
--- a/app/components/custom_actions/row_component.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-module CustomActions
- class RowComponent < ::RowComponent
- def action
- row
- end
-
- def name
- link_to action.name, edit_custom_action_path(action)
- end
-
- delegate :description, to: :action
-
- def sort
- helpers.reorder_links("custom_action", { action: "update", id: action }, method: :put)
- end
-
- def button_links
- [
- edit_link,
- delete_link
- ]
- end
-
- def edit_link
- link_to(
- helpers.op_icon("icon icon-edit"),
- helpers.edit_custom_action_path(action),
- title: t(:button_edit)
- )
- end
-
- def delete_link
- link_to(
- helpers.op_icon("icon icon-delete"),
- helpers.custom_action_path(action),
- data: {
- turbo_method: :delete,
- turbo_confirm: I18n.t(:text_are_you_sure)
- },
- title: t(:button_delete)
- )
- end
- end
-end
diff --git a/app/components/custom_actions/table_component.rb b/app/components/custom_actions/table_component.rb
deleted file mode 100644
index 324f8f7dc57..00000000000
--- a/app/components/custom_actions/table_component.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-module CustomActions
- class TableComponent < ::TableComponent
- columns :name, :description, :sort
-
- def headers
- [
- ["name", { caption: CustomAction.human_attribute_name(:name) }],
- ["description", { caption: CustomAction.human_attribute_name(:description) }],
- ["sort", { caption: I18n.t(:label_sort) }]
- ]
- end
-
- def sortable?
- false
- end
-
- def inline_create_link
- link_to new_custom_action_path,
- aria: { label: t("custom_actions.new") },
- class: "wp-inline-create--add-link",
- title: t("custom_actions.new") do
- helpers.op_icon("icon icon-add")
- end
- end
- end
-end
diff --git a/app/contracts/automations/cu_contract.rb b/app/contracts/automations/cu_contract.rb
new file mode 100644
index 00000000000..258a3f63bd8
--- /dev/null
+++ b/app/contracts/automations/cu_contract.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require "model_contract"
+
+module Automations
+ class CuContract < ::ModelContract
+ def self.model
+ Automation
+ end
+
+ attribute :name
+ attribute :description
+
+ attribute :actions do
+ errors.add(:actions, :empty) if model.actions.empty?
+ model.actions.each { |action| action.validate(errors) }
+ end
+
+ attribute :conditions do
+ model.conditions.each { |condition| condition.validate(errors) }
+ end
+ end
+end
diff --git a/app/contracts/automations/execute_contract.rb b/app/contracts/automations/execute_contract.rb
new file mode 100644
index 00000000000..5e3bdadd7c5
--- /dev/null
+++ b/app/contracts/automations/execute_contract.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Automations
+ class ExecuteContract < BaseContract
+ property :lock_version
+ property :work_package_id
+
+ validates :work_package_id, presence: true
+ validate :work_package_visible
+ validate :automation_conditions_fulfilled
+
+ private
+
+ def work_package_visible
+ return unless model.work_package_id
+
+ errors.add(:work_package_id, :does_not_exist) unless WorkPackage.visible(user).where(id: model.work_package_id).exists?
+ end
+
+ def automation_conditions_fulfilled
+ return unless model.work_package_id
+ return unless options[:automation]
+
+ work_package = WorkPackage.visible(user).find_by(id: model.work_package_id)
+ return unless work_package
+
+ errors.add(:base, :error_unauthorized) unless options[:automation].conditions_fulfilled?(work_package, user)
+ end
+ end
+end
diff --git a/app/contracts/custom_actions/cu_contract.rb b/app/contracts/custom_actions/cu_contract.rb
deleted file mode 100644
index d9a479bbf9f..00000000000
--- a/app/contracts/custom_actions/cu_contract.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-require "model_contract"
-
-# Contract for create (c) and update (u)
-module CustomActions
- class CuContract < ::ModelContract
- def self.model
- CustomAction
- end
-
- def initialize(model, user = nil)
- super
- end
-
- attribute :name
- attribute :description
-
- attribute :actions do
- if model.actions.empty?
- errors.add :actions, :empty
- end
- model.actions.each do |action|
- action.validate(errors)
- end
- end
-
- attribute :conditions do
- model.conditions.each do |condition|
- condition.validate(errors)
- end
- end
- end
-end
diff --git a/app/contracts/custom_actions/execute_contract.rb b/app/contracts/custom_actions/execute_contract.rb
deleted file mode 100644
index 8f327dd7806..00000000000
--- a/app/contracts/custom_actions/execute_contract.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-module CustomActions
- class ExecuteContract < BaseContract
- property :lock_version
- property :work_package_id
-
- validates :work_package_id, presence: true
- validate :work_package_visible
- validate :custom_action_conditions_fulfilled
-
- private
-
- def work_package_visible
- return unless model.work_package_id
-
- unless WorkPackage.visible(user).where(id: model.work_package_id).exists?
- errors.add(:work_package_id, :does_not_exist)
- end
- end
-
- def custom_action_conditions_fulfilled
- return unless model.work_package_id
- return unless options[:custom_action]
-
- work_package = WorkPackage.visible(user).find_by(id: model.work_package_id)
- return unless work_package
-
- unless options[:custom_action].conditions_fulfilled?(work_package, user)
- errors.add(:base, :error_unauthorized)
- end
- end
- end
-end
diff --git a/app/controllers/automations_controller.rb b/app/controllers/automations_controller.rb
new file mode 100644
index 00000000000..0b0666171a5
--- /dev/null
+++ b/app/controllers/automations_controller.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+class AutomationsController < ApplicationController
+ before_action :require_admin
+
+ guard_enterprise_feature(:custom_actions, only: %i[new create edit update]) do
+ redirect_to action: :index
+ end
+
+ before_action :find_automation, only: %i[edit update destroy]
+ before_action :pad_params, only: %i[create update]
+
+ layout "admin"
+
+ def index
+ @automations = Automation.order_by_position.includes(:triggers)
+ end
+
+ def new
+ @automation = Automation.new
+ @automation.triggers.build(type: "Automations::Triggers::Manual")
+ end
+
+ def edit; end
+
+ def create
+ Automations::CreateService
+ .new(user: current_user)
+ .call(attributes: permitted_params.automation.to_h,
+ &index_or_render(:new))
+ end
+
+ def update
+ Automations::UpdateService
+ .new(action: @automation, user: current_user)
+ .call(attributes: permitted_params.automation.to_h,
+ &index_or_render(:edit))
+ end
+
+ def destroy
+ @automation.destroy
+
+ redirect_to automations_path, status: :see_other
+ end
+
+ private
+
+ def find_automation
+ @automation = Automation.find(params[:id])
+ end
+
+ def index_or_render(render_action)
+ ->(call) {
+ call.on_success do
+ redirect_to automations_path, status: :see_other
+ end
+
+ call.on_failure do
+ @automation = call.result
+ render action: render_action, status: :unprocessable_entity
+ end
+ }
+ end
+
+ def pad_params
+ return if !params[:automation] || params[:automation][:move_to]
+
+ params[:automation][:conditions] ||= {}
+ params[:automation][:actions] ||= {}
+ params[:automation][:triggers_attributes] ||= [{ type: "Automations::Triggers::Manual", options: { button_label: params[:automation][:name] } }]
+ end
+end
diff --git a/app/controllers/custom_actions_controller.rb b/app/controllers/custom_actions_controller.rb
deleted file mode 100644
index 62c766a5896..00000000000
--- a/app/controllers/custom_actions_controller.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-class CustomActionsController < ApplicationController
- before_action :require_admin
-
- guard_enterprise_feature(:custom_actions, only: %i[new create edit update]) do
- redirect_to action: :index
- end
-
- before_action :find_custom_action, only: %i(edit update destroy)
- before_action :pad_params, only: %i(create update)
-
- layout "admin"
-
- def index
- @custom_actions = CustomAction.order_by_position
- end
-
- def new
- @custom_action = CustomAction.new
- end
-
- def edit; end
-
- def create
- CustomActions::CreateService
- .new(user: current_user)
- .call(attributes: permitted_params.custom_action.to_h,
- &index_or_render(:new))
- end
-
- def update
- CustomActions::UpdateService
- .new(action: @custom_action, user: current_user)
- .call(attributes: permitted_params.custom_action.to_h,
- &index_or_render(:edit))
- end
-
- def destroy
- @custom_action.destroy
-
- redirect_to custom_actions_path, status: :see_other
- end
-
- private
-
- def find_custom_action
- @custom_action = CustomAction.find(params[:id])
- end
-
- def index_or_render(render_action)
- ->(call) {
- call.on_success do
- redirect_to custom_actions_path, status: :see_other
- end
-
- call.on_failure do
- @custom_action = call.result
- render action: render_action, status: :unprocessable_entity
- end
- }
- end
-
- # If no action/condition is set in the view, the
- # actions/conditions already existing on a custom action should be removed.
- # But because it is not feasible to have an empty and hidden hash object in a form
- # we have to pad the params here.
- def pad_params
- return if !params[:custom_action] || params[:custom_action][:move_to]
-
- params[:custom_action][:conditions] ||= {}
- params[:custom_action][:actions] ||= {}
- end
-end
diff --git a/app/models/custom_action.rb b/app/models/automation.rb
similarity index 51%
rename from app/models/custom_action.rb
rename to app/models/automation.rb
index c37d6ddb831..4458809a59b 100644
--- a/app/models/custom_action.rb
+++ b/app/models/automation.rb
@@ -1,40 +1,24 @@
# frozen_string_literal: true
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-class CustomAction < ApplicationRecord
+class Automation < ApplicationRecord
validates :name, length: { maximum: 255, minimum: 1 }
- serialize :actions, coder: CustomActions::Actions::Serializer
- has_and_belongs_to_many :status_conditions, class_name: "Status"
- has_and_belongs_to_many :role_conditions, class_name: "Role"
- has_and_belongs_to_many :type_conditions, class_name: "Type"
- has_and_belongs_to_many :project_conditions, class_name: "Project"
+ validate :must_have_at_least_one_trigger
+ validate :must_not_have_more_than_one_manual_trigger
+
+ serialize :actions, coder: Automations::Actions::Serializer
+ before_validation :ensure_manual_trigger
+
+ has_and_belongs_to_many :status_conditions, class_name: "Status", join_table: :automations_statuses
+ has_and_belongs_to_many :role_conditions, class_name: "Role", join_table: :automations_roles
+ has_and_belongs_to_many :type_conditions, class_name: "Type", join_table: :automations_types
+ has_and_belongs_to_many :project_conditions, class_name: "Project", join_table: :automations_projects
+
+ has_many :triggers,
+ -> { order(:position, :id) },
+ class_name: "Automations::Triggers::Base",
+ dependent: :destroy,
+ inverse_of: :automation
+ accepts_nested_attributes_for :triggers
after_save :persist_conditions
@@ -43,19 +27,18 @@ class CustomAction < ApplicationRecord
acts_as_list
+ scope :with_manual_trigger, -> {
+ joins(:triggers).where(automation_triggers: { type: "Automations::Triggers::Manual" }).distinct
+ }
+
def initialize(*args)
ret = super
-
- if actions.nil?
- self.actions = []
- end
-
+ self.actions ||= []
ret
end
def reload(*args)
@conditions = nil
-
super
end
@@ -77,7 +60,7 @@ class CustomAction < ApplicationRecord
end
def available_actions
- ::CustomActions::Register.actions.map(&:all).flatten
+ ::Automations::Register.actions.map(&:all).flatten
end
def all_conditions
@@ -104,11 +87,17 @@ class CustomAction < ApplicationRecord
end
def self.available_conditions
- ::CustomActions::Register.conditions
+ ::Automations::Register.conditions
end
private
+ def ensure_manual_trigger
+ return unless triggers.reject(&:marked_for_destruction?).empty?
+
+ triggers.build(type: "Automations::Triggers::Manual", options: { button_label: name })
+ end
+
def all_of(availables, actual)
availables.map do |available|
existing = actual.detect { |a| a.key == available.key }
@@ -124,4 +113,13 @@ class CustomAction < ApplicationRecord
condition_class.setter(self, condition)
end
end
+
+ def must_have_at_least_one_trigger
+ errors.add(:triggers, :blank) if triggers.reject(&:marked_for_destruction?).empty?
+ end
+
+ def must_not_have_more_than_one_manual_trigger
+ manual_triggers = triggers.reject(&:marked_for_destruction?).count { |trigger| trigger.type == "Automations::Triggers::Manual" }
+ errors.add(:triggers, :invalid) if manual_triggers > 1
+ end
end
diff --git a/app/models/custom_actions/actions/assigned_to.rb b/app/models/automations/actions/assigned_to.rb
similarity index 92%
rename from app/models/custom_actions/actions/assigned_to.rb
rename to app/models/automations/actions/assigned_to.rb
index 2d0655e161b..87923628d76 100644
--- a/app/models/custom_actions/actions/assigned_to.rb
+++ b/app/models/automations/actions/assigned_to.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::AssignedTo < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::MeAssociated
+class Automations::Actions::AssignedTo < Automations::Actions::Base
+ include Automations::Actions::Strategies::MeAssociated
def self.key
:assigned_to
diff --git a/app/models/custom_actions/actions/base.rb b/app/models/automations/actions/base.rb
similarity index 95%
rename from app/models/custom_actions/actions/base.rb
rename to app/models/automations/actions/base.rb
index 3b131d6f80d..aae8e4bb925 100644
--- a/app/models/custom_actions/actions/base.rb
+++ b/app/models/automations/actions/base.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Base
+class Automations::Actions::Base
attr_reader :values
DEFAULT_PRIORITY = 100
@@ -98,10 +98,6 @@ class CustomActions::Actions::Base
private
- def deconstruct_keys(*)
- { type:, custom_field_based: respond_to?(:custom_field) }
- end
-
def validate_value_required(errors)
if required? && values.empty?
errors.add :actions,
diff --git a/app/models/custom_actions/actions/custom_field.rb b/app/models/automations/actions/custom_field.rb
similarity index 81%
rename from app/models/custom_actions/actions/custom_field.rb
rename to app/models/automations/actions/custom_field.rb
index dd796273c4f..4b5dca1692b 100644
--- a/app/models/custom_actions/actions/custom_field.rb
+++ b/app/models/automations/actions/custom_field.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::CustomField < CustomActions::Actions::Base
+class Automations::Actions::CustomField < Automations::Actions::Base
class << self
def key
custom_field.attribute_name.to_sym
@@ -40,7 +40,7 @@ class CustomActions::Actions::CustomField < CustomActions::Actions::Base
def all
WorkPackageCustomField
- .usable_as_custom_action
+ .usable_as_automation
.map do |cf|
create_subclass(cf)
end
@@ -57,7 +57,7 @@ class CustomActions::Actions::CustomField < CustomActions::Actions::Base
private
def create_subclass(custom_field)
- klass = Class.new(CustomActions::Actions::CustomField)
+ klass = Class.new(Automations::Actions::CustomField)
klass.define_singleton_method(:custom_field) do
custom_field
end
@@ -69,23 +69,23 @@ class CustomActions::Actions::CustomField < CustomActions::Actions::Base
def strategy(custom_field)
case custom_field.field_format
when "string"
- CustomActions::Actions::Strategies::String
+ Automations::Actions::Strategies::String
when "text"
- CustomActions::Actions::Strategies::Text
+ Automations::Actions::Strategies::Text
when "link"
- CustomActions::Actions::Strategies::Link
+ Automations::Actions::Strategies::Link
when "int"
- CustomActions::Actions::Strategies::Integer
+ Automations::Actions::Strategies::Integer
when "float"
- CustomActions::Actions::Strategies::Float
+ Automations::Actions::Strategies::Float
when "date"
- CustomActions::Actions::Strategies::Date
+ Automations::Actions::Strategies::Date
when "bool"
- CustomActions::Actions::Strategies::Boolean
+ Automations::Actions::Strategies::Boolean
when "user"
- CustomActions::Actions::Strategies::UserCustomField
+ Automations::Actions::Strategies::UserCustomField
when "list", "version"
- CustomActions::Actions::Strategies::AssociatedCustomField
+ Automations::Actions::Strategies::AssociatedCustomField
end
end
end
diff --git a/app/models/custom_actions/actions/date.rb b/app/models/automations/actions/date.rb
similarity index 92%
rename from app/models/custom_actions/actions/date.rb
rename to app/models/automations/actions/date.rb
index 7e4f3bee380..571788b3313 100644
--- a/app/models/custom_actions/actions/date.rb
+++ b/app/models/automations/actions/date.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Date < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Date
+class Automations::Actions::Date < Automations::Actions::Base
+ include Automations::Actions::Strategies::Date
def self.key
:date
diff --git a/app/models/custom_actions/actions/done_ratio.rb b/app/models/automations/actions/done_ratio.rb
similarity index 92%
rename from app/models/custom_actions/actions/done_ratio.rb
rename to app/models/automations/actions/done_ratio.rb
index c885bb79e4b..d51ecec36b9 100644
--- a/app/models/custom_actions/actions/done_ratio.rb
+++ b/app/models/automations/actions/done_ratio.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::DoneRatio < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Integer
+class Automations::Actions::DoneRatio < Automations::Actions::Base
+ include Automations::Actions::Strategies::Integer
def self.key
:done_ratio
diff --git a/app/models/custom_actions/actions/due_date.rb b/app/models/automations/actions/due_date.rb
similarity index 90%
rename from app/models/custom_actions/actions/due_date.rb
rename to app/models/automations/actions/due_date.rb
index e0836b1f032..658e346291d 100644
--- a/app/models/custom_actions/actions/due_date.rb
+++ b/app/models/automations/actions/due_date.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::DueDate < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::DateProperty
+class Automations::Actions::DueDate < Automations::Actions::Base
+ include Automations::Actions::Strategies::DateProperty
def self.key
:due_date
diff --git a/app/models/custom_actions/actions/estimated_hours.rb b/app/models/automations/actions/estimated_hours.rb
similarity index 91%
rename from app/models/custom_actions/actions/estimated_hours.rb
rename to app/models/automations/actions/estimated_hours.rb
index dcec6856db9..1c2b18e79b3 100644
--- a/app/models/custom_actions/actions/estimated_hours.rb
+++ b/app/models/automations/actions/estimated_hours.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::EstimatedHours < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Float
+class Automations::Actions::EstimatedHours < Automations::Actions::Base
+ include Automations::Actions::Strategies::Float
def self.key
:estimated_hours
diff --git a/app/models/custom_actions/actions/inexistent.rb b/app/models/automations/actions/inexistent.rb
similarity index 94%
rename from app/models/custom_actions/actions/inexistent.rb
rename to app/models/automations/actions/inexistent.rb
index 215f95a1cae..f73665e3456 100644
--- a/app/models/custom_actions/actions/inexistent.rb
+++ b/app/models/automations/actions/inexistent.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Inexistent < CustomActions::Actions::Base
+class Automations::Actions::Inexistent < Automations::Actions::Base
def self.key
:inexistent
end
diff --git a/app/models/custom_actions/actions/notify.rb b/app/models/automations/actions/notify.rb
similarity index 93%
rename from app/models/custom_actions/actions/notify.rb
rename to app/models/automations/actions/notify.rb
index e88a50edf5d..dda26006920 100644
--- a/app/models/custom_actions/actions/notify.rb
+++ b/app/models/automations/actions/notify.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Notify < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Associated
+class Automations::Actions::Notify < Automations::Actions::Base
+ include Automations::Actions::Strategies::Associated
def apply(work_package)
comment = principals.where(id: values).map do |p|
diff --git a/app/models/custom_actions/actions/priority.rb b/app/models/automations/actions/priority.rb
similarity index 91%
rename from app/models/custom_actions/actions/priority.rb
rename to app/models/automations/actions/priority.rb
index 7826a99c87e..97011b57fc2 100644
--- a/app/models/custom_actions/actions/priority.rb
+++ b/app/models/automations/actions/priority.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Priority < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Associated
+class Automations::Actions::Priority < Automations::Actions::Base
+ include Automations::Actions::Strategies::Associated
def associated
IssuePriority
diff --git a/app/models/custom_actions/actions/project.rb b/app/models/automations/actions/project.rb
similarity index 92%
rename from app/models/custom_actions/actions/project.rb
rename to app/models/automations/actions/project.rb
index 5c893303fd0..c1d6f78ba9c 100644
--- a/app/models/custom_actions/actions/project.rb
+++ b/app/models/automations/actions/project.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Project < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Associated
+class Automations::Actions::Project < Automations::Actions::Base
+ include Automations::Actions::Strategies::Associated
PRIORITY = 10
diff --git a/app/models/custom_actions/actions/responsible.rb b/app/models/automations/actions/responsible.rb
similarity index 92%
rename from app/models/custom_actions/actions/responsible.rb
rename to app/models/automations/actions/responsible.rb
index c0b8e59f09f..c83d1531620 100644
--- a/app/models/custom_actions/actions/responsible.rb
+++ b/app/models/automations/actions/responsible.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Responsible < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::MeAssociated
+class Automations::Actions::Responsible < Automations::Actions::Base
+ include Automations::Actions::Strategies::MeAssociated
def type
:user
diff --git a/app/models/custom_actions/actions/serializer.rb b/app/models/automations/actions/serializer.rb
similarity index 93%
rename from app/models/custom_actions/actions/serializer.rb
rename to app/models/automations/actions/serializer.rb
index 81ca8efab3e..1905419e896 100644
--- a/app/models/custom_actions/actions/serializer.rb
+++ b/app/models/automations/actions/serializer.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Serializer
+module Automations::Actions::Serializer
module_function
def load(value)
@@ -39,13 +39,13 @@ module CustomActions::Actions::Serializer
.filter_map do |key, values|
klass = nil
- CustomActions::Register
+ Automations::Register
.actions
.detect do |a|
klass = a.for(key)
end
- klass ||= CustomActions::Actions::Inexistent
+ klass ||= Automations::Actions::Inexistent
klass.new(values)
end
diff --git a/app/models/custom_actions/actions/start_date.rb b/app/models/automations/actions/start_date.rb
similarity index 90%
rename from app/models/custom_actions/actions/start_date.rb
rename to app/models/automations/actions/start_date.rb
index 9d5fc185d48..5fd880de18b 100644
--- a/app/models/custom_actions/actions/start_date.rb
+++ b/app/models/automations/actions/start_date.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::StartDate < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::DateProperty
+class Automations::Actions::StartDate < Automations::Actions::Base
+ include Automations::Actions::Strategies::DateProperty
def self.key
:start_date
diff --git a/app/models/custom_actions/actions/status.rb b/app/models/automations/actions/status.rb
similarity index 91%
rename from app/models/custom_actions/actions/status.rb
rename to app/models/automations/actions/status.rb
index 30a939d3813..e1942004e50 100644
--- a/app/models/custom_actions/actions/status.rb
+++ b/app/models/automations/actions/status.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Status < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Associated
+class Automations::Actions::Status < Automations::Actions::Base
+ include Automations::Actions::Strategies::Associated
def self.key
:status
diff --git a/app/models/custom_actions/actions/strategies/associated.rb b/app/models/automations/actions/strategies/associated.rb
similarity index 92%
rename from app/models/custom_actions/actions/strategies/associated.rb
rename to app/models/automations/actions/strategies/associated.rb
index e608b67b638..ffbeb2615de 100644
--- a/app/models/custom_actions/actions/strategies/associated.rb
+++ b/app/models/automations/actions/strategies/associated.rb
@@ -28,9 +28,9 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::Associated
- include CustomActions::ValidateAllowedValue
- include CustomActions::ValuesToInteger
+module Automations::Actions::Strategies::Associated
+ include Automations::ValidateAllowedValue
+ include Automations::ValuesToInteger
def allowed_values
@allowed_values ||= begin
diff --git a/app/models/custom_actions/actions/strategies/associated_custom_field.rb b/app/models/automations/actions/strategies/associated_custom_field.rb
similarity index 88%
rename from app/models/custom_actions/actions/strategies/associated_custom_field.rb
rename to app/models/automations/actions/strategies/associated_custom_field.rb
index 97ccda753dc..ee731e0be06 100644
--- a/app/models/custom_actions/actions/strategies/associated_custom_field.rb
+++ b/app/models/automations/actions/strategies/associated_custom_field.rb
@@ -28,9 +28,9 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::AssociatedCustomField
- include CustomActions::Actions::Strategies::Associated
- include CustomActions::Actions::Strategies::CustomField
+module Automations::Actions::Strategies::AssociatedCustomField
+ include Automations::Actions::Strategies::Associated
+ include Automations::Actions::Strategies::CustomField
def associated
custom_field
diff --git a/app/models/custom_actions/actions/strategies/boolean.rb b/app/models/automations/actions/strategies/boolean.rb
similarity index 93%
rename from app/models/custom_actions/actions/strategies/boolean.rb
rename to app/models/automations/actions/strategies/boolean.rb
index 96ed10bbbbd..80d559d3fff 100644
--- a/app/models/custom_actions/actions/strategies/boolean.rb
+++ b/app/models/automations/actions/strategies/boolean.rb
@@ -21,8 +21,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::Boolean
- include CustomActions::ValidateAllowedValue
+module Automations::Actions::Strategies::Boolean
+ include Automations::ValidateAllowedValue
def allowed_values
[
diff --git a/app/models/custom_actions/actions/strategies/custom_field.rb b/app/models/automations/actions/strategies/custom_field.rb
similarity index 96%
rename from app/models/custom_actions/actions/strategies/custom_field.rb
rename to app/models/automations/actions/strategies/custom_field.rb
index 3d9c2071f9d..f9fbe832e28 100644
--- a/app/models/custom_actions/actions/strategies/custom_field.rb
+++ b/app/models/automations/actions/strategies/custom_field.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::CustomField
+module Automations::Actions::Strategies::CustomField
def apply(work_package)
if work_package.respond_to?(custom_field.attribute_setter)
set_custom_field_value(work_package)
diff --git a/app/models/custom_actions/actions/strategies/date.rb b/app/models/automations/actions/strategies/date.rb
similarity index 97%
rename from app/models/custom_actions/actions/strategies/date.rb
rename to app/models/automations/actions/strategies/date.rb
index 2ad203fafa8..2b80e9fe16e 100644
--- a/app/models/custom_actions/actions/strategies/date.rb
+++ b/app/models/automations/actions/strategies/date.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::Date
+module Automations::Actions::Strategies::Date
def values=(values)
super(Array(values).map { |v| to_date_or_nil(v) }.uniq)
end
diff --git a/app/models/custom_actions/actions/strategies/date_property.rb b/app/models/automations/actions/strategies/date_property.rb
similarity index 92%
rename from app/models/custom_actions/actions/strategies/date_property.rb
rename to app/models/automations/actions/strategies/date_property.rb
index e599ca8263d..dfe6c63f652 100644
--- a/app/models/custom_actions/actions/strategies/date_property.rb
+++ b/app/models/automations/actions/strategies/date_property.rb
@@ -28,6 +28,6 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::DateProperty
- include CustomActions::Actions::Strategies::Date
+module Automations::Actions::Strategies::DateProperty
+ include Automations::Actions::Strategies::Date
end
diff --git a/app/models/custom_actions/actions/strategies/float.rb b/app/models/automations/actions/strategies/float.rb
similarity index 93%
rename from app/models/custom_actions/actions/strategies/float.rb
rename to app/models/automations/actions/strategies/float.rb
index 6059086a3fe..be893101601 100644
--- a/app/models/custom_actions/actions/strategies/float.rb
+++ b/app/models/automations/actions/strategies/float.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::Float
- include CustomActions::Actions::Strategies::ValidateInRange
+module Automations::Actions::Strategies::Float
+ include Automations::Actions::Strategies::ValidateInRange
def values=(values)
super(Array(values).map { |v| to_float_or_nil(v) }.uniq)
diff --git a/app/models/custom_actions/actions/strategies/integer.rb b/app/models/automations/actions/strategies/integer.rb
similarity index 89%
rename from app/models/custom_actions/actions/strategies/integer.rb
rename to app/models/automations/actions/strategies/integer.rb
index d69938c4f85..58942e37a38 100644
--- a/app/models/custom_actions/actions/strategies/integer.rb
+++ b/app/models/automations/actions/strategies/integer.rb
@@ -28,9 +28,9 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::Integer
- include CustomActions::ValuesToInteger
- include CustomActions::Actions::Strategies::ValidateInRange
+module Automations::Actions::Strategies::Integer
+ include Automations::ValuesToInteger
+ include Automations::Actions::Strategies::ValidateInRange
def type
:integer_property
diff --git a/app/models/custom_actions/actions/strategies/link.rb b/app/models/automations/actions/strategies/link.rb
similarity index 93%
rename from app/models/custom_actions/actions/strategies/link.rb
rename to app/models/automations/actions/strategies/link.rb
index 94fc5e11523..5c822ead478 100644
--- a/app/models/custom_actions/actions/strategies/link.rb
+++ b/app/models/automations/actions/strategies/link.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::Link
- include CustomActions::Actions::Strategies::ValuesToString
+module Automations::Actions::Strategies::Link
+ include Automations::Actions::Strategies::ValuesToString
def type
:link_property
diff --git a/app/models/custom_actions/actions/strategies/me_associated.rb b/app/models/automations/actions/strategies/me_associated.rb
similarity index 92%
rename from app/models/custom_actions/actions/strategies/me_associated.rb
rename to app/models/automations/actions/strategies/me_associated.rb
index 241df7b15be..9d36a8fb6d5 100644
--- a/app/models/custom_actions/actions/strategies/me_associated.rb
+++ b/app/models/automations/actions/strategies/me_associated.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::MeAssociated
- include ::CustomActions::Actions::Strategies::Associated
+module Automations::Actions::Strategies::MeAssociated
+ include ::Automations::Actions::Strategies::Associated
def me_value
[current_user_value_key, current_user_name]
@@ -66,7 +66,7 @@ module CustomActions::Actions::Strategies::MeAssociated
end
def current_user_name
- I18n.t("custom_actions.actions.assigned_to.executing_user_value")
+ I18n.t("automations.actions.assigned_to.executing_user_value")
end
def has_me_value?
diff --git a/app/models/custom_actions/actions/strategies/string.rb b/app/models/automations/actions/strategies/string.rb
similarity index 92%
rename from app/models/custom_actions/actions/strategies/string.rb
rename to app/models/automations/actions/strategies/string.rb
index ca8707e5c29..1bf1ff84f92 100644
--- a/app/models/custom_actions/actions/strategies/string.rb
+++ b/app/models/automations/actions/strategies/string.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::String
- include CustomActions::Actions::Strategies::ValuesToString
+module Automations::Actions::Strategies::String
+ include Automations::Actions::Strategies::ValuesToString
def type
:string_property
diff --git a/app/models/custom_actions/actions/strategies/text.rb b/app/models/automations/actions/strategies/text.rb
similarity index 92%
rename from app/models/custom_actions/actions/strategies/text.rb
rename to app/models/automations/actions/strategies/text.rb
index 1ceea830858..d733868aad1 100644
--- a/app/models/custom_actions/actions/strategies/text.rb
+++ b/app/models/automations/actions/strategies/text.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::Text
- include CustomActions::Actions::Strategies::ValuesToString
+module Automations::Actions::Strategies::Text
+ include Automations::Actions::Strategies::ValuesToString
def type
:text_property
diff --git a/app/models/custom_actions/actions/strategies/user_custom_field.rb b/app/models/automations/actions/strategies/user_custom_field.rb
similarity index 93%
rename from app/models/custom_actions/actions/strategies/user_custom_field.rb
rename to app/models/automations/actions/strategies/user_custom_field.rb
index 022c723cf85..8609e9e117e 100644
--- a/app/models/custom_actions/actions/strategies/user_custom_field.rb
+++ b/app/models/automations/actions/strategies/user_custom_field.rb
@@ -28,9 +28,9 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::UserCustomField
- include ::CustomActions::Actions::Strategies::CustomField
- include ::CustomActions::Actions::Strategies::MeAssociated
+module Automations::Actions::Strategies::UserCustomField
+ include ::Automations::Actions::Strategies::CustomField
+ include ::Automations::Actions::Strategies::MeAssociated
def type
:user
diff --git a/app/models/custom_actions/actions/strategies/validate_in_range.rb b/app/models/automations/actions/strategies/validate_in_range.rb
similarity index 97%
rename from app/models/custom_actions/actions/strategies/validate_in_range.rb
rename to app/models/automations/actions/strategies/validate_in_range.rb
index 51b83d11120..b90e13800b6 100644
--- a/app/models/custom_actions/actions/strategies/validate_in_range.rb
+++ b/app/models/automations/actions/strategies/validate_in_range.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::ValidateInRange
+module Automations::Actions::Strategies::ValidateInRange
def minimum
nil
end
diff --git a/app/models/custom_actions/actions/strategies/values_to_string.rb b/app/models/automations/actions/strategies/values_to_string.rb
similarity index 96%
rename from app/models/custom_actions/actions/strategies/values_to_string.rb
rename to app/models/automations/actions/strategies/values_to_string.rb
index 94e26c46905..d2e90002ad8 100644
--- a/app/models/custom_actions/actions/strategies/values_to_string.rb
+++ b/app/models/automations/actions/strategies/values_to_string.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Actions::Strategies::ValuesToString
+module Automations::Actions::Strategies::ValuesToString
def values=(values)
super(Array(values).map { |v| to_string_or_nil(v) }.uniq)
end
diff --git a/app/models/custom_actions/actions/type.rb b/app/models/automations/actions/type.rb
similarity index 92%
rename from app/models/custom_actions/actions/type.rb
rename to app/models/automations/actions/type.rb
index 530dd86d854..412f7047dbd 100644
--- a/app/models/custom_actions/actions/type.rb
+++ b/app/models/automations/actions/type.rb
@@ -28,8 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Actions::Type < CustomActions::Actions::Base
- include CustomActions::Actions::Strategies::Associated
+class Automations::Actions::Type < Automations::Actions::Base
+ include Automations::Actions::Strategies::Associated
PRIORITY = 20
diff --git a/app/models/custom_actions/conditions/base.rb b/app/models/automations/conditions/base.rb
similarity index 77%
rename from app/models/custom_actions/conditions/base.rb
rename to app/models/automations/conditions/base.rb
index 9852d382fbc..594094626fd 100644
--- a/app/models/custom_actions/conditions/base.rb
+++ b/app/models/automations/conditions/base.rb
@@ -28,11 +28,11 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Conditions::Base
+class Automations::Conditions::Base
attr_reader :values
- prepend CustomActions::ValuesToInteger
- include CustomActions::ValidateAllowedValue
+ prepend Automations::ValuesToInteger
+ include Automations::ValidateAllowedValue
def initialize(values = nil)
self.values = values
@@ -74,38 +74,38 @@ class CustomActions::Conditions::Base
validate_allowed_value(errors, :conditions)
end
- def self.getter(custom_action)
- ids = custom_action.send(association_ids)
+ def self.getter(automation)
+ ids = automation.send(association_ids)
new(ids) if ids.any?
end
- def self.setter(custom_action, condition)
+ def self.setter(automation, condition)
if condition
- custom_action.send(:"#{association_ids}=", condition.values)
+ automation.send(:"#{association_ids}=", condition.values)
else
- custom_action.send(:"#{association_key}").clear
+ automation.send(:"#{association_key}").clear
end
end
- def self.custom_action_scope(work_packages, user)
- custom_action_scope_has_current(work_packages, user)
- .or(custom_action_scope_has_no)
+ def self.automation_scope(work_packages, user)
+ automation_scope_has_current(work_packages, user)
+ .or(automation_scope_has_no)
end
- def self.custom_action_scope_has_current(work_packages, _user)
- CustomAction
+ def self.automation_scope_has_current(work_packages, _user)
+ Automation
.includes(association_key)
.where(habtm_table => { key_id => Array(work_packages).map { |w| w.send(key_id) }.uniq })
end
- private_class_method :custom_action_scope_has_current
+ private_class_method :automation_scope_has_current
- def self.custom_action_scope_has_no
- CustomAction
+ def self.automation_scope_has_no
+ Automation
.includes(association_key)
.where(habtm_table => { key_id => nil })
end
- private_class_method :custom_action_scope_has_no
+ private_class_method :automation_scope_has_no
def self.pluralized_key
key.to_s.pluralize.to_sym
@@ -113,7 +113,7 @@ class CustomActions::Conditions::Base
private_class_method :pluralized_key
def self.habtm_table
- :"custom_actions_#{pluralized_key}"
+ :"automations_#{pluralized_key}"
end
private_class_method :habtm_table
diff --git a/app/models/custom_actions/conditions/inexistent.rb b/app/models/automations/conditions/inexistent.rb
similarity index 94%
rename from app/models/custom_actions/conditions/inexistent.rb
rename to app/models/automations/conditions/inexistent.rb
index 5cbf25aac5f..04702b51e0d 100644
--- a/app/models/custom_actions/conditions/inexistent.rb
+++ b/app/models/automations/conditions/inexistent.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Conditions::Inexistent < CustomActions::Conditions::Base
+class Automations::Conditions::Inexistent < Automations::Conditions::Base
def self.key
:inexistent
end
diff --git a/app/models/custom_actions/conditions/project.rb b/app/models/automations/conditions/project.rb
similarity index 95%
rename from app/models/custom_actions/conditions/project.rb
rename to app/models/automations/conditions/project.rb
index 807a7bdfc79..296532dfc3b 100644
--- a/app/models/custom_actions/conditions/project.rb
+++ b/app/models/automations/conditions/project.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Conditions::Project < CustomActions::Conditions::Base
+class Automations::Conditions::Project < Automations::Conditions::Base
def self.key
:project
end
diff --git a/app/models/custom_actions/conditions/role.rb b/app/models/automations/conditions/role.rb
similarity index 89%
rename from app/models/custom_actions/conditions/role.rb
rename to app/models/automations/conditions/role.rb
index 77af34115ff..49f85b115d7 100644
--- a/app/models/custom_actions/conditions/role.rb
+++ b/app/models/automations/conditions/role.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Conditions::Role < CustomActions::Conditions::Base
+class Automations::Conditions::Role < Automations::Conditions::Base
def fulfilled_by?(work_package, user)
values.empty? ||
(self.class.roles_in_project(work_package, user).map(&:id) & values).any?
@@ -49,8 +49,8 @@ class CustomActions::Conditions::Role < CustomActions::Conditions::Base
private
- def custom_action_scope_has_current(work_packages, user)
- CustomAction
+ def automation_scope_has_current(work_packages, user)
+ Automation
.includes(association_key)
.where(habtm_table => { key_id => roles_in_project(work_packages, user) })
end
@@ -67,11 +67,11 @@ class CustomActions::Conditions::Role < CustomActions::Conditions::Base
end
def with_request_store(projects)
- RequestStore.store[:custom_actions_role] ||= Hash.new do |hash, hash_projects|
+ RequestStore.store[:automations_role] ||= Hash.new do |hash, hash_projects|
hash[hash_projects] = yield hash_projects
end
- RequestStore.store[:custom_actions_role][projects]
+ RequestStore.store[:automations_role][projects]
end
end
diff --git a/app/models/custom_actions/conditions/status.rb b/app/models/automations/conditions/status.rb
similarity index 94%
rename from app/models/custom_actions/conditions/status.rb
rename to app/models/automations/conditions/status.rb
index c6b246e0d65..c5069e596d8 100644
--- a/app/models/custom_actions/conditions/status.rb
+++ b/app/models/automations/conditions/status.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Conditions::Status < CustomActions::Conditions::Base
+class Automations::Conditions::Status < Automations::Conditions::Base
def self.key
:status
end
diff --git a/app/models/custom_actions/conditions/type.rb b/app/models/automations/conditions/type.rb
similarity index 95%
rename from app/models/custom_actions/conditions/type.rb
rename to app/models/automations/conditions/type.rb
index 37c3410516d..3510cd75ba8 100644
--- a/app/models/custom_actions/conditions/type.rb
+++ b/app/models/automations/conditions/type.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-class CustomActions::Conditions::Type < CustomActions::Conditions::Base
+class Automations::Conditions::Type < Automations::Conditions::Base
def self.key
:type
end
diff --git a/app/models/custom_actions/register.rb b/app/models/automations/register.rb
similarity index 64%
rename from app/models/custom_actions/register.rb
rename to app/models/automations/register.rb
index e49123fd52c..0645fa7dc24 100644
--- a/app/models/custom_actions/register.rb
+++ b/app/models/automations/register.rb
@@ -28,32 +28,32 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::Register
+module Automations::Register
class << self
def actions
[
- CustomActions::Actions::AssignedTo,
- CustomActions::Actions::Responsible,
- CustomActions::Actions::Status,
- CustomActions::Actions::Priority,
- CustomActions::Actions::CustomField,
- CustomActions::Actions::Type,
- CustomActions::Actions::Project,
- CustomActions::Actions::Notify,
- CustomActions::Actions::DoneRatio,
- CustomActions::Actions::EstimatedHours,
- CustomActions::Actions::StartDate,
- CustomActions::Actions::DueDate,
- CustomActions::Actions::Date
+ Automations::Actions::AssignedTo,
+ Automations::Actions::Responsible,
+ Automations::Actions::Status,
+ Automations::Actions::Priority,
+ Automations::Actions::CustomField,
+ Automations::Actions::Type,
+ Automations::Actions::Project,
+ Automations::Actions::Notify,
+ Automations::Actions::DoneRatio,
+ Automations::Actions::EstimatedHours,
+ Automations::Actions::StartDate,
+ Automations::Actions::DueDate,
+ Automations::Actions::Date
]
end
def conditions
[
- CustomActions::Conditions::Status,
- CustomActions::Conditions::Role,
- CustomActions::Conditions::Type,
- CustomActions::Conditions::Project
+ Automations::Conditions::Status,
+ Automations::Conditions::Role,
+ Automations::Conditions::Type,
+ Automations::Conditions::Project
]
end
end
diff --git a/app/models/automations/triggers/base.rb b/app/models/automations/triggers/base.rb
new file mode 100644
index 00000000000..e441e5734b2
--- /dev/null
+++ b/app/models/automations/triggers/base.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Automations
+ module Triggers
+ class Base < ApplicationRecord
+ self.table_name = "automation_triggers"
+
+ belongs_to :automation, inverse_of: :triggers
+
+ acts_as_list scope: :automation
+ end
+ end
+end
diff --git a/app/models/automations/triggers/manual.rb b/app/models/automations/triggers/manual.rb
new file mode 100644
index 00000000000..5cbd85f787f
--- /dev/null
+++ b/app/models/automations/triggers/manual.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Automations
+ module Triggers
+ class Manual < Base
+ store_attribute :options, :button_label, :string
+
+ validates :button_label, presence: true, length: { maximum: 255 }
+ end
+ end
+end
diff --git a/app/models/custom_actions/validate_allowed_value.rb b/app/models/automations/validate_allowed_value.rb
similarity index 96%
rename from app/models/custom_actions/validate_allowed_value.rb
rename to app/models/automations/validate_allowed_value.rb
index b85f7678b06..8b85beb754e 100644
--- a/app/models/custom_actions/validate_allowed_value.rb
+++ b/app/models/automations/validate_allowed_value.rb
@@ -21,7 +21,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::ValidateAllowedValue
+module Automations::ValidateAllowedValue
private
def validate_allowed_value(errors, attribute)
diff --git a/app/models/custom_actions/values_to_integer.rb b/app/models/automations/values_to_integer.rb
similarity index 97%
rename from app/models/custom_actions/values_to_integer.rb
rename to app/models/automations/values_to_integer.rb
index c36aa8fbea6..6894a3f90c7 100644
--- a/app/models/custom_actions/values_to_integer.rb
+++ b/app/models/automations/values_to_integer.rb
@@ -28,7 +28,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-module CustomActions::ValuesToInteger
+module Automations::ValuesToInteger
def values=(values)
super(Array(values).map { |v| to_integer_or_nil(v) }.uniq)
end
diff --git a/app/models/permitted_params.rb b/app/models/permitted_params.rb
index 6934800f519..d5959c9f066 100644
--- a/app/models/permitted_params.rb
+++ b/app/models/permitted_params.rb
@@ -92,12 +92,12 @@ class PermittedParams
params.require(:custom_field).permit(*self.class.permitted_attributes[:custom_field])
end
- def custom_action
+ def automation
whitelisted = params
- .require(:custom_action)
- .permit(*self.class.permitted_attributes[:custom_action])
+ .require(:automation)
+ .permit(*self.class.permitted_attributes[:automation])
- whitelisted.merge(params[:custom_action].slice(:actions, :conditions).permit!)
+ whitelisted.merge(params[:automation].slice(:actions, :conditions).permit!)
end
def custom_field_type
@@ -506,11 +506,12 @@ class PermittedParams
hexcode
move_to
),
- custom_action: %i(
- name
- description
- move_to
- ),
+ automation: [
+ :name,
+ :description,
+ :move_to,
+ { triggers_attributes: [:id, :type, :position, { options: {} }, :_destroy] }
+ ],
custom_field: [
:editable,
:field_format,
diff --git a/app/models/work_package.rb b/app/models/work_package.rb
index d4a110bbdd4..2afc54bf2c1 100644
--- a/app/models/work_package.rb
+++ b/app/models/work_package.rb
@@ -36,7 +36,7 @@ class WorkPackage < ApplicationRecord
include WorkPackage::AskBeforeDestruction
include WorkPackage::TimeEntriesCleaner
include WorkPackage::Ancestors
- include WorkPackage::CustomActioned
+ include WorkPackage::Automatable
include WorkPackage::Hooks
include WorkPackages::DerivedDates
include WorkPackages::SpentTime
diff --git a/app/models/work_package/automatable.rb b/app/models/work_package/automatable.rb
new file mode 100644
index 00000000000..132c80953ef
--- /dev/null
+++ b/app/models/work_package/automatable.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module WorkPackage::Automatable
+ extend ActiveSupport::Concern
+
+ included do
+ def automations(user)
+ @automations = Automation
+ .available_conditions
+ .inject(Automation.all) do |scope, condition|
+ scope.merge(condition.automation_scope(self, user))
+ end
+ end
+
+ # API compatibility for /api/v3/custom_actions
+ def custom_actions(user)
+ automations(user)
+ end
+ end
+end
diff --git a/app/models/work_package/custom_actioned.rb b/app/models/work_package/custom_actioned.rb
deleted file mode 100644
index 0d88d078c31..00000000000
--- a/app/models/work_package/custom_actioned.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-module WorkPackage::CustomActioned
- extend ActiveSupport::Concern
-
- included do
- def custom_actions(user)
- @custom_actions = CustomAction
- .available_conditions
- .inject(CustomAction.all) do |scope, condition|
- scope.merge(condition.custom_action_scope(self, user))
- end
- end
- end
-end
diff --git a/app/models/work_package_custom_field.rb b/app/models/work_package_custom_field.rb
index a021fc7084e..ad79998aaae 100644
--- a/app/models/work_package_custom_field.rb
+++ b/app/models/work_package_custom_field.rb
@@ -43,7 +43,7 @@ class WorkPackageCustomField < CustomField
scopes :visible,
:on_visible_type_and_project
- scope :usable_as_custom_action, -> {
+ scope :usable_as_automation, -> {
where.not(field_format: %w[hierarchy weighted_item_list])
.order(:name)
}
diff --git a/app/services/custom_actions/base_service.rb b/app/services/automations/base_service.rb
similarity index 52%
rename from app/services/custom_actions/base_service.rb
rename to app/services/automations/base_service.rb
index dfc18ab4f7e..cb5e6fda85d 100644
--- a/app/services/custom_actions/base_service.rb
+++ b/app/services/automations/base_service.rb
@@ -1,34 +1,6 @@
# frozen_string_literal: true
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-class CustomActions::BaseService
+class Automations::BaseService
include Shared::BlockService
attr_accessor :user
@@ -38,7 +10,7 @@ class CustomActions::BaseService
&)
set_attributes(action, attributes)
- contract = CustomActions::CuContract.new(action)
+ contract = Automations::CuContract.new(action)
result = ServiceResult.new(success: contract.validate && action.save,
result: action,
errors: contract.errors)
@@ -51,10 +23,12 @@ class CustomActions::BaseService
def set_attributes(action, attributes)
actions_attributes = attributes.delete(:actions)
conditions_attributes = attributes.delete(:conditions)
- action.attributes = attributes
+ triggers_attributes = attributes.delete(:triggers_attributes)
+ action.attributes = attributes
set_actions(action, actions_attributes.symbolize_keys) if actions_attributes
set_conditions(action, conditions_attributes.symbolize_keys) if conditions_attributes
+ set_triggers(action, triggers_attributes) if triggers_attributes
end
def set_actions(action, actions_attributes)
@@ -66,21 +40,15 @@ class CustomActions::BaseService
end
def remove_actions(action, keys)
- keys.each do |key|
- remove_action(action, key)
- end
+ keys.each { |key| remove_action(action, key) }
end
def update_actions(action, key_values)
- key_values.each do |key, values|
- update_action(action, key, values)
- end
+ key_values.each { |key, values| update_action(action, key, values) }
end
def add_actions(action, key_values)
- key_values.each do |key, values|
- add_action(action, key, values)
- end
+ key_values.each { |key, values| add_action(action, key, values) }
end
def update_action(action, key, values)
@@ -102,10 +70,14 @@ class CustomActions::BaseService
end
def available_action_for(action, key)
- action.available_actions.detect { |a| a.key == key } || CustomActions::Actions::Inexistent
+ action.available_actions.detect { |a| a.key == key } || Automations::Actions::Inexistent
end
def available_condition_for(action, key)
- action.available_conditions.detect { |a| a.key == key } || CustomActions::Conditions::Inexistent
+ action.available_conditions.detect { |a| a.key == key } || Automations::Conditions::Inexistent
+ end
+
+ def set_triggers(action, attributes)
+ action.assign_attributes(triggers_attributes: attributes)
end
end
diff --git a/app/services/automations/create_service.rb b/app/services/automations/create_service.rb
new file mode 100644
index 00000000000..96897a7478d
--- /dev/null
+++ b/app/services/automations/create_service.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class Automations::CreateService < Automations::BaseService
+ def initialize(user:)
+ self.user = user
+ end
+
+ def call(attributes:, action: Automation.new, &block)
+ super
+ end
+end
diff --git a/app/services/automations/update_service.rb b/app/services/automations/update_service.rb
new file mode 100644
index 00000000000..f718a3631f2
--- /dev/null
+++ b/app/services/automations/update_service.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class Automations::UpdateService < Automations::BaseService
+ attr_accessor :user,
+ :action
+
+ def initialize(action:, user:)
+ self.action = action
+ self.user = user
+ end
+
+ def call(attributes:, &)
+ super(attributes:, action:, &)
+ end
+end
diff --git a/app/services/automations/update_work_package_service.rb b/app/services/automations/update_work_package_service.rb
new file mode 100644
index 00000000000..44af8e6a69d
--- /dev/null
+++ b/app/services/automations/update_work_package_service.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+class Automations::UpdateWorkPackageService
+ include Shared::BlockService
+ include Contracted
+
+ attr_accessor :user,
+ :action
+
+ def initialize(action:, user:)
+ self.action = action
+ self.user = user
+ self.contract_class = ::WorkPackages::UpdateContract
+ end
+
+ def call(work_package:, &)
+ apply_actions(work_package, action.actions)
+
+ result = ::WorkPackages::UpdateService
+ .new(user:,
+ model: work_package)
+ .call
+
+ block_with_result(result, &)
+ end
+
+ private
+
+ def apply_actions(work_package, actions)
+ changes_before = work_package.changes.dup
+ apply_actions_sorted(work_package, actions)
+
+ success, errors = validate(work_package, user)
+ retry_apply_actions(work_package, actions, errors, changes_before) unless success
+ end
+
+ def retry_apply_actions(work_package, actions, errors, changes_before)
+ new_actions = without_invalid_actions(actions, errors)
+
+ if new_actions.any? && actions.length != new_actions.length
+ work_package.restore_attributes(work_package.changes.keys - changes_before.keys)
+ apply_actions(work_package, new_actions)
+ end
+ end
+
+ def without_invalid_actions(actions, errors)
+ invalid_keys = errors.attribute_names.map { |k| append_id(k) }
+ actions.reject { |a| invalid_keys.include?(append_id(a.key)) }
+ end
+
+ def apply_actions_sorted(work_package, actions)
+ actions.sort_by(&:priority).each { |a| a.apply(work_package) }
+ end
+
+ def append_id(sym)
+ "#{sym.to_s.chomp('_id')}_id"
+ end
+end
diff --git a/app/services/custom_actions/create_service.rb b/app/services/custom_actions/create_service.rb
deleted file mode 100644
index 1feb0a00397..00000000000
--- a/app/services/custom_actions/create_service.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-class CustomActions::CreateService < CustomActions::BaseService
- def initialize(user:)
- self.user = user
- end
-
- def call(attributes:,
- action: CustomAction.new,
- &block)
- super
- end
-end
diff --git a/app/services/custom_actions/update_service.rb b/app/services/custom_actions/update_service.rb
deleted file mode 100644
index 12d1d04add6..00000000000
--- a/app/services/custom_actions/update_service.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-class CustomActions::UpdateService < CustomActions::BaseService
- attr_accessor :user,
- :action
-
- def initialize(action:, user:)
- self.action = action
- self.user = user
- end
-
- def call(attributes:, &)
- super(attributes:, action:, &)
- end
-end
diff --git a/app/services/custom_actions/update_work_package_service.rb b/app/services/custom_actions/update_work_package_service.rb
deleted file mode 100644
index d4058deaf33..00000000000
--- a/app/services/custom_actions/update_work_package_service.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# frozen_string_literal: true
-
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# 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.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-class CustomActions::UpdateWorkPackageService
- include Shared::BlockService
- include Contracted
-
- attr_accessor :user,
- :action
-
- def initialize(action:, user:)
- self.action = action
- self.user = user
- self.contract_class = ::WorkPackages::UpdateContract
- end
-
- def call(work_package:, &)
- apply_actions(work_package, action.actions)
-
- result = ::WorkPackages::UpdateService
- .new(user:,
- model: work_package)
- .call
-
- block_with_result(result, &)
- end
-
- private
-
- def apply_actions(work_package, actions)
- changes_before = work_package.changes.dup
-
- apply_actions_sorted(work_package, actions)
-
- success, errors = validate(work_package, user)
- unless success
- retry_apply_actions(work_package, actions, errors, changes_before)
- end
- end
-
- def retry_apply_actions(work_package, actions, errors, changes_before)
- new_actions = without_invalid_actions(actions, errors)
-
- if new_actions.any? && actions.length != new_actions.length
- work_package.restore_attributes(work_package.changes.keys - changes_before.keys)
- apply_actions(work_package, new_actions)
- end
- end
-
- def without_invalid_actions(actions, errors)
- invalid_keys = errors.attribute_names.map { |k| append_id(k) }
-
- actions.reject { |a| invalid_keys.include?(append_id(a.key)) }
- end
-
- def apply_actions_sorted(work_package, actions)
- actions
- .sort_by(&:priority)
- .each { |a| a.apply(work_package) }
- end
-
- def append_id(sym)
- "#{sym.to_s.chomp('_id')}_id"
- end
-end
diff --git a/app/views/automations/_form.html.erb b/app/views/automations/_form.html.erb
new file mode 100644
index 00000000000..0671cc69182
--- /dev/null
+++ b/app/views/automations/_form.html.erb
@@ -0,0 +1,120 @@
+<% active_section_keys = @automation.actions.map(&:key) %>
+<% trigger = @automation.triggers.detect { |t| t.is_a?(Automations::Triggers::Manual) } || @automation.triggers.build(type: "Automations::Triggers::Manual") %>
+
+