app/helpers/application_helper.rb
module ApplicationHelper
include ApplicationHelper::ViewsShared
include ApplicationHelper::Flash
include ApplicationHelper::Listnav
include ApplicationHelper::Navbar
include ApplicationHelper::PageLayouts
include ApplicationHelper::Tasks
include Mixins::Sandbox
include JsHelper
include StiRoutingHelper
include ToolbarHelper
include TextualSummaryHelper
ActionView::Helpers::NumberHelper.prepend NumberHelper # override rails number helper with our needs for number_to_human_size
include Title
include ReactjsHelper
include Webpack
VALID_PERF_PARENTS = {
"EmsCluster" => :ems_cluster,
"Host" => :host
}.freeze
# Need to generate paths w/o hostname by default to make proxying work.
#
def url_for_only_path(args)
url_for(:only_path => true, **args)
end
def api_collection_path(klass, *options)
identifier = api_identifier_by_class(klass)
send("api_#{identifier}_path", *options)
end
def api_resource_path(record, *options)
identifier = api_identifier_by_class(record.class).to_s.singularize
send("api_#{identifier}_path", nil, record.id, *options)
end
def api_identifier_by_class(klass)
raise "API plugin not loaded" unless defined?(Api::ApiConfig)
@api_cc ||= Api::CollectionConfig.new
@api_cc.name_for_klass(klass) || @api_cc.name_for_subclass(klass)
end
def settings(*path)
@settings ||= {}
@settings.fetch_path(*path)
end
def settings_default(default, *path)
settings(*path) || default
end
def websocket_origin
proto = request.ssl? ? 'wss' : 'ws'
# Retrieve the host that needs to be explicitly allowed for websocket connections
host = if request.env['HTTP_X_FORWARDED_HOST']
# Use the first proxy (production)
request.env['HTTP_X_FORWARDED_HOST'].split(/,\s*/).first
else
# Use the HOST header (development)
request.env['HTTP_HOST']
end
"#{proto}://#{host}"
end
# Create a hidden div area based on a condition (using for hiding nav panes)
def hidden_div_if(condition, options = {}, &block)
hidden_tag_if(:div, condition, options, &block)
end
# Create a hidden span tag based on a condition (using for hiding nav panes)
def hidden_span_if(condition, options = {}, &block)
hidden_tag_if(:span, condition, options, &block)
end
def hidden_tag_if(tag, condition, options = {}, &block)
options[:style] = "display: none" if condition
if block_given?
content_tag(tag, options, &block)
else
# TODO: Remove this old open-tag-only way in favor of block style
tag(tag, options, true)
end
end
def hover_class(item)
if item.fetch_path(:link) ||
item.fetch_path(:value).kind_of?(Array) &&
item[:value].any? { |val| val[:link] }
''
else
'no-hover'
end
end
# Check role based authorization for a UI task
def role_allows?(**options)
features = Array(options[:feature])
if features.blank?
$log.debug("Auth failed - no feature was specified (required)")
return false
end
# Detect if queried features are missing from the database and possibly invalid
if !Rails.env.production? && features.detect { |feature| !MiqProductFeature.feature_exists?(feature) }
message = "#{__method__} no feature was found with identifier: #{features.inspect}. Correct the identifier or add it to miq_product_features.yml."
identifiers = MiqProductFeature.features.keys
if Rails.env.development?
raise message
elsif Rails.env.test? && identifiers.length >= 5
raise("#{message} Note: detected features: #{identifiers.inspect}")
end
end
Rbac.role_allows?(:user => User.current_user, **options) rescue false
end
module_function :role_allows?
public :role_allows?
# NB: This differs from controller_for_model; until they're unified,
# make sure you have the right one.
def model_to_controller(record)
record.class.base_model.name.underscore
end
CONTROLLER_TO_MODEL = {
"ManageIQ::Providers::CloudManager::Template" => VmOrTemplate,
"ManageIQ::Providers::CloudManager::Vm" => VmOrTemplate,
"ManageIQ::Providers::InfraManager::Template" => VmOrTemplate,
"ManageIQ::Providers::InfraManager::Vm" => VmOrTemplate,
"ManageIQ::Providers::AutomationManager" => ConfigurationScript
}.freeze
def controller_to_model
model = self.class.model
CONTROLLER_TO_MODEL[model.to_s] || model
end
MODEL_STRING = {
"all_vms" => VmOrTemplate,
"all_miq_templates" => MiqTemplate,
"based_volumes" => CloudVolume,
"instances" => Vm,
"images" => MiqTemplate,
"groups" => Account,
"users" => Account,
"host_services" => SystemService,
"chargebacks" => ChargebackRate,
"playbooks" => ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook,
"physical_servers_with_host" => PhysicalServer,
"manageiq/providers/automation_managers" => ConfigurationScript,
"vms" => VmOrTemplate,
"ServiceCatalog" => ServiceTemplate
}.freeze
HAS_ASSOCATION = {
"groups" => "groups",
"users" => "users",
"event_logs" => "event_logs",
"OsProcess" => "processes",
"scan_histories" => "scan_histories",
"based_volumes" => "based_volumes",
"PersistentVolume" => "persistent_volumes",
"PhysicalSwitch" => "physical_switches"
}.freeze
def model_to_report_data
# @report_data_additional_options[:model] is most important, others can be removed
return @report_data_additional_options[:model] if @report_data_additional_options && @report_data_additional_options[:model]
return @display.classify if @display && @display != "main"
return params[:db].classify if params[:db]
return params[:display].classify if params[:display]
controller.class.model.to_s if defined? controller.class.model
end
def model_string_to_constant(model_string)
MODEL_STRING[model_string] || model_string.singularize.classify.constantize
end
def restful_routed?(record_or_model)
model = if record_or_model.kind_of?(Class)
record_or_model
else
record_or_model.class
end
model = ui_base_model(model)
respond_to?("#{model.model_name.route_key}_path")
end
# Returns whether records support feature or not.
#
# Params:
# records - an array of record instances or a single instance of a record
# feature - symbol
# Returns:
# boolean - true if all records support the feature
# - false in case the record (or one of many records) does not
# support the feature
def records_support_feature?(records, feature)
Array.wrap(records).all? { |record| record.supports?(feature.to_sym) }
end
# Create a url for a record that links to the proper controller
def url_for_db(db, action = "show", item = nil)
if item && restful_routed?(item)
return polymorphic_path(item)
end
if @vm && %w[Account User Group Patch GuestApplication].include?(db)
return url_for_only_path(:controller => "vm_or_template",
:action => @lastaction,
:id => @vm,
:show => @id)
elsif @host && %w[Patch GuestApplication].include?(db)
return url_for_only_path(:controller => "host", :action => @lastaction, :id => @host, :show => @id)
else
controller, action = db_to_controller(db, action)
return url_for_only_path(:controller => controller, :action => action, :id => @id)
end
end
TREE_WITH_TAB = {
"diagnostics_server_list" => "svr",
"db_details" => "tb",
"report_info" => "msc"
}.freeze
# Create a url to show a record from the passed in view
def view_to_url(view, parent = nil)
association = view_to_association(view, parent)
if association.nil?
controller, action = db_to_controller(view.db)
if controller == "ems_cloud" && action == "show"
return ems_clouds_path
end
if controller == "ems_infra" && action == "show"
return ems_infras_path
end
if controller == "ems_physical_infra" && action == "show"
return ems_physical_infras_path
end
if controller == "ems_container" && action == "show"
return ems_containers_path
end
if controller == "ems_network" && action == "show"
return ems_networks_path
end
if controller == "ems_storage" && action == "show"
return ems_storages_path
end
if request[:controller] == 'service' && view.db == 'GenericObject'
action = 'show'
return url_for_only_path(:action => action, :id => params[:id]) + "?display=generic_objects&generic_object_id="
end
if @explorer
# showing a list view of another CI inside vmx
if %w[SecurityGroup
SecurityPolicy
SecurityPolicyRule
FloatingIp
NetworkRouter
NetwokrService
NetworkPort
CloudNetwork
CloudSubnet
LoadBalancer
CloudVolume].include?(view.db)
return url_for_only_path(:controller => controller, :action => "show") + "/"
elsif ["Vm"].include?(view.db) && parent && request.parameters[:controller] != "vm"
# this is to handle link to a vm in vm explorer from service explorer
return url_for_only_path(:controller => "vm_or_template", :action => "show") + "/"
elsif %w[MiqWidget
ConfigurationScript
MiqReportResult].include?(view.db) &&
%w[report].include?(request.parameters[:controller])
suffix = ''
if params[:tab_id] == "saved_reports" || params[:pressed] == "miq_report_run" || params[:action] == "reload"
suffix = x_node
end
return "/" + request.parameters[:controller] + "/tree_select?id=" + suffix
elsif %w[User MiqGroup MiqUserRole Tenant].include?(view.db) &&
%w[ops].include?(request.parameters[:controller])
if @tagging
return false # when tagging Users, Groups, Roles and Tenants, the table is non-clickable
else
return "/" + request.parameters[:controller] + "/tree_select/?id=" + x_node.split("-")[1]
end
elsif view.db == "MiqServer" &&
%w[ops report].include?(request.parameters[:controller])
return "/" + request.parameters[:controller] + "/tree_select/?id=" + TREE_WITH_TAB[active_tab]
elsif %w[ScanItemSet
MiqSchedule
PxeServer
PxeImageType
Storage
CustomizationTemplate].include?(view.db) &&
%w[ops pxe report].include?(params[:controller])
return "/#{params[:controller]}/tree_select/?id=#{TreeBuilder.get_prefix_for_model(view.db)}"
else
return url_for_only_path(:action => action) + "/" # In explorer, don't jump to other controllers
end
else
controller = case controller
when 'template_cloud'
'vm_cloud'
when 'template_infra'
'vm_infra'
when 'miq_ae_domain'
'miq_ae_class'
else
controller
end
return url_for_only_path(:controller => 'restful_redirect', :model => 'ExtManagementSystem') if controller == 'ext_management_system'
return url_for_only_path(:controller => controller, :action => action, :id => nil) + "/"
end
else
# need to add a check for @explorer while setting controller incase building a link for details screen to show items
# i.e users list view screen inside explorer needs to point to vm_or_template controller
return url_for_only_path(:controller => parent.kind_of?(VmOrTemplate) && !@explorer ? parent.class.base_model.to_s.underscore : request.parameters["controller"],
:action => association,
:id => parent.id) + "?#{@explorer ? "x_show" : "show"}="
end
end
def view_to_association(view, parent)
case view.db
when "OrchestrationStackOutput" then "outputs"
when "OrchestrationStackParameter" then "parameters"
when "OrchestrationStackResource" then "resources"
when 'AdvancedSetting', 'Filesystem', 'FirewallRule', 'GuestApplication', 'Patch',
'RegistryItem', 'ScanHistory', 'OpenscapRuleResult'
then view.db.tableize
when "SystemService"
case parent.class.base_class.to_s.downcase
when "host" then "host_services"
when "vm" then @lastaction
end
when "CloudService" then "host_cloud_services"
else view.scoped_association
end
end
# Convert a db name to a controller name and an action
def db_to_controller(db, action = "show")
action = "x_show" if @explorer
case db
when "ActionSet"
controller = "miq_action"
action = "show_set"
when "AutomationRequest", "MiqProvision"
controller = "miq_request"
action = "show"
when "ConditionSet"
controller = "condition"
when "ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource"
controller = "ansible_repository"
when "ScanItemSet"
controller = "ops"
action = "ap_show"
when "User", "Group", "Patch", "GuestApplication"
controller = "vm"
action = @lastaction
when "Host" && action == 'x_show'
controller = "infra_networking"
action = @lastaction
when "MiqReportResult"
if params[:controller] == "chargeback_report"
controller = "chargeback_report"
action = "show"
else
controller = "report"
action = "show_saved"
end
when "MiqSchedule"
if request.parameters["controller"] == "report"
controller = "report"
action = "show_schedule"
else
controller = "ops"
action = "schedule_show"
end
when "MiqAeClass"
controller = "miq_ae_class"
action = "show_instances"
when "MiqAeInstance"
controller = "miq_ae_class"
action = "show_details"
when "PlacementGroup"
controller = "placement_group"
action = "show"
when "SecurityGroup"
controller = "security_group"
action = "show"
when "ServiceResource", "ServiceTemplate"
controller = "catalog"
when "ManageIQ::Providers::ExternalAutomationManager::ConfigurationScript"
controller = "configuration_script"
when "ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook"
controller = "ansible_playbook"
when "ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Credential"
controller = "ansible_credential"
when "ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Credential"
controller = "embedded_terraform_credential"
when "ManageIQ::Providers::EmbeddedTerraform::AutomationManager::ConfigurationScriptSource"
controller = "embedded_terraform_repository"
when "ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Template"
controller = "embedded_terraform_template"
when "ManageIQ::Providers::Workflows::AutomationManager::Workflow"
controller = "workflow"
when "ManageIQ::Providers::Workflows::AutomationManager::ConfigurationScriptSource"
controller = "workflow_repository"
when "ManageIQ::Providers::Workflows::AutomationManager::Credential"
controller = "workflow_credential"
when "MiqWorker"
controller = request.parameters[:controller]
when "ManageIQ::Providers::ExternalAutomationManager", "OrchestrationStackOutput", "OrchestrationStackParameter", "OrchestrationStackResource",
"ManageIQ::Providers::CloudManager::OrchestrationStack",
"ManageIQ::Providers::CloudManager::CloudDatabase",
"ManageIQ::Providers::ConfigurationManager",
"ManageIQ::Providers::AnsibleTower::AutomationManager::ConfiguredSystem",
"ManageIQ::Providers::AnsibleTower::AutomationManager::Job", "ConfigurationScript"
controller = request.parameters[:controller]
when "ContainerVolume"
controller = "persistent_volume"
when /^ManageIQ::Providers::(\w+)Manager$/
controller = "ems_#{$1.underscore}"
when /^ManageIQ::Providers::(\w+)Manager::(\w+)$/
controller = "#{$2.underscore}_#{$1.underscore}"
when "EmsAutomation"
controller = "ems_automation"
when "GenericObject" && request.parameters[:controller] == 'service'
controller = request.parameters[:controller]
action = 'generic_object'
else
controller = db.underscore
end
return controller, action
end
# Method to create the center toolbar XML
def build_toolbar(tb_name)
_toolbar_builder.build_toolbar(tb_name)
end
def _toolbar_builder
ToolbarBuilder.new(
self,
binding,
:active => @active,
:changed => @changed,
:condition => @condition,
:condition_policy => @condition_policy,
:dashboard => @dashboard,
:display => @display,
:edit => @edit,
:explorer => @explorer,
:ght_type => @ght_type,
:html => @html,
:lastaction => @lastaction,
:layout => @layout,
:miq_request => @miq_request,
:msg_title => @msg_title,
:perf_options => @perf_options,
:policy => @policy,
:record => @record,
:report => @report,
:report_result_id => @report_result_id,
:request_tab => @request_tab,
:resolve => @resolve,
:sb => @sb,
:selected_zone => @selected_zone,
:settings => @settings,
:showtype => @showtype,
:tabform => @tabform,
:widget_running => @widget_running,
:widgetsets => @widgetsets,
:render_chart => @render_chart,
)
end
# Convert a field (Vm.hardware.disks-size) to a col (disks.size)
def field_to_col(field)
dbs, fld = field.split("-")
(dbs.include?(".") ? "#{dbs.split(".").last}.#{fld}" : fld)
end
def controller_model_name(controller)
ui_lookup(:model => (controller.camelize + "Controller").constantize.model.name)
end
def is_browser?(name)
browser_name = browser_info(:name)
name.kind_of?(Array) ? name.include?(browser_name) : (browser_name == name)
end
def is_browser_os?(os)
browser_os = browser_info(:os)
os.kind_of?(Array) ? os.include?(browser_os) : (browser_os == os)
end
def browser_info(typ)
session.fetch_path(:browser, typ).to_s
end
############# Following methods generate JS lines for render page blocks
def javascript_for_timer_type(timer_type)
case timer_type
when "Monthly"
[
javascript_hide("weekly_span"),
javascript_hide("daily_span"),
javascript_hide("hourly_span"),
javascript_show("monthly_span")
]
when "Weekly"
[
javascript_hide("daily_span"),
javascript_hide("hourly_span"),
javascript_hide("monthly_span"),
javascript_show("weekly_span")
]
when "Daily"
[
javascript_hide("hourly_span"),
javascript_hide("monthly_span"),
javascript_hide("weekly_span"),
javascript_show("daily_span")
]
when "Hourly"
[
javascript_hide("daily_span"),
javascript_hide("monthly_span"),
javascript_hide("weekly_span"),
javascript_show("hourly_span")
]
when nil
[]
else
[
javascript_hide("daily_span"),
javascript_hide("hourly_span"),
javascript_hide("monthly_span"),
javascript_hide("weekly_span")
]
end
end
# Show/hide the Save and Reset buttons based on whether changes have been made
def javascript_for_miq_button_visibility(display, prefix = nil)
if prefix
"miqButtons('#{display ? 'show' : 'hide'}', '#{prefix}');".html_safe
else
"miqButtons('#{display ? 'show' : 'hide'}');".html_safe
end
end
def javascript_for_miq_button_visibility_changed(changed)
return "" if changed == session[:changed]
session[:changed] = changed
javascript_for_miq_button_visibility(changed)
end
# reload all toolbars
def javascript_reload_toolbars
"sendDataWithRx({redrawToolbar: #{toolbar_from_hash.to_json}});"
end
def set_edit_timer_from_schedule(schedule)
@edit[:new][:timer] ||= ReportHelper::Timer.new
if schedule.run_at.nil?
t = Time.now.in_time_zone(@edit[:tz]) + 1.day # Default date/time to tomorrow in selected time zone
@edit[:new][:timer].typ = 'Once'
@edit[:new][:timer].start_date = "#{t.month}/#{t.day}/#{t.year}"
else
@edit[:new][:timer].update_from_miq_schedule(schedule.run_at, @edit[:tz])
end
end
# Check if a parent chart has been selected and applies
def perf_parent?
@perf_options[:model] == "VmOrTemplate" &&
@perf_options[:typ] != "realtime" &&
VALID_PERF_PARENTS.keys.include?(@perf_options[:parent])
end
# Determine the type of report (performance/trend/chargeback) based on the model
def model_report_type(model)
if model
if model.ends_with?("Performance", "MetricsRollup")
return :performance
elsif model == ApplicationController::TREND_MODEL
return :trend
elsif model.starts_with?("Chargeback")
return model.downcase.to_sym
end
end
nil
end
def show_taskbar_in_header?
return false if @explorer
return false if controller.action_name.end_with?("tagging_edit")
hide_actions = %w[
auth_error
change_tab
show
]
return false if @layout == "" && hide_actions.include?(controller.action_name)
hide_layouts = %w[
about
chargeback
container_dashboard
ems_infra_dashboard
exception
miq_ae_automate_button
miq_ae_class
miq_ae_export
miq_ae_tools
miq_policy_export
miq_policy_rsop
ops
pxe
report
server_build
]
return false if hide_layouts.include?(@layout)
return false if @layout == "configuration" && @tabform != "ui_4"
true
end
def taskbar_in_header?
# this is just @show_taskbar ||= show_taskbar_in_header? .. but nil
if @show_taskbar.nil?
@show_taskbar = show_taskbar_in_header?
else
@show_taskbar
end
end
# checking if any of the toolbar is visible
def toolbars_visible?
(@toolbars['history_tb'] || @toolbars['center_tb'] || @toolbars['view_tb']) &&
(@toolbars['history_tb'] != 'blank_view_tb' && @toolbars['history_tb'] != 'blank_view_tb' && @toolbars['view_tb'] != 'blank_view_tb')
end
def check_if_button_is_implemented
if !@flash_array && !@refresh_partial # if no button handler ran, show not implemented msg
add_flash(_("Button not yet implemented"), :error)
@refresh_partial = "layouts/flash_msg"
@refresh_div = "flash_msg_div"
elsif @flash_array && @lastaction == "show"
@ems = @record = identify_record(params[:id])
@refresh_partial = "layouts/flash_msg"
@refresh_div = "flash_msg_div"
end
end
# Return a blank tb if a placeholder is needed for AJAX explorer screens, return nil if no center toolbar to be shown
delegate :center_toolbar_filename, :to => :_toolbar_chooser
delegate :x_view_toolbar_filename, :to => :_toolbar_chooser
delegate :view_toolbar_filename, :to => :_toolbar_chooser
def _toolbar_chooser
ToolbarChooser.new(
self,
binding,
:alert_profiles => @alert_profiles,
:conditions => @conditions,
:dialog => @dialog,
:display => @display,
:explorer => @explorer,
:in_a_form => @in_a_form,
:lastaction => @lastaction,
:layout => @layout,
:nodetype => @nodetype,
:policies => @policies,
:record => @record,
:report => @report,
:sb => @sb,
:showtype => @showtype,
:tabform => @tabform,
:view => @view,
:center_toolbar => @center_toolbar
)
end
# Calculate hash of toolbars to render
#
# keys are toolbar <div> names and values are toobar identifiers (now YAML files)
#
def calculate_toolbars
toolbars = {}
if display_back_button? # taskbar branch
toolbars['summary_center_tb'] = controller.restful? ? "summary_center_restful_tb" : "summary_center_tb"
end
# FIXME: singular vs plural for controller.class.toolbar_singular
toolbars['center_tb'] = if controller.class.toolbar_plural.present? && params[:action] == 'show_list'
"#{controller.class.toolbar_plural}_center_tb"
elsif controller.class.toolbar_singular.present?
"#{controller.class.toolbar_singular}_center_tb"
elsif controller.try(:toolbar)
controller.toolbar.to_s
else
center_toolbar_filename
end
toolbars['custom_tb'] = controller.custom_toolbar
toolbars['view_tb'] = inner_layout_present? ? x_view_toolbar_filename : view_toolbar_filename
toolbars
end
# check if back to summary button needs to be show
def display_back_button?
# don't need to back button if @record is not there or @record doesnt have name or
# evm_display_name column, i.e MiqProvisionRequest
return false if @display == "dashboard"
if (@lastaction != "show" || (@lastaction == "show" && @display != "main")) &&
@record &&
(@record.respond_to?('name') && !@record.name.nil?)
return true
else
return false
end
end
def display_adv_search?
%w[auth_key_pair_cloud
storage_service
storage_resource
host_initiator
physical_storage
automation_manager_configured_system
availability_zone
ems_automation
cloud_database
cloud_network
cloud_object_store_container
cloud_object_store_object
cloud_subnet
cloud_tenant
cloud_volume
cloud_volume_backup
cloud_volume_snapshot
cloud_volume_type
configuration_job
configuration_profile
configuration_script
configured_system
container
container_build
container_group
container_image
container_image_registry
container_node
container_project
container_replicator
container_route
container_service
container_template
ems_cloud
ems_cluster
ems_configuration
ems_container
ems_infra
ems_network
ems_physical_infra
ems_storage
flavor
floating_ip
host
host_initiator_group
host_aggregate
load_balancer
miq_template
network_port
network_router
network_service
network_service_entry
offline
orchestration_stack
persistent_volume
physical_server
placement_group
provider_foreman
resource_pool
retired
security_group
security_policy
security_policy_rule
service
services
storage
templates
volume_mapping
vm].include?(@layout)
end
def default_search?(search_name)
@default_search.present? && @default_search.name == search_name
end
def no_default_search?(search_id)
@default_search.blank? && search_id.to_i.zero?
end
def expression_selected_id_or_name(id_or_name, search)
@edit[:expression][:selected] && @edit[:expression][:selected][id_or_name] == search && !@edit[:custom_search]
end
def expression_selected_nil_or_id(search_id)
@edit[:expression][:selected].nil? && @edit[:selected].nil? || expression_selected_id_or_name(:id, search_id.to_i)
end
# Returns description of a filter, for default filter also with "(Default)"
def search_description(search)
if default_search?(search.name) ||
@edit && no_default_search?(search.id) &&
settings_default('0', :default_search, @edit&.dig(@expkey, :exp_model).to_s.to_sym).to_s == '0'
_("%{description} (Default)") % {:description => search.description}
else
_("%{description}") % {:description => search.description}
end
end
# Returns class for a filter from Global filters to highlight it
def def_searches_active_filter?(search)
if @edit && @edit[:expression] &&
((default_search?(search.name) || no_default_search?(search.id)) && expression_selected_nil_or_id(search.id) ||
(@edit[:expression][:selected] && @edit[:expression][:selected][:id].zero? && search.id.to_i.zero? ||
expression_selected_id_or_name(:name, search.name)))
'active'
else
''
end
end
# Returns class for a filter from My filters to highlight it
def my_searches_active_filter?(search)
if @edit && @edit[:expression] &&
(default_search?(search.name) && expression_selected_nil_or_id(search.id) ||
(@edit[:expression][:selected].nil? && search.id.to_i.zero? ||
expression_selected_id_or_name(:name, search.name)))
'active'
else
''
end
end
# Do we show or hide the clear_search link in the list view title
def clear_search_status
!!(@edit&.fetch_path(:adv_search_applied, :text))
end
# Should we allow the user input checkbox be shown for an atom in the expression editor
QS_VALID_USER_INPUT_OPERATORS = ["=", "!=", ">", ">=", "<", "<=", "INCLUDES", "STARTS WITH", "ENDS WITH", "CONTAINS"].freeze
QS_VALID_FIELD_TYPES = %i[string boolean integer float percent bytes megabytes].freeze
def qs_show_user_input_checkbox?
return true if @edit[:expression_method]
return false unless @edit[:adv_search_open] # Only allow user input for advanced searches
return false unless QS_VALID_USER_INPUT_OPERATORS.include?(@edit[@expkey][:exp_key])
val = (@edit[@expkey][:exp_typ] == "field" && # Field atoms with certain field types return true
QS_VALID_FIELD_TYPES.include?(@edit[@expkey][:val1][:type])) ||
(@edit[@expkey][:exp_typ] == "tag" && # Tag atoms with a tag category chosen return true
@edit[@expkey][:exp_tag]) ||
(@edit[@expkey][:exp_typ] == "count" && # Count atoms with a count col chosen return true
@edit[@expkey][:exp_count])
val
end
# Should we allow the field alias checkbox to be shown for an atom in the expression editor
def adv_search_show_alias_checkbox?
@edit[:adv_search_open] # Only allow field aliases for advanced searches
end
def pressed2model_action(pressed)
pressed =~ /^(ems_cluster|miq_template|infra_networking|ems_automation)_(.*)$/ ? [$1, $2] : pressed.split('_', 2)
end
def model_for_vm(record)
raise _("Record is not VmOrTemplate class") unless record.kind_of?(VmOrTemplate)
if record.kind_of?(ManageIQ::Providers::CloudManager::Vm)
ManageIQ::Providers::CloudManager::Vm
elsif record.kind_of?(ManageIQ::Providers::InfraManager::Vm)
ManageIQ::Providers::InfraManager::Vm
elsif record.kind_of?(ManageIQ::Providers::CloudManager::Template)
ManageIQ::Providers::CloudManager::Template
elsif record.kind_of?(ManageIQ::Providers::InfraManager::Template)
ManageIQ::Providers::InfraManager::Template
end
end
def controller_for_vm(model)
case model.to_s
when "ManageIQ::Providers::CloudManager::Template", "ManageIQ::Providers::CloudManager::Vm"
"vm_cloud"
when "ManageIQ::Providers::InfraManager::Template", "ManageIQ::Providers::InfraManager::Vm"
"vm_infra"
else
"vm_or_template"
end
end
def model_from_active_tree(tree)
case tree
when :instances_filter_tree
"ManageIQ::Providers::CloudManager::Vm"
when :images_filter_tree
"ManageIQ::Providers::CloudManager::Template"
when :vms_filter_tree
"ManageIQ::Providers::InfraManager::Vm"
when :templates_filter_tree
"ManageIQ::Providers::InfraManager::Template"
when :templates_images_filter_tree
"MiqTemplate"
when :vms_instances_filter_tree
"Vm"
end
end
def object_types_for_flash_message(klass, record_ids)
if klass == VmOrTemplate
object_ary = klass.where(:id => record_ids).collect { |rec| ui_lookup(:model => model_for_vm(rec).to_s) }
obj_hash = object_ary.each.with_object(Hash.new(0)) { |obj, h| h[obj] += 1 }
obj_hash.collect { |k, v| v == 1 ? k : k.pluralize }.sort.to_sentence
else
object = ui_lookup(:model => klass.to_s)
record_ids.length == 1 ? object : object.pluralize
end
end
def pagination_or_gtl_request?
%i[ppsetting searchtag entry sortby sort_choice page].find { |k| params[k] }
end
def update_gtl_div(action_url = 'explorer', button_div = 'center_tb')
render :update do |page|
page << javascript_prologue
page.replace("gtl_div",
:partial => "layouts/x_gtl",
:locals => {:action_url => action_url, :button_div => button_div})
page << "miqSparkle(false)"
end
end
def perfmenu_click?
return false unless params[:menu_click]
perf_menu_click
true
end
def javascript_process_redirect_args(args)
# there's no model for ResourceController - defaulting to traditional routing
begin
model = self.class.model
rescue StandardError => _err
model = nil
end
if model && args.class == Hash && args[:action] == 'show' && restful_routed?(model)
args.delete(:action)
polymorphic_path_redirect(model, args)
else
args
end
end
def javascript_redirect(args)
render :update do |page|
page << javascript_prologue
page.redirect_to(args)
end
end
def polymorphic_path_redirect(model, args)
record = args[:record] ? args[:record] : model.find(args[:id] || params[:id])
args.delete(:record)
args.delete(:id)
polymorphic_path(record, args)
end
def javascript_open_window(url)
ex = ExplorerPresenter.open_window(url)
ex.spinner_off
render :json => ex.for_render
end
# this keeps the main_div wrapping tag, replaces only the inside
def replace_main_div(args, options = {})
ex = ExplorerPresenter.main_div.update('main_div', render_to_string(args))
ex.replace("flash_msg_div", render_to_string(:partial => "layouts/flash_msg")) if options[:flash]
ex.scroll_top if @flash_array.present?
ex.spinner_off if options[:spinner_off]
render :json => ex.for_render
end
def javascript_miq_button_visibility(changed)
render :json => ExplorerPresenter.buttons(changed).for_render
end
def record_no_longer_exists?(what, model = nil)
return false unless what.nil?
if !@bang || @flash_array.empty?
# We already added a better flash message in 'identify_record'
# in that case we keep that flash message
# otherwise we make a new one.
# FIXME: a refactoring of identify_record and related is needed
add_flash(
if model.present?
_("%{model} no longer exists") % {:model => ui_lookup(:model => model)}
else
_("Error: Record no longer exists in the database")
end,
:error, true
)
session[:flash_msgs] = @flash_array
end
# Error message is displayed in 'show_list' action if such action exists
# otherwise we assume that the 'explorer' action must exist that will display it.
redirect_to(:action => respond_to?(:show_list) ? 'show_list' : 'explorer')
end
def pdf_page_size_style
"#{@options[:page_layout]}"
end
DOWNLOAD_VIEW_LAYOUTS = %w[action
auth_key_pair_cloud
automation_manager_configured_system
availability_zone
cloud_database
cloud_network
cloud_object_store_container
cloud_object_store_object
cloud_subnet
cloud_tenant
cloud_volume
cloud_volume_backup
cloud_volume_snapshot
cloud_volume_type
configuration_job
configuration_profile
configuration_script_source
configured_system
container
container_build
container_dashboard
container_group
container_image
container_image_registry
container_node
container_project
container_replicator
container_route
container_service
container_template
storage_resource
storage_service
host_initiator
ems_storage
ems_cloud
ems_cluster
ems_configuration
ems_container
ems_infra
ems_infra_dashboard
ems_network
ems_physical_infra
event
flavor
floating_ip
generic_object
generic_object_definition
guest_device
host
host_aggregate
load_balancer
manageiq/providers/embedded_ansible/automation_manager/playbook
manageiq/providers/embedded_ansible/automation_manager/credential
manageiq/providers/embedded_automation_manager/configuration_script_source
manageiq/providers/workflows/automation_manager/workflow
manageiq/providers/workflows/automation_manager/credential
miq_schedule
miq_template
network_port
network_router
network_service
network_service_entry
offline
orchestration_stack
physical_rack
physical_chassis
physical_switch
physical_storage
physical_server
persistent_volume
placement_group
policy
policy_group
security_policy
security_policy_rule
policy_profile
resource_pool
retired
scan_profile
security_group
services
storage
templates].freeze
def render_download_view_tb?
DOWNLOAD_VIEW_LAYOUTS.include?(@layout) && !@record && !@tagitems &&
!@ownershipitems && !@retireitems && !@politems && !@in_a_form &&
%w[show show_list].include?(params[:action]) && @display != "custom_button_events"
end
def placeholder_if_present(password)
password.present? ? "\u25cf" * 8 : ''
end
def miq_tab_header(id, active = nil, options = {}, &_block)
tag_options = {:class => "#{options[:class]} #{active == id ? 'active' : ''}",
'role' => 'tab',
'tabindex' => 0,
'aria-selected' => "#{active == id ? 'true' : 'false'}",
'aria-controls' => "#{id}",
:id => "#{id}_tab"}.merge!(options)
content_tag(:li, tag_options) do
content_tag(:a, :href => "##{id}", 'data-toggle' => 'tab') do
yield
end
end
end
def miq_tab_content(id, active = nil, options = {}, &_block)
lazy = options[:lazy] && active != id
classname = %w[tab-pane]
classname << options[:class] if options[:class]
classname << 'active' if active == id
classname << 'lazy' if lazy
options.delete(:lazy)
options.delete(:class)
content_tag(:div, :id => id, 'role' => 'tabpanel', 'aria-labelledby' => "#{id}_tab", :class => classname.join(' '), **options) do
yield unless lazy
end
end
def tree_with_advanced_search?
%i[
images_tree
images_filter_tree
instances_tree
instances_filter_tree
providers_tree
storage_tree
templates_filter_tree
templates_images_filter_tree
vandt_tree
vms_filter_tree
vms_instances_filter_tree
].include?(x_tree[:tree])
end
CONTENT_TYPE_ID = {
"report" => "r",
"menu" => "m",
"chart" => "c"
}.freeze
def process_show_list_options(options, curr_model = nil)
@report_data_additional_options = ApplicationController::ReportDataAdditionalOptions.from_options(options)
@report_data_additional_options.with_quadicon_options(
:embedded => @embedded,
:showlinks => @showlinks,
:policy_sim => @policy_sim,
:lastaction => @lastaction,
:in_a_form => @in_a_form,
:display => @display
)
@report_data_additional_options.with_row_button(@row_button) if @row_button
@report_data_additional_options.with_menu_click(params[:menu_click]) if params[:menu_click]
@report_data_additional_options.with_sb_controller(params[:sb_controller]) if params[:sb_controller]
@report_data_additional_options.with_model(curr_model) if curr_model
@report_data_additional_options.with_no_checkboxes(@no_checkboxes || options[:no_checkboxes])
@report_data_additional_options.with_checkboxes_clicked(params[:miq_grid_checks]) if params[:miq_grid_checks]
@report_data_additional_options.freeze
end
def from_additional_options(additional_options)
if additional_options[:match_via_descendants].present?
additional_options[:match_via_descendants] = additional_options[:match_via_descendants].constantize
end
if additional_options[:parent_id].present? && additional_options[:parent_class_name].present?
parent_id = additional_options[:parent_id]
parent_class = additional_options[:parent_class_name].constantize
additional_options[:parent] = parent_class.find(parent_id) if parent_class < ActiveRecord::Base
end
@row_button = additional_options[:row_button]
@no_checkboxes = additional_options[:no_checkboxes]
additional_options
end
# Restore instance variables necessary for proper rendering of quadicons.
# This is a temporary solution that is ot be replaced by proper
# parametrization of an ancessor class of QuadiconHelper.
def restore_quadicon_options(quadicon_options)
@embedded = quadicon_options[:embedded]
@showlinks = quadicon_options[:showlinks]
@policy_sim = quadicon_options[:policy_sim]
# @explorer
# @view.db
# @parent
@lastaction = quadicon_options[:lastaction]
# we also need to pass the @display because @display passed throught the
# session does not persist the null value
@display = quadicon_options[:display]
# need to pass @in_a_form so get_view does not set advanced search options
# in the forms that render gtl that mess up @edit
@in_a_form = quadicon_options[:in_a_form]
end
# Wrapper around jquery-rjs' remote_function which adds an extra .html_safe()
# Remove if merged: https://github.com/amatsuda/jquery-rjs/pull/3
def remote_function(options)
super(options).to_str
end
def appliance_name
MiqServer.my_server.name
end
def rbac_common_feature_for_buttons(pressed)
# return feature that should be checked for the button that came in
case pressed
when "rbac_project_add", "rbac_tenant_add"
"rbac_tenant_add"
else
pressed
end
end
def route_exists?(hash)
begin
url_for_only_path(hash)
rescue
return false
end
true
end
def translate_header_text(text)
if text == "Region"
Vmdb::Appliance.PRODUCT_NAME + " " + _(text)
else
_(text)
end
end
def parse_nodetype_and_id(x_node)
x_node.split('_').last.split('-')
end
def r
@r ||= proc { |opts| render_to_string(opts) }
end
# Test if just succesfully deleted an entity that was being displayed
def single_delete_test(any_button = false)
@flash_array.present? && @single_delete &&
(any_button || params[:pressed] == "#{table_name}_delete")
end
# redirect to show_list (after succesfully deleted the entity being displayed)
def single_delete_redirect
javascript_redirect(:action => 'show_list',
:flash_msg => @flash_array[0][:message],
:flash_error => @flash_array[0][:level] == :error)
end
def accessible_select_event_types
ApplicationController::Timelines::SELECT_EVENT_TYPE.map { |key, value| [_(key), value] }
end
def unique_html_id(prefix = 'unknown')
"#{prefix}-#{rand(36**8).to_s(36)}"
end
def self.miq_favicon_path
Settings.server.custom_favicon ? '/upload/custom_favicon.ico' : ActionController::Base.helpers.image_path('favicon.ico')
end
def miq_favicon_link_tag
favicon_link_tag(ApplicationHelper.miq_favicon_path)
end
def provider_paused?(record)
provider = if record.kind_of?(ExtManagementSystem)
record
elsif record.respond_to?(:ext_management_system)
record.ext_management_system
elsif record.respond_to?(:manager)
record.manager
end
provider.try(:enabled?) == false
end
# Return a proper column for an appropriate target klass
def columns_for_klass(klass)
if klass == 'Tenant'
[:name, :use_config_for_attributes]
elsif klass.safe_constantize.column_names.include?('name')
[:name]
else
[:description]
end
end
def safe_right_cell_text
return '' if @right_cell_text.nil?
ActiveSupport::SafeBuffer === @right_cell_text ? raw(@right_cell_text) : @right_cell_text
end
def camelize_quadicon(quad)
quad.keys.each_with_object({}) { |k, h| h[k.to_s.camelcase(:lower)] = quad[k] }
end
def miq_toolbar(toolbars)
limit = ::Settings.ui.custom_button_count || 3
react('MiqToolbar', :kebabLimit => limit, :toolbars => toolbars)
end
def miq_structured_list(data)
react('MiqStructuredList', {:title => data[:title],
:headers => data[:headers],
:rows => data[:rows],
:message => data[:message],
:mode => "miq_summary #{data[:mode]}"})
end
end