ManageIQ/manageiq-ui-classic

View on GitHub
app/controllers/catalog_controller.rb

Summary

Maintainability
F
1 mo
Test Coverage
F
51%
class CatalogController < ApplicationController
  include AutomateTreeHelper
  include Mixins::ServiceDialogCreationMixin
  include Mixins::BreadcrumbsMixin
  include Mixins::AutomationMixin
  include Mixins::ImageValidationMixin

  before_action :check_privileges
  before_action :get_session_data
  after_action :cleanup_action
  after_action :set_session_data
  helper ProvisionCustomizeHelper
  helper MiqAeClassHelper # need the playbook_label

  def self.model
    @model ||= ServiceTemplate
  end

  def self.table_name
    @table_name ||= "service_template"
  end

  def index
    flash_to_session
    redirect_to(:action => 'explorer')
  end

  CATALOG_X_BUTTON_ALLOWED_ACTIONS = {
    'ab_button_new'                 => :ab_button_new,
    'ab_button_edit'                => :ab_button_edit,
    'ab_group_edit'                 => :ab_group_edit,
    'ab_group_new'                  => :ab_group_new,
    'ab_group_reorder'              => :ab_group_reorder,
    'svc_catalog_provision'         => :svc_catalog_provision,
    'st_catalog_delete'             => :st_catalog_delete,

    'atomic_catalogitem_edit'       => :servicetemplate_edit,
    'atomic_catalogitem_new'        => :servicetemplate_edit,
    'catalogitem_edit'              => :servicetemplate_edit,
    'catalogitem_copy'              => :servicetemplate_copy,
    'catalogitem_new'               => :servicetemplate_edit,

    'catalogitem_tag'               => :st_tags_edit,
    'catalogitem_ownership'         => :servicetemplate_ownership,

    'orchestration_template_add'    => :ot_add,
    'orchestration_template_edit'   => :ot_edit,
    'orchestration_template_copy'   => :ot_copy,
    'orchestration_template_remove' => :ot_remove_submit,
    'orchestration_template_tag'    => :ot_tags_edit,
    'service_dialog_from_ot'        => :service_dialog_from_ot,
    'st_catalog_edit'               => :st_catalog_edit,
    'st_catalog_new'                => :st_catalog_edit,
  }.freeze

  ORCHESTRATION_TEMPLATES_NODES = {
    'ManageIQ::Providers::Amazon::CloudManager::OrchestrationTemplate'     => "otcfn",
    'ManageIQ::Providers::Openstack::CloudManager::OrchestrationTemplate'  => "othot",
    'ManageIQ::Providers::Azure::CloudManager::OrchestrationTemplate'      => "otazu",
    'ManageIQ::Providers::AzureStack::CloudManager::OrchestrationTemplate' => "otazs",
    'ManageIQ::Providers::Openstack::CloudManager::VnfdTemplate'           => "otvnf",
    'ManageIQ::Providers::Vmware::CloudManager::OrchestrationTemplate'     => "otvap",
    'ManageIQ::Providers::Vmware::InfraManager::OrchestrationTemplate'     => "otovf"
  }.freeze

  # when methods are evaluated from this constant and return true that means: column is displayed
  DISPLAY_GTL_METHODS = [
    :user_super_admin?
  ].freeze

  def user_super_admin?
    current_user.super_admin_user?
  end

  def x_button
    # setting this here so it can be used in the common code
    @sb[:applies_to_class] = 'ServiceTemplate'
    generic_x_button(CATALOG_X_BUTTON_ALLOWED_ACTIONS)
  end

  EDIT_CATALOG_FEATURES = %w[
    atomic_catalogitem_edit
    catalogitem_edit
    atomic_catalogitem_new
    catalogitem_new
  ].freeze

  def assert_privileges_for_servicetemplate_edit
    if params[:pressed].present? && EDIT_CATALOG_FEATURES.include?(params[:pressed])
      assert_privileges(params[:pressed])
    elsif params[:button].blank?
      assert_privileges('atomic_catalogitem_edit')
    end
  end

  def servicetemplate_edit
    assert_privileges_for_servicetemplate_edit

    checked_id = find_checked_items.first || params[:id]
    @sb[:cached_waypoint_ids] = MiqAeClass.waypoint_ids_for_state_machines
    @record = checked_id.present? ? find_record_with_rbac(ServiceTemplate, checked_id) : ServiceTemplate.new
    @sb[:st_form_active_tab] = "basic"
    composite_type = @record.service_type == "composite"
    new_atomic_item = params[:pressed] == "atomic_catalogitem_new" || (params[:button].present? && session[:edit][:new][:service_type] == "atomic")
    if checked_id.present? && composite_type || checked_id.nil? && !new_atomic_item
      st_edit
    else
      atomic_st_edit
    end
  end

  def ot_orchestration_managers
    assert_privileges("orchestration_templates_view")

    render :json => available_orchestration_managers_for_template_type(params['template_type'])
  end

  def servicetemplate_copy
    assert_privileges("catalogitem_edit")

    checked_id = find_checked_items.first || params[:id]
    @record = find_record_with_rbac(ServiceTemplate, checked_id)
    if !@record.template_valid?
      add_flash(_("This item is not valid and cannot be copied."), :error)
      javascript_flash
    elsif @record.type == 'ServiceTemplateAnsiblePlaybook'
      add_flash(_("ServiceTemplateAnsiblePlaybook cannot be copied."), :error)
      javascript_flash
    else
      @tabactive = false
      @in_a_form = true
      @edit = {}
      session[:changed] = false
      replace_right_cell(:action => "copy_catalog")
    end
  end

  def save_copy_catalog
    assert_privileges("catalogitem_edit")

    record = find_record_with_rbac(ServiceTemplate, params[:id])
    message = nil
    if record.present?
      saved = record.template_copy(params[:name], :copy_tags => params[:copy_tags])
    else
      saved = false
      message = _("Record not found.")
    end
    render :json => {:message => message}, :status => saved ? 200 : 400
  end

  def servicetemplate_copy_cancel
    assert_privileges("catalogitem_new")

    add_flash(_("Copy of a Service Catalog Item was cancelled by the user"), :warning)
    @sb[:action] = @edit = @record = nil
    @in_a_form = false
    replace_right_cell(:replace_trees => trees_to_replace([:sandt]))
  end

  def servicetemplate_copy_saved
    assert_privileges("catalogitem_new")

    add_flash(_("Copy of a Service Catalog Item was successfully saved"))
    @sb[:action] = @edit = @record = nil
    @in_a_form = false
    replace_right_cell(:replace_trees => trees_to_replace(%i[sandt svccat stcat]))
  end

  def servicetemplates_names
    assert_privileges("catalog_items_view")

    render :json => {:names => Rbac.filtered(ServiceTemplate).pluck(:name)}
  end

  def atomic_st_edit
    assert_privileges(params[:id] ? 'atomic_catalogitem_edit' : 'atomic_catalogitem_new')

    # reset the active tree back to :sandt_tree, it was changed temporairly to display automate entry point tree in a popup div
    self.x_active_tree = 'sandt_tree'
    case params[:button]
    when "cancel"
      if session[:edit][:rec_id]
        add_flash(_("Edit of Service Catalog Item \"%{name}\" was cancelled by the user") %
          {:name => session[:edit][:new][:description]})
      else
        add_flash(_("Add of new Service Catalog Item was cancelled by the user"))
      end
      @sb[:action] = @edit = @record = nil
      @in_a_form = false
      replace_right_cell
    when "save", "add"
      assert_privileges("atomic_catalogitem_#{params[:button] == "save" ? "edit" : "new"}")
      atomic_req_submit
    when "reset", nil # Reset or first time in
      @_params[:org_controller] = "service_template"
      if params[:button] == "reset"
        add_flash(_("All changes have been reset"), :warning)
      end
      if !@record.id.nil? && need_prov_dialogs?(@record.prov_type)
        request = MiqRequest.find_by(:id => @record.service_resources[0].resource_id) if @record.service_resources[0]&.resource_id
        if request
          prov_set_form_vars(request) # Set vars from existing request
        else
          add_flash(_("Can not edit selected item, Request is missing"), :error)
          @edit = @record = nil
          replace_right_cell
          return
        end
      else
        # prov_set_form_vars
        @edit ||= {} # Set default vars
        @edit[:new] ||= {}
        @edit[:current] ||= {}
        @edit[:key] = "prov_edit__new"
      end
      @edit[:new][:st_prov_type] = @record.prov_type if @record.prov_type.present?
      # set name and description for ServiceTemplate record
      set_form_vars
      @edit[:new][:service_type] = "atomic"
      @edit[:rec_id] = @record.try(:id)
      @edit[:current] = copy_hash(@edit[:new])

      @tabactive = @edit[:new][:current_tab_key]
      @in_a_form = true
      session[:changed] = false
      replace_right_cell(:action => "at_st_new")
    end
  end

  def atomic_form_field_changed
    assert_privileges(session&.fetch_path(:edit, :rec_id) ? "atomic_catalogitem_edit" : "atomic_catalogitem_new")

    # need to check req_id in session since we are using common code for prov requests and atomic ST screens
    id = session[:edit][:req_id] || "new"
    return unless load_edit("prov_edit__#{id}", "replace_cell__explorer")
    get_form_vars
    build_automate_tree(:automate_catalog) if automate_tree_needed?
    if params[:st_prov_type] # build request screen for selected item type
      @_params[:org_controller] = "service_template"
      if ansible_playbook_type? || terraform_template_type?
        @record = ServiceTemplate.new
        # waiting for back-end PR to be merged to implement this
        # if false
        #   add_flash(_("Before adding Ansible Service, at least 1 repository, 1 playbook, 1 credential must exist in VMDB"), :error)
        #   javascript_flash
        #   return
        # end
      else
        prov_set_form_vars if need_prov_dialogs?(params[:st_prov_type])
        @record = class_service_template(params[:st_prov_type]).new
        set_form_vars
        @edit[:new][:st_prov_type] = params[:st_prov_type] if params[:st_prov_type]
        @edit[:new][:service_type] = "atomic"
        default_entry_point(@edit[:new][:st_prov_type],
                            @edit[:new][:service_type])
        @edit[:rec_id] = @record.try(:id)
        @tabactive = @edit[:new][:current_tab_key]
      end
      @edit[:current] = copy_hash(@edit[:new])
    end

    changed = (@edit[:new] != @edit[:current])

    if changed && @edit[:new][:ovf_template_id]
      ovf_template = ManageIQ::Providers::Vmware::InfraManager::OrchestrationTemplate.find_by(:id => @edit[:new][:ovf_template_id])
      @edit[:new][:src_vm_id] = @edit[:new][:ovf_template_id]
      ovf_template.refresh_field_values(@edit[:new])

      @edit[:available_folders] = ovf_template.allowed_folders
                                              .collect { |m| [m.last, m.first] }
                                              .sort
      @edit[:available_resource_pools] = ovf_template.allowed_resource_pools
                                                     .collect { |m| [m.last, m.first] }
                                                     .sort
      @edit[:available_datacenters] = ovf_template.allowed_datacenters
                                                  .collect { |m| [m.last, m.first] }
                                                  .sort
      @edit[:available_hosts] = ovf_template.allowed_hosts
                                            .collect { |h| [h.name, h.id] }
                                            .sort
      @edit[:available_storages] = ovf_template.allowed_storages
                                               .collect { |s| [s.name, s.id] }
                                               .sort
    end

    render :update do |page|
      page << javascript_prologue
      if @edit[:new][:st_prov_type] == "generic_terraform_template"
        page.replace("form_div", :partial => "tt_react_form")
        page << javascript_hide("form_buttons_div")
      elsif @edit[:new][:st_prov_type] == "generic_ansible_playbook"
        page.replace("form_div", :partial => "st_angular_form")
        page << javascript_hide("form_buttons_div")
      else
        # for generic/orchestration type tabs do not show up on screen
        # as there is only a single tab when form is initialized
        # when display in catalog is checked, replace div so tabs can be redrawn
        if (params[:st_prov_type] || (params[:display] && @edit[:new][:st_prov_type].starts_with?("generic"))) || params[:ovf_template_id]
          page.replace("form_div", :partial => "st_form")
        end
        if automate_tree_needed?
          page.replace("basic_info_div", :partial => "form_basic_info")
        end
        if params[:display]
          page << "miq_tabs_show_hide('#details_tab', '#{(params[:display] == "1")}')"
        end
        page.replace_html("provision_entry_point", :partial => "provision_entry_point") if params[:provision_entry_point_type]
        page.replace_html("reconfigure_entry_point", :partial => "reconfigure_entry_point") if params[:reconfigure_entry_point_type]
        page.replace_html("retire_entry_point", :partial => "retire_entry_point") if params[:retire_entry_point_type]

        %w[fqname reconfigure_fqname retire_fqname].each do |name|
          if params[name.to_sym] && @edit[:new][name.to_sym].present?
            page << "$('##{name}_remove').attr('disabled', false);"
          end
        end
        if changed != session[:changed]
          page << javascript_for_miq_button_visibility(changed)
          session[:changed] = changed
        end
        page.replace_html("price_span", @edit[:new][:code_currency])
        page << set_spinner_off
      end
    end
  end

  # VM or Template show selected, redirect to proper controller
  def show
    assert_privileges("catalog_items_view")

    @sb[:action] = nil
    @explorer = true if request.xml_http_request? # Ajax request means in explorer
    record = ServiceTemplate.find(params[:id])
    if !@explorer
      tree_node_id = TreeBuilder.build_node_id(record)
      redirect_to(:controller => "catalog",
                  :action     => "explorer",
                  :id         => tree_node_id)
      return
    else
      redirect_to(:action => 'show', :controller => record.class.base_model.to_s.underscore, :id => record.id)
    end
  end

  def explorer
    @explorer = true
    @lastaction = "explorer"
    @report_deleted = params[:report_deleted] == 'true' if params[:report_deleted]
    @sb[:action] = nil

    # if AJAX request, replace right cell, and return
    if request.xml_http_request?
      replace_right_cell
      return
    end

    if params[:id] && !params[:button] # If a tree node id came in, show in one of the trees
      @nodetype, id = parse_nodetype_and_id(params[:id])
      self.x_active_tree   = 'sandt_tree'
      self.x_active_accord = 'sandt'
      st = ServiceTemplate.find(params[:id].split("-").last)
      prefix = st.service_template_catalog_id ? "stc-#{st.service_template_catalog_id}_st-" : "-Unassigned_st-"
      self.x_node = "#{prefix}#{id}"
      get_node_info(x_node)
    else
      @in_a_form = false
    end

    build_accordions_and_trees

    if params[:commit] == "Upload" && session.fetch_path(:edit, :new, :sysprep_enabled, 1) == "Sysprep Answer File"
      upload_sysprep_file
      set_form_locals_for_sysprep
    end
    template_locals = {:locals => {:controller => "catalog"}}
    template_locals[:locals].merge!(fetch_playbook_details) if need_ansible_locals?
    template_locals[:locals].merge!(fetch_terraform_template_details) if need_terraform_locals?
    template_locals[:locals].merge!(fetch_ct_details) if need_container_template_locals?
    template_locals[:locals].merge!(fetch_ovf_template_details) if need_ovf_template_locals?

    render :layout => "application", :action => "explorer", :locals => template_locals
  end

  def set_form_locals_for_sysprep
    @pages = false
    @edit[:explorer] = true
    @sb[:st_form_active_tab] = "request"
    @right_cell_text = _("Adding a new Service Catalog Item")
    @x_edit_buttons_locals = {:action_url => "servicetemplate_edit"}
  end

  def identify_catalog(id = nil)
    kls = TreeBuilder.get_model_for_prefix(@nodetype) == "MiqTemplate" ? VmOrTemplate : ServiceTemplate
    @record = identify_record(id || params[:id], kls)
    @tenants_tree = build_tenants_tree if kls == ServiceTemplate # Build the tree with available tenants for the Catalog Item/Bundle
    add_flash(_("This item is invalid"), :warning) unless @flash_array || @record.try(:template_valid?)
  end

  # ST clicked on in the explorer right cell
  def x_show
    @sb[:action] = nil
    @explorer = true
    if x_active_tree == :stcat_tree
      assert_privileges("st_catalog_view")

      if params[:rec_id]
        # link to Catalog Item clicked on catalog summary screen
        self.x_active_tree = :sandt_tree
        self.x_active_accord = 'sandt'
        @record = ServiceTemplate.find(params[:rec_id])
      else
        @record = ServiceTemplateCatalog.find(params[:id])
      end
    elsif x_active_tree == :sandt_tree
      assert_privileges("catalog_items_view")

      identify_catalog(params[:id])
      @record ||= ServiceTemplateCatalog.find(params[:id])
    elsif x_active_tree == :ot_tree
      assert_privileges("orchestration_templates_view")

      @record ||= OrchestrationTemplate.find(params[:id])
    else
      assert_privileges("svc_catalog_provision", "svc_catalog_archive", "svc_catalog_unarchive")

      identify_catalog(params[:id])
      @record ||= ServiceTemplateCatalog.find(params[:id])
    end
    params[:id] = x_build_node_id(@record) # Get the tree node id
    tree_select
  end

  def st_edit
    assert_privileges(params[:id] ? 'catalogitem_edit' : 'catalogitem_new')

    # reset the active tree back to :sandt_tree, it was changed temporairly to display automate entry point tree in a popup div
    self.x_active_tree = 'sandt_tree'
    case params[:button]
    when "cancel"
      if session[:edit][:rec_id]
        add_flash(_("Edit of Catalog Bundle \"%{name}\" was cancelled by the user") %
                    {:name => session[:edit][:new][:description]})
      else
        add_flash(_("Add of new Catalog Bundle was cancelled by the user"))
      end
      @sb[:action] = @edit = @record = nil
      @in_a_form = false
      replace_right_cell
    when "save", "add"
      return unless load_edit("st_edit__#{params[:id] || "new"}", "replace_cell__explorer")

      get_form_vars
      if @edit[:new][:name].blank?
        add_flash(_("Name is required"), :error)
      end

      if @edit[:new][:selected_resources].empty?
        add_flash(_("Resource must be selected"), :error)
      end
      add_flash(_("Provisioning Entry Point is required"), :error) if @edit[:new][:fqname].blank?
      validate_price
      dialog_catalog_check

      if @flash_array
        javascript_flash
        return
      end
      @st = @edit[:rec_id] ? ServiceTemplate.find(@edit[:rec_id]) : ServiceTemplate.new
      st_set_record_vars(@st)
      if @add_rsc
        if @st.save
          set_resource_action(@st)
          flash_key = if params[:button] == "save"
                        _("Catalog Bundle \"%{name}\" was saved")
                      else
                        _("Catalog Bundle \"%{name}\" was added")
                      end
          add_flash(flash_key % {:name => @edit[:new][:name]})
          @changed = session[:changed] = false
          @in_a_form = false
          @edit = session[:edit] = @record = nil
          replace_right_cell(:replace_trees => trees_to_replace(%i[sandt svccat stcat]))
        else
          @st.errors.each do |error|
            add_flash("#{error.attribute.to_s.capitalize} #{error.message}", :error)
          end
          @changed = session[:changed] = (@edit[:new] != @edit[:current])
          javascript_flash
        end
      else
        javascript_flash
        return
      end
    when "reset", nil # Reset or first time in
      st_set_form_vars
      if params[:button] == "reset"
        add_flash(_("All changes have been reset"), :warning)
      end
      @changed = session[:changed] = false
      replace_right_cell(:action => "st_new")
      return
    end
  end

  # AJAX driven routine to check for changes in ANY field on the form
  def st_form_field_changed
    assert_privileges(session&.fetch_path(:edit, :rec_id) ? "catalogitem_edit" : "catalogitem_new")

    id = session[:edit][:rec_id] || 'new'
    return unless load_edit("st_edit__#{id}", "replace_cell__explorer")

    @group_idx = false
    default_entry_point("generic", "composite") if params[:display]
    st_get_form_vars
    changed = (@edit[:new] != @edit[:current])
    build_automate_tree(:automate_catalog) # Build Catalog Items tree
    render :update do |page|
      page << javascript_prologue
      page.replace("basic_info_div", :partial => "form_basic_info") if params[:resource_id] || params[:display]
      page.replace("resources_info_div", :partial => "form_resources_info") if params[:resource_id] || @group_idx
      if params[:display]
        page << "miq_tabs_show_hide('#details_tab', '#{(params[:display] == "1")}')"
      end
      if changed != session[:changed]
        session[:changed] = changed
        page << javascript_for_miq_button_visibility(changed)
      end
      page << "miqSparkle(false);"
    end
  end

  def st_upload_image
    assert_privileges("st_catalog_edit")

    err = false
    identify_catalog(params[:id])
    image_file = params.dig(:upload, :image)
    if params[:pressed]
      @record.picture = nil
      @record.save
      msg = _("Custom Image successfully removed")
    elsif !image_file&.respond_to?(:read)
      msg = _("Use the Choose file button to locate a .png or .jpg image file")
      err = true
    elsif !valid_image_file?(image_file)
      msg = _("Custom Image must be a .png or .jpg file")
      err = true
    else
      ext = image_file.original_filename.split(".").last.downcase
      picture = {:content => image_file.read, :extension => ext}
      if @record.picture.nil?
        @record.picture = Picture.new(picture)
      else
        @record.picture.update(picture)
      end
      @record.save
      msg = _("Custom Image file \"%{name}\" successfully uploaded") %
            {:name => image_file.original_filename}
    end
    params[:id] = x_build_node_id(@record) # Get the tree node id
    add_flash(msg, err == true ? :error : nil)
    respond_to do |format|
      format.js { replace_right_cell(:replace_trees => trees_to_replace(%i[sandt svccat stcat])) }
      format.html do # HTML, send error screen
        explorer
      end
      format.any { head :not_found } # Anything else, just send 404
    end
  end

  def resource_delete
    assert_new_or_edit_by_service_type

    return unless load_edit("st_edit__#{params[:id]}", "replace_cell__explorer")

    @edit[:new][:rsc_groups][params[:grp_id].to_i].each do |r|
      next if r[:id].to_s != params[:rec_id]

      @edit[:new][:available_resources][r[:resource_id]] = r[:name] # add it back to available resources pulldown
      @edit[:new][:selected_resources].delete(r[:resource_id]) # delete it from to selected resources
      @edit[:new][:rsc_groups][params[:grp_id].to_i].delete(r) # delete element from group
      rearrange_provision_order(@edit[:new][:rsc_groups], r[:provision_index])
    end

    # if resource has been deleted from group, rearrange groups incase group is now empty.
    rearrange_groups_array
    build_automate_tree(:automate_catalog) # Build Catalog Items tree
    changed = (@edit[:new] != @edit[:current])
    @available_catalogs = available_catalogs.sort # Get available catalogs with tenants and ancestors
    @tenants_tree = build_tenants_tree # Build the tree with available tenants
    fetch_zones
    render :update do |page|
      page << javascript_prologue
      page.replace("basic_info_div", :partial => "form_basic_info")
      page.replace("resources_info_div", :partial => "form_resources_info")
      if changed != session[:changed]
        session[:changed] = changed
        page << javascript_for_miq_button_visibility(changed)
      end
      page << "miqSparkle(false);"
    end
  end

  # Edit user or group tags
  def st_tags_edit
    assert_privileges("catalogitem_tag")
    tags_edit("ServiceTemplate")
  end

  # Edit user or group tags
  def ot_tags_edit
    assert_privileges("orchestration_template_tag")
    tags_edit("OrchestrationTemplate")
  end

  # Edit user or group tags
  def tags_edit(klass)
    case params[:button]
    when "cancel"
      x_edit_tags_cancel
    when "save", "add"
      x_edit_tags_save
    when "reset", nil # Reset or first time in
      x_edit_tags_reset(klass) # pass in the DB
    end
  end

  def get_ae_tree_edit_key(type)
    case type
    when 'provision'   then :fqname
    when 'retire'      then :retire_fqname
    when 'reconfigure' then :reconfigure_fqname
    end
  end
  private :get_ae_tree_edit_key

  def need_prov_dialogs?(type)
    !type.starts_with?('generic')
  end
  helper_method :need_prov_dialogs?

  def assert_new_or_edit_by_service_type
    service_type = session&.fetch_path(:edit, :current, :service_type)
    edit_feature = "atomic_catalogitem_edit"
    new_feature  = "atomic_catalogitem_new"

    if service_type == "composite"
      edit_feature = "catalogitem_edit"
      new_feature  = "catalogitem_new"
    end

    assert_privileges(session&.fetch_path(:edit, :rec_id) ? edit_feature : new_feature)
  end

  private :assert_new_or_edit_by_service_type

  def ae_tree_select_toggle
    assert_new_or_edit_by_service_type

    @edit = session[:edit]
    self.x_active_tree = :sandt_tree
    at_tree_select_toggle(:automate_catalog, get_ae_tree_edit_key(@edit[:ae_field_typ]))
    x_node_set(@edit[:active_id], :automate_catalog_tree) if params[:button] == 'submit'
    session[:edit] = @edit
  end

  # Method to open the workflows dialog box
  # params[:field]    => :fqname || :retire_fqname || :reconfigure_fqname
  # params[:selected] => Holds the value of the *_configuration_script_id
  def embedded_workflows_modal
    @edit = session[:edit]
    type = ENTRY_POINT_TYPES[params[:field].to_sym][:type]
    render :update do |page|
      page << javascript_prologue
      page.replace_html("#{type}-workflows", :partial => "embedded_workflows_modal",
                                             :locals  => {
                                               :field    => params[:field],
                                               :selected => params[:selected],
                                               :type     => type,
                                             })
      page << javascript_show(params[:field])
      page << javascript_show("#{params[:field]}_modal")
      page << "$('##{params[:type]}_modal').addClass('modal fade in');"
    end
  end

  def ae_tree_select_discard
    assert_new_or_edit_by_service_type

    ae_tree_key = get_ae_tree_edit_key(params[:typ])
    @edit = session[:edit]
    @edit[:new][params[:typ]] = nil
    @edit[:new][ae_tree_key] = ''
    # build_automate_tree(:automate_catalog) # Build Catalog Items tree unless @edit[:ae_tree_select]
    render :update do |page|
      page << javascript_prologue
      @changed = (@edit[:new] != @edit[:current])
      x_node_set(@edit[:active_id], :automate_catalog_tree)
      page << javascript_hide("ae_tree_select_div")
      page << javascript_hide("blocker_div")
      page << "$('##{ae_tree_key}_remove').attr('disabled', true);"
      page << "$('##{ae_tree_key}').val('#{@edit[:new][ae_tree_key]}');"
      page << "$('##{ae_tree_key}').prop('title', '#{@edit[:new][ae_tree_key]}');"
      @edit[:ae_tree_select] = false
      page << javascript_for_miq_button_visibility(@changed)
      page << "miqTreeActivateNodeSilently('automate_catalog_tree', 'root');"
      page << "miqSparkle(false);"
    end
    session[:edit] = @edit
  end

  def ae_tree_select
    assert_new_or_edit_by_service_type

    @edit = session[:edit]
    at_tree_select(get_ae_tree_edit_key(@edit[:ae_field_typ]))
    session[:edit] = @edit
  end

  def svc_catalog_provision
    assert_privileges("svc_catalog_provision")
    checked = find_checked_items
    checked[0] = params[:id] if checked.blank? && params[:id]
    st = find_record_with_rbac(ServiceTemplate, checked[0])
    @right_cell_text = _("Order Service \"%{name}\"") % {:name => st.name}
    ra = nil
    st.resource_actions.each do |r|
      next unless r.action.downcase == "provision" && r.dialog_id

      # find the first provision action, run the dialog
      ra = r
      break
    end
    if ra
      @explorer = true
      options = {}
      options[:header] = @right_cell_text
      options[:target_id] = st.id
      options[:target_kls] = st.class.name
      options[:dialog_locals] = DialogLocalService.new.determine_dialog_locals_for_svc_catalog_provision(
        ra, st, svc_catalog_provision_finish_submit_endpoint
      )
      @in_a_form = true
      replace_right_cell(:action => "dialog_provision", :dialog_locals => options[:dialog_locals])
    else
      # if catalog item has no dialog and provision button was pressed from list view
      add_flash(_("No Ordering Dialog is available"), :warning)
      replace_right_cell
    end
  end

  def servicetemplate_ownership
    @explorer = true
    set_ownership
    replace_right_cell(:action => 'ownership')
  end

  def st_catalog_edit
    assert_privileges((params[:id] || session&.fetch_path(:edit, :rec_id)) ? "st_catalog_edit" : "st_catalog_new")

    case params[:button]
    when "cancel"
      if session[:edit][:rec_id]
        add_flash(_("Edit of Catalog \"%{name}\" was cancelled by the user") % {:name => session[:edit][:new][:name]})
      else
        add_flash(_("Add of new Catalog was cancelled by the user"))
      end
      @sb[:action] = @edit = nil
      @in_a_form = false
      replace_right_cell
    when "save", "add"
      add_flash(_("Catalog \"%{name}\" was saved") % {:name => params[:name]})
      @changed = session[:changed] = false
      @in_a_form = false
      @edit = session[:edit] = nil
      replace_right_cell(:replace_trees => trees_to_replace(%i[sandt svccat stcat]))
    when nil # First time in
      st_catalog_set_form_vars
      @changed = session[:changed] = false
      replace_right_cell(:action => "st_catalog_edit")
      nil
    end
  end

  def template_to_node_name(object)
    ORCHESTRATION_TEMPLATES_NODES[object.class.name]
  end

  def node_name_to_template_name(node_name)
    node_elems = node_name.split('-')
    if node_elems[1]
      ORCHESTRATION_TEMPLATES_NODES.invert[node_elems[1]]
    end
  end

  def ot_edit
    assert_privileges("orchestration_template_edit")
    checked = find_checked_items
    checked[0] = params[:id] if checked.blank? && params[:id]
    @record = find_record_with_rbac(OrchestrationTemplate, checked[0])
    if @record.in_use?
      add_flash(_("Orchestration template \"%{name}\" is read-only and cannot be edited.") %
        {:name => @record.name}, :error)
      get_node_info(x_node)
      replace_right_cell(:action => x_node)
      return
    end
    ot_edit_set_form_vars(_("Editing %{record_name}"))
    replace_right_cell(:action => "ot_edit")
  end

  def ot_copy
    assert_privileges("orchestration_template_copy")
    ot_edit_set_form_vars(_("Copying %{record_name}"))
    @edit[:new][:name] = @edit[:current][:name] = _("Copy of %{name}") % {:name => @edit[:new][:name]}
    replace_right_cell(:action => "ot_copy")
  end

  def ot_remove_submit
    assert_privileges("orchestration_template_remove")
    elements = find_records_with_rbac(OrchestrationTemplate, checked_or_params)
    elements.each do |ot|
      if ot.in_use?
        add_flash(_("Orchestration template \"%{name}\" is read-only and cannot be deleted.") %
          {:name => ot.name}, :error)
      else
        begin
          ot.remote_proxy = true
          ot.destroy
        rescue StandardError => bang
          add_flash(_("Error during 'Orchestration Template Deletion': %{error_message}") %
            {:error_message => bang.message}, :error)
        else
          add_flash(_("Orchestration Template \"%{name}\" was deleted.") % {:name => ot.name})
        end
      end
    end
    self.x_node = elements.length > 1 ? 'root' : "xx-#{template_to_node_name(elements[0])}"
    replace_right_cell(:replace_trees => trees_to_replace([:ot]))
  end

  def ot_add
    assert_privileges("orchestration_template_add")
    ot_type = x_node == "root" ? "ManageIQ::Providers::Amazon::CloudManager::OrchestrationTemplate" : node_name_to_template_name(x_node)
    @edit = {:new => {:type => ot_type}}
    @edit[:current] = @edit[:new].dup
    @edit[:key] = "ot_add__new"
    @right_cell_text = _("Adding a new Orchestration Template")
    @in_a_form = true
    replace_right_cell(:action => "ot_add")
  end

  def service_dialog_from_ot
    assert_privileges("service_dialog_from_ot")
    ot = OrchestrationTemplate.find(params[:id])
    @right_cell_text = _("Adding a new Service Dialog from Orchestration Template \"%{name}\"") % {:name => ot.name}
    # id for create service dialog from ot for react form
    @edit = {:rec_id => ot.id}
    @in_a_form = true
    replace_right_cell(:action => "service_dialog_from_ot")
  end

  def ot_show
    assert_privileges("orchestration_templates_view")
    id = params.delete(:id)
    ot = OrchestrationTemplate.find(id)
    self.x_active_tree = :ot_tree
    self.x_active_accord = 'ot'
    x_tree_init(:ot_tree, :ot, "OrchestrationTemplate") unless x_tree
    ot_type = template_to_node_name(ot)
    x_tree[:open_nodes].push("xx-#{ot_type}") unless x_tree[:open_nodes].include?("xx-#{ot_type}")
    self.x_node = "ot-#{ot.id}"
    x_tree[:open_nodes].push(x_node)
    add_flash(params[:flash_message]) if params.key?(:flash_message)
    explorer
  end

  private

  # Method to return the entry point name and its automation type
  # Used for summary and edit pages.
  def resource_action_entry_point(resource_action)
    cs_id = resource_action.configuration_script_id
    if cs_id
      workflow = ConfigurationScriptPayload.find_by(:id => cs_id)
      {:name => workflow&.name, :type => embedded_workflow_key, :configuration_script_id => cs_id}
    else
      {:name => resource_action.fqname, :type => embedded_automate_key, :configuration_script_id => nil}
    end
  end

  def build_tenants_tree
    tenants = @record ? @record.additional_tenants : Tenant.where(:id => @edit[:new][:tenant_ids])
    catalog_bundle = @edit.present? && @edit[:key] && @edit[:key].starts_with?('st_edit') # Get the info if adding/editing Catalog Item or Bundle; not important if only displaying
    TreeBuilderTenants.new('tenants_tree', @sb, true, :additional_tenants => tenants, :selectable => @edit.present?, :show_tenant_tree => ansible_playbook_type? || terraform_template_type?, :catalog_bundle => catalog_bundle)
  end

  def svc_catalog_provision_finish_submit_endpoint
    role_allows?(:feature => "miq_request_show_list", :any => true) ? "/miq_request/show_list" : "/catalog/explorer"
  end

  def ansible_playbook_type?
    prov_type = if params[:st_prov_type]
                  params[:st_prov_type]
                elsif @record
                  @record.prov_type
                elsif @edit
                  @edit[:new][:st_prov_type]
                end
    if prov_type == 'generic_ansible_playbook'
      @current_region = MiqRegion.my_region.region
    end
    prov_type == 'generic_ansible_playbook'
  end

  def terraform_template_type?
    prov_type = if params[:st_prov_type]
                  params[:st_prov_type]
                elsif @record
                  @record.prov_type
                elsif @edit
                  @edit[:new][:st_prov_type]
                end
    if prov_type == 'generic_terraform_template'
      @current_region = MiqRegion.my_region.region
    end
    prov_type == 'generic_terraform_template'
  end

  # Get all the available Catalogs
  def available_catalogs
    Rbac.filtered(ServiceTemplateCatalog.all).collect do |sc|
      if sc.tenant.present?
        tenant_names = []
        sc.tenant.ancestor_ids.map do |t|
          tenant_names.push(Tenant.find_by(:id => t).name)
        end
        tenant_names.push(sc.tenant.name)
        tenant_names = tenant_names.join("/")
      end
      [tenant_names.present? ? "#{tenant_names}/" + sc.name : sc.name, sc.id]
    end
  end

  def remove_resources_display(remove_resources)
    case remove_resources
    when 'no_without_playbook', 'no_with_playbook'
      _('No')
    when 'pre_with_playbook'
      _('Before Playbook runs')
    when 'post_with_playbook'
      _('After Playbook runs')
    else
      _('Yes')
    end
  end
  helper_method :remove_resources_display

  def features
    [
      {
        :role     => "svc_catalog_accord",
        :role_any => true,
        :name     => :svccat,
        :title    => _("Service Catalogs")
      },

      {
        :role     => "catalog_items_accord",
        :role_any => true,
        :name     => :sandt,
        :title    => _("Catalog Items")
      },
      {
        :role     => "orchestration_templates_accord",
        :role_any => true,
        :name     => :ot,
        :title    => _("Orchestration Templates")
      },
      {
        :role     => "st_catalog_accord",
        :role_any => true,
        :name     => :stcat,
        :title    => _("Catalogs")
      }
    ].map { |hsh| ApplicationController::Feature.new_with_hash(hsh) }
  end

  def class_service_template(prov_type)
    if content_library?
      ManageIQ::Providers::Vmware::InfraManager::OvfServiceTemplate
    elsif prov_type.starts_with?('generic')
      prov_type.gsub(/(generic)(_.*)?/, 'service_template\2').classify.constantize
    else
      ServiceTemplate
    end
  end

  def atomic_req_submit
    id = session[:edit][:req_id] || "new"
    return unless load_edit("prov_edit__#{id}", "show_list")

    if @edit[:new][:name].blank?
      # check for service template required fields before creating a request
      add_flash(_("Name is required"), :error)
    end
    if @edit[:new][:st_prov_type] == 'generic' && @edit[:new][:generic_subtype].blank?
      add_flash(_('Subtype is required.'), :error)
    end

    # for Ansible Tower items, check for Provider first
    if @edit[:new][:st_prov_type] == 'generic_ansible_tower' || @edit[:new][:st_prov_type] == 'generic_awx'
      if @edit[:new][:manager_id].blank?
        add_flash(_("Provider is required, please select one from the list"), :error)
      elsif @edit[:new][:template_id].blank?
        # ensure Job Template is selected as well, required field
        add_flash(_("Template is required, please select one from the list"), :error)
      end
    end

    # For Orchestration catalog item, reverse edit flow and check Template selection first
    if @edit[:new][:st_prov_type] == 'generic_orchestration'
      if @edit[:new][:template_id].blank?
        add_flash(_("Orchestration Template is required, please select one from the list"), :error)
      elsif @edit[:new][:manager_id].blank?
        # ensure Provider is selectied, required field
        add_flash(_("Provider is required, please select one from the list"), :error)
      end
    end

    # For Content Library OVF TEmplate catalog item
    if @edit[:new][:st_prov_type] == 'generic_ovf_template'
      add_flash(_("OVF Template is required, please select one from the list"), :error) if @edit[:new][:ovf_template_id].blank?
      add_flash(_("Resource Pool is required, please select one from the list"), :error) if @edit[:new][:resource_pool_id].blank?
      validate_vm_name if @edit[:new][:vm_name].present?
    end

    add_flash(_("Provisioning Entry Point is required"), :error) if @edit[:new][:fqname].blank?
    validate_price
    # Check for a Dialog if Display in Catalog is selected
    dialog_catalog_check

    # Check the validity of the entry points
    %i[fqname reconfigure_fqname retire_fqname].each do |fqname|
      type = entry_point_fields(fqname)[:type]
      if embedded_automate(@edit[:new][type])
        next if @edit[:new][fqname].blank? || !MiqAeClass.find_homonymic_instances_across_domains(current_user, @edit[:new][fqname]).empty?

        case fqname
        when :fqname
          add_flash(_('Please correct invalid Provisioning Entry Point prior to saving'), :error)
        when :reconfigure_fqname
          add_flash(_('Please correct invalid Reconfigure Entry Point prior to saving'), :error)
        when :retire_fqname
          add_flash(_('Please correct invalid Retirement Entry Point prior to saving'), :error)
        end
      end
    end

    # set request for non generic ST
    if @edit[:wf] && need_prov_dialogs?(@edit[:new][:st_prov_type])
      request = @edit[:wf].make_request(@edit[:req_id], @edit[:new])
      if request && request&.errors.present?
        request.errors.each do |error|
          add_flash("#{error.attribute.to_s.capitalize} #{error.message}", :error)
        end
      else
        validate_fields
      end
    end

    if @flash_array
      javascript_flash
      return
    end
    get_form_vars # need to get long_description
    if @edit[:new][:st_prov_type] == "generic_container_template"
      st = if @edit[:rec_id]
             ServiceTemplateContainerTemplate.find_by(:id => @edit[:rec_id]).update_catalog_item(add_container_template_vars)
           else
             ServiceTemplateContainerTemplate.create_catalog_item(add_container_template_vars)
           end
    elsif @edit[:new][:st_prov_type] == 'generic_ovf_template'
      st = if @edit[:rec_id]
             ManageIQ::Providers::Vmware::InfraManager::OvfServiceTemplate.find_by(:id => @edit[:rec_id]).update_catalog_item(set_record_vars_ovf_template)
           else
             ManageIQ::Providers::Vmware::InfraManager::OvfServiceTemplate.create_catalog_item(set_record_vars_ovf_template, User.current_user)
           end
    else
      st = if @edit[:rec_id]
             ServiceTemplate.find_by(:id => @edit[:rec_id])
           else
             class_service_template(@edit[:new][:st_prov_type]).new
           end
      common_st_record_vars(st)
      add_orchestration_template_vars(st) if st.kind_of?(ServiceTemplateOrchestration)
      add_ansible_tower_job_template_vars(st) if st.kind_of?(ServiceTemplateAnsibleTower) || st.kind_of?(ServiceTemplateAwx)
      add_server_profile_template_vars(st) if @edit[:new][:st_prov_type] == 'cisco_intersight'
      st.service_type = "atomic"

      if request
        st.remove_all_resources
        st.add_resource(request) if need_prov_dialogs?(@edit[:new][:st_prov_type])
      end
    end
    st.currency = @edit[:new][:currency] ? Currency.find_by(:id => @edit[:new][:currency].to_i) : nil
    st.price    = st.currency ? @edit[:new][:price] : nil if @edit[:new][:price]

    if st.save
      set_resource_action(st) unless st.kind_of?(ServiceTemplateContainerTemplate)
      flash_key = params[:button] == "save" ? _("Service Catalog Item \"%{name}\" was saved") : _("Service Catalog Item \"%{name}\" was added")
      add_flash(flash_key % {:name => @edit[:new][:name]})
      @changed = session[:changed] = false
      @in_a_form = false
      @edit = session[:edit] = @record = nil
      replace_right_cell(:replace_trees => trees_to_replace(%i[sandt svccat stcat]))
    else
      st.errors.each do |error|
        add_flash("#{error.attribute.to_s.capitalize} #{error.message}", :error)
      end
      @changed = session[:changed] = (@edit[:new] != @edit[:current])
      javascript_flash
    end
  end

  def service_template_list(scope, options = {})
    @no_checkboxes = x_active_tree == :svccat_tree
    if x_active_tree == :svccat_tree
      @gtl_small_tiles = true
      @row_button = true if role_allows?(:feature => 'svc_catalog_provision') # Show a button instead of the checkbox
      options[:gtl_dbname] = :catalog
    end
    options[:named_scope] = scope
    process_show_list(options)
  end

  def ot_edit_set_form_vars(right_cell_text)
    checked = find_checked_items
    checked[0] = params[:id] if checked.blank? && params[:id]
    @record = checked[0] ? find_record_with_rbac(OrchestrationTemplate, checked[0]) : OrchestrationTemplate.new
    @edit = {:current => {:name        => @record.name,
                          :description => @record.description,
                          :content     => @record.content,
                          :draft       => @record.draft,
                          :type        => @record.type,
                          :manager_id  => @record.ems_id},
             :rec_id  => @record.id}

    @edit[:current][:available_managers] = available_orchestration_managers_for_template_type(@record.type)
    @edit[:new] = @edit[:current].dup
    @edit[:key] = "ot_edit__#{@record.id}"
    @right_cell_text = right_cell_text % {:record_name => @record.name}
    @in_a_form = true
  end

  def st_catalog_set_form_vars
    checked = find_checked_items
    checked[0] = params[:id] if checked.blank? && params[:id]

    @record = checked[0] ? find_record_with_rbac(ServiceTemplateCatalog, checked[0]) : ServiceTemplateCatalog.new
    @right_cell_text = if @record.id
                         _("Editing Catalog \"%{name}\"") % {:name => @record.name}
                       else
                         _("Adding a new Catalog")
                       end
    @edit = {}
    @edit[:new] = {}
    @edit[:rec_id] = @record.id
    @edit[:new][:name] = @record.name
    @edit[:current] = {} # because of locking tree in replace_right_cell method
    @in_a_form = true
  end

  def st_catalog_delete
    assert_privileges("st_catalog_delete")
    elements = []
    if params[:id]
      elements.push(params[:id])
      process_elements(elements, ServiceTemplateCatalog, "destroy") unless elements.empty?
      self.x_node = "root"
    else # showing 1 element, delete it
      elements = find_checked_items
      if elements.empty?
        add_flash(_("No Catalogs were selected for deletion"), :error)
      end
      process_elements(elements, ServiceTemplateCatalog, "destroy") unless elements.empty?
    end
    params[:id] = nil
    replace_right_cell(:replace_trees => trees_to_replace(%i[sandt svccat stcat]))
  end

  def trees_to_replace(trees)
    trees_to_replace = []
    trees_to_replace.push(:stcat) if trees.include?(:stcat) && role_allows?(:feature => "st_catalog_accord")
    trees_to_replace.push(:sandt) if trees.include?(:sandt) && role_allows?(:feature => "catalog_items_view")
    trees_to_replace.push(:svccat) if trees.include?(:svccat) && role_allows?(:feature => "svc_catalog_accord")
    trees_to_replace.push(:ot) if trees.include?(:ot) &&
                                  role_allows?(:feature => "orchestration_templates_accord", :any => true)
    trees_to_replace
  end

  # Method to prepare the data needed for resource_actions
  # prefix[:name] = 'Provision' || 'Reconfigure' || 'Retirement'
  # prefix[:type] = :provision || :reconfigure || :retire
  # key           = :fqname || :reconfigure_fqname || :retire_fqname
  def entry_point_keys
    ENTRY_POINT_TYPES.map do |key, prefix|
      {
        :name               => prefix[:name],
        :automate_edit_key  => key,
        :type_key           => "#{prefix[:type]}_entry_point_type".to_sym,
        :workflows_edit_key => "#{prefix[:type]}_configuration_script_id".to_sym
      }
    end
  end

  def set_resource_action(st)
    d = @edit[:new][:dialog_id].nil? ? nil : Dialog.where(:id => @edit[:new][:dialog_id]).first

    entry_point_keys.each do |action|
      ra = st.resource_actions
             .create_with(
               :configuration_script_id => @edit[:new][action[:workflows_edit_key]],
               :ae_attributes           => {:service_action => action[:name]}
             )
             .find_or_initialize_by(:action => action[:name])
      if @edit[:new][action[:automate_edit_key]].blank? && @edit[action[:workflows_edit_key]].blank?
        st.resource_actions.where(:action => action[:name]).first.try(:destroy)
      else
        fqname                  = @edit[:new][action[:automate_edit_key]]  if @edit[:new][action[:type_key]] == embedded_automate_key
        configuration_script_id = @edit[:new][action[:workflows_edit_key]] if @edit[:new][action[:type_key]] == embedded_workflow_key
        ra.update!(:dialog => d, :fqname => fqname, :configuration_script_id => configuration_script_id)
      end
    end
  end

  # sets record variables common to both atomic and composite service templates
  def common_st_record_vars(st)
    st.name = @edit[:new][:name]
    st.description = @edit[:new][:description]
    st.long_description = @edit[:new][:display] ? @edit[:new][:long_description] : nil
    st.provision_cost = @edit[:new][:provision_cost]
    st.display = @edit[:new][:display]
    st.service_template_catalog = if @edit[:new][:catalog_id].blank?
                                    nil
                                  else
                                    ServiceTemplateCatalog.find(@edit[:new][:catalog_id])
                                  end
    st.prov_type = @edit[:new][:st_prov_type]
    st.generic_subtype = @edit[:new][:generic_subtype] if @edit[:new][:st_prov_type] == 'generic'
    st.zone_id = @edit[:new][:zone_id]
    st.additional_tenants = Tenant.where(:id => @edit[:new][:tenant_ids]) # Selected Additional Tenants in the tree
    st.currency = @edit[:new][:currency] ? Currency.find_by(:id => @edit[:new][:currency].to_i) : nil
    st.price    = st.currency ? @edit[:new][:price] : nil if @edit[:new][:price]
  end

  def st_set_record_vars(st)
    common_st_record_vars(st)
    st.remove_all_resources
    @add_rsc = true
    unless @edit[:new][:selected_resources].empty?
      @edit[:new][:selected_resources].each do |r|
        rsc = ServiceTemplate.find(r)
        @edit[:new][:rsc_groups].each_with_index do |groups, i|
          groups.each do |sr|
            options = {}
            options[:group_idx] = i
            options[:provision_index] = sr[:provision_index]
            options[:start_action] = sr[:start_action]
            options[:stop_action] = sr[:stop_action]
            options[:start_delay] = sr[:start_delay].to_i
            options[:stop_delay] = sr[:stop_delay].to_i
            options[:scaling_min] = sr[:scaling_min].to_i
            options[:scaling_max] = sr[:scaling_max].to_i
            next unless sr[:resource_id].to_s == rsc.id.to_s

            begin
              st.add_resource(rsc, options)
            rescue MiqException::MiqServiceCircularReferenceError => bang
              @add_rsc = false
              add_flash(_("Error during 'Resource Add': %{error_message}") %
                {:error_message => bang.message}, :error)
              break
            end
          end
        end
      end
    end
  end

  # common code for both st/at set_form_vars
  def set_form_vars
    @edit[:new][:name] = @record.name
    @edit[:new][:description] = @record.description
    @edit[:new][:long_description] = @record.long_description
    @edit[:new][:provision_cost] = @record.provision_cost
    @edit[:new][:display] = @record.display || false
    @edit[:new][:catalog_id] = @record.service_template_catalog.try(:id)
    @edit[:new][:dialog_id] = nil # initialize
    @edit[:new][:st_prov_type] ||= @record.prov_type
    @edit[:new][:generic_subtype] = @record.generic_subtype || "custom" if @edit[:new][:st_prov_type] == 'generic'
    @edit[:new][:tenant_ids] = @record.additional_tenant_ids
    @tenants_tree = build_tenants_tree # Build the tree with available tenants
    @available_catalogs = available_catalogs.sort # Get available catalogs with tenants and ancestors
    @additional_tenants = @edit[:new][:tenant_ids].map(&:to_s) # Get ids of selected Additional Tenants in the Tenants tree
    available_orchestration_templates if @record.kind_of?(ServiceTemplateOrchestration)
    available_ansible_tower_managers if @record.kind_of?(ServiceTemplateAnsibleTower) || @record.kind_of?(ServiceTemplateAwx)
    available_container_managers if @record.kind_of?(ServiceTemplateContainerTemplate)
    fetch_zones
    @edit[:new][:zone_id] = @record.zone_id

    @edit[:new][:currency] = @record.currency ? @record.currency.id : nil
    @edit[:new][:code_currency] = @record.currency ? code_currency_label(@record.currency.id) : _("Price / Month")
    @edit[:new][:price] = @record.price

    # initialize entry_point fields and its type to nil
    ENTRY_POINT_TYPES.each do |key, _prefix|
      fields = entry_point_fields(key)
      @edit[:new][key] = @edit[:new][fields[:type]] = @edit[:new][fields[:configuration_script_id]] = nil
      @edit[:new][fields[:previous]] = {:embedded_automate => nil, :embedded_workflow => nil}
      @edit[:new][fields[:type]] = default_entry_point_type
    end

    @record.resource_actions.each do |ra|
      @edit[:new][:dialog_id] = ra.dialog_id.to_i

      # To display the automation_type and its entry point values in edit page.
      entry_point = resource_action_entry_point(ra)

      if ra.action.downcase == 'provision'
        @edit[:new][:fqname] = entry_point[:name]
        @edit[:new][:provision_entry_point_type] = entry_point[:type]
        @edit[:new][:provision_configuration_script_id] = entry_point[:configuration_script_id]
      elsif ra.action.downcase == 'reconfigure'
        @edit[:new][:reconfigure_fqname] = entry_point[:name]
        @edit[:new][:reconfigure_entry_point_type] = entry_point[:type]
        @edit[:new][:reconfigure_configuration_script_id] = entry_point[:configuration_script_id]
      elsif ra.action.downcase == 'retirement'
        @edit[:new][:retire_fqname] = entry_point[:name]
        @edit[:new][:retire_entry_point_type] = entry_point[:type]
        @edit[:new][:retire_configuration_script_id] = entry_point[:configuration_script_id]
      end
    end
    load_available_dialogs
    @right_cell_text = if @record.id.blank?
                         _("Adding a new Service Catalog Item")
                       else
                         _("Editing Service Catalog Item \"%{name}\"") % {:name => @record.name}
                       end
    build_automate_tree(:automate_catalog) # Build Catalog Items tree
    form_available_vars_ovf_template if @record.kind_of?(ManageIQ::Providers::Vmware::InfraManager::OvfServiceTemplate)
  end

  def fetch_zones
    @zones = Zone.visible.in_my_region.order(Zone.arel_table[:description].lower).pluck(:description, :id)
  end

  def st_set_form_vars
    @edit = {}
    @edit[:rec_id] = @record.id
    @edit[:key] = "st_edit__#{@record.id || "new"}"
    @edit[:url] = "servicetemplate_edit"
    @edit[:new] = {}
    @edit[:current] = {}
    set_form_vars
    # Set the default entry points if the record not yet in the DB
    default_entry_point("generic", "composite") if @record.id.nil?
    @edit[:new][:service_type] = "composite"
    @edit[:new][:rsc_groups] = []
    @edit[:new][:selected_resources] = []

    len = @record.service_resources.size
    len.times do |l|
      next unless @record.group_has_resources?(l)

      @edit[:new][:rsc_groups][l] ||= []
      @record.each_group_resource(l) do |sr|
        @edit[:new][:selected_resources].push(sr.resource_id)
        # storing keys that are needed in ui in hash instead of storing an object
        r = {}
        r[:name] = sr.resource_name
        r[:id] = sr.id
        r[:resource_id] = sr.resource_id
        r[:start_action] = sr.start_action || "Power On"
        r[:stop_action] = sr.stop_action || "Shutdown"
        r[:start_delay] = sr.start_delay || 0
        r[:stop_delay] = sr.stop_delay || 0
        r[:scaling_min] = sr.scaling_min || 1
        r[:scaling_max] = sr.scaling_max || sr.scaling_min
        r[:provision_index] = sr.provision_index || 0
        @edit[:new][:rsc_groups][l].push(r)
      end
    end
    # add one extra group to show in pulldown so resources can be moved into it.
    @edit[:new][:rsc_groups].push([]) if @edit[:new][:selected_resources].length > 1
    @edit[:new][:provision_order] = recalculate_provision_order

    @edit[:new][:available_resources] = {}
    get_available_resources("ServiceTemplate")
    load_available_dialogs
    @edit[:current] = copy_hash(@edit[:new])
    @right_cell_text = if @record.id.blank?
                         _("Adding a new Catalog Bundle")
                       else
                         _("Editing Catalog Bundle \"%{name}\"") % {:name => @record.name}
                       end

    @in_a_form = true
  end

  def rearrange_groups_array
    # keep count of how many groups are deleted
    g_idx = 0
    # flag to check whether an empty group was deleted so next group elements can be moved up
    arr_delete = false

    @edit[:new][:rsc_groups].each_with_index do |group, i|
      if group.empty?
        g_idx = i
        arr_delete = true
      else
        # update group_idx of resources in group incase previous one got deleted
        @edit[:new][:rsc_groups].delete_at(g_idx) if arr_delete
        arr_delete = false
        g_idx = 0
      end
    end
    # delete any empty groups at the end of the groups array and leave only 1 empty group
    # i.e if on screen resources were assigned to group 1 & 2, pulldown had 1,2,3 in it, now if all resources were moved to group 1, get rid of 3 from pulldown
    prev = 0
    @edit[:new][:rsc_groups].each_with_index do |g, i|
      if i.zero?
        prev = g
      end
      if i.positive? && prev.empty? && g.empty?
        @edit[:new][:rsc_groups].delete_at(i)
      end
      prev = g
    end

    # add another empty element to groups array if it doesn't exist to keep one extra in group pulldown
    @edit[:new][:rsc_groups].push([]) if @edit[:new][:selected_resources].length > 1 && !@edit[:new][:rsc_groups][@edit[:new][:rsc_groups].length - 1].empty?
  end

  def get_available_resources(kls)
    @edit[:new][:available_resources] = {}
    Rbac.filtered(kls.constantize.public_service_templates.where("(type is null or type != 'ServiceTemplateAnsiblePlaybook') and service_type != 'composite'")).select(:id, :name).each do |r|
      # don't add the servicetemplate record that's being edited, or add all vm templates
      if r.id.to_s != @edit[:rec_id].to_s && !@edit[:new][:selected_resources].include?(r.id)
        @edit[:new][:available_resources][r.id] = r.name
      end
    end
  end

  # Returns true if the edit_new's field is 'embedded_automate'.
  def automate_field(edit_new, field)
    type = entry_point_fields(field)[:type]
    embedded_automate(edit_new[type])
  end

  # Method to set the entry_point's type, value and previous value.
  # type     = provision_entry_point_type || reconfigure_entry_point_type || retire_entry_point_type
  # previous = fqname_previous || reconfigure_fqname_previous || retire_fqname_previous
  def default_entry_point(prov_type, service_type)
    klass = class_service_template(prov_type)
    ENTRY_POINT_TYPES.each do |key, _prefix|
      fields            = entry_point_fields(key)
      type              = fields[:type]
      previous          = fields[:previous]

      # sets the type to embedded_automate || embedded_workflow
      @edit[:new][type] = params[type] || default_entry_point_type

      # sets the value of entry_point
      is_automate       = embedded_automate(@edit[:new][type])
      entry_point       = nil
      if is_automate
        entry_point = klass.default_provisioning_entry_point(service_type) if key == :fqname
        entry_point = klass.default_retirement_entry_point if key == :retire_fqname
        entry_point = klass.default_reconfiguration_entry_point if key == :reconfigure_fqname
      end
      @edit[:new][key] = is_automate ? entry_point : nil

      # sets the value of previously selected entry_point_value
      @edit[:new][previous] = {:embedded_automate => nil, :embedded_workflow => nil}
      previous_type = is_automate ? embedded_automate_key : embedded_workflow_key
      @edit[:new][previous][previous_type.to_sym] = @edit[:new][key]
    end
  end

  def get_form_vars
    copy_params_if_present(@edit[:new], params, %i[st_prov_type name description provision_cost catalog_id dialog_id generic_subtype long_description zone_id price retire_fqname reconfigure_fqname fqname])

    @edit[:new][:display] = params[:display] == "1" if params[:display] # @edit[:new][:display] should't be changed if params[:display] is not set
    # saving it in @edit as well, to use it later because prov_set_form_vars resets @edit[:new]
    @edit[:st_prov_type] = @edit[:new][:st_prov_type]
    @edit[:new][:long_description] = @edit[:new][:long_description].to_s + "..." if params[:transOne]
    fetch_zones
    checked_tenants if params[:check] # Save checked Additional Tenants to @edit

    @tenants_tree = build_tenants_tree # Build the tree with available tenants
    @available_catalogs = available_catalogs.sort # Get available catalogs with tenants and ancestors
    @additional_tenants = @edit[:new][:tenant_ids].map(&:to_s) # Get ids of selected Additional Tenants in the Tenants tree

    if params[:currency]
      @edit[:new][:currency] = params[:currency].blank? ? nil : params[:currency].to_i
      @edit[:new][:code_currency] = @edit[:new][:currency] ? code_currency_label(params[:currency]) : _('Price / Month')
    end

    if params[:server_profile_template_id]
      @edit[:new][:server_profile_template_id] = params[:server_profile_template_id]
    end

    field_changed = params[:form_field_changed] ? true : false

    ENTRY_POINT_TYPES.each do |key, prefix|
      type_key = "#{prefix[:type]}_entry_point_type".to_sym
      automation_type_changed = false
      if params[type_key]
        automation_type_changed = (params[type_key] != @edit[:new][type_key])
        # Assigns the new entry_point type when the select box is changed.
        @edit[:new][type_key] = params[type_key]
      end

      workflows_edit_key = "#{prefix[:type]}_configuration_script_id".to_sym
      @edit[:new][workflows_edit_key] = params[workflows_edit_key] if params[workflows_edit_key]

      restore_previous_entry_point(key, type_key) if field_changed && automation_type_changed
    end

    get_form_vars_orchestration if @edit[:new][:st_prov_type] == 'generic_orchestration'
    fetch_form_vars_ansible_or_ct if %w[generic_ansible_tower generic_awx generic_container_template].include?(@edit[:new][:st_prov_type])
    fetch_form_vars_ovf_template if @edit[:new][:st_prov_type] == 'generic_ovf_template'
    fetch_form_vars_server_profile_templates if @edit[:new][:st_prov_type] == 'cisco_intersight'
  end

  # Method to display previously selected entry_point when automation_type is changed.
  def restore_previous_entry_point(key, type_key)
    current_entry_point = @edit[:new][key]
    previous_type = embedded_automate(params[type_key]) ? embedded_workflow_key : embedded_automate_key
    @edit[:new][key] = @edit[:new]["#{key}_previous".to_sym][params[type_key].to_sym]
    @edit[:new]["#{key}_previous".to_sym][previous_type.to_sym] = current_entry_point
  end

  def code_currency_label(currency)
    _('Price / Month (in %{currency})') % {:currency => Currency.find(currency).code}
  end

  def checked_tenants
    new_id = params[:id].split('-').pop.to_i if params[:id].starts_with?('tn')
    tenant = Tenant.find(new_id)
    new_ids = [new_id] + tenant.descendants.pluck(:id)
    tenant_ids = @edit[:new][:tenant_ids]
    if params[:check] == '1' # Adding/checking Tenant(s) in the tree for the Catalog Item
      tenant_ids += new_ids
    elsif params[:check] == '0' # Unchecking selected Tenant(s)
      new_ids += tenant.ancestors.pluck(:id)
      new_ids.each { |t| tenant_ids.delete(t) }
    end
    @edit[:new][:tenant_ids] = tenant_ids.sort.uniq
  end

  def available_container_managers
    @edit[:new][:available_managers] =
      ManageIQ::Providers::ContainerManager.all.collect { |t| [t.name, t.id] }.sort
    ct = ContainerTemplate.find_by(:id => @record.config_info[:provision][:container_template_id]) if @record.config_info[:provision] && @record.config_info[:provision][:container_template_id]
    @edit[:new][:template_id] = ct.try(:id)
    @edit[:new][:manager_id] = ct.try(:ext_management_system).try(:id)
    available_container_templates(@edit[:new][:manager_id]) if @edit[:new][:manager_id]
  end

  def get_form_vars_orchestration
    if params[:template_id]
      if params[:template_id] == ""
        @edit[:new][:available_managers] = []
        @edit[:new][:template_id]        = nil
        @edit[:new][:manager_id]         = nil
      else
        @edit[:new][:template_id] = params[:template_id]
        available_orchestration_managers(params[:template_id])
      end
    end
    @edit[:new][:manager_id] = params[:manager_id] if params[:manager_id]
  end

  def fetch_form_vars_ansible_or_ct
    if params[:manager_id]
      if params[:manager_id] == ""
        @edit[:new][:available_templates] = []
        @edit[:new][:template_id]         = nil
        @edit[:new][:manager_id]          = nil
      else
        @edit[:new][:manager_id] = params[:manager_id]
        available_job_templates(params[:manager_id]) if @edit[:new][:st_prov_type] == 'generic_ansible_tower' || @edit[:new][:st_prov_type] == 'generic_awx'
        available_container_templates(params[:manager_id]) if @edit[:new][:st_prov_type] == 'generic_container_template'
      end
    end
    @edit[:new][:template_id] = params[:template_id] if params[:template_id]
  end

  def available_orchestration_managers_for_template_type(template_type)
    template_type = template_type.to_s.safe_constantize
    return [] unless template_type && template_type < OrchestrationTemplate

    template_type.eligible_managers.collect { |m| [m.name, m.id] }.sort
  end

  def available_orchestration_managers(template_id)
    @edit[:new][:available_managers] = OrchestrationTemplate.find(template_id)
                                                            .eligible_managers
                                                            .collect { |m| [m.name, m.id] }
                                                            .sort
  end

  def available_orchestration_templates
    @edit[:new][:available_templates] = OrchestrationTemplate.available
                                                             .collect { |t| [t.name.to_s, t.id] }
                                                             .sort
    @edit[:new][:template_id] = @record.orchestration_template.try(:id)
    @edit[:new][:manager_id] = @record.orchestration_manager.try(:id)
    available_orchestration_managers(@record.orchestration_template.id) if @record.orchestration_template
  end

  def available_container_templates(manager_id)
    method = @edit[:new][:st_prov_type] == 'generic_ansible_tower' || @edit[:new][:st_prov_type] == 'generic_awx' ? 'configuration_scripts' : 'container_templates'
    @edit[:new][:available_templates] =
      ExtManagementSystem.find_by(:id => manager_id).send(method).collect { |t| [t.name, t.id] }.sort
  end

  def available_job_templates(manager_id)
    @edit[:new][:available_templates] = []
    all_job_templates, all_workflow_templates = fetch_all_templates(manager_id)
    @edit[:new][:available_templates].push(["",
                                            [["<#{_('Choose a Template')}>",
                                              :selected => "<#{_('Choose a Template')}>",
                                              :disabled => "<#{_('Choose a Template')}>",
                                              :style    => 'display:none']]])
    @edit[:new][:available_templates].push(["Job Templates", all_job_templates]) if all_job_templates.present?
    @edit[:new][:available_templates].push(["Workflow Templates", all_workflow_templates]) if all_workflow_templates.present?
  end

  def fetch_all_templates(manager_id)
    all_templates = ExtManagementSystem.find_by(:id => manager_id).configuration_scripts.sort_by(&:name)
    workflow_templates = all_templates.collect { |t| [t.name, t.id] if t.kind_of?(ManageIQ::Providers::AutomationManager::ConfigurationWorkflow) }.compact
    job_templates = all_templates.collect { |t| [t.name, t.id] if t.kind_of?(ManageIQ::Providers::AutomationManager::ConfigurationScript) }.compact - workflow_templates
    return job_templates, workflow_templates
  end

  def available_ansible_tower_managers
    @edit[:new][:available_managers] =
      ManageIQ::Providers::AutomationManager.all.collect { |t| [t.name, t.id] }.sort
    @edit[:new][:template_id] = @record.job_template.try(:id)
    @edit[:new][:manager_id] = @record.job_template.try(:manager).try(:id)
    available_job_templates(@edit[:new][:manager_id]) if @edit[:new][:manager_id]
  end

  def add_orchestration_template_vars(st)
    st.orchestration_template = @edit[:new][:template_id].nil? ? nil : OrchestrationTemplate.find(@edit[:new][:template_id])
    st.orchestration_manager  = @edit[:new][:manager_id].nil? ? nil : ExtManagementSystem.find(@edit[:new][:manager_id])
  end

  def add_ansible_tower_job_template_vars(st)
    st.job_template = @edit[:new][:template_id].nil? ? nil : ConfigurationScript.find(@edit[:new][:template_id])
  end

  def add_server_profile_template_vars(service_template)
    service_template.options[:server_profile_template_id] = @edit[:new][:server_profile_template_id].nil? ? nil : @edit[:new][:server_profile_template_id]
  end

  def add_container_template_vars
    st_options = {}
    st_options[:name] = @edit[:new][:name]
    st_options[:description] = @edit[:new][:description]
    st_options[:long_description] = @edit[:new][:display] ? @edit[:new][:long_description] : nil
    st_options[:provision_cost] = @edit[:new][:provision_cost]
    st_options[:display] = @edit[:new][:display]

    st_options[:service_template_catalog_id] = @edit[:new][:catalog_id].nil? ? nil : @edit[:new][:catalog_id]
    st_options[:config_info] = {
      :provision => {
        :container_template_id => @edit[:new][:template_id],
        :dialog_id             => @edit[:new][:dialog_id]
      }
    }
    provision = st_options[:config_info][:provision]
    provision[:fqname] = @edit[:new][:fqname] if @edit[:new][:fqname]
    provision[:reconfigure_fqname] = @edit[:new][:reconfigure_fqname] if @edit[:new][:reconfigure_fqname]
    provision[:retire_fqname] = @edit[:new][:retire_fqname] if @edit[:new][:retire_fqname]
    st_options
  end

  def st_get_form_vars
    get_form_vars
    if params[:resource_id]
      # adding new service resource, so need to lookup actual vm or service template record and set defaults
      sr = ServiceTemplate.find(params[:resource_id])
      # storing keys that are needed in ui in hash instead of storing an object
      r = {}
      r[:name] = sr.name
      r[:id] = sr.id
      r[:resource_id] = sr.id
      r[:start_action] = "Power On"
      r[:stop_action] = "Shutdown"
      r[:start_delay] = 0
      r[:stop_delay] = 0
      r[:scaling_min] = 1
      r[:scaling_max] = r[:scaling_min]
      r[:provision_index] = 0
      @edit[:new][:selected_resources].push(sr.id) unless @edit[:new][:selected_resources].include?(sr.id)
      @edit[:new][:rsc_groups][0] ||= [] # initialize array is adding new record

      # add another empty element to groups array if it doesn't exist to keep one extra in group pulldown
      @edit[:new][:rsc_groups].push([]) if @edit[:new][:selected_resources].length > 1 && !@edit[:new][:rsc_groups][@edit[:new][:rsc_groups].length - 1].empty?

      # push a new resource into highest existing/populated group
      @edit[:new][:rsc_groups].each_with_index do |g, i|
        next if g.present?

        id = i.zero? ? 0 : i - 1
        @edit[:new][:rsc_groups][id].push(r) unless @edit[:new][:rsc_groups][id].include?(r)
        break
      end
      @edit[:new][:provision_order] = recalculate_provision_order
    else
      # check if group idx change transaction came in
      params.each do |var, val|
        vars = var.split("_")
        if vars[0] == "gidx"
          rid = vars[1]
          # push a new resource into highest existing/populated group
          @group_changed = false
          @edit[:new][:rsc_groups].each_with_index do |groups, i|
            groups.each do |g|
              next unless g[:id].to_i == rid.to_i

              @edit[:new][:rsc_groups][val.to_i - 1].push(g)
              @edit[:new][:rsc_groups][i].delete(g)
              @group_changed = true
              break
            end
            break if @group_changed
          end

          rearrange_groups_array

          # setting flag to check whether to refresh screen
          @group_idx = true
        else
          param_name = [vars[0], vars[1]].join('_')
          keys = %w[provision_index scaling_max scaling_min start_action start_delay stop_action stop_delay]
          if keys.include?(param_name)
            @edit[:new][:rsc_groups].each_with_index do |groups, i|
              groups.sort_by { |gr| gr[:name].downcase }.each_with_index do |g, k|
                keys.each do |key|
                  param_key   = "#{key}_#{i}_#{k}".to_sym
                  param_value = params[param_key]
                  key         = key.to_sym

                  # convert start/stop delay into seconds, need to convert other values to_i
                  case key
                  when :start_delay, :stop_delay
                    g[key] = param_value.to_i * 60 if param_value
                  when :scaling_min
                    g[key] = param_value.to_i if param_value
                    # set flag to true so screen can be refreshed to adjust scaling_max pull down
                    g[:scaling_max] = g[:scaling_min] if g[:scaling_max] < g[:scaling_min]
                    @group_idx = true
                  when :scaling_max
                    g[key] = param_value.to_i if param_value
                  when :provision_index
                    if param_value
                      p_index = @edit[:new][:rsc_groups].flatten.collect { |rg| rg[:provision_index].to_i }.sort

                      # if index that came in is being used more than once
                      if p_index.count(g[key]) > 1
                        g[key] = param_value.to_i - 1
                      elsif p_index.count(g[key]) == 1
                        # if index being changed occur once
                        # rearrange all provision order values
                        rearrange_provision_order(@edit[:new][:rsc_groups], g[key])
                        g[key] = if param_value.to_i > p_index.last
                                   p_index.last
                                 else
                                   param_value.to_i - 1
                                 end
                      end
                      # recalculate values for pull-down
                      @edit[:new][:provision_order] = recalculate_provision_order
                    end
                  else
                    g[key] = param_value if param_value
                  end
                end
              end
            end
          end
        end
      end
    end

    # recalculate available resources, if resource id selected
    get_available_resources("ServiceTemplate") if params[:resource_id]
    @in_a_form = true
  end

  # building/rebuilding provision order pull down
  # add one extra number in pull down
  def recalculate_provision_order
    order = @edit[:new][:rsc_groups].flatten.collect { |r| r[:provision_index].to_i }.sort.uniq
    order.empty? ? order.push(1) : order.push(order.last + 1)
  end

  # rearrange provision order values so numbers aren't skipped
  def rearrange_provision_order(resources, current_index_value)
    resources.flatten.collect do |group|
      group[:provision_index] -= 1 if group[:provision_index] > current_index_value
    end
  end

  ROOT_NODE_MODELS = {
    :svccat_tree => "Service",                # TreeBuilderServiceCatalog "Service Catalogs"
    :sandt_tree  => "ServiceTemplate",        # TreeBuilderCatalogItems   "Catalog Items"
    :ot_tree     => "OrchestrationTemplate",  # TreeBuilderOrchestrationTemplates "Orch. Templates"
    :stcat_tree  => "ServiceTemplateCatalog", # TreeBuilderCatalogs       "Catalogs"
  }.freeze

  def root_node_model(tree)
    ROOT_NODE_MODELS[tree]
  end

  def root_node_right_cell_text(tree)
    case tree
    when :svccat_tree
      _('All Services')
    when :sandt_tree
      _('All Catalog Items')
    when :ot_tree
      _('All Orchestration Templates')
    when :stcat_tree
      _('All Catalogs')
    end
  end

  def get_node_info_handle_root_node
    if x_active_tree == :svccat_tree
      service_template_list(%i[displayed with_existent_service_template_catalog_id public_service_templates], :no_checkboxes => true)
    else
      process_show_list(get_show_list_options(root_node_model(x_active_tree)))
    end
    @right_cell_text = root_node_right_cell_text(x_active_tree)
  end

  def get_show_list_options(typ)
    options = {:model => typ&.constantize}
    if x_active_tree == :sandt_tree
      options[:named_scope] = :public_service_templates
    elsif x_active_tree == :ot_tree
      options[:named_scope] = :orderable
    end
    options
  end

  def get_node_info_handle_ot_folder_nodes
    typ = node_name_to_template_name(x_node)
    @right_cell_text = _("All %{models}") % {:models => ui_lookup(:models => typ)}
    options = {:model       => typ.constantize,
               :gtl_dbname  => :orchestrationtemplate,
               :named_scope => :orderable}
    process_show_list(options)
  end

  def get_node_info_handle_simple_leaf_node(id)
    show_record(id)
    @right_cell_text = _("%{model} \"%{name}\"") % {:name => @record.name, :model => ui_lookup(:model => TreeBuilder.get_model_for_prefix(@nodetype))}
  end

  def get_node_info_handle_unassigned_node
    scope = [:public_service_templates, [:without_service_template_catalog_id]]
    service_template_list(scope, :no_order_button => true)
    @right_cell_text = _("Services in Catalog \"Unassigned\"")
  end

  def get_node_info_handle_stc_node(id)
    scope = if x_active_tree == :sandt_tree
              # catalog items accordion also shows the non-"Display in Catalog" items
              [:public_service_templates, [:with_service_template_catalog_id, id]]
            else
              [:displayed, [:with_service_template_catalog_id, id]]
            end
    service_template_list(scope, :no_order_button => true)
    stc = ServiceTemplateCatalog.find(id)
    @right_cell_text = _("Services in Catalog \"%{name}\"") % {:name => stc.name}
  end

  def get_node_info_handle_leaf_node_stcat(id)
    @record = ServiceTemplateCatalog.find(id)
    @record_service_templates = Rbac.filtered(@record.service_templates, :named_scope => :public_service_templates)
    typ = TreeBuilder.get_model_for_prefix(@nodetype)
    @right_cell_text = _("%{model} \"%{name}\"") % {:name => @record.name, :model => ui_lookup(:model => typ)}
  end

  def get_node_info_handle_leaf_node_ot(id)
    @record = OrchestrationTemplate.find(id)
    @right_cell_text = _("%{model} \"%{name}\"") % {:name  => @record.name,
                                                    :model => ui_lookup(:model => @record.class.name)}
  end

  def get_node_info_handle_leaf_node(id)
    show_record(id)
    if @record.atomic? && need_prov_dialogs?(@record.prov_type)
      @miq_request = MiqRequest.find_by(:id => @record.service_resources[0].resource_id) if @record.service_resources[0]&.resource_id
      if @miq_request
        prov_set_show_vars
      else
        @options   = nil
        @no_wf_msg = _("Request is missing for selected item")
      end
    end
    unless @record.prov_type == "generic_ansible_playbook" || @record.prov_type == "generic_terraform_template"
      @sb[:dialog_label]       = _("No Dialog")
      @sb[:fqname]             = nil
      @sb[:reconfigure_fqname] = nil
      @sb[:retire_fqname]      = nil
      @record.resource_actions.each do |ra|
        d = Dialog.where(:id => ra.dialog_id).first

        # To display the automation_type and its entry point values in summary page.
        entry_point = resource_action_entry_point(ra)

        @sb[:dialog_label] = d.label if d
        case ra.action.downcase
        when 'provision'
          @sb[:fqname] = entry_point[:name]
          @sb[:provision_entry_point_type] = entry_point[:type]
          @sb[:provision_configuration_script_id] = entry_point[:configuration_script_id]
        when 'reconfigure'
          @sb[:reconfigure_fqname] = entry_point[:name]
          @sb[:reconfigure_entry_point_type] = entry_point[:type]
          @sb[:reconfigure_configuration_script_id] = entry_point[:configuration_script_id]
        when 'retirement'
          @sb[:retire_fqname] = entry_point[:name]
          @sb[:retire_entry_point_type] = entry_point[:type]
          @sb[:retire_configuration_script_id] = entry_point[:configuration_script_id]
        end
      end
      # saving values of ServiceTemplate catalog id and resource that are needed in view to build the link
      @sb[:stc_nodes] = {}
      @record.service_resources.each do |r|
        st = ServiceTemplate.find_by(:id => r.resource_id)
        @sb[:stc_nodes][r.resource_id] = st.service_template_catalog_id || "Unassigned" unless st.nil?
      end
    end
    if params[:action] == "x_show"
      prefix = @record.service_template_catalog_id ? "stc-#{@record.service_template_catalog_id}" : "-Unassigned"
      self.x_node = "#{prefix}_#{params[:id]}"
    end
    typ = x_active_tree == :svccat_tree ? "Service" : TreeBuilder.get_model_for_prefix(@nodetype)
    @right_cell_text = _("%{model} \"%{name}\"") % {:name => @record.name, :model => ui_lookup(:model => typ)}
  end

  # Get all info for the node about to be displayed
  def get_node_info(treenodeid, _show_list = true)
    @explorer ||= true
    @nodetype, id = parse_nodetype_and_id(valid_active_node(treenodeid))
    # saving this so it can be used while adding buttons/groups in buttons editor
    @sb[:applies_to_id] = id
    if %w[cb cbg].include?(@nodetype)
      # buttons folder or nodes under that were clicked
      build_resolve_screen
      buttons_get_node_info(treenodeid)
    else
      @sb[:buttons_node] = false
      if %w[Vm MiqTemplate ServiceResource].include?(TreeBuilder.get_model_for_prefix(@nodetype))
        get_node_info_handle_simple_leaf_node(id)
      elsif x_node == "root"
        get_node_info_handle_root_node
      elsif %w[xx-otcfn xx-othot xx-otazu xx-otazs xx-otvnf xx-otvap xx-otovf].include?(x_node)
        get_node_info_handle_ot_folder_nodes
      elsif x_active_tree == :stcat_tree
        get_node_info_handle_leaf_node_stcat(id)
      elsif x_active_tree == :ot_tree
        get_node_info_handle_leaf_node_ot(id)
      elsif id == "Unassigned"
        get_node_info_handle_unassigned_node
      elsif @nodetype == "stc"
        get_node_info_handle_stc_node(id)
      else
        get_node_info_handle_leaf_node(id)
      end
    end
    {:view => @view, :pages => @pages}
  end

  def fetch_ct_details
    ct_details = {}
    provision = @record.config_info[:provision]
    ct_details[:provisioning] = {}
    ct = ContainerTemplate.find_by(:id => provision[:container_template_id])
    ct_details[:provisioning][:template_name] = ct.try(:name)
    ct_details[:provisioning][:provider_name] = ct.try(:ext_management_system).try(:name)
    ct_details
  end

  def content_library_type?
    prov_type = if params[:st_prov_type]
                  params[:st_prov_type]
                elsif @record
                  @record.prov_type
                elsif @edit
                  @edit[:new][:st_prov_type]
                end
    prov_type == 'generic_ovf_template'
  end

  def content_library?
    content_library = content_library_type?
    @current_region = MiqRegion.my_region.region if content_library
    content_library
  end
  helper_method :content_library?

  def fetch_ovf_template_details
    ovf_template_details = {}
    ovf_template_details[:provisioning] = {}
    provision = @record.config_info[:provision]

    rp = ResourcePool.find_by(:id => provision[:resource_pool_id])
    ovf_template_details[:provisioning][:resource_pool_name] = rp.try(:name)

    dc = Datacenter.find_by(:id => provision[:datacenter_id])
    ovf_template_details[:provisioning][:datacenter_name] = dc.try(:name)

    host = Host.find_by(:id => provision[:host_id])
    ovf_template_details[:provisioning][:host_name] = host.try(:name)

    storage = Storage.find_by(:id => provision[:storage_id])
    ovf_template_details[:provisioning][:storage_name] = storage.try(:name)

    network = Lan.find_by(:id => provision[:network_id])
    ovf_template_details[:provisioning][:network_name] = network.try(:name)

    ovf_template_details[:provisioning][:disk_format] = provision[:disk_format]

    folder =
      if dc
        dc.folders.find { |f| f.name == 'vm' }.try(:ems_ref)
      else
        EmsFolder.find_by(:id => provision[:ems_folder_id]).try(:name)
      end
    ovf_template_details[:provisioning][:ems_folder_name] = folder if folder

    ovf_template = ManageIQ::Providers::Vmware::InfraManager::OrchestrationTemplate.find_by(:id => provision[:ovf_template_id])
    ovf_template_details[:provisioning][:ovf_template_name] = ovf_template.try(:name)

    ovf_template_details
  end

  def fetch_form_vars_ovf_template
    @edit[:new][:accept_all_eula] = params[:accept_all_eula] == "1" if params[:accept_all_eula]
    copy_params_if_present(@edit[:new], params, %i[datacenter_id disk_format ems_folder_id host_id network_id ovf_template_id resource_pool_id storage_id vm_name])
    form_available_vars_ovf_template if params[:st_prov_type] || params[:ovf_template_id]
  end

  def form_available_vars_ovf_template
    @edit[:available_ovf_templates] = ManageIQ::Providers::Vmware::InfraManager::OrchestrationTemplate.all
                                                                                                      .collect { |m| [m.name, m.id] }
                                                                                                      .sort
    @edit[:disk_formats] = {
      "thick"            => _("thick - Lazy Zero"),
      "eagerZeroedThick" => _("thick - Eager Zero"),
      "thin"             => _("thin")
    }

    # set from existing record
    if @record.try(:id) && params[:button] != "save"
      options = @record.config_info[:provision]
      @edit[:new][:ovf_template_id] ||= options[:ovf_template_id]
      @edit[:new][:datacenter_id] ||= options[:datacenter_id]
      @edit[:new][:vm_name] ||= options[:vm_name]
      @edit[:new][:resource_pool_id] ||= options[:resource_pool_id]
      @edit[:new][:ems_folder_id] ||= options[:ems_folder_id]
      @edit[:new][:host_id] ||= options[:host_id]
      @edit[:new][:storage_id] ||= options[:storage_id]
      @edit[:new][:disk_format] ||= options[:disk_format]
      @edit[:new][:network_id] ||= options[:network_id]
      @edit[:new][:accept_all_eula] ||= options[:accept_all_eula] == true
      @edit[:new][:fqname] ||= options[:fqname]
    end

    if @edit[:new][:ovf_template_id]
      ovf_template = ManageIQ::Providers::Vmware::InfraManager::OrchestrationTemplate.find_by(:id => @edit[:new][:ovf_template_id])
      @edit[:available_datacenters] = ovf_template.allowed_datacenters
                                                  .collect { |m| [m.last, m.first] }
                                                  .sort
      @edit[:available_resource_pools] = ovf_template.allowed_resource_pools
                                                     .collect { |m| [m.last, m.first] }
                                                     .sort
      @edit[:available_folders] = ovf_template.allowed_folders
                                              .collect { |m| [m.last, m.first] }
                                              .sort
      @edit[:available_hosts] = ovf_template.allowed_hosts
                                            .collect { |h| [h.name, h.id] }
                                            .sort
      @edit[:available_storages] = ovf_template.allowed_storages
                                               .collect { |s| [s.name, s.id] }
                                               .sort
      @edit[:available_vlans] = ovf_template.allowed_vlans
                                            .collect { |v| [v.last, v.first] }
                                            .sort
    else
      @edit[:available_resource_pools] = []
      @edit[:available_datacenters]    = []
      @edit[:available_folders]        = []
      @edit[:available_hosts]          = []
      @edit[:available_storages]       = []
      @edit[:available_vlans]          = []
      @edit[:new][:resource_pool_id]   = nil
      @edit[:new][:datacenter_id]      = nil
      @edit[:new][:host_id]            = nil
      @edit[:new][:storage_id]         = nil
      @edit[:new][:disk_format]        = nil
      @edit[:new][:network_id]         = nil
      @edit[:new][:ems_folder_id]      = nil
    end
  end

  def set_record_vars_ovf_template
    options = {}
    options[:name] = @edit[:new][:name]
    options[:description] = @edit[:new][:description]
    options[:long_description] = @edit[:new][:display] ? @edit[:new][:long_description] : nil
    options[:provision_cost] = @edit[:new][:provision_cost]
    options[:display] = @edit[:new][:display]
    options[:zone_id] = @edit[:new][:zone_id] if @edit[:new][:zone_id]
    options[:additional_tenants] = Tenant.where(:id => @edit[:new][:tenant_ids]) if @edit[:new][:tenant_ids]
    options[:service_template_catalog_id] = @edit[:new][:catalog_id].nil? ? nil : @edit[:new][:catalog_id]
    provision = {}
    provision[:ovf_template_id] = @edit[:new][:ovf_template_id] if @edit[:new][:ovf_template_id]
    provision[:datacenter_id] = @edit[:new][:datacenter_id] if @edit[:new][:datacenter_id]
    provision[:vm_name] = @edit[:new][:vm_name] if @edit[:new][:vm_name]
    provision[:resource_pool_id] = @edit[:new][:resource_pool_id] if @edit[:new][:resource_pool_id]
    provision[:ems_folder_id] = @edit[:new][:ems_folder_id] if @edit[:new][:ems_folder_id]
    provision[:host_id] = @edit[:new][:host_id] if @edit[:new][:host_id]
    provision[:storage_id] = @edit[:new][:storage_id] if @edit[:new][:storage_id]
    provision[:disk_format] = @edit[:new][:disk_format] if @edit[:new][:disk_format]
    provision[:network_id] = @edit[:new][:network_id] if @edit[:new][:network_id]
    provision[:accept_all_eula] = @edit[:new][:accept_all_eula] if @edit[:new][:accept_all_eula]
    provision[:fqname] = @edit[:new][:fqname] if @edit[:new][:fqname]
    options[:config_info] = {:provision => provision}
    options
  end

  def need_ovf_template_locals?
    x_active_tree == :sandt_tree &&
      TreeBuilder.get_model_for_prefix(@nodetype) == "ServiceTemplate" &&
      @record.prov_type == "generic_ovf_template"
  end

  def validate_vm_name
    ems_id = ManageIQ::Providers::Vmware::InfraManager::OrchestrationTemplate.find_by(:id => @edit[:new][:ovf_template_id]).ems_id
    add_flash(_("VM Name already exists, Please select a different VM Name"), :error) if VmOrTemplate.find_by(:name => @edit[:new][:vm_name], :ems_id => ems_id).present?
  end

  def fetch_form_vars_server_profile_templates
    form_available_server_profile_templates if params[:st_prov_type]
  end

  def form_available_server_profile_templates
    @edit[:available_server_profile_templates] = PhysicalServerProfileTemplate.all.collect { |m| [m.name, m.id] }.sort
  end

  def automate_tree_needed?
    options = %i[display template_id manager_id ovf_template_id datacenter_id resource_pool_id ems_folder_id host_id storage_id]
    options.any? { |x| params[x] }
  end
  helper_method :automate_tree_needed?

  def fetch_playbook_details
    playbook_details = {}
    provision = @record.config_info[:provision]
    provisioning_details = {}
    provisioning_details[:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource, provision[:repository_id])
    provisioning_details[:playbook] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook, provision[:playbook_id])
    provisioning_details[:machine_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential, provision[:credential_id])
    provisioning_details[:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential, provision[:network_credential_id]) if provision[:network_credential_id]
    provisioning_details[:cloud_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::CloudCredential, provision[:cloud_credential_id]) if provision[:cloud_credential_id]
    provisioning_details[:vault_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::VaultCredential, provision[:vault_credential_id]) if provision[:vault_credential_id]
    provisioning_details[:execution_ttl] = provision[:execution_ttl]
    provisioning_details[:verbosity] = provision[:verbosity]
    provisioning_details[:log_output] = provision[:log_output]
    provisioning_details[:become_enabled] = provision[:become_enabled] == true ? _('Yes') : _('No')
    playbook_details[:provisioning] = provisioning_details
    fetch_dialog(playbook_details, provision[:dialog_id], :provisioning)

    if @record.config_info[:retirement]
      retirement = @record.config_info[:retirement]
      retirement_details = {}
      retirement_details[:remove_resources] = retirement[:remove_resources]
      if retirement[:repository_id]
        retirement_details[:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource, retirement[:repository_id])
        retirement_details[:playbook] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook, retirement[:playbook_id])
        retirement_details[:machine_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential, retirement[:credential_id])
        retirement_details[:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential, retirement[:network_credential_id]) if retirement[:network_credential_id]
        retirement_details[:cloud_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::CloudCredential, retirement[:cloud_credential_id]) if retirement[:cloud_credential_id]
        retirement_details[:vault_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::VaultCredential, retirement[:vault_credential_id]) if retirement[:vault_credential_id]
      end
      retirement_details[:execution_ttl] = retirement[:execution_ttl]
      retirement_details[:verbosity] = retirement[:verbosity]
      retirement_details[:log_output] = retirement[:log_output]
      retirement_details[:become_enabled] = retirement[:become_enabled] == true ? _('Yes') : _('No')
      playbook_details[:retirement] = retirement_details
    end
    playbook_details
  end

  def fetch_terraform_template_details
    terraform_template_details = {}
    provision = @record.config_info[:provision]
    provisioning_details = {}
    provisioning_details[:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::ConfigurationScriptSource, provision[:repository_id])
    provisioning_details[:template] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::ConfigurationScriptPayload, provision[:configuration_script_payload_id])
    provisioning_details[:credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Credential, provision[:credential_id])
    provisioning_details[:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::NetworkCredential, provision[:network_credential_id]) if provision[:network_credential_id]
    provisioning_details[:execution_ttl] = provision[:execution_ttl]
    provisioning_details[:verbosity] = provision[:verbosity]
    provisioning_details[:log_output] = provision[:log_output]
    provisioning_details[:become_enabled] = provision[:become_enabled] == true ? _('Yes') : _('No')
    terraform_template_details[:provisioning] = provisioning_details
    fetch_dialog(terraform_template_details, provision[:dialog_id], :provisioning)

    # NOTE: This code is commented out since the retirement tab is not needed yet
    # if @record.config_info[:retirement]
    #   retirement = @record.config_info[:retirement]
    #   terraform_template_details[:retirement] = {}
    #   terraform_template_details[:retirement][:remove_resources] = retirement[:remove_resources]
    #   if retirement[:repository_id]
    #     terraform_template_details[:retirement][:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::ConfigurationScriptSource, retirement[:repository_id])
    #     terraform_template_details[:retirement][:template] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::ConfigurationScriptPayload, retirement[:configuration_script_payload_id])
    #     terraform_template_details[:retirement][:credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Credential, retirement[:credential_id])
    #     terraform_template_details[:retirement][:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::NetworkCredential, retirement[:network_credential_id]) if retirement[:network_credential_id]
    #   end
    #   terraform_template_details[:retirement][:execution_ttl] = retirement[:execution_ttl]
    #   terraform_template_details[:retirement][:verbosity] = retirement[:verbosity]
    #   terraform_template_details[:retirement][:log_output] = retirement[:log_output]
    #   terraform_template_details[:retirement][:become_enabled] = retirement[:become_enabled] == true ? _('Yes') : _('No')
    # end
    terraform_template_details
  end

  def fetch_dialog(playbook_details, dialog_id, key)
    return nil if dialog_id.nil?

    dialog = Dialog.find_by(:id => dialog_id)
    return nil if dialog.nil?

    playbook_details[key][:dialog] = dialog.name
    playbook_details[key][:dialog_id] = dialog.id
  end

  def open_parent_nodes(record)
    existing_node = nil # Init var

    if record.kind_of?(OrchestrationTemplate)
      parents = [:id => template_to_node_name(record)]
    else
      # Check for parent nodes missing from vandt tree and return them if any
      parent_rec = ServiceTemplateCatalog.find_by(:id => record.service_template_catalog_id) # nil is a valid value
      parents = if parent_rec.nil?
                  [parent_rec, :id => "-Unassigned"]
                else
                  [parent_rec, :id => "stc-#{record.service_template_catalog_id}"]
                end
    end
    # Go up thru the parents and find the highest level unopened, mark all as opened along the way
    unless parents.empty? || # Skip if no parents or parent already open
           x_tree[:open_nodes].include?(parents.last[:id])
      parents.reverse_each do |p|
        next if p.nil?

        p_node = x_build_node_id(p)
        unless x_tree[:open_nodes].include?(p_node)
          x_tree[:open_nodes].push(p_node)
          existing_node = p_node
        end
      end
    end
    add_nodes = {:key => existing_node, :nodes => tree_add_child_nodes(existing_node)} if existing_node
    self.x_node = if params[:rec_id]
                    "stc-#{record.service_template_catalog_id}_st-#{record.id}"
                  elsif record.kind_of?(OrchestrationTemplate)
                    "xx-#{parents.last[:id]}_ot-#{record.id}"
                  else
                    "#{parents.last[:id]}_#{params[:id]}"
                  end
    add_nodes
  end

  # Replace the right cell of the explorer
  def replace_right_cell(options = {})
    action, replace_trees, presenter = options.values_at(:action, :replace_trees, :presenter)
    @explorer = true

    # FIXME: make this functional
    get_node_info(x_node) unless @tagging || @edit || @in_a_form
    replace_trees   = @replace_trees   if @replace_trees    # get_node_info might set this
    right_cell_text = @right_cell_text if @right_cell_text  # get_node_info might set this too

    trees = build_replaced_trees(replace_trees, %i[sandt svccat stcat ot])

    type, _id = parse_nodetype_and_id(x_node)

    allowed_records = %w[MiqTemplate OrchestrationTemplate Service ServiceTemplate ServiceTemplateCatalog]
    record_showing = (type && allowed_records.include?(TreeBuilder.get_model_for_prefix(type)) && @record.present?) || params[:action] == "x_show"
    # Clicked on right cell record, open the tree enough to show the node, if not already showing
    if params[:action] == "x_show" && x_active_tree != :stcat_tree &&
       @record && # Showing a record
       !@in_a_form # Not in a form
      add_nodes = open_parent_nodes(@record) # Open the parent nodes of selected record, if not open
    end

    v_tb =
      case x_active_tree
      when :sandt_tree
        if record_showing && !@in_a_form
          if TreeBuilder.get_model_for_prefix(@nodetype) == "MiqTemplate"
            build_toolbar("summary_view_tb")
          end
        elsif !%w[xx csb cbg cb].include?(@nodetype) && !@in_a_form
          build_toolbar("download_view_tb")
        end
      when :svccat_tree, :stcat_tree, :ot_tree
        build_toolbar("download_view_tb") unless record_showing || @in_a_form
      end

    c_tb = build_toolbar(center_toolbar_filename) unless x_active_tree == :svccat_tree && @in_a_form

    presenter ||= ExplorerPresenter.right_cell(
      :active_tree => x_active_tree,
      :add_nodes   => add_nodes
    )
    reload_trees_by_presenter(presenter, trees)

    if @sb[:buttons_node]
      if action == "group_reorder"
        right_cell_text = _("Button Group Reorder")
      end
    end
    presenter[:right_cell_text] = right_cell_text

    # Replace right cell divs
    content = if @tagging
                action_url = x_active_tree == :ot_tree ? "ot_tags_edit" : "st_tags_edit"
                r[:partial => "layouts/x_tagging", :locals => {:action_url => action_url}]
              elsif action && %w[at_st_new st_new].include?(action) && terraform_template_type?
                r[:partial => "tt_react_form"]
              elsif action && %w[at_st_new st_new].include?(action)
                r[:partial => ansible_playbook_type? ? "st_angular_form" : "st_form"]
              elsif action && %w[ownership].include?(action)
                r[:partial => @refresh_partial]
              elsif action && %w[st_catalog_new st_catalog_edit].include?(action)
                r[:partial => "stcat_form"]
              elsif action == "dialog_provision"
                r[:partial => "shared/dialogs/dialog_provision", :locals => options[:dialog_locals]]
              elsif %w[ot_add ot_copy ot_edit service_dialog_from_ot copy_catalog].include?(action)
                r[:partial => action]
              elsif record_showing
                if TreeBuilder.get_model_for_prefix(@nodetype) == "MiqTemplate"
                  r[:partial => "layouts/textual_groups_generic"]
                elsif @sb[:buttons_node]
                  r[:partial => "shared/buttons/ab_list"]
                else
                  template_locals = {:controller => "catalog"}
                  template_locals.merge!(fetch_playbook_details) if need_ansible_locals?
                  template_locals.merge!(fetch_terraform_template_details) if need_terraform_locals?
                  template_locals.merge!(fetch_ct_details) if need_container_template_locals?
                  template_locals.merge!(fetch_ovf_template_details) if need_ovf_template_locals?
                  r[:partial => "catalog/#{x_active_tree}_show", :locals => template_locals]
                end
              elsif @sb[:buttons_node]
                r[:partial => "shared/buttons/ab_list"]
              else
                r[:partial => "layouts/x_gtl"]
              end
    presenter.update(:main_div, content)

    # have to make Catalog Items accordion active incase link on Catalog show screen was pressed

    # Decide whether to show paging controls
    if @tagging
      presenter.hide(:toolbar).show(:paging_div)
      presenter.show(:form_buttons_div).remove_paging
    elsif record_showing || @in_a_form || @sb[:buttons_node] ||
          (@pages && (@items_per_page == ONE_MILLION || @pages[:items] == 0))
      if %w[button_edit group_edit group_reorder at_st_new st_new st_catalog_new st_catalog_edit copy_catalog].include?(action)
        presenter.hide(:toolbar).show(:paging_div)
        # incase it was hidden for summary screen, and incase there were no records on show_list
        presenter.remove_paging
        if (action == 'at_st_new' && (ansible_playbook_type? || terraform_template_type?)) || %w[st_catalog_new st_catalog_edit copy_catalog].include?(action)
          presenter.hide(:form_buttons_div)
        else
          presenter.show(:form_buttons_div)
        end
        locals = {:record_id => @edit[:rec_id]}
        case action
        when 'group_edit'
          locals[:action_url] = @edit[:rec_id] ? 'group_update' : 'group_create'
        when 'group_reorder'
          locals[:action_url]   = 'ab_group_reorder'
          locals[:multi_record] = true
        when 'button_edit'
          locals[:action_url] = @edit[:rec_id] ? 'button_update' : 'button_create'
        when 'st_catalog_new', 'st_catalog_edit'
          locals[:action_url] = 'st_catalog_edit'
        else
          locals[:action_url] = 'servicetemplate_edit'
          locals[:serialize] = true
        end
        presenter.update(:form_buttons_div, r[:partial => "layouts/x_edit_buttons", :locals => locals]) if allow_presenter_update(action)
      elsif action == "dialog_provision"
        presenter.hide(:toolbar)
        # incase it was hidden for summary screen, and incase there were no records on show_list
        presenter.hide(:form_buttons_div, :paging_div).remove_paging
      else
        # Added so buttons can be turned off even tho div is not being displayed it still pops up Abandon changes box when trying to change a node on tree after saving a record
        presenter.hide(:buttons_on, :form_buttons_div).show(:toolbar).hide(:paging_div)
      end
    else
      presenter.hide(:form_buttons_div).show(:toolbar, :paging_div)
    end

    # hide form buttons and toolbar for react forms actions
    if %w[ot_add ot_edit ot_copy service_dialog_from_ot].include?(action)
      presenter.hide(:toolbar, :paging_div, :form_buttons_div)
    else
      presenter.set_visibility(c_tb.present? || v_tb.present?, :toolbar)
    end
    presenter.reload_toolbars(:center => c_tb, :view => v_tb)

    presenter[:record_id] = determine_record_id_for_presenter
    presenter[:lock_sidebar] = @edit && @edit[:current] || action == 'copy_catalog'
    presenter[:osf_node] = x_node
    presenter.reset_one_trans

    presenter.update(:breadcrumbs, r[:partial => 'layouts/breadcrumbs'])

    render :json => presenter.for_render
  end

  # This method disables the action buttons of the old button-group form page.
  def allow_presenter_update(action)
    restricted_actions = ['group_edit']
    action ? restricted_actions.exclude?(action.to_s) : false
  end

  def need_ansible_locals?
    x_active_tree == :sandt_tree &&
      TreeBuilder.get_model_for_prefix(@nodetype) == "ServiceTemplate" &&
      @record.prov_type == "generic_ansible_playbook"
  end

  def need_terraform_locals?
    x_active_tree == :sandt_tree &&
      TreeBuilder.get_model_for_prefix(@nodetype) == "ServiceTemplate" &&
      @record.prov_type == "generic_terraform_template"
  end

  def need_container_template_locals?
    x_active_tree == :sandt_tree &&
      TreeBuilder.get_model_for_prefix(@nodetype) == "ServiceTemplate" &&
      @record.prov_type == "generic_container_template"
  end

  def show_record(id = nil)
    @sb[:action] = nil
    @display = params[:display] || "main" unless pagination_or_gtl_request?

    @lastaction = "show"
    @showtype = "config"
    identify_catalog(id)

    return if record_no_longer_exists?(@record)
  end

  def get_session_data
    @title      = _("Catalog Items")
    @layout     = "catalogs"
    @lastaction = session[:svc_lastaction]
    @options    = session[:prov_options]
    @resolve    = session[:resolve] if session[:resolve]
  end

  def set_session_data
    session[:svc_lastaction] = @lastaction
    session[:prov_options]   = @options if @options
    session[:resolve]        = @resolve if @resolve
  end

  def dialog_catalog_check
    return unless @edit[:new][:display] && (@edit[:new][:dialog_id].nil? || @edit[:new][:dialog_id].to_i.zero?)

    add_flash(_("Dialog has to be set if Display in Catalog is chosen"), :error)
  end

  def validate_price
    if @edit[:new][:currency] && @edit[:new][:price].blank?
      add_flash(_("Price / Month is required"), :error)
    end
    add_flash(_("Price must be a numeric value"), :error) if @edit[:new][:price].present? && !float_value?(@edit[:new][:price])
  end

  def float_value?(value)
    value.to_s =~ /(^(\d+)(\.)?(\d+)?)|(^(\d+)?(\.)(\d+))/
  end

  def x_edit_tags_reset(db)
    @tagging = session[:tag_db] = db
    checked_ids = find_checked_items.empty? ? [params[:id]] : find_checked_items
    @object_ids = find_records_with_rbac(db.safe_constantize, checked_ids).ids
    if params[:button] == 'reset'
      id = params[:id] if params[:id]
      return unless load_edit("#{session[:tag_db]}_edit_tags__#{id}", 'replace_cell__explorer')

      @object_ids = @edit[:object_ids]
      session[:tag_db] = @tagging = @edit[:tagging]
    else
      @object_ids[0] = params[:id] if @object_ids.blank? && params[:id]
      session[:tag_db] = @tagging = params[:tagging] if params[:tagging]
    end

    session[:assigned_filters] = assigned_filters
    x_tags_set_form_vars
    @in_a_form = true
    session[:changed] = false
    add_flash(_('All changes have been reset'), :warning) if params[:button] == "reset"
    @right_cell_text = _("Editing %{model} Tags for \"%{name}\"") % {:name  => ui_lookup(:models => @tagging),
                                                                     :model => current_tenant.name}

    replace_right_cell(:action => @sb[:action])
  end

  def breadcrumbs_options
    {
      :breadcrumbs => [
        {:title => _("Services")},
        {:title => _("Catalogs")},
      ],
    }
  end

  menu_section :svc
  feature_for_actions %w[ab_button_new ab_button_edit ab_group_new ab_group_edit], *EXP_EDITOR_ACTIONS
end