Revision 09ce8a63
Added by Ori Rabin almost 9 years ago
app/assets/javascripts/application.js | ||
---|---|---|
//= require hidden_values
|
||
//= require select_on_click
|
||
//= require select2
|
||
//= require underscore
|
||
|
||
$(document).on('ContentLoad', function(){onContentLoad()});
|
||
Turbolinks.enableProgressBar();
|
app/assets/javascripts/lookup_keys.js | ||
---|---|---|
//on load
|
||
$(function() {
|
||
$(document).on("ContentLoad", function() {
|
||
//select the first tab
|
||
select_first_tab();
|
||
$(document).on('click', '.nav-tabs a[data-toggle="tab"]', function(){select_first_tab();});
|
||
... | ... | |
$('.tabs-left .col-md-4').removeClass('col-md-4').addClass('col-md-8')
|
||
//remove variable click event
|
||
$(document).on('click', '.smart-var-tabs li a span', function(){ remove_node(this);});
|
||
fill_in_matchers();
|
||
$('.matchers').parents('form').on('submit', function(){
|
||
build_match();
|
||
})
|
||
$('.matcher_key').select2('destroy');
|
||
})
|
||
|
||
function select_first_tab(){
|
||
... | ... | |
content = fix_template_context(content, context);
|
||
var new_id = new Date().getTime();
|
||
content = fix_template_names(content, assoc, new_id);
|
||
|
||
var field = '';
|
||
if (assoc == 'lookup_keys') {
|
||
$('#smart_vars .smart-var-tabs .active, #smart_vars .stacked-content .active').removeClass('active');
|
||
... | ... | |
$('#smart_vars .smart-var-tabs').prepend(pill);
|
||
field = $('#smart_vars .stacked-content').prepend($(content).addClass('active'));
|
||
$('#smart_vars .smart-var-tabs li.active a').show('highlight', 500);
|
||
} else if (assoc == 'lookup_values') {
|
||
field = $(item).parent().find('tbody').first().append($(content).find('tr'));
|
||
$(item).parent().find('table').removeClass('hidden');
|
||
} else {
|
||
field = $(content).insertBefore($(item));
|
||
}
|
||
$(item).closest("form").trigger({type: 'nested:fieldAdded', field: field});
|
||
$('a[rel="popover"]').popover({html: true});
|
||
$('a[rel="twipsy"]').tooltip();
|
||
$(field).find('select').select2({ allowClear: true });
|
||
return new_id;
|
||
}
|
||
|
||
... | ... | |
var mergeOverrides = fields.find("[id$='_merge_overrides']");
|
||
var avoidDuplicates = fields.find("[id$='_avoid_duplicates']");
|
||
var overrideMergeDiv = fields.find("[id$='lookup_key_override_merge']");
|
||
var validators = fields.find("[id^='optional_input_validators']");
|
||
|
||
changeCheckboxEnabledStatus(mergeOverrides, keyType == 'array' || keyType == 'hash');
|
||
changeCheckboxEnabledStatus(avoidDuplicates, keyType == 'array' && $(mergeOverrides).attr('checked') == 'checked');
|
||
overrideMergeDiv.toggle(keyType == 'array' || keyType == 'hash');
|
||
validators.collapse('show');
|
||
validators.parent().find('legend').removeClass('collapsed');
|
||
}
|
||
|
||
function mergeOverridesChanged(item) {
|
||
... | ... | |
|
||
function filterByEnvironment(item){
|
||
if ($(item).val()=="") {
|
||
$('ul.smart-var-tabs li[data-used-environments] a').removeClass('text-muted');
|
||
$('ul.smart-var-tabs li[data-used-environments] a').removeClass('hidden');
|
||
return;
|
||
}
|
||
var selected = $(item).find('option:selected').text();
|
||
$('ul.smart-var-tabs li[data-used-environments] a').addClass('text-muted');
|
||
$('ul.smart-var-tabs li[data-used-environments*="'+selected+'"] a').removeClass('text-muted');
|
||
$('ul.smart-var-tabs li[data-used-environments] a').addClass('hidden');
|
||
$('ul.smart-var-tabs li[data-used-environments*="'+selected+'"] a').removeClass('hidden');
|
||
}
|
||
|
||
function filterByClassParam(item) {
|
||
var term = $(item).val().trim();
|
||
if (term.length > 0) {
|
||
$('ul.smart-var-tabs li[data-used-environments]').removeClass('search-marker').addClass('hide');
|
||
$('ul.smart-var-tabs li[data-used-environments] a[href*='+term+']:not(.selected-marker)').parent().addClass('search-marker').removeClass('hide');
|
||
$('ul.smart-var-tabs li[data-used-environments]').removeClass('search-marker').addClass('hidden');
|
||
$('ul.smart-var-tabs li[data-used-environments] a[href*='+term+']:not(.selected-marker)').parent().addClass('search-marker').removeClass('hidden');
|
||
} else{
|
||
$('ul.smart-var-tabs li[data-used-environments]:not(.selected-marker)').addClass('search-marker').removeClass('hide');
|
||
$('ul.smart-var-tabs li[data-used-environments]:not(.selected-marker)').addClass('search-marker').removeClass('hidden');
|
||
}
|
||
return false;
|
||
}
|
||
... | ... | |
var validator_rule_field = $(item).closest('.fields').find("[id$='_validator_rule']");
|
||
validator_rule_field.attr('disabled', validatorType == "" ? 'disabled' : null);
|
||
}
|
||
|
||
const KEY_DELM = ",";
|
||
const EQ_DELM = "=";
|
||
|
||
function match_to_key_value(match){
|
||
var regex = new RegExp('[' + KEY_DELM + EQ_DELM + ']');
|
||
|
||
var keys = [], values = [],
|
||
split_matcher = match.replace(/(\s+,) | (,\s+)/g, '').split(regex);
|
||
|
||
$.each(split_matcher, function (index, value) {
|
||
if (index % 2 === 0) {
|
||
keys.push(value);
|
||
} else {
|
||
values.push(value);
|
||
}
|
||
});
|
||
|
||
return [keys.join(KEY_DELM), values.join(KEY_DELM)];
|
||
}
|
||
|
||
function key_value_to_match(keys, values){
|
||
var match = "";
|
||
keys.split(KEY_DELM).forEach(function (el, index) {
|
||
match += el + EQ_DELM + values.split(KEY_DELM)[index] + KEY_DELM;
|
||
});
|
||
|
||
return match.slice(0, -1);
|
||
}
|
||
|
||
function fill_in_matchers(){
|
||
$('.matchers').each(function () {
|
||
var matcher = $(this);
|
||
var match = matcher.find('.match').val();
|
||
var matcher_key = matcher.find('.matcher_key');
|
||
var matcher_value = matcher.find('.matcher_value');
|
||
var order = matcher.closest('.matcher-parent').find('#order').val().split('\n');
|
||
matcher_key.empty();
|
||
matcher_key.append("<option></option>");
|
||
$.each(order, function (index, value) {
|
||
matcher_key.append($("<option>", {value: _.escape(value), html: _.escape(value)}));
|
||
});
|
||
if (match) {
|
||
var key_value = match_to_key_value(match);
|
||
matcher_key.find("option[value='" + key_value[0] + "']").attr('selected', 'selected');
|
||
matcher_value.val(key_value[1]);
|
||
}
|
||
});
|
||
}
|
||
|
||
function build_match() {
|
||
$('.matchers').each(function () {
|
||
var match = $(this).find('.match');
|
||
var matcher_key = $(this).find('.matcher_key');
|
||
var matcher_value = $(this).find('.matcher_value');
|
||
match.val(key_value_to_match(matcher_key.val(), matcher_value.val()));
|
||
});
|
||
}
|
||
|
app/assets/stylesheets/application.scss | ||
---|---|---|
height: 100vh !important;
|
||
width: 100vw !important;
|
||
}
|
||
|
||
.expander {
|
||
cursor: pointer;
|
||
*cursor: hand;
|
||
.caret{
|
||
border-width: 8px;
|
||
transform: rotate(0deg);
|
||
transition-duration: 0.8s;
|
||
}
|
||
&.collapsed .caret{
|
||
transform: rotate(-90deg);
|
||
}
|
||
}
|
||
|
||
.btn-fullscreen{
|
||
margin-right: 10px;
|
||
}
|
app/assets/stylesheets/bootstrap_and_overrides.scss | ||
---|---|---|
|
||
// help-inline is not defined in Bootstrap3
|
||
.help-inline{
|
||
margin: 0 5px;
|
||
line-height: 2.428571;
|
||
margin: 0;
|
||
display: inline;
|
||
color: #737373;
|
||
}
|
||
|
||
.well {
|
||
... | ... | |
.puppetca-filters {
|
||
min-width: 150px;
|
||
}
|
||
|
||
legend {
|
||
margin-bottom: 10px;
|
||
}
|
app/assets/stylesheets/puppetclasses.scss | ||
---|---|---|
.fields {
|
||
border-top: 1px dotted lightgrey;
|
||
padding-top: 10px;
|
||
&:nth-child(3) {
|
||
border-top: none;
|
||
}
|
||
}
|
||
}
|
||
|
||
.lookup-keys-container {
|
||
h6 {
|
||
margin-top: 0px;
|
||
}
|
||
|
||
.help-block {
|
||
margin: 0px;
|
||
}
|
||
|
||
input[type=checkbox]{
|
||
margin-top: 11px;
|
||
}
|
||
}
|
app/helpers/common_parameters_helper.rb | ||
---|---|---|
end
|
||
end
|
||
|
||
def use_puppet_default_help link_title = _("Explain use Puppet default"), title = _("Use Puppet default")
|
||
def use_puppet_default_help link_title = nil, title = _("Use Puppet default")
|
||
popover(link_title, _("Do not send this parameter via the ENC.<br>Puppet will use the value defined in the manifest."), :title => title)
|
||
end
|
||
end
|
app/helpers/layout_helper.rb | ||
---|---|---|
text = options.delete(:help_text)
|
||
inline = options.delete(:help_inline)
|
||
field(f, attr, options) do
|
||
help_inline = inline.blank? ? '' : content_tag(:span, inline, :class => "help-block")
|
||
help_inline = inline.blank? ? '' : content_tag(:span, inline, :class => "help-inline")
|
||
f.check_box(attr, options, checked_value, unchecked_value) + " #{text} " + help_inline.html_safe
|
||
end
|
||
end
|
||
... | ... | |
end
|
||
|
||
def field(f, attr, options = {})
|
||
error = f.object.errors[attr] if f && f.object.respond_to?(:errors)
|
||
table_field = options.delete(:table_field)
|
||
error = f.object.errors[attr] if f && f.object.respond_to?(:errors)
|
||
help_inline = help_inline(options.delete(:help_inline), error)
|
||
help_block = content_tag(:span, options.delete(:help_block), :class => "help-block")
|
||
size_class = options.delete(:size) || "col-md-4"
|
||
content_tag(:div, :class=> "clearfix") do
|
||
content_tag :div, :class => "form-group #{error.empty? ? "" : 'has-error'}",
|
||
:id => options.delete(:control_group_id) do
|
||
required = options.delete(:required) # we don't want to use html5 required attr so we delete the option
|
||
required_mark = ' *' if required.nil? ? is_required?(f, attr) : required
|
||
label = options[:label] == :none ? '' : options.delete(:label)
|
||
label ||= ((clazz = f.object.class).respond_to?(:gettext_translation_for_attribute_name) &&
|
||
s_(clazz.gettext_translation_for_attribute_name attr)) if f
|
||
label = label.present? ? label_tag(attr, "#{label}#{required_mark}".html_safe, :class => "col-md-2 control-label") : ''
|
||
fullscreen = options[:fullscreen] ? fullscreen_button("$(this).prev().find('textarea')") : ""
|
||
label.html_safe +
|
||
content_tag(:div, :class => size_class) do
|
||
yield.html_safe + help_block.html_safe
|
||
end.html_safe + fullscreen + help_inline.html_safe
|
||
size_class = options.delete(:size) || "col-md-4"
|
||
label = add_label(options, f, attr)
|
||
|
||
if table_field
|
||
add_help_to_label(size_class, label, help_inline, '') do
|
||
yield
|
||
end.html_safe
|
||
else
|
||
help_block = content_tag(:span, options.delete(:help_block), :class => "help-block")
|
||
|
||
content_tag(:div, :class => "clearfix") do
|
||
content_tag :div, :class => "form-group #{error.empty? ? "" : 'has-error'}",
|
||
:id => options.delete(:control_group_id) do
|
||
fullscreen = options[:fullscreen] ? fullscreen_button("$(this).prev().find('textarea')") : ""
|
||
add_help_to_label(size_class, label, help_inline, fullscreen) do
|
||
yield.html_safe + help_block.html_safe
|
||
end
|
||
end.html_safe
|
||
end
|
||
end
|
||
end
|
||
|
||
def add_help_to_label(size_class, label, help_inline, fullscreen)
|
||
label.html_safe +
|
||
content_tag(:div, :class => size_class) do
|
||
yield
|
||
end.html_safe + fullscreen + help_inline.html_safe
|
||
end
|
||
|
||
# The target should have class="collapse [out|in]" out means collapsed on load and in means expanded.
|
||
# Target must also have a unique id.
|
||
def collapsing_legend(title, target, collapsed = '')
|
||
content_tag(:legend, :class => "expander #{collapsed}", :data => {:toggle => 'collapse', :target => target}) do
|
||
content_tag(:span, '', :class => 'caret') + title
|
||
end
|
||
end
|
||
|
||
def check_required options, f, attr
|
||
required = options.delete(:required) # we don't want to use html5 required attr so we delete the option
|
||
return ' *' if required.nil? ? is_required?(f, attr) : required
|
||
end
|
||
|
||
def add_label options, f, attr
|
||
label_size = options.delete(:label_size) || "col-md-2"
|
||
required_mark = check_required(options, f, attr)
|
||
label = options[:label] == :none ? '' : options.delete(:label)
|
||
label ||= ((clazz = f.object.class).respond_to?(:gettext_translation_for_attribute_name) &&
|
||
s_(clazz.gettext_translation_for_attribute_name attr)) if f
|
||
label = label.present? ? label_tag(attr, "#{label}#{required_mark}".html_safe, :class => label_size + " control-label") : ''
|
||
label
|
||
end
|
||
|
||
def is_required?(f, attr)
|
||
return false unless f && f.object.class.respond_to?(:validators_on)
|
||
f.object.class.validators_on(attr).any? do |validator|
|
||
... | ... | |
end
|
||
|
||
def fullscreen_button(element = "$(this).prev()")
|
||
button_tag(:type => 'button', :class => 'btn btn-default btn-sm', :onclick => "set_fullscreen(#{element})", :title => _("Full screen")) do
|
||
button_tag(:type => 'button', :class => 'btn btn-default btn-sm btn-fullscreen', :onclick => "set_fullscreen(#{element})", :title => _("Full screen")) do
|
||
icon_text('resize-full')
|
||
end
|
||
end
|
app/helpers/lookup_keys_helper.rb | ||
---|---|---|
def param_type_selector(f, options = {})
|
||
selectable_f f, :key_type, options_for_select(LookupKey::KEY_TYPES.map { |e| [_(e),e] }, f.object.key_type),{},
|
||
options.merge({ :disabled => (f.object.is_param && !f.object.override), :size => "col-md-8",
|
||
:help_block => popover(_("Parameter types"),_("<dl>" +
|
||
:help_inline => popover("",_("<dl>" +
|
||
"<dt>String</dt> <dd>Everything is taken as a string.</dd>" +
|
||
"<dt>Boolean</dt> <dd>Common representation of boolean values are accepted.</dd>" +
|
||
"<dt>Integer</dt> <dd>Integer numbers only, can be negative.</dd>" +
|
||
... | ... | |
selectable_f f, :validator_type, options_for_select(LookupKey::VALIDATOR_TYPES.map { |e| [_(e),e] }, f.object.validator_type),{:include_blank => _("None")},
|
||
{ :disabled => (f.object.is_param && !f.object.override), :size => "col-md-8",
|
||
:onchange => 'validatorTypeSelected(this)',
|
||
:help_block => popover(_("Validator type"),_("<dl>" +
|
||
:help_inline => popover("",_("<dl>" +
|
||
"<dt>List</dt> <dd>A list of the allowed values, specified in the Validator rule field.</dd>" +
|
||
"<dt>Regexp</dt> <dd>Validates the input with the regular expression in the Validator rule field.</dd>" +
|
||
"</dl>"), :title => _("Validation types")).html_safe}
|
app/models/lookup_key.rb | ||
---|---|---|
|
||
KEY_DELM = ","
|
||
EQ_DELM = "="
|
||
VALUE_REGEX =/\A[^#{KEY_DELM}]+#{EQ_DELM}[^#{KEY_DELM}]+(#{KEY_DELM}[^#{KEY_DELM}]+#{EQ_DELM}[^#{KEY_DELM}]+)*\Z/
|
||
|
||
audited :associated_with => :audit_class, :allow_mass_assignment => true, :except => :lookup_values_count
|
||
validates_lengths_from_database
|
||
... | ... | |
|
||
has_many :lookup_values, :dependent => :destroy, :inverse_of => :lookup_key
|
||
accepts_nested_attributes_for :lookup_values,
|
||
:reject_if => lambda { |a| a[:value].blank? && (a[:use_puppet_default].nil? || a[:use_puppet_default] == "0")},
|
||
:reject_if => :reject_invalid_lookup_values,
|
||
:allow_destroy => true
|
||
|
||
before_validation :validate_and_cast_default_value, :unless => Proc.new{|p| p.use_puppet_default }
|
||
... | ... | |
write_attribute(:path, using_default ? nil : v)
|
||
end
|
||
|
||
def reject_invalid_lookup_values(attributes)
|
||
attributes[:match].empty? ||
|
||
(attributes[:value].blank? &&
|
||
(attributes[:use_puppet_default].nil? || attributes[:use_puppet_default] == "0"))
|
||
end
|
||
|
||
def default_value_before_type_cast
|
||
value_before_type_cast default_value
|
||
end
|
app/models/lookup_value.rb | ||
---|---|---|
audited :associated_with => :lookup_key, :allow_mass_assignment => true
|
||
|
||
belongs_to :lookup_key, :counter_cache => true
|
||
validates :match, :presence => true, :uniqueness => {:scope => :lookup_key_id}
|
||
validates :match, :presence => true, :uniqueness => {:scope => :lookup_key_id}, :format => LookupKey::VALUE_REGEX
|
||
validate :value_present?
|
||
delegate :key, :to => :lookup_key
|
||
before_validation :sanitize_match
|
app/views/lookup_keys/_fields.html.erb | ||
---|---|---|
<div id='<%= (f.object.key || 'new_lookup_keys').to_s.gsub(' ','_') + '_' + f.object.id.to_s %>' class='tab-pane fields' >
|
||
<div id='<%= (f.object.key || 'new_lookup_keys').to_s.gsub(' ', '_') + '_' + f.object.id.to_s %>' class='tab-pane fields'>
|
||
<% is_param = f.object.is_param %>
|
||
|
||
<%= text_f(f, :environment_classes, :value => f.object.environment_classes.map(&:environment).to_sentence, :label => _('Puppet Environments'),:size => "col-md-8", :disabled=>true) if is_param%>
|
||
|
||
<%= remove_child_link(_("Remove %s?") % (f.object.new_record? ? _("Variable") : f.object), f , {:class => 'btn btn-danger hide'}) unless controller_name == "lookup_keys" %>
|
||
<%= text_f f, :key, :disabled => f.object.is_param, :size => "col-md-8" %>
|
||
<%= f.hidden_field :key if is_param %>
|
||
<%= textarea_f f, :description, :rows => :auto, :size => "col-md-8" %>
|
||
|
||
<%= show_puppet_class f %>
|
||
<%= checkbox_f(f, :override, :onchange => 'toggleOverrideValue(this)', :size => "col-md-8",
|
||
:help_block => _('Whether the smart variable value is managed by Foreman')
|
||
) if is_param%>
|
||
|
||
<%= param_type_selector(f, :onchange => 'keyTypeChange(this)') %>
|
||
<%= checkbox_f(f, :use_puppet_default, :label => _('Use Puppet default'), :size => "col-md-8",
|
||
:help_block => use_puppet_default_help,
|
||
:onchange=>'toggleUsePuppetDefaultValue(this, "default_value")',
|
||
:disabled => (f.object.is_param && !f.object.override)) if is_param %>
|
||
<%= textarea_f f, :default_value, :value => f.object.default_value_before_type_cast,:size => "col-md-8",
|
||
:disabled => (f.object.is_param && (!f.object.override || f.object.use_puppet_default)),
|
||
:fullscreen => :true,
|
||
:rows => :auto, :help_block => _("Value to use when there is no match") %>
|
||
</br>
|
||
<div <%= "id=#{(f.object.key || 'new_lookup_keys').to_s.gsub(' ','_')}_lookup_key_override_value" %> style=<%= "display:none;" if (f.object.is_param && !f.object.override) %>>
|
||
<legend><%= _("Optional input validator") %></legend>
|
||
<p class="help-block">
|
||
<%= _('Note that if you use ERB as a value of parameter, value will be validated during ENC evaluation. If value is invalid, ENC evaluation will fail.') %>
|
||
</p>
|
||
<%= checkbox_f(f, :required, :size => "col-md-8", :disabled => !f.object.override,
|
||
:help_block => _("If checked, will raise an error if there is no default value and no matcher provide a value.")
|
||
<%= remove_child_link(_("Remove %s?") % (f.object.new_record? ? _("Variable") : f.object), f, { :class => 'btn btn-danger hide' }) unless controller_name == "lookup_keys" %>
|
||
<fieldset>
|
||
<legend><%= _("Parameter details") %></legend>
|
||
<%= text_f f, :key, :disabled => f.object.is_param, :size => "col-md-8" %>
|
||
<%= f.hidden_field :key if is_param %>
|
||
<%= textarea_f f, :description, :rows => :auto, :size => "col-md-8" %>
|
||
<%= text_f(f, :environment_classes, :value => f.object.environment_classes.map(&:environment).to_sentence, :label => _('Puppet Environments'), :size => "col-md-8", :disabled => true) if is_param %>
|
||
<%= show_puppet_class f %>
|
||
</fieldset>
|
||
<fieldset>
|
||
<legend><%= _("Default behavior") %></legend>
|
||
<h6><%= _("Override the default value of the Puppet class parameter.") if f.object.is_param%></h6>
|
||
<%= checkbox_f(f, :override, :onchange => 'toggleOverrideValue(this)', :size => "col-md-8",
|
||
:help_inline => popover('', _('Whether the class parameter value is managed by Foreman.'))
|
||
) if is_param %>
|
||
<%= validator_type_selector f %>
|
||
<%= text_f f, :validator_rule, :size => "col-md-8", :disabled => f.object.validator_type.blank? %>
|
||
<div <%= "id=#{(f.object.key || 'new_lookup_keys').to_s.gsub(' ','_')}_lookup_key_override_merge" %> style=<%= "display:none;" if (!f.object.merge_overrides) %>>
|
||
<legend><%= _("Override merging options") %></legend>
|
||
<%= checkbox_f(f, :merge_overrides, :onchange => 'mergeOverridesChanged(this)',
|
||
:disabled => !f.object.supports_merge?, :size => "col-md-8",
|
||
:help_block => _("Should the matchers continue to look for matches after first find (only array/hash type). Note: merging overrides ignores all matchers that use Puppet default")) %>
|
||
<%= checkbox_f(f, :avoid_duplicates, :disabled => (!f.object.supports_uniq? || !f.object.merge_overrides), :size => "col-md-8",
|
||
:help_block => _("Should the matched result avoid duplicate values (only array type).")) %>
|
||
</div>
|
||
|
||
<legend><%= _("Override value for specific hosts") %></legend>
|
||
<%= textarea_f f, :path, :rows => :auto, :label => _("Order"), :size => "col-md-8", :value => f.object.path,
|
||
:help_block => popover(_("The order in which values are resolved"),
|
||
_("The order in which matchers keys are processed, first match wins.<br> You may use multiple attributes as a matcher key, for example, an order of <code>host group, environment</code> would expect a matcher such as <code>hostgroup = \"web servers\", environment = production</code>"), :title => _("The order in which values are resolved")).html_safe
|
||
%>
|
||
|
||
<div class="children_fields lookup_values">
|
||
<%= new_child_fields_template(f, :lookup_values, {:partial => "lookup_keys/value", :form_builder_attrs => {:is_param => is_param}}) %>
|
||
<%= f.fields_for :lookup_values do |lookup_values| %>
|
||
<%= render 'lookup_keys/value', :f => lookup_values, :is_param => is_param %>
|
||
<% end %>
|
||
<%= add_child_link '+ ' + _("Add Matcher-Value"), :lookup_values, { :title => _('add a new matcher-value pair')} %>
|
||
<%= documentation_button('4.2.6SmartMatchers') %>
|
||
<%= param_type_selector(f, :onchange => 'keyTypeChange(this)') %>
|
||
<%= textarea_f f, :default_value, :value => f.object.default_value_before_type_cast, :size => "col-md-8",
|
||
:disabled => (f.object.is_param && (!f.object.override || f.object.use_puppet_default)),
|
||
:fullscreen => :true,
|
||
:rows => :auto, :help_inline => popover('', _("Value to use when there is no match.")) %>
|
||
<%= checkbox_f(f, :use_puppet_default, :label => _('Use Puppet default'), :size => "col-md-8",
|
||
:help_inline => use_puppet_default_help,
|
||
:onchange => 'toggleUsePuppetDefaultValue(this, "default_value")',
|
||
:disabled => (f.object.is_param && !f.object.override)) if is_param %>
|
||
</br>
|
||
</fieldset>
|
||
<fieldset>
|
||
<%= collapsing_legend _("Optional input validator"), "#optional_input_validators_#{f.object.id}", "collapsed" %>
|
||
<div id="optional_input_validators_<%= f.object.id %>" class="collapse out">
|
||
<p class="help-block">
|
||
<%= _('Note that if you use ERB as a value of parameter, value will be validated during ENC evaluation. If value is invalid, ENC evaluation will fail.') %>
|
||
</p>
|
||
<%= checkbox_f(f, :required, :size => "col-md-8", :disabled => !f.object.override,
|
||
:help_inline => popover('', _("If checked, will raise an error if there is no default value and no matcher provide a value."))
|
||
) if is_param %>
|
||
<%= validator_type_selector f %>
|
||
<%= text_f f, :validator_rule, :size => "col-md-8", :disabled => f.object.validator_type.blank? %>
|
||
</div>
|
||
</fieldset>
|
||
</br>
|
||
<div class="matcher-parent" <%= "id=#{(f.object.key || 'new_lookup_keys').to_s.gsub(' ', '_')}_lookup_key_override_value" %> style=<%= "display:none;" if (f.object.is_param && !f.object.override) %>>
|
||
<fieldset>
|
||
<legend><%= _("Prioritize attribute order") %></legend>
|
||
<h6><%= popover("", _("The order in which matchers keys are processed, first match wins.<br> You may use multiple attributes as a matcher key, for example, an order of <code>host group, environment</code> would expect a matcher such as <code>hostgroup = \"web servers\", environment = production</code>"),
|
||
:title => _("The order in which values are resolved.")).html_safe %> <%= _("Set the order in which values are resolved.") %></h6>
|
||
<%= textarea_f f, :path, :rows => :auto, :label => _("Order"), :id => 'order', :size => "col-md-8", :onchange => 'fill_in_matchers()', :value => f.object.path %>
|
||
<%= checkbox_f(f, :merge_overrides, :onchange => 'mergeOverridesChanged(this)', :table_field => true,
|
||
:disabled => !f.object.supports_merge?, :size => "col-md-1", :label_size => "col-md-3",
|
||
:help_inline => popover("", _("Continue to look for matches after first find (only array/hash type)? Note: merging overrides ignores all matchers that use Puppet default."))) %>
|
||
<%= checkbox_f(f, :avoid_duplicates, :disabled => (!f.object.supports_uniq? || !f.object.merge_overrides),
|
||
:size => "col-md-1", :label_size => "col-md-4", :table_field => true,
|
||
:help_inline => popover("", _("Avoid duplicate values when merging them (only array type)?"))) %>
|
||
</fieldset>
|
||
</br>
|
||
<fieldset>
|
||
<legend><%= _("Specify matchers") %> <%= documentation_button('4.2.6SmartMatchers') %></legend>
|
||
<div class="children_fields lookup_values">
|
||
<%= render 'lookup_keys/values', :f => f, :is_param => is_param %>
|
||
</div>
|
||
</fieldset>
|
||
</div>
|
||
</div>
|
app/views/lookup_keys/_value.html.erb | ||
---|---|---|
<div class="fields">
|
||
<%= text_f f, :match, :size => "col-md-8",
|
||
:help_block => popover(_("Explain matchers"), _("Matcher is a combination of an attribute and its value, if they match, the value below would be provided.<br> You may use any attribute foreman knows about, such as facts etc for example: <code> domain = example.com </code> or <code> is_virtual = true</code>"),
|
||
:title => _("Matcher"))
|
||
%>
|
||
<%= checkbox_f(f, :use_puppet_default, :label => _('Use Puppet default'), :size => "col-md-8",
|
||
:help_block => use_puppet_default_help,
|
||
:onchange=>'toggleUsePuppetDefaultValue(this, "value")') if is_param %>
|
||
<%= textarea_f f, :value, :rows => :auto, :value => f.object.value_before_type_cast, :size => "col-md-8",
|
||
<% if is_template %>
|
||
<table>
|
||
<% end %>
|
||
<tr class="fields matchers form-group <%= 'has-error' if f.object.errors.any? %>">
|
||
<td>
|
||
<%= f.hidden_field :match, :class => 'match' %>
|
||
<%= select_tag '', nil, :class => 'matcher_key' %>
|
||
=
|
||
<%= text_field_tag '', nil, :class => 'matcher_value' %>
|
||
</td>
|
||
<td>
|
||
<%= f.text_area :value, :rows => line_count(f, :value), :class => 'form-control', :'data-property' => 'value',
|
||
:disabled => f.object.use_puppet_default,
|
||
:fullscreen => :true,
|
||
:help_inline => remove_child_link(icon_text("remove"), f, {:title => _('remove value')}) %>
|
||
</div>
|
||
:placeholder => _("Value") %>
|
||
</td>
|
||
<td>
|
||
<%= fullscreen_button("$(this).parent().prev().find('textarea')") %>
|
||
</td>
|
||
<td class="ca">
|
||
<%= f.check_box :use_puppet_default, :'data-property' => 'use_puppet_default',
|
||
:disabled => !is_param,
|
||
:onchange => 'toggleUsePuppetDefaultValue(this, "value")' if is_param %>
|
||
</td>
|
||
<td>
|
||
<span class="help-block">
|
||
<%= link_to_remove_fields('', f) %>
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
<% if f.object.errors.any? %>
|
||
<tr class="has-error">
|
||
<td colspan="5">
|
||
<span class="help-block">
|
||
<%= f.object.errors.full_messages.to_sentence %>
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
<% end %>
|
||
<% if is_template %>
|
||
</table>
|
||
<% end %>
|
app/views/lookup_keys/_values.html.erb | ||
---|---|---|
<table class="table table-condensed <%= 'hidden' unless f.object.lookup_values.present? %>">
|
||
<thead>
|
||
<tr>
|
||
<th colspan='2' class='col-md-6'><%= _('Attribute type') %>
|
||
<span class="help-inline">
|
||
<%= popover("", _("Matcher is a combination of an attribute and its value, if they match, the value below would be provided.<br> You may use any attribute Foreman knows about, such as facts etc for example: <code> domain = example.com </code> or <code> is_virtual = true</code>."),
|
||
:title => _("Explain matchers")).html_safe %>
|
||
</span></th>
|
||
<th class='col-md-4'><%= _('Value') %></th>
|
||
<th></th>
|
||
<% if is_param %>
|
||
<th class='col-md-2'><%= _('Use Puppet default') %>
|
||
<span class="help-inline"> <%= use_puppet_default_help() %></span>
|
||
</th>
|
||
<% end %>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
|
||
<tbody>
|
||
<%= f.fields_for :lookup_values do |lookup_values| %>
|
||
<%= render 'lookup_keys/value', :f => lookup_values, :is_param => is_param, :is_template => false %>
|
||
<% end %>
|
||
</tbody>
|
||
</table>
|
||
<%= new_child_fields_template(f, :lookup_values, { :partial => "lookup_keys/value", :form_builder_attrs => { :is_param => is_param, :is_template => true } }) %>
|
||
<%= add_child_link '+ ' + _("Add Matcher"), :lookup_values, { :title => _('add a new matcher') } %>
|
app/views/puppetclasses/_form.html.erb | ||
---|---|---|
<div class='input-group'>
|
||
<span class="input-group-addon">@</span>
|
||
<%= select_tag "environment_filter", options_from_collection_for_select(@puppetclass.environments, "id", "name"),
|
||
:include_blank => "All Environments - (Not filtered)",:class=>'form-control', :onchange=>'filterByEnvironment(this)'%>
|
||
:prompt => _("All environments - (not filtered)"),:class=>'form-control', :onchange=>'filterByEnvironment(this)'%>
|
||
</div>
|
||
</div>
|
||
<div class='col-md-6 text-right'>
|
bundler.d/assets.rb | ||
---|---|---|
gem 'jquery_pwstrength_bootstrap', '~> 1.2'
|
||
gem 'jquery-turbolinks', '~> 2.1'
|
||
gem 'select2-rails', '~> 3.5'
|
||
gem 'underscore-rails', '~> 1.8'
|
||
end
|
test/functional/api/v2/override_values_controller_test.rb | ||
---|---|---|
assert_response :success
|
||
end
|
||
|
||
[{ :value => 'xyz=10'}, { :match => 'string'}].each do |override_value|
|
||
[{ :value => 'xyz=10'}, { :match => 'os=string'}].each do |override_value|
|
||
test "should not create override value without #{override_value.keys.first}" do
|
||
lookup_key = FactoryGirl.create(:lookup_key, :puppetclass => puppetclasses(:two))
|
||
refute lookup_key.override
|
test/unit/lookup_value_test.rb | ||
---|---|---|
assert value.valid?
|
||
end
|
||
|
||
test "boolean lookup value should not allow for nil" do
|
||
test "boolean lookup value should not allow for nil value" do
|
||
#boolean key
|
||
key = lookup_keys(:three)
|
||
value = LookupValue.new(:value => nil, :match => "hostgroup=Common", :lookup_key_id => key.id)
|
||
refute value.valid?
|
||
end
|
||
|
||
test "lookup value should allow valid key" do
|
||
key = lookup_keys(:three)
|
||
value = LookupValue.new(:value => true, :match => "hostgroup=Common", :lookup_key_id => key.id)
|
||
assert_valid value
|
||
end
|
||
|
||
test "lookup value should allow valid multiple key" do
|
||
key = lookup_keys(:three)
|
||
value = LookupValue.new(:value => true, :match => "hostgroup=Common,domain=example.com", :lookup_key_id => key.id)
|
||
assert_valid value
|
||
end
|
||
|
||
test "lookup value should not allow for nil key" do
|
||
key = lookup_keys(:three)
|
||
value = LookupValue.new(:value => true, :match => "", :lookup_key_id => key.id)
|
||
refute_valid value
|
||
end
|
||
|
||
test "lookup value will be rejected for invalid key" do
|
||
key = lookup_keys(:three)
|
||
value = LookupValue.new(:value => true, :match => "hostgroup=", :lookup_key_id => key.id)
|
||
refute_valid value
|
||
assert_equal "is invalid", value.errors[:match].first
|
||
end
|
||
|
||
test "lookup value will be rejected for invalid multiple key" do
|
||
key = lookup_keys(:three)
|
||
value = LookupValue.new(:value => true, :match => "hostgroup=Common,domain=", :lookup_key_id => key.id)
|
||
refute_valid value
|
||
assert_equal "is invalid", value.errors[:match].first
|
||
end
|
||
|
||
context "when key is a boolean and default_value is a string" do
|
||
def setup
|
||
@key = FactoryGirl.create(:lookup_key, :as_smart_class_param,
|
Also available in: Unified diff
Fixes #4419 - rearranging smart class parameters edit form