From dea73a7938b3761ec3aaf7b8ae2cbfbcd176e322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Mon, 11 May 2026 21:27:00 +0200 Subject: [PATCH 1/3] Move all custom actions into an automations namespace --- .../index_component.rb} | 18 ++- .../row_component.rb | 31 +++- .../cu_contract.rb | 21 +-- .../execute_contract.rb | 16 +- ...ontroller.rb => automations_controller.rb} | 43 +++--- .../{custom_action.rb => automation.rb} | 61 ++++++-- .../actions/assigned_to.rb | 4 +- .../actions/base.rb | 2 +- .../actions/custom_field.rb | 28 ++-- .../actions/date.rb | 4 +- .../actions/done_ratio.rb | 4 +- .../actions/due_date.rb | 4 +- .../actions/estimated_hours.rb | 4 +- .../actions/inexistent.rb | 2 +- .../actions/notify.rb | 4 +- .../actions/priority.rb | 4 +- .../actions/project.rb | 4 +- .../actions/responsible.rb | 4 +- .../actions/serializer.rb | 6 +- .../actions/start_date.rb | 4 +- .../actions/status.rb | 4 +- .../actions/strategies/associated.rb | 6 +- .../strategies/associated_custom_field.rb | 6 +- .../actions/strategies/boolean.rb | 32 +++- .../actions/strategies/custom_field.rb | 2 +- .../actions/strategies/date.rb | 4 +- .../actions/strategies/date_property.rb | 4 +- .../actions/strategies/float.rb | 4 +- .../actions/strategies/integer.rb | 6 +- .../actions/strategies/link.rb | 4 +- .../actions/strategies/me_associated.rb | 6 +- .../actions/strategies/string.rb | 4 +- .../actions/strategies/text.rb | 4 +- .../actions/strategies/user_custom_field.rb | 6 +- .../actions/strategies/validate_in_range.rb | 2 +- .../actions/strategies/values_to_string.rb | 2 +- .../actions/type.rb | 4 +- .../conditions/base.rb | 40 +++-- .../conditions/inexistent.rb | 2 +- .../conditions/project.rb | 2 +- .../conditions/role.rb | 12 +- .../conditions/status.rb | 2 +- .../conditions/type.rb | 2 +- .../register.rb | 36 ++--- app/models/automations/triggers/base.rb | 41 +++++ .../models/automations/triggers/manual.rb | 11 +- .../validate_allowed_value.rb | 30 +++- .../values_to_integer.rb | 2 +- app/models/permitted_params.rb | 19 +-- app/models/work_package.rb | 2 +- .../{custom_actioned.rb => automatable.rb} | 17 +- app/models/work_package_custom_field.rb | 2 +- .../base_service.rb | 37 +++-- .../create_service.rb | 7 +- .../update_service.rb | 3 +- .../update_work_package_service.rb | 12 +- .../_form.html.erb | 145 +++++++++--------- .../_trigger_fields_manual.html.erb | 42 +++++ .../edit.html.erb | 12 +- app/views/automations/index.html.erb | 60 ++++++++ .../new.html.erb | 12 +- app/views/custom_actions/index.html.erb | 31 ---- config/initializers/menus.rb | 6 +- config/locales/en.yml | 24 +++ config/routes.rb | 2 +- ...8_convert_custom_actions_to_automations.rb | 115 ++++++++++++++ .../custom_action_representer.rb | 9 +- .../v3/custom_actions/custom_actions_api.rb | 8 +- .../{custom_action.rb => automation.rb} | 37 +++-- .../work_package_eager_loading_wrapper.rb | 2 +- .../cu_contract_spec.rb | 22 +-- ...spec.rb => automations_controller_spec.rb} | 82 +++++----- spec/factories/automation_factory.rb | 51 ++++++ .../automations_link_value_spec.rb} | 11 +- .../automations_me_value_spec.rb} | 13 +- .../automations_spec.rb} | 126 ++++++++------- spec/helpers/no_results_helper_spec.rb | 7 +- ...stom_action_representer_generation_spec.rb | 16 +- ...spec.rb => automation_integration_spec.rb} | 30 ++-- .../work_package_representer_spec.rb | 12 +- ...stom_action_spec.rb => automation_spec.rb} | 56 +++---- .../actions/assigned_to_spec.rb | 13 +- .../actions/custom_field_spec.rb | 10 +- .../actions/date_spec.rb | 14 +- .../actions/done_ratio_spec.rb | 4 +- .../actions/due_date_spec.rb | 4 +- .../actions/estimated_hours_spec.rb | 4 +- .../actions/notify_spec.rb | 21 +-- .../actions/priority_spec.rb | 6 +- .../actions/project_spec.rb | 6 +- .../actions/responsible_spec.rb | 13 +- .../actions/start_date_spec.rb | 4 +- .../actions/status_spec.rb | 6 +- .../strategies/user_custom_field_spec.rb | 28 ++-- .../actions/type_spec.rb | 2 +- .../conditions/project_spec.rb | 22 ++- .../conditions/role_spec.rb | 28 ++-- .../conditions/status_spec.rb | 22 ++- .../conditions/type_spec.rb | 18 +-- .../shared_expectations.rb | 42 ++--- spec/models/permitted_params_spec.rb | 4 +- ...ec.rb => work_package_automations_spec.rb} | 30 ++-- .../custom_actions/custom_actions_api_spec.rb | 24 ++- ...om_actions_spec.rb => automations_spec.rb} | 38 ++--- .../update_service_spec.rb | 28 ++-- .../update_work_package_service_spec.rb | 38 +++-- .../{custom_actions => automations}/edit.rb | 9 +- .../{custom_actions => automations}/form.rb | 20 ++- .../{custom_actions => automations}/index.rb | 14 +- .../{custom_actions => automations}/new.rb | 4 +- .../work_packages/abstract_work_package.rb | 10 +- 111 files changed, 1246 insertions(+), 818 deletions(-) rename app/components/{custom_actions/table_component.rb => automations/index_component.rb} (73%) rename app/components/{custom_actions => automations}/row_component.rb (71%) rename app/contracts/{custom_actions => automations}/cu_contract.rb (79%) rename app/contracts/{custom_actions => automations}/execute_contract.rb (79%) rename app/controllers/{custom_actions_controller.rb => automations_controller.rb} (61%) rename app/models/{custom_action.rb => automation.rb} (61%) rename app/models/{custom_actions => automations}/actions/assigned_to.rb (92%) rename app/models/{custom_actions => automations}/actions/base.rb (98%) rename app/models/{custom_actions => automations}/actions/custom_field.rb (79%) rename app/models/{custom_actions => automations}/actions/date.rb (92%) rename app/models/{custom_actions => automations}/actions/done_ratio.rb (92%) rename app/models/{custom_actions => automations}/actions/due_date.rb (90%) rename app/models/{custom_actions => automations}/actions/estimated_hours.rb (91%) rename app/models/{custom_actions => automations}/actions/inexistent.rb (95%) rename app/models/{custom_actions => automations}/actions/notify.rb (93%) rename app/models/{custom_actions => automations}/actions/priority.rb (91%) rename app/models/{custom_actions => automations}/actions/project.rb (92%) rename app/models/{custom_actions => automations}/actions/responsible.rb (92%) rename app/models/{custom_actions => automations}/actions/serializer.rb (93%) rename app/models/{custom_actions => automations}/actions/start_date.rb (90%) rename app/models/{custom_actions => automations}/actions/status.rb (91%) rename app/models/{custom_actions => automations}/actions/strategies/associated.rb (92%) rename app/models/{custom_actions => automations}/actions/strategies/associated_custom_field.rb (88%) rename app/models/{custom_actions => automations}/actions/strategies/boolean.rb (50%) rename app/models/{custom_actions => automations}/actions/strategies/custom_field.rb (96%) rename app/models/{custom_actions => automations}/actions/strategies/date.rb (96%) rename app/models/{custom_actions => automations}/actions/strategies/date_property.rb (92%) rename app/models/{custom_actions => automations}/actions/strategies/float.rb (92%) rename app/models/{custom_actions => automations}/actions/strategies/integer.rb (89%) rename app/models/{custom_actions => automations}/actions/strategies/link.rb (93%) rename app/models/{custom_actions => automations}/actions/strategies/me_associated.rb (92%) rename app/models/{custom_actions => automations}/actions/strategies/string.rb (92%) rename app/models/{custom_actions => automations}/actions/strategies/text.rb (92%) rename app/models/{custom_actions => automations}/actions/strategies/user_custom_field.rb (93%) rename app/models/{custom_actions => automations}/actions/strategies/validate_in_range.rb (97%) rename app/models/{custom_actions => automations}/actions/strategies/values_to_string.rb (96%) rename app/models/{custom_actions => automations}/actions/type.rb (92%) rename app/models/{custom_actions => automations}/conditions/base.rb (76%) rename app/models/{custom_actions => automations}/conditions/inexistent.rb (94%) rename app/models/{custom_actions => automations}/conditions/project.rb (95%) rename app/models/{custom_actions => automations}/conditions/role.rb (86%) rename app/models/{custom_actions => automations}/conditions/status.rb (94%) rename app/models/{custom_actions => automations}/conditions/type.rb (95%) rename app/models/{custom_actions => automations}/register.rb (64%) create mode 100644 app/models/automations/triggers/base.rb rename spec/factories/custom_action_factory.rb => app/models/automations/triggers/manual.rb (86%) rename app/models/{custom_actions => automations}/validate_allowed_value.rb (50%) rename app/models/{custom_actions => automations}/values_to_integer.rb (97%) rename app/models/work_package/{custom_actioned.rb => automatable.rb} (79%) rename app/services/{custom_actions => automations}/base_service.rb (75%) rename app/services/{custom_actions => automations}/create_service.rb (90%) rename app/services/{custom_actions => automations}/update_service.rb (95%) rename app/services/{custom_actions => automations}/update_work_package_service.rb (91%) rename app/views/{custom_actions => automations}/_form.html.erb (60%) create mode 100644 app/views/automations/_trigger_fields_manual.html.erb rename app/views/{custom_actions => automations}/edit.html.erb (83%) create mode 100644 app/views/automations/index.html.erb rename app/views/{custom_actions => automations}/new.html.erb (84%) delete mode 100644 app/views/custom_actions/index.html.erb create mode 100644 db/migrate/20260907113318_convert_custom_actions_to_automations.rb rename lib/api/v3/work_packages/eager_loading/{custom_action.rb => automation.rb} (61%) rename spec/contracts/{custom_actions => automations}/cu_contract_spec.rb (81%) rename spec/controllers/{custom_actions_controller_spec.rb => automations_controller_spec.rb} (85%) create mode 100644 spec/factories/automation_factory.rb rename spec/features/work_packages/{custom_actions/custom_actions_link_value_spec.rb => automations/automations_link_value_spec.rb} (88%) rename spec/features/work_packages/{custom_actions/custom_actions_me_value_spec.rb => automations/automations_me_value_spec.rb} (85%) rename spec/features/work_packages/{custom_actions/custom_actions_spec.rb => automations/automations_spec.rb} (83%) rename spec/lib/api/v3/work_packages/eager_loading/{custom_actions_integration_spec.rb => automation_integration_spec.rb} (69%) rename spec/models/{custom_action_spec.rb => automation_spec.rb} (76%) rename spec/models/{custom_actions => automations}/actions/assigned_to_spec.rb (87%) rename spec/models/{custom_actions => automations}/actions/custom_field_spec.rb (98%) rename spec/models/{custom_actions => automations}/actions/date_spec.rb (88%) rename spec/models/{custom_actions => automations}/actions/done_ratio_spec.rb (96%) rename spec/models/{custom_actions => automations}/actions/due_date_spec.rb (95%) rename spec/models/{custom_actions => automations}/actions/estimated_hours_spec.rb (95%) rename spec/models/{custom_actions => automations}/actions/notify_spec.rb (81%) rename spec/models/{custom_actions => automations}/actions/priority_spec.rb (92%) rename spec/models/{custom_actions => automations}/actions/project_spec.rb (92%) rename spec/models/{custom_actions => automations}/actions/responsible_spec.rb (87%) rename spec/models/{custom_actions => automations}/actions/start_date_spec.rb (95%) rename spec/models/{custom_actions => automations}/actions/status_spec.rb (92%) rename spec/models/{custom_actions => automations}/actions/strategies/user_custom_field_spec.rb (88%) rename spec/models/{custom_actions => automations}/actions/type_spec.rb (97%) rename spec/models/{custom_actions => automations}/conditions/project_spec.rb (79%) rename spec/models/{custom_actions => automations}/conditions/role_spec.rb (77%) rename spec/models/{custom_actions => automations}/conditions/status_spec.rb (80%) rename spec/models/{custom_actions => automations}/conditions/type_spec.rb (84%) rename spec/models/{custom_actions => automations}/shared_expectations.rb (92%) rename spec/models/work_package/{work_package_custom_actions_spec.rb => work_package_automations_spec.rb} (80%) rename spec/routing/{custom_actions_spec.rb => automations_spec.rb} (61%) rename spec/services/{custom_actions => automations}/update_service_spec.rb (86%) rename spec/services/{custom_actions => automations}/update_work_package_service_spec.rb (84%) rename spec/support/pages/admin/{custom_actions => automations}/edit.rb (90%) rename spec/support/pages/admin/{custom_actions => automations}/form.rb (87%) rename spec/support/pages/admin/{custom_actions => automations}/index.rb (89%) rename spec/support/pages/admin/{custom_actions => automations}/new.rb (96%) diff --git a/app/components/custom_actions/table_component.rb b/app/components/automations/index_component.rb similarity index 73% rename from app/components/custom_actions/table_component.rb rename to app/components/automations/index_component.rb index 324f8f7dc576..fdaa9b214d01 100644 --- a/app/components/custom_actions/table_component.rb +++ b/app/components/automations/index_component.rb @@ -28,14 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -module CustomActions - class TableComponent < ::TableComponent - columns :name, :description, :sort +module Automations + class IndexComponent < ::TableComponent + columns :name, :triggers, :conditions, :actions, :sort def headers [ - ["name", { caption: CustomAction.human_attribute_name(:name) }], - ["description", { caption: CustomAction.human_attribute_name(:description) }], + ["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 @@ -45,10 +47,10 @@ def sortable? end def inline_create_link - link_to new_custom_action_path, - aria: { label: t("custom_actions.new") }, + link_to new_automation_path, + aria: { label: t("automations.new") }, class: "wp-inline-create--add-link", - title: t("custom_actions.new") do + title: t("automations.new") do helpers.op_icon("icon icon-add") end end diff --git a/app/components/custom_actions/row_component.rb b/app/components/automations/row_component.rb similarity index 71% rename from app/components/custom_actions/row_component.rb rename to app/components/automations/row_component.rb index 2f3f065f605a..5bd09372d89a 100644 --- a/app/components/custom_actions/row_component.rb +++ b/app/components/automations/row_component.rb @@ -28,20 +28,37 @@ # See COPYRIGHT and LICENSE files for more details. #++ -module CustomActions +module Automations class RowComponent < ::RowComponent - def action + def automation row end def name - link_to action.name, edit_custom_action_path(action) + link_to automation.name, edit_automation_path(automation) end - delegate :description, to: :action + 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("custom_action", { action: "update", id: action }, method: :put) + helpers.reorder_links("automation", { action: "update", id: automation }, method: :put) end def button_links @@ -54,7 +71,7 @@ def button_links def edit_link link_to( helpers.op_icon("icon icon-edit"), - helpers.edit_custom_action_path(action), + helpers.edit_automation_path(automation), title: t(:button_edit) ) end @@ -62,7 +79,7 @@ def edit_link def delete_link link_to( helpers.op_icon("icon icon-delete"), - helpers.custom_action_path(action), + helpers.automation_path(automation), data: { turbo_method: :delete, turbo_confirm: I18n.t(:text_are_you_sure) diff --git a/app/contracts/custom_actions/cu_contract.rb b/app/contracts/automations/cu_contract.rb similarity index 79% rename from app/contracts/custom_actions/cu_contract.rb rename to app/contracts/automations/cu_contract.rb index d9a479bbf9fb..69801603a09d 100644 --- a/app/contracts/custom_actions/cu_contract.rb +++ b/app/contracts/automations/cu_contract.rb @@ -30,33 +30,22 @@ require "model_contract" -# Contract for create (c) and update (u) -module CustomActions +module Automations class CuContract < ::ModelContract def self.model - CustomAction - end - - def initialize(model, user = nil) - super + Automation 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 + errors.add(:actions, :empty) if model.actions.empty? + model.actions.each { |action| action.validate(errors) } end attribute :conditions do - model.conditions.each do |condition| - condition.validate(errors) - end + model.conditions.each { |condition| condition.validate(errors) } end end end diff --git a/app/contracts/custom_actions/execute_contract.rb b/app/contracts/automations/execute_contract.rb similarity index 79% rename from app/contracts/custom_actions/execute_contract.rb rename to app/contracts/automations/execute_contract.rb index 8f327dd78062..4252e0fd283c 100644 --- a/app/contracts/custom_actions/execute_contract.rb +++ b/app/contracts/automations/execute_contract.rb @@ -28,35 +28,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -module CustomActions +module Automations 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 + validate :automation_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 + errors.add(:work_package_id, :does_not_exist) unless WorkPackage.visible(user).exists?(id: model.work_package_id) end - def custom_action_conditions_fulfilled + def automation_conditions_fulfilled return unless model.work_package_id - return unless options[:custom_action] + return unless options[:automation] 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 + errors.add(:base, :error_unauthorized) unless options[:automation].conditions_fulfilled?(work_package, user) end end end diff --git a/app/controllers/custom_actions_controller.rb b/app/controllers/automations_controller.rb similarity index 61% rename from app/controllers/custom_actions_controller.rb rename to app/controllers/automations_controller.rb index 62c766a58961..249754d5dbd0 100644 --- a/app/controllers/custom_actions_controller.rb +++ b/app/controllers/automations_controller.rb @@ -28,75 +28,72 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class CustomActionsController < ApplicationController +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_custom_action, only: %i(edit update destroy) - before_action :pad_params, only: %i(create update) + before_action :find_automation, only: %i[edit update destroy] + before_action :pad_params, only: %i[create update] layout "admin" def index - @custom_actions = CustomAction.order_by_position + @automations = Automation.order_by_position.includes(:triggers) end def new - @custom_action = CustomAction.new + @automation = Automation.new + @automation.triggers.build(type: "Automations::Triggers::Manual") end def edit; end def create - CustomActions::CreateService + Automations::CreateService .new(user: current_user) - .call(attributes: permitted_params.custom_action.to_h, + .call(attributes: permitted_params.automation.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, + Automations::UpdateService + .new(action: @automation, user: current_user) + .call(attributes: permitted_params.automation.to_h, &index_or_render(:edit)) end def destroy - @custom_action.destroy + @automation.destroy! - redirect_to custom_actions_path, status: :see_other + redirect_to automations_path, status: :see_other end private - def find_custom_action - @custom_action = CustomAction.find(params[:id]) + def find_automation + @automation = Automation.find(params.expect(:id)) end def index_or_render(render_action) ->(call) { call.on_success do - redirect_to custom_actions_path, status: :see_other + redirect_to automations_path, status: :see_other end call.on_failure do - @custom_action = call.result + @automation = 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] + return if !params[:automation] || params[:automation][:move_to] - params[:custom_action][:conditions] ||= {} - params[:custom_action][:actions] ||= {} + params[:automation][:conditions] ||= {} + params[:automation][:actions] ||= {} end end diff --git a/app/models/custom_action.rb b/app/models/automation.rb similarity index 61% rename from app/models/custom_action.rb rename to app/models/automation.rb index c37d6ddb831f..cae2ddf36ef0 100644 --- a/app/models/custom_action.rb +++ b/app/models/automation.rb @@ -28,13 +28,28 @@ # 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 + + # This code was moved from custom actions and it's decisions unchanged + # rubocop:disable Rails/HasAndBelongsToMany + 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 + # rubocop:enable Rails/HasAndBelongsToMany + + 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 +58,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,16 +91,14 @@ def all_actions end def available_actions - ::CustomActions::Register.actions.map(&:all).flatten + ::Automations::Register.actions.map(&:all).flatten end def all_conditions all_of(available_conditions, conditions) end - def available_conditions - self.class.available_conditions - end + delegate :available_conditions, to: :class def conditions @conditions ||= available_conditions.filter_map do |condition_class| @@ -104,11 +116,17 @@ def conditions_fulfilled?(work_package, user) 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 +142,13 @@ def persist_conditions 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 2d0655e161be..87923628d76b 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 98% rename from app/models/custom_actions/actions/base.rb rename to app/models/automations/actions/base.rb index 3b131d6f80dc..ea78ba237067 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 diff --git a/app/models/custom_actions/actions/custom_field.rb b/app/models/automations/actions/custom_field.rb similarity index 79% rename from app/models/custom_actions/actions/custom_field.rb rename to app/models/automations/actions/custom_field.rb index dd796273c4fc..1872cac30125 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 @@ def custom_field def all WorkPackageCustomField - .usable_as_custom_action + .usable_as_automation .map do |cf| create_subclass(cf) end @@ -57,7 +57,7 @@ def for(key) 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,30 +69,28 @@ def create_subclass(custom_field) 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 - def custom_field - self.class.custom_field - end + delegate :custom_field, to: :class def human_name custom_field.name 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 7e4f3bee3802..571788b33137 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 c885bb79e4bc..d51ecec36b95 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 e0836b1f032d..658e346291df 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 dcec6856db95..1c2b18e79b36 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 95% rename from app/models/custom_actions/actions/inexistent.rb rename to app/models/automations/actions/inexistent.rb index 0be4c169ba7d..d5f8a757e7c3 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 e88a50edf5d0..dda26006920f 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 7826a99c87e0..97011b57fc26 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 5c893303fd08..c1d6f78ba9c5 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 c0b8e59f09f2..c83d1531620b 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 81ca8efab3e1..1905419e896b 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 @@ def load(value) .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 9d5fc185d48c..5fd880de18b2 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 30a939d38130..e1942004e504 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 e608b67b6389..ffbeb2615ded 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 97ccda753dc9..ee731e0be06e 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 50% rename from app/models/custom_actions/actions/strategies/boolean.rb rename to app/models/automations/actions/strategies/boolean.rb index 96ed10bbbbda..dc098d69513f 100644 --- a/app/models/custom_actions/actions/strategies/boolean.rb +++ b/app/models/automations/actions/strategies/boolean.rb @@ -1,5 +1,33 @@ # 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. +#++ + # OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: # Copyright (C) 2006-2017 Jean-Philippe Lang # Copyright (C) 2010-2013 the ChiliProject Team @@ -21,8 +49,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 3d9c2071f9d5..f9fbe832e283 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 96% rename from app/models/custom_actions/actions/strategies/date.rb rename to app/models/automations/actions/strategies/date.rb index 2ad203fafa83..c69632e86d07 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 @@ -48,7 +48,7 @@ def apply(work_package) def date_to_apply if values.first == "%CURRENT_DATE%" - Date.today + Time.zone.today else values.first 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 e599ca8263da..dfe6c63f6525 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 92% rename from app/models/custom_actions/actions/strategies/float.rb rename to app/models/automations/actions/strategies/float.rb index 69692717366d..103f0101b0b2 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 d69938c4f85c..58942e37a38d 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 94fc5e11523a..5c822ead478b 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 241df7b15bec..9d36a8fb6d5f 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 @@ def current_user_value_key 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 ca8707e5c290..1bf1ff84f926 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 1ceea8308582..d733868aad1a 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 022c723cf855..8609e9e117e0 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 51b83d111207..b90e13800b6a 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 94e26c46905e..d2e90002ad85 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 8d156c2ee856..0fa83ce52252 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 76% rename from app/models/custom_actions/conditions/base.rb rename to app/models/automations/conditions/base.rb index 9852d382fbc3..c4875674c265 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 @@ -62,9 +62,7 @@ def fulfilled_by?(work_package, _user) (work_package.respond_to?(:"#{key}_id") && values.include?(work_package.send(:"#{key}_id"))) end - def key - self.class.key - end + delegate :key, to: :class def self.key raise SubclassResponsibilityError @@ -74,38 +72,38 @@ def validate(errors) 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 +111,7 @@ def self.pluralized_key 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 5cbf25aac5fe..04702b51e0d9 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 807a7bdfc79a..296532dfc3b8 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 86% rename from app/models/custom_actions/conditions/role.rb rename to app/models/automations/conditions/role.rb index 77af34115ff9..29d2fa37637d 100644 --- a/app/models/custom_actions/conditions/role.rb +++ b/app/models/automations/conditions/role.rb @@ -28,10 +28,10 @@ # 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? + self.class.roles_in_project(work_package, user).map(&:id).intersect?(values) end class << self @@ -49,8 +49,8 @@ def roles_in_project(work_packages, user) 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 @@ def projects_of(work_packages) 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 c6b246e0d65a..c5069e596d83 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 af6ff9ba148f..ba60a021e22e 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 e49123fd52cb..0645fa7dc24e 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 000000000000..cc9d2958d6e4 --- /dev/null +++ b/app/models/automations/triggers/base.rb @@ -0,0 +1,41 @@ +# 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 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/spec/factories/custom_action_factory.rb b/app/models/automations/triggers/manual.rb similarity index 86% rename from spec/factories/custom_action_factory.rb rename to app/models/automations/triggers/manual.rb index 1fa4b6cc3f35..3b80a7016f8b 100644 --- a/spec/factories/custom_action_factory.rb +++ b/app/models/automations/triggers/manual.rb @@ -28,9 +28,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -FactoryBot.define do - factory :custom_action do - sequence(:name) { |n| "Custom action #{n} - name" } - sequence(:description) { |n| "Custom action #{n} - description" } +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 50% rename from app/models/custom_actions/validate_allowed_value.rb rename to app/models/automations/validate_allowed_value.rb index b85f7678b066..32dd280e20d0 100644 --- a/app/models/custom_actions/validate_allowed_value.rb +++ b/app/models/automations/validate_allowed_value.rb @@ -1,5 +1,33 @@ # 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. +#++ + # OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: # Copyright (C) 2006-2017 Jean-Philippe Lang # Copyright (C) 2010-2013 the ChiliProject Team @@ -21,7 +49,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 c36aa8fbea69..6894a3f90c70 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 ec0b77f51ecf..8ac8956447cc 100644 --- a/app/models/permitted_params.rb +++ b/app/models/permitted_params.rb @@ -92,12 +92,12 @@ def custom_field 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 @@ -507,11 +507,12 @@ def self.permitted_attributes 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 0706f73d421e..d4066af82f45 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 # Must stay above WorkPackage::Journalized: its after_save persists the # version rows that the journal snapshot then reads. diff --git a/app/models/work_package/custom_actioned.rb b/app/models/work_package/automatable.rb similarity index 79% rename from app/models/work_package/custom_actioned.rb rename to app/models/work_package/automatable.rb index 0d88d078c315..cf63ed4a3b76 100644 --- a/app/models/work_package/custom_actioned.rb +++ b/app/models/work_package/automatable.rb @@ -28,16 +28,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -module WorkPackage::CustomActioned +module WorkPackage::Automatable 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)) + 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_field.rb b/app/models/work_package_custom_field.rb index 45547925f280..792076725138 100644 --- a/app/models/work_package_custom_field.rb +++ b/app/models/work_package_custom_field.rb @@ -44,7 +44,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 75% rename from app/services/custom_actions/base_service.rb rename to app/services/automations/base_service.rb index dfc18ab4f7ee..02449a8dbd33 100644 --- a/app/services/custom_actions/base_service.rb +++ b/app/services/automations/base_service.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class CustomActions::BaseService +class Automations::BaseService include Shared::BlockService attr_accessor :user @@ -38,7 +38,7 @@ def call(attributes:, &) set_attributes(action, attributes) - contract = CustomActions::CuContract.new(action) + contract = Automations::CuContract.new(action, user) result = ServiceResult.new(success: contract.validate && action.save, result: action, errors: contract.errors) @@ -51,10 +51,12 @@ def call(attributes:, 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) end def set_actions(action, actions_attributes) @@ -66,21 +68,15 @@ def set_actions(action, actions_attributes) 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 +98,23 @@ def set_conditions(action, conditions_attributes) 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) + attributes ||= default_trigger_attributes(action) + return if attributes.blank? + + action.assign_attributes(triggers_attributes: attributes) + end + + def default_trigger_attributes(action) + return [] if action.triggers.any?(Automations::Triggers::Manual) + + [{ type: "Automations::Triggers::Manual", options: { button_label: action.name } }] end end diff --git a/app/services/custom_actions/create_service.rb b/app/services/automations/create_service.rb similarity index 90% rename from app/services/custom_actions/create_service.rb rename to app/services/automations/create_service.rb index 1feb0a003972..32def61a4c06 100644 --- a/app/services/custom_actions/create_service.rb +++ b/app/services/automations/create_service.rb @@ -28,14 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class CustomActions::CreateService < CustomActions::BaseService +class Automations::CreateService < Automations::BaseService def initialize(user:) self.user = user + super() end - def call(attributes:, - action: CustomAction.new, - &block) + def call(attributes:, action: Automation.new, &block) super end end diff --git a/app/services/custom_actions/update_service.rb b/app/services/automations/update_service.rb similarity index 95% rename from app/services/custom_actions/update_service.rb rename to app/services/automations/update_service.rb index 12d1d04add66..193b6c10e782 100644 --- a/app/services/custom_actions/update_service.rb +++ b/app/services/automations/update_service.rb @@ -28,13 +28,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class CustomActions::UpdateService < CustomActions::BaseService +class Automations::UpdateService < Automations::BaseService attr_accessor :user, :action def initialize(action:, user:) self.action = action self.user = user + super() end def call(attributes:, &) diff --git a/app/services/custom_actions/update_work_package_service.rb b/app/services/automations/update_work_package_service.rb similarity index 91% rename from app/services/custom_actions/update_work_package_service.rb rename to app/services/automations/update_work_package_service.rb index d4058deaf335..03e5d6e8f004 100644 --- a/app/services/custom_actions/update_work_package_service.rb +++ b/app/services/automations/update_work_package_service.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class CustomActions::UpdateWorkPackageService +class Automations::UpdateWorkPackageService include Shared::BlockService include Contracted @@ -56,13 +56,10 @@ def call(work_package:, &) 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 + retry_apply_actions(work_package, actions, errors, changes_before) unless success end def retry_apply_actions(work_package, actions, errors, changes_before) @@ -76,14 +73,11 @@ def retry_apply_actions(work_package, actions, errors, changes_before) 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) } + actions.sort_by(&:priority).each { |a| a.apply(work_package) } end def append_id(sym) diff --git a/app/views/custom_actions/_form.html.erb b/app/views/automations/_form.html.erb similarity index 60% rename from app/views/custom_actions/_form.html.erb rename to app/views/automations/_form.html.erb index 90bfaa92e1f1..857ab1133c84 100644 --- a/app/views/custom_actions/_form.html.erb +++ b/app/views/automations/_form.html.erb @@ -1,4 +1,34 @@ -<% active_section_keys = @custom_action.actions.map(&:key) %> +<%#-- 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. + +++#%> + +<% 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") %>
<%= f.text_field :name, required: true, container_class: "-middle" %> @@ -7,16 +37,27 @@ <%= f.text_area :description, container_class: "-middle" %>
-
- - <%= t("custom_actions.conditions") %> - +
+ <%= t("automations.trigger") %> +
+ <%= styled_label_tag "automation_trigger_type", t("automations.triggers.name"), class: "-top" %> +
+ <%= styled_text_field_tag "automation_trigger_type", + t("automations.triggers.manual.label"), + disabled: true, + container_class: "-middle" %> +
+
+ <%= render partial: "trigger_fields_manual", locals: { trigger: } %> +
- <% @custom_action.all_conditions.each do |condition| %> -
- <%= styled_label_tag("custom_action_conditions_#{condition.key}", condition.human_name, class: "-top") %> - <% input_name = "custom_action[conditions][#{condition.key}]" %> +
+ <%= t("automations.conditions") %> + <% @automation.all_conditions.each do |condition| %> +
+ <%= styled_label_tag("automation_conditions_#{condition.key}", condition.human_name, class: "-top") %> + <% input_name = "automation[conditions][#{condition.key}]" %>
<% if condition.key == :project %> @@ -26,7 +67,7 @@ filters: [{ name: "active", operator: "=", values: ["t"] }], resource: "projects", inputName: input_name, - labelForId: "custom_action_actions_#{condition.key}", + labelForId: "automation_conditions_#{condition.key}", inputValue: condition.values } %> <% else %> @@ -38,31 +79,28 @@ model: condition.value_objects.map { |v| { id: v[:value], name: v[:label] } }, inputName: input_name, bindLabel: "name", - labelForId: "custom_action_conditions_#{condition.key}" + labelForId: "automation_conditions_#{condition.key}" } %> <% end %>
-
<% end %>
-
- - <%= t("custom_actions.actions.name") %> - +
+ <%= t("automations.actions.name") %> -
- <% @custom_action.all_actions.each do |action| %> +
+ <% @automation.all_actions.each do |action| %>
>
- <%= styled_label_tag("custom_action_actions_#{action.key}", action.human_name, class: "-top") %> + <%= styled_label_tag("automation_actions_#{action.key}", action.human_name, class: "-top") %> + <% input_name = "automation[actions][#{action.key}]" %> - <% input_name = "custom_action[actions][#{action.key}]" %> <% if %i(associated_property boolean user project).include?(action.type) %>
@@ -75,7 +113,7 @@ resource: "projects", inputName: input_name, appendTo: "body", - labelForId: "custom_action_actions_#{action.key}", + labelForId: "automation_actions_#{action.key}", inputValue: action.values.first } %> <% in { type: :user, custom_field_based: false } %> @@ -98,7 +136,7 @@ { id: action.current_user_value_key, name: action.current_user_name } ], searchKey: "any_name_attribute", - labelForId: "custom_action_actions_#{action.key}", + labelForId: "automation_actions_#{action.key}", focusDirectly: false } %> <% else %> @@ -112,12 +150,12 @@ model: action.multi_value? ? selected : selected.first, inputName: input_name, bindLabel: "name", - labelForId: "custom_action_actions_#{action.key}" + labelForId: "automation_actions_#{action.key}" } %> <% end %>
- <% elsif %i(date_property).include?(action.type) %> + <% elsif action.type == :date_property %>
<% date = action.values.first %> <%= angular_component_tag "opce-custom-date-action-admin", @@ -125,74 +163,41 @@
<% elsif %i(string_property text_property).include?(action.type) %>
- <%= styled_text_field_tag input_name, - action.values, - container_class: "-slim", - step: "any" %> + <%= styled_text_field_tag input_name, action.values, container_class: "-slim" %>
- <% elsif %i(link_property).include?(action.type) %> + <% elsif action.type == :link_property %>
- <%= styled_url_field_tag input_name, - action.values, - container_class: "-slim", - step: "any" %> + <%= styled_url_field_tag input_name, action.values, container_class: "-slim" %>
- <% elsif action.type == :float_property %> + <% elsif %i(float_property integer_property).include?(action.type) %>
<%= styled_number_field_tag input_name, action.values, container_class: "-slim", min: action.minimum, max: action.maximum, - step: "any" %> -
- <% elsif action.type == :integer_property %> -
- <%= styled_number_field_tag input_name, - action.values, - container_class: "-slim", - min: action.minimum, - max: action.maximum, - step: 1 %> + step: action.type == :integer_property ? 1 : "any" %>
<% end %> - <%= - render( - Primer::Beta::IconButton.new( - icon: :x, - size: :small, - scheme: :invisible, - type: :button, - aria: { label: t(:button_close) }, - data: { action: "click->hide-sections#hide" } - ) - ) - %> + + <%= render(Primer::Beta::IconButton.new(icon: :x, size: :small, scheme: :invisible, type: :button, aria: { label: t(:button_close) }, data: { action: "click->hide-sections#hide" })) %>
<% end %>
-
-
-