morpheus-cli 6.2.3 → 6.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,625 @@
1
+ require 'morpheus/cli/cli_command'
2
+ require 'securerandom'
3
+
4
+ class Morpheus::Cli::LibraryFormsCommand
5
+ include Morpheus::Cli::CliCommand
6
+ include Morpheus::Cli::LibraryHelper
7
+
8
+ set_command_name :'library-forms'
9
+ register_subcommands :list, :get, :add, :update, :remove
10
+
11
+ def connect(opts)
12
+ @api_client = establish_remote_appliance_connection(opts)
13
+ @library_instance_types_interface = @api_client.library_instance_types
14
+ @provision_types_interface = @api_client.provision_types
15
+ @option_types_interface = @api_client.option_types
16
+ @option_type_forms_interface = @api_client.option_type_forms
17
+ end
18
+
19
+ def handle(args)
20
+ handle_subcommand(args)
21
+ end
22
+
23
+ def list(args)
24
+ options = {}
25
+ params = {}
26
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
27
+ opts.banner = subcommand_usage()
28
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
29
+ add_query_parameter(params, 'labels', parse_labels(val))
30
+ end
31
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
32
+ add_query_parameter(params, 'allLabels', parse_labels(val))
33
+ end
34
+ build_standard_list_options(opts, options)
35
+ opts.footer = "List option forms."
36
+ end
37
+ optparse.parse!(args)
38
+ # verify_args!(args:args, optparse:optparse, count:0)
39
+ if args.count > 0
40
+ options[:phrase] = args.join(" ")
41
+ end
42
+ connect(options)
43
+ params.merge!(parse_list_options(options))
44
+ @option_type_forms_interface.setopts(options)
45
+ if options[:dry_run]
46
+ print_dry_run @option_type_forms_interface.dry.list(params)
47
+ return
48
+ end
49
+ json_response = @option_type_forms_interface.list(params)
50
+ render_response(json_response, options, rest_list_key) do
51
+ option_type_forms = json_response[rest_list_key]
52
+ subtitles = []
53
+ subtitles += parse_list_subtitles(options)
54
+ print_h1 "Morpheus Forms", subtitles, options
55
+ if option_type_forms.empty?
56
+ print cyan,"No forms found.",reset,"\n"
57
+ else
58
+ rows = option_type_forms.collect do |option_type_form|
59
+ {
60
+ id: option_type_form['id'],
61
+ name: option_type_form['name'],
62
+ code: option_type_form['code'],
63
+ labels: option_type_form['labels'],
64
+ description: option_type_form['description'],
65
+ }
66
+ end
67
+ columns = [
68
+ :id,
69
+ :name,
70
+ :code,
71
+ {:labels => {:display_method => lambda {|it| format_list(it[:labels], '', 3) rescue '' }}},
72
+ :description,
73
+ ]
74
+ print cyan
75
+ print as_pretty_table(rows, columns, options)
76
+ print reset
77
+ print_results_pagination(json_response)
78
+ end
79
+ print reset,"\n"
80
+ end
81
+ end
82
+
83
+ def get(args)
84
+ options = {}
85
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
86
+ opts.banner = subcommand_usage("[form]")
87
+ build_standard_get_options(opts, options)
88
+ opts.footer = <<-EOT
89
+ Get details about a form.
90
+ [form] is required. This is the name or id of a form.
91
+ EOT
92
+ end
93
+ optparse.parse!(args)
94
+ verify_args!(args:args, optparse:optparse, min:1)
95
+ connect(options)
96
+ id_list = parse_id_list(args)
97
+ return run_command_for_each_arg(id_list) do |arg|
98
+ _get(arg, options)
99
+ end
100
+ end
101
+
102
+ def _get(id, options)
103
+ params = {}
104
+ params.merge!(parse_query_options(options))
105
+ if id.to_s !~ /\A\d{1,}\Z/
106
+ # option_type_form = find_by_name(:option_type_form, id)
107
+ option_type_form = find_option_type_form_by_name_or_id(id)
108
+ return 1, "Form not found" if option_type_form.nil?
109
+ id = option_type_form['id']
110
+ end
111
+ @option_type_forms_interface.setopts(options)
112
+ if options[:dry_run]
113
+ print_dry_run @option_type_forms_interface.dry.get(id.to_i, params)
114
+ return
115
+ end
116
+ json_response = @option_type_forms_interface.get(id.to_i, params)
117
+ render_response(json_response, options, rest_object_key) do
118
+ option_type_form = json_response[rest_object_key]
119
+ print_h1 "Form Details", options
120
+ print cyan
121
+ print_description_list({
122
+ "ID" => 'id',
123
+ "Name" => 'name',
124
+ "Code" => 'code',
125
+ "Description" => 'description',
126
+ "Labels" => lambda {|it| format_list(it['labels']) },
127
+ }, option_type_form, options)
128
+
129
+ # show option types
130
+ print_h2 "Form Inputs"
131
+ #print format_option_types_table(option_type_form['options'], options, nil, true)
132
+ print format_option_types_table(option_type_form['options'], options, 'config.customOptions')
133
+ print reset,"\n"
134
+
135
+ # show Field Groups
136
+ field_groups = option_type_form['fieldGroups']
137
+ if field_groups && field_groups.size > 0
138
+ field_groups.each do |field_group|
139
+ print_h2 "#{field_group['name']}"
140
+ #print format_option_types_table(field_group['options'], options, nil, true)
141
+ if field_group['options'] && !field_group['options'].empty?
142
+ print format_option_types_table(field_group['options'], options, 'config.customOptions')
143
+ print reset,"\n"
144
+ else
145
+ print cyan, "This field group is empty", reset, "\n\n"
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ def add(args)
153
+ options = {}
154
+ my_option_types = nil
155
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
156
+ opts.banner = subcommand_usage("[name] [options]")
157
+ build_option_type_options(opts, options, new_option_type_form_option_types())
158
+ # maybe use --inputs for less confusion
159
+ opts.on('--options OPTIONS', String, "List of option type inputs to add to the form, this list can include full JSON objects or just the id to use an existing option eg. --options '[5,6,7,{\"fieldName\":\"input\",\"fieldLabel\":\"Input\"}]'") do |val|
160
+ val = "[#{val.strip}]" unless val.strip.to_s[0] == '[' && val.strip.to_s[-1] == ']'
161
+ begin
162
+ options[:selected_options] = JSON.parse(val)
163
+ rescue
164
+ raise_command_error "Failed to parse --options value '#{val}' as JSON"
165
+ end
166
+ end
167
+ build_standard_add_options(opts, options)
168
+ opts.footer = "Create a new form."
169
+ end
170
+ optparse.parse!(args)
171
+ verify_args!(args:args, optparse:optparse, max:1)
172
+ if args.count == 1
173
+ options[:options]['name'] = args[0]
174
+ end
175
+ connect(options)
176
+ parse_payload(options, rest_object_key) do |payload|
177
+ form_payload = prompt_new_form(options)
178
+ #form_payload.deep_compact!.booleanize! # remove empty values and convert checkbox "on" and "off" to true and false
179
+ payload.deep_merge!({rest_object_key => form_payload})
180
+ # cleanup payload
181
+ # remove transient option params used for prompting for list of inputs
182
+ payload[rest_object_key].keys.each do |k|
183
+ if k == "option" || k.to_s =~ /^option\d+$/ || k == "fieldGroup" || k.to_s =~ /^fieldGroup\d+$/
184
+ payload[rest_object_key].delete(k)
185
+ end
186
+ end
187
+ end
188
+ execute_api(@option_type_forms_interface, :create, [], options, rest_object_key) do |json_response|
189
+ form = json_response[rest_object_key]
190
+ print_green_success "Added form #{form['name']}"
191
+ _get(form['id'], options)
192
+ end
193
+ end
194
+
195
+ def update(args)
196
+ options = {}
197
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
198
+ opts.banner = subcommand_usage("[form] [options]")
199
+ build_option_type_options(opts, options, update_option_type_form_option_types())
200
+ build_standard_update_options(opts, options)
201
+ opts.footer = <<-EOT
202
+ Update a form.
203
+ [form] is required. This is the name or id of a form.
204
+ EOT
205
+ end
206
+ optparse.parse!(args)
207
+ verify_args!(args:args, optparse:optparse, count:1)
208
+ connect(options)
209
+ form = find_option_type_form_by_name_or_id(args[0])
210
+ return 1, "Form not found" if form.nil?
211
+ parse_payload(options, rest_object_key) do |payload|
212
+ option_types = update_option_type_form_option_types()
213
+ v_prompt = no_prompt(option_types, options)
214
+ #v_prompt.deep_compact!.booleanize! # remove empty values and convert checkbox "on" and "off" to true and false
215
+ payload.deep_merge!({rest_object_key => v_prompt})
216
+ if payload[rest_object_key].empty? # || options[:no_prompt]
217
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
218
+ end
219
+ end
220
+ execute_api(@option_type_forms_interface, :update, [form['id']], options, 'backup') do |json_response|
221
+ form = json_response[rest_object_key]
222
+ print_green_success "Updated form #{form['name']}"
223
+ _get(form['id'], options.merge(params:{}))
224
+ end
225
+ end
226
+
227
+ def remove(args)
228
+ options = {}
229
+ params = {}
230
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
231
+ opts.banner = subcommand_usage("[form]")
232
+ build_standard_remove_options(opts, options)
233
+ opts.footer = <<-EOT
234
+ Delete a form.
235
+ [form] is required. This is the name or id of a form.
236
+ EOT
237
+ end
238
+ optparse.parse!(args)
239
+ verify_args!(args:args, optparse:optparse, count:1)
240
+ connect(options)
241
+ form = find_option_type_form_by_name_or_id(args[0])
242
+ return 1, "Form not found" if form.nil?
243
+ parse_options(options, params)
244
+ confirm!("Are you sure you want to delete the form #{form['name']}?", options)
245
+ execute_api(@option_type_forms_interface, :destroy, [form['id']], options) do |json_response|
246
+ print_green_success "Removed form #{form['name']}"
247
+ end
248
+ end
249
+
250
+ private
251
+
252
+ def rest_list_key
253
+ option_type_form_list_key
254
+ end
255
+
256
+ def rest_object_key
257
+ option_type_form_object_key
258
+ end
259
+
260
+ def option_type_form_list_key
261
+ "optionTypeForms"
262
+ end
263
+
264
+ def option_type_form_object_key
265
+ "optionTypeForm"
266
+ end
267
+
268
+ def find_option_type_form_by_name_or_id(val)
269
+ if val.to_s =~ /\A\d{1,}\Z/
270
+ return find_option_type_form_by_id(val)
271
+ else
272
+ return find_option_type_form_by_name(val)
273
+ end
274
+ end
275
+
276
+ def find_option_type_form_by_id(id)
277
+ begin
278
+ json_response = @option_type_forms_interface.get(id.to_i)
279
+ return json_response[option_type_form_object_key]
280
+ rescue RestClient::Exception => e
281
+ if e.response && e.response.code == 404
282
+ print_red_alert "Form not found by id #{id}"
283
+ return nil
284
+ else
285
+ raise e
286
+ end
287
+ end
288
+ end
289
+
290
+ def find_option_type_form_by_name(name)
291
+ json_results = @option_type_forms_interface.list({name: name.to_s})
292
+ records = json_results[option_type_form_list_key]
293
+ if json_results['optionTypeForms'].empty?
294
+ print_red_alert "Form not found by name '#{name}'"
295
+ return nil
296
+ elsif records.size > 1
297
+ print_red_alert "More than one #{label.downcase} found by name '#{val}'"
298
+ print_error "\n"
299
+ puts_error as_pretty_table(records, [:id, :name], {color:red})
300
+ print_red_alert "Try using ID instead"
301
+ print_error reset,"\n"
302
+ return nil
303
+ end
304
+ option_type_form = json_results['optionTypeForms'][0]
305
+ return option_type_form
306
+ end
307
+
308
+ # def get_available_option_list_types
309
+ # [
310
+ # {'name' => 'REST', 'value' => 'rest'},
311
+ # {'name' => 'Morpheus Api', 'value' => 'api'},
312
+ # {'name' => 'LDAP', 'value' => 'ldap'},
313
+ # {'name' => 'Manual', 'value' => 'manual'}
314
+ # ]
315
+ # end
316
+
317
+ # def find_option_list_type(code)
318
+ # get_available_option_list_types.find {|it| code == it['value'] || code == it['name'] }
319
+ # end
320
+
321
+ def new_option_type_form_option_types()
322
+ [
323
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Form name'},
324
+ {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => true, 'description' => 'Unique form code'},
325
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
326
+ {'shorthand' => '-l', 'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false, 'noPrompt' => true, 'processValue' => lambda {|val| parse_labels(val) }},
327
+ ]
328
+ end
329
+
330
+ def update_option_type_form_option_types()
331
+ list = new_option_type_form_option_types()
332
+ list.each {|it|
333
+ it.delete('required')
334
+ it.delete('defaultValue')
335
+ it.delete('skipSingleOption')
336
+ }
337
+ list
338
+ end
339
+
340
+ # CLI Form builder
341
+
342
+ def prompt_new_form(options)
343
+ form_payload = {}
344
+ form_payload = prompt(new_option_type_form_option_types(), options)
345
+ # prompt for options
346
+ form_payload['options'] = prompt_new_form_options(options)
347
+ form_payload['fieldGroups'] = prompt_new_field_groups(options)
348
+
349
+ return form_payload
350
+ end
351
+
352
+ # prompts user to define a list of new option types
353
+ # returns array of option type objects {'fieldName' => "input1", 'fieldLabel' => "Input 1"}
354
+ def prompt_new_form_options(options={}, field_group_context=nil)
355
+ #puts "Source Headers:"
356
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
357
+ option_types = []
358
+ i = 0
359
+ field_context = "option#{i+1}"
360
+ context_value_map = options[:options] # should just be options or options.deep_merge(options[:options] || {})
361
+ if field_group_context
362
+ context_value_map = context_value_map ? (context_value_map[field_group_context] || {}) : {}
363
+ end
364
+ selected_options = options[:selected_options] || [] # user passing in --options '[42,{"fieldName":"foo","fieldLabel":"Foo"}]'
365
+ # puts "selected_options: #{selected_options.inspect}"
366
+ has_another_option_type = context_value_map[field_context] || selected_options[0]
367
+ add_another_option_type = has_another_option_type || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add an Input?", {default: true}))
368
+ while add_another_option_type do
369
+ print_h2 "Input #{i+1}"
370
+ full_context = [field_group_context, field_context].select {|it| it.to_s != "" }.join('.')
371
+ option_type = prompt_new_option_type(options, selected_options[i], full_context)
372
+ print "\n"
373
+ option_types << option_type
374
+ i += 1
375
+ field_context = "option#{i+1}"
376
+ has_another_option_type = context_value_map && context_value_map[field_context]
377
+ add_another_option_type = has_another_option_type || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another Input?", {default: false}))
378
+ end
379
+
380
+ return option_types
381
+ end
382
+
383
+ def prompt_new_option_type(options, selected_value=nil, field_context=nil)
384
+ option_type = {}
385
+ if selected_value
386
+ if selected_value.is_a?(Hash)
387
+ option_type = selected_value
388
+ else
389
+ existing_option_type = find_option_type_by_name_or_id(selected_value)
390
+ raise_command_error "Option Type not found for '#{selected_value}'" if existing_option_type.nil?
391
+ option_type['id'] = existing_option_type['id']
392
+ end
393
+ return option_type
394
+ end
395
+ # Use Existing Input? then skip all other inputs
396
+ # context_value_map = field_context ? (options[:options][field_context] || {}) : {}
397
+ context_value_map = field_context ? get_object_value(options[:options], field_context) : options[:options]
398
+ if context_value_map && context_value_map['id']
399
+ context_value_map['existing'] = "on"
400
+ end
401
+ use_existing = prompt_value({'fieldContext' => field_context, 'fieldName' => 'existing', 'fieldLabel' => 'Use Existing', 'type' => 'checkbox', 'required' => true, 'defaultValue' => false, 'description' => "Use an existing input instead of customizing a new one for this form"}, options)
402
+ if use_existing.to_s == "on" || use_existing.to_s == "yes" || use_existing.to_s == "true"
403
+ existing_id = prompt_value({'fieldContext' => field_context, 'fieldName' => 'id', 'fieldLabel' => 'Existing Input', 'type' => 'select', 'optionSource' => 'optionTypes', 'required' => true, 'description' => "Choose an existing input"}, options)
404
+ option_type['id'] = existing_id.to_i
405
+ else
406
+ # prompt for a new option type
407
+ option_types = new_form_input_option_types
408
+ option_types.each {|it| it['fieldContext'] = field_context }
409
+ results = prompt(option_types, options)
410
+ results.booleanize! #.deep_compact!
411
+ # option_type = field_context ? results[field_context] : results
412
+ option_type = field_context ? get_object_value(results, field_context) : results
413
+ end
414
+ return option_type
415
+ end
416
+
417
+ # prompts user to define a list of field groups and their options
418
+ # returns array of option type objects {'fieldName' => "input1", 'fieldLabel' => "Input 1"}
419
+ def prompt_new_field_groups(options={})
420
+ #puts "Source Headers:"
421
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
422
+ field_groups = []
423
+ selected_field_groups = options[:selected_field_groups] || [] # user passing in --options '[42,{"fieldName":"foo","fieldLabel":"Foo"}]'
424
+ # puts "selected_field_groups: #{selected_field_groups.inspect}"
425
+ i = 0
426
+ field_context = "fieldGroup#{i+1}"
427
+ has_another_field_group = options[:options][field_context] || selected_field_groups[0]
428
+ add_another_field_group = has_another_field_group || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add a Field Group?", {default: false}))
429
+ while add_another_field_group do
430
+ print_h2 "Field Group #{i+1}"
431
+ field_group = prompt_new_field_group(options, selected_field_groups[i], field_context)
432
+ print "\n"
433
+ field_groups << field_group
434
+ i += 1
435
+ field_context = "fieldGroup#{i+1}"
436
+ has_another_field_group = options[:options] && options[:options][field_context]
437
+ add_another_field_group = has_another_field_group || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another Field Group?", {default: false}))
438
+ end
439
+
440
+ return field_groups
441
+ end
442
+
443
+ def prompt_new_field_group(options, selected_value=nil, field_context=nil)
444
+ field_group = {}
445
+ # if selected_value
446
+ # if selected_value.is_a?(Hash)
447
+ # field_group = selected_value
448
+ # end
449
+ # return field_group
450
+ # end
451
+
452
+ # prompt for a field group
453
+ field_group_option_types = [
454
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'This field sets the name attribute for the field group.', 'defaultValue' => 'new fieldgroup'},
455
+ # {'fieldName' => 'code', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'This field sets the code attribute for the field group.', 'defaultValue' => SecureRandom.uuid},
456
+ # {'fieldName' => 'localizedName', 'fieldLabel' => 'Localized Name', 'type' => 'typeahead', 'optionSource' => 'messageCodes', 'description' => 'i18n code for the name'},
457
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'description' => 'This field sets the name attribute for the input.'},
458
+ {'fieldName' => 'collapsible', 'fieldLabel' => 'Collapsible', 'type' => 'checkbox', 'defaultValue' => true, 'description' => 'Field group is collapsible'},
459
+ {'fieldName' => 'defaultCollapsed', 'fieldLabel' => 'Default Collapsed', 'type' => 'checkbox', 'defaultValue' => true, 'description' => 'Collapse field group by default'},
460
+ {'fieldName' => 'visibleOnCode', 'fieldLabel' => 'Visibility Field', 'type' => 'text', 'description' => 'A fieldName that will trigger visibility of this field group'},
461
+ ]
462
+ field_group_option_types.each {|it| it['fieldContext'] = field_context }
463
+ results = prompt(field_group_option_types, options)
464
+ results.booleanize! #.deep_compact!
465
+ field_group = field_context ? results[field_context] : results
466
+ field_group['code'] = SecureRandom.uuid unless field_group['code']
467
+ # prompt for options
468
+ field_group['options'] = prompt_new_form_options(options, field_context)
469
+
470
+ return field_group
471
+ end
472
+
473
+ # not used yet
474
+ def prompt_edit_form(form, params, options)
475
+ form_payload = {}
476
+ selected_options = options[:selected_options] || [] # user passing in --options [42,{"fieldName":"foo","fieldLabel":"Foo"}]
477
+ # this prompts for an action for each option on the list: keep, edit, remove
478
+ new_options = []
479
+ Array(form['options']).each_with_index do |option_type, i|
480
+
481
+ field_context = i == 0 ? "option" : "option#{i+1}"
482
+ results = prompt_edit_option_type(option_type, options, selected_options[i], field_context)
483
+ if results.nil?
484
+ # deleted
485
+ next
486
+ end
487
+ new_options << results[field_context]
488
+ end
489
+ form_payload['options'] = new_options
490
+
491
+ # todo: fieldGroups
492
+ Array(form['fieldGroups']).each do |option_type|
493
+ end
494
+
495
+
496
+ return form_payload
497
+ end
498
+
499
+ def prompt_edit_option_type(current_option_type, options, selected_value=nil, field_context=nil)
500
+ option_type = {'id' => current_option_type['id']}
501
+ # if selected_value
502
+ # if selected_value.is_a?(Hash)
503
+ # option_type = selected_value
504
+ # else
505
+ # existing_option_type = find_option_type_by_name_or_id(selected_value)
506
+ # raise_command_error "Option Type not found for '#{selected_value}'" if existing_option_type.nil?
507
+ # option_type['id'] = existing_option_type['id']
508
+ # end
509
+ # return option_type
510
+ # end
511
+
512
+ action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
513
+ v_prompt = prompt([{'fieldContext' => field_context, 'fieldName' => 'action', 'type' => 'select', 'fieldLabel' => "Modify/Keep/Delete Input '#{current_option_type['fieldLabel']}' (ID: #{current_option_type['id']})", 'selectOptions' => action_options, 'required' => true, 'defaultValue' => 'keep', 'description' => 'Modify, Keep or Remove form input?'}], options[:options])
514
+ action = v_prompt[field_context]['action']
515
+
516
+ if action == 'delete'
517
+ # deleted input is just excluded from list
518
+ option_type = nil
519
+ elsif action == 'keep'
520
+ # no changes
521
+ elsif action == 'modify'
522
+ # Modify existing input
523
+
524
+ # Use Existing Input?
525
+ # If yes then then skip all other inputs
526
+ if options[:options][field_context] && options[:options][field_context]['id']
527
+ options[:options][field_context]['existing'] = "on"
528
+ end
529
+ use_existing = prompt_value({'fieldContext' => field_context, 'fieldName' => 'existing', 'fieldLabel' => 'Use Existing', 'type' => 'checkbox', 'required' => true, 'defaultValue' => (current_option_type['formField'] ? false : true), 'description' => "Use an existing input instead of customizing a new one for this form"}, options)
530
+ if use_existing.to_s == "on" || use_existing.to_s == "yes" || use_existing.to_s == "true"
531
+ existing_id = prompt_value({'fieldContext' => field_context, 'fieldName' => 'id', 'fieldLabel' => 'Existing Input', 'type' => 'select', 'optionSource' => 'optionTypes', 'required' => true, 'defaultValue' => (current_option_type['formField'] ? nil : current_option_type['name']), 'description' => "Choose an existing input"}, options)
532
+ option_type['id'] = existing_id.to_i
533
+ else
534
+ # prompt to edit the existing option type
535
+ option_types = update_form_input_option_types
536
+ option_types.each {|it| it['fieldContext'] = field_context }
537
+ results = prompt(option_types, options)
538
+ results.booleanize! #.deep_compact!
539
+ if field_context
540
+ results = results[field_context]
541
+ end
542
+ option_type.deep_merge!(results) if results
543
+ end
544
+ end
545
+
546
+ return option_type
547
+ end
548
+
549
+ def new_form_input_option_types()
550
+ [
551
+ {'code' => 'optionType.type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => get_available_form_input_types(), 'defaultValue' => 'text', 'required' => true},
552
+ {'fieldName' => 'optionList', 'fieldLabel' => 'Option List', 'type' => 'select', 'optionSource' => 'optionTypeLists', 'required' => true, 'dependsOnCode' => 'optionType.type:select', 'description' => "The Option List to be the source of options when type is 'select'."},
553
+ {'fieldName' => 'fieldLabel', 'fieldLabel' => 'Field Label', 'type' => 'text', 'required' => true, 'description' => 'This is the input label that shows typically to the left of a custom option.'},
554
+ {'fieldName' => 'fieldCode', 'fieldLabel' => 'Localized Label', 'type' => 'typeahead', 'optionSource' => 'messageCodes', 'description' => 'i18n code for the label'},
555
+ {'fieldName' => 'fieldName', 'fieldLabel' => 'Field Name', 'type' => 'text', 'required' => true, 'description' => 'This field sets the name attribute for the input.'},
556
+ {'fieldName' => 'defaultValue', 'fieldLabel' => 'Default Value', 'type' => 'text', :preprocesser => lambda do |option_type, api_client, api_params|
557
+ input_type = option_type['fieldContext'] ? api_params[option_type['fieldContext']]['type'] : api_params['type']
558
+ if input_type == 'checkbox'
559
+ # option_type.merge!({'type' => 'select', 'selectOptions' => [{"name" => "On", "value" => "on"},{"name" => "Off", "value" => "off"}]})
560
+ option_type.merge!({'type' => 'checkbox'})
561
+ end
562
+ end
563
+ },
564
+ {'fieldName' => 'placeHolder', 'fieldLabel' => 'Placeholder', 'type' => 'text', 'description' => 'Text that is displayed when the field is empty'},
565
+ {'fieldName' => 'helpBlock', 'fieldLabel' => 'Help Block', 'type' => 'text', 'description' => 'This is the explaination of the input that shows typically underneath the option.'},
566
+ {'fieldName' => 'helpBlockFieldCode', 'fieldLabel' => 'Localized Help Block', 'type' => 'typeahead', 'optionSource' => 'messageCodes', 'description' => 'i18n code for the help block'},
567
+ {'fieldName' => 'required', 'fieldLabel' => 'Required', 'type' => 'checkbox', 'defaultValue' => false},
568
+ {'fieldName' => 'exportMeta', 'fieldLabel' => 'Export As Tag', 'type' => 'checkbox', 'defaultValue' => false, 'description' => 'Export as Tag'},
569
+ {'fieldName' => 'displayValueOnDetails', 'fieldLabel' => 'Display Value On Details', 'type' => 'checkbox', 'defaultValue' => false},
570
+ {'fieldName' => 'isLocked', 'fieldLabel' => 'Locked', 'type' => 'checkbox', 'defaultValue' => false},
571
+ {'fieldName' => 'isHidden', 'fieldLabel' => 'Hidden', 'type' => 'checkbox', 'defaultValue' => false},
572
+ {'fieldName' => 'excludeFromSearch', 'fieldLabel' => 'Exclude From Search', 'type' => 'checkbox', 'defaultValue' => false},
573
+ # Advanced
574
+ {'fieldName' => 'dependsOnCode', 'fieldLabel' => 'Dependent Field', 'type' => 'text', 'description' => 'A fieldName that will trigger reloading this input'},
575
+ {'fieldName' => 'visibleOnCode', 'fieldLabel' => 'Visibility Field', 'type' => 'text', 'description' => 'A fieldName that will trigger visibility of this input'},
576
+ {'fieldName' => 'verifyPattern', 'fieldLabel' => 'Verify Pattern', 'type' => 'text', 'dependsOnCode' => 'optionType.type:text', 'description' => 'A regexp string that validates the input, use (?i) to make the matcher case insensitive'},
577
+ {'fieldName' => 'requireOnCode', 'fieldLabel' => 'Require Field', 'type' => 'text', 'description' => 'A fieldName that will trigger required attribute of this input'},
578
+ ]
579
+ end
580
+
581
+ def update_form_input_option_types()
582
+ list = new_option_type_form_option_types()
583
+ list.each {|it|
584
+ it.delete('required')
585
+ it.delete('defaultValue')
586
+ it.delete('skipSingleOption')
587
+ }
588
+ list
589
+ end
590
+
591
+ def get_available_form_input_types()
592
+ {
593
+ checkbox: "Checkbox",
594
+ hidden: "Hidden",
595
+ number: "Number",
596
+ password: "Password",
597
+ radio: "Radio",
598
+ select: "Select List",
599
+ text: "Text",
600
+ textarea: "Textarea",
601
+ byteSize: "Byte Size",
602
+ 'code-editor': "Code Editor",
603
+ fileContent: "File Content",
604
+ logoSelector: "Icon Picker",
605
+ keyValue: "Key Value",
606
+ textArray: "Text Array",
607
+ typeahead: "Typeahead",
608
+ cloud: "Cloud",
609
+ diskManager: "Disks",
610
+ environment: "Environment",
611
+ ports: "Exposed Ports",
612
+ group: "Group",
613
+ 'instances-input': "Instances",
614
+ layout: "Layout",
615
+ networkManager: "Networks",
616
+ plan: "Plan",
617
+ resourcePool: "Resource Pool",
618
+ secGroup: "Security Groups",
619
+ 'servers-input': "Servers",
620
+ 'virtual-image': "Virtual Image",
621
+ vmwFolders: "Vmw Folders",
622
+ httpHeader: "Headers",
623
+ }.collect {|k,v| {'name' => v.to_s, 'value' => k.to_s } }
624
+ end
625
+ end