I thought I should circle back and share my results. I leveraged the knowledge shared by both Jeff and Travis to condense the form changes down to just two additional lines. All the rest of the functionality is encapsulated in the initializer.
I should back up a bit and explain the objective. We wanted to add some dynamic elements to some of our app forms to show a list of SLA and queue choices based on the user’s entitlements. Further, the default SLA selection should be blank and the queue selection widget should remain hidden until an SLA is specified. If the user has no entitlements, these elements should not appear at all in the rendered form.
In addition, the form.yml.erb
files are shared among multiple teams and not all of them use SLA’s. We wanted to minimize the impact of this feature on the form files to ease maintenance, etc. We are looking forward to the new features in 3.0 which should help with this config sharing, but it will likely take some time before we see that in production.
With the initializer code we have now, we just need to add one line to the form
section and one line to the attributes
section of the form.yml
files.
Like this:
form:
...
<%= UserOptions.sla_form_elements %>
...
attributes:
...
<%= UserOptions.sla_widgets %>
...
The initializer code is below. I have a software background, but I’m not really familiar with ruby. I’ll be happy to hear any suggestions for improving the code.
Thanks again for your help with this!
Chris
# this initializer defines the UserOptions class, which can be referenced by app forms to populate
# UI elements for sla and queue selection (for those users who have access to group-specific slas).
# for details about how dynamic form elements work, see the example at https://osc.github.io/ood-documentation/release-1.3/app-development/tutorials-interactive-apps/add-custom-queue/local-dynamic-list.html?highlight=form%20yml%20erb
class UserOptions
# define some paths
@@bsla_path = "/path/to/bin/bsla"
@@group_config_dir = "/path/to/groups"
@@lsf_envdir = '/path/to/lsf/conf'
# hard-coded list of queue choices
@@queues = [ 'short', 'long' ]
# text added to the 'form' section of the form yml file
@@form_elements = <<-EOF
- ood_user_sla
- ood_user_queue
EOF
# first part of sla selection widget definition
@@sla_widget_preamble = <<-EOF
ood_user_sla:
label: SLA
help: |
Select an SLA from the drop-down.
widget: select
options:
EOF
# when a user has access to group-specific slas, the default sla selection widget appears in the form and the default selection
# is empty, i.e. no sla. while there is no sla selected, the queue selection widget is hidden.
@@sla_widget_empty_option = <<-EOF
- [ "", "none", data-hide-ood-user-queue: true ]
EOF
# template for populating selection widget options
@@generic_widget_option = <<-'EOF'
- [ "%{option_text}", "%{option_value}" ]
EOF
# first part of queue selection widget definition
@@queue_widget_preamble = <<-EOF
ood_user_queue:
label: Queue
help: |
Select a queue from the drop-down.
widget: select
value: "short"
options:
EOF
# use bsla to fetch the list of all sla's defined by the system config
def self.system_slas
@system_slas ||= begin
slas = %x{LSF_ENVDIR=#{@@lsf_envdir} #{@@bsla_path} | /usr/bin/awk 'match(\$0, /SERVICE CLASS NAME:\\s*(\\S+_\\S+)$/, m) {print m[1]}'}
if $?.exitstatus != 0
puts('Non-zero exit code from sla fetch command pipeline: #{$?.exitstatus}')
return
end
@system_slas = slas.split("\n")
end
@system_slas
end
# search group config files to fetch the list of sla's available to the current user
def self.user_slas
@user_slas ||= begin
uslas = []
user = ENV['USER']
for sla in system_slas
group_file_name = "user_#{sla}"
group_file = File.join(@@group_config_dir, group_file_name)
%x{/bin/grep #{user} #{group_file}}
if $?.exitstatus == 0
uslas.push(sla)
end
end
@user_slas = uslas
end
@user_slas
end
# return the yml 'form' section definitions appropriate to the current user's sla access
def self.sla_form_elements
@sla_form_elements ||= begin
if ! user_slas.to_a.empty?
template = @@form_elements
ERB.new(template, trim_mode: nil, eoutvar: "@sla_form_elements").result binding
end
@sla_form_elements
end
@sla_form_elements
end
# return the yml 'attibutes' section definitions appropriate to the current user's sla access
def self.sla_widgets
@sla_widgets ||= begin
if ! user_slas.to_a.empty?
template = @@sla_widget_preamble
# populate the selection options, including a leading blank selection
template += @@sla_widget_empty_option
user_slas.each do |item|
value_hash = {
option_text: item,
option_value: item
}
template += sprintf(@@generic_widget_option, value_hash)
end
template += "\n"
template += @@queue_widget_preamble
@@queues.each do |item|
value_hash = {
option_text: item,
option_value: item
}
template += sprintf(@@generic_widget_option, value_hash)
end
ERB.new(template, trim_mode: nil, eoutvar: "@sla_widgets").result binding
end
end
@sla_widgets
end
end
# calling these here initializes all the instance variables on load
UserOptions.sla_form_elements
UserOptions.sla_widgets