morpheus-cli 4.2.15 → 4.2.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -186,49 +186,42 @@ class Morpheus::Cli::LibraryOptionListsCommand
186
186
  my_option_types = nil
187
187
  list_type = nil
188
188
  optparse = Morpheus::Cli::OptionParser.new do |opts|
189
- opts.banner = subcommand_usage("[type] [options]")
190
- opts.on( '-t', '--type TYPE', "Option List Type. (rest, manual)" ) do |val|
191
- list_type = val
192
- # options[:options] ||= {}
193
- # options[:options]['type'] = val
194
- end
189
+ opts.banner = subcommand_usage("[name] [options]")
195
190
  build_option_type_options(opts, options, new_option_type_list_option_types())
196
191
  build_standard_add_options(opts, options)
197
192
  opts.footer = "Create a new option list."
198
193
  end
199
194
  optparse.parse!(args)
200
-
201
-
195
+ verify_args!(args:args, optparse:optparse, max:1)
196
+ if args.count == 1
197
+ options[:options]['name'] = args[0]
198
+ end
199
+
202
200
  connect(options)
203
201
  begin
204
- passed_options = options[:options].reject {|k,v| k.is_a?(Symbol) }
205
202
  payload = nil
206
203
  if options[:payload]
207
204
  payload = options[:payload]
208
- # support -O OPTION switch on top of --payload
209
- if !passed_options.empty?
210
- payload['optionTypeList'] ||= {}
211
- payload['optionTypeList'].deep_merge!(passed_options)
212
- end
205
+ payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
213
206
  else
214
- if !list_type
215
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => get_available_option_list_types, 'defaultValue' => 'rest', 'required' => true}], options[:options], @api_client, {})
216
- list_type = v_prompt['type']
217
- end
218
- params = passed_options
219
- v_prompt = Morpheus::Cli::OptionTypes.prompt(new_option_type_list_option_types(list_type), options[:options], @api_client, options[:params])
220
- params.deep_merge!(v_prompt)
221
- params['type'] = list_type
222
- if params['type'] == 'rest'
207
+ payload = {}
208
+ payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
209
+ list_payload = Morpheus::Cli::OptionTypes.prompt(new_option_type_list_option_types(), options[:options], @api_client, options[:params])
210
+ if list_payload['type'] == 'rest'
223
211
  # prompt for Source Headers
224
- source_headers = prompt_source_headers(options)
225
- if !source_headers.empty?
226
- params['config'] ||= {}
227
- params['config']['sourceHeaders'] = source_headers
212
+ if !(payload['optionTypeList']['config'] && payload['optionTypeList']['config']['sourceHeaders'])
213
+ source_headers = prompt_source_headers(options)
214
+ if !source_headers.empty?
215
+ list_payload['config'] ||= {}
216
+ list_payload['config']['sourceHeaders'] = source_headers
217
+ end
228
218
  end
229
219
  end
230
- list_payload = params
231
- payload = {'optionTypeList' => list_payload}
220
+ # tweak payload for API
221
+ ['ignoreSSLErrors', 'realTime'].each { |k|
222
+ list_payload[k] = ['on','true'].include?(list_payload[k].to_s) if list_payload.key?(k)
223
+ }
224
+ payload.deep_merge!({'optionTypeList' => list_payload})
232
225
  end
233
226
  @option_type_lists_interface.setopts(options)
234
227
  if options[:dry_run]
@@ -262,41 +255,31 @@ class Morpheus::Cli::LibraryOptionListsCommand
262
255
  begin
263
256
  option_type_list = find_option_type_list_by_name_or_id(args[0])
264
257
  exit 1 if option_type_list.nil?
265
- passed_options = options[:options].reject {|k,v| k.is_a?(Symbol) }
266
258
  payload = nil
267
259
  if options[:payload]
268
260
  payload = options[:payload]
269
- # support -O OPTION switch on top of --payload
270
- if !passed_options.empty?
271
- payload['optionTypeList'] ||= {}
272
- payload['optionTypeList'].deep_merge!(passed_options)
273
- end
261
+ payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
274
262
  else
275
- list_type = option_type_list['type']
276
- prompt_options = update_option_type_list_option_types(list_type)
277
- params = passed_options
278
- v_prompt = Morpheus::Cli::OptionTypes.no_prompt(prompt_options, options[:options], @api_client, options[:params])
279
- params.deep_merge!(v_prompt)
280
-
281
- if list_type == 'rest'
263
+ payload = {}
264
+ payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
265
+ list_payload = Morpheus::Cli::OptionTypes.no_prompt(update_option_type_option_types(), options[:options], @api_client)
266
+ if list_payload['type'] == 'rest'
282
267
  # parse Source Headers
283
- source_headers = prompt_source_headers(options.merge({no_prompt: true}))
284
- if !source_headers.empty?
285
- #params['config'] ||= option_type_list['config'] || {}
286
- params['config'] ||= {}
287
- params['config']['sourceHeaders'] = source_headers
268
+ if !(payload['optionTypeList']['config'] && payload['optionTypeList']['config']['sourceHeaders'])
269
+ source_headers = prompt_source_headers(options.merge({no_prompt: true}))
270
+ if !source_headers.empty?
271
+ #params['config'] ||= option_type_list['config'] || {}
272
+ params['config'] ||= {}
273
+ params['config']['sourceHeaders'] = source_headers
274
+ end
288
275
  end
289
276
  end
290
- if params.empty?
291
- print_red_alert "Specify at least one option to update"
292
- puts optparse
293
- exit 1
294
- end
295
- if params.key?('required')
296
- params['required'] = ['on','true'].include?(params['required'].to_s)
297
- end
298
- list_payload = params
299
- payload = {'optionTypeList' => list_payload}
277
+ # tweak payload for API
278
+ ['ignoreSSLErrors', 'realTime'].each { |k|
279
+ list_payload[k] = ['on','true'].include?(list_payload[k].to_s) if list_payload.key?(k)
280
+ }
281
+ payload.deep_merge!({'optionTypeList' => list_payload})
282
+ raise_command_error "Specify at least one option to update.\n#{optparse}" if payload['optionTypeList'].empty?
300
283
  end
301
284
  @option_type_lists_interface.setopts(options)
302
285
  if options[:dry_run]
@@ -355,42 +338,13 @@ class Morpheus::Cli::LibraryOptionListsCommand
355
338
 
356
339
  private
357
340
 
358
- def find_option_type_list_by_name_or_id(val)
359
- if val.to_s =~ /\A\d{1,}\Z/
360
- return find_option_type_list_by_id(val)
361
- else
362
- return find_option_type_list_by_name(val)
363
- end
364
- end
365
-
366
- def find_option_type_list_by_id(id)
367
- begin
368
- json_response = @option_type_lists_interface.get(id.to_i)
369
- return json_response['optionTypeList']
370
- rescue RestClient::Exception => e
371
- if e.response && e.response.code == 404
372
- print_red_alert "Option List not found by id #{id}"
373
- exit 1
374
- else
375
- raise e
376
- end
377
- end
378
- end
379
-
380
- def find_option_type_list_by_name(name)
381
- json_results = @option_type_lists_interface.list({name: name.to_s})
382
- if json_results['optionTypeLists'].empty?
383
- print_red_alert "Option List not found by name #{name}"
384
- exit 1
385
- end
386
- option_type_list = json_results['optionTypeLists'][0]
387
- return option_type_list
388
- end
341
+ # finders are in LibraryHelper
389
342
 
390
343
  def get_available_option_list_types
391
344
  [
392
345
  {'name' => 'REST', 'value' => 'rest'},
393
346
  {'name' => 'Morpheus Api', 'value' => 'api'},
347
+ {'name' => 'LDAP', 'value' => 'ldap'},
394
348
  {'name' => 'Manual', 'value' => 'manual'}
395
349
  ]
396
350
  end
@@ -399,49 +353,31 @@ class Morpheus::Cli::LibraryOptionListsCommand
399
353
  get_available_option_list_types.find {|it| code == it['value'] || code == it['name'] }
400
354
  end
401
355
 
402
- def new_option_type_list_option_types(list_type='rest')
403
- if list_type.to_s.downcase == 'rest'
404
- [
356
+ def new_option_type_list_option_types()
357
+ [
358
+ # rest
405
359
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
406
360
  {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
407
- #{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => get_available_option_list_types, 'defaultValue' => 'rest', 'required' => true, 'displayOrder' => 3},
408
- {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 3},
409
- {'fieldName' => 'sourceUrl', 'fieldLabel' => 'Source Url', 'type' => 'text', 'required' => true, 'description' => "A REST URL can be used to fetch list data and is cached in the appliance database.", 'displayOrder' => 4},
410
- {'fieldName' => 'ignoreSSLErrors', 'fieldLabel' => 'Ignore SSL Errors', 'type' => 'checkbox', 'defaultValue' => 'off', 'displayOrder' => 5},
411
- {'fieldName' => 'realTime', 'fieldLabel' => 'Real Time', 'type' => 'checkbox', 'defaultValue' => 'off', 'displayOrder' => 6},
412
- {'fieldName' => 'sourceMethod', 'fieldLabel' => 'Source Method', 'type' => 'select', 'selectOptions' => [{'name' => 'GET', 'value' => 'GET'}, {'name' => 'POST', 'value' => 'POST'}], 'defaultValue' => 'GET', 'required' => true, 'displayOrder' => 7},
361
+ {'code' => 'optionTypeList.type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => get_available_option_list_types, 'defaultValue' => 'rest', 'required' => true, 'description' => 'Option List Type. eg. rest, api, ldap, manual', 'displayOrder' => 3},
362
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 4},
363
+ {'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'sourceUrl', 'fieldLabel' => 'Source Url', 'type' => 'text', 'required' => true, 'description' => "A REST URL can be used to fetch list data and is cached in the appliance database.", 'displayOrder' => 5},
364
+ {'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'ignoreSSLErrors', 'fieldLabel' => 'Ignore SSL Errors', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 6},
365
+ {'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'realTime', 'fieldLabel' => 'Real Time', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 7},
366
+ {'dependsOnCode' => 'optionTypeList.type:rest', 'fieldName' => 'sourceMethod', 'fieldLabel' => 'Source Method', 'type' => 'select', 'selectOptions' => [{'name' => 'GET', 'value' => 'GET'}, {'name' => 'POST', 'value' => 'POST'}], 'defaultValue' => 'GET', 'required' => true, 'displayOrder' => 8},
413
367
  # sourceHeaders component (is done afterwards manually)
414
- {'fieldName' => 'initialDataset', 'fieldLabel' => 'Initial Dataset', 'type' => 'code-editor', 'description' => "Create an initial json dataset to be used as the collection for this option list. It should be a list containing objects with properties 'name', and 'value'. However, if there is a translation script, that will also be passed through.", 'displayOrder' => 8},
415
- {'fieldName' => 'translationScript', 'fieldLabel' => 'Translation Script', 'type' => 'code-editor', 'description' => "Create a js script to translate the result data object into an Array containing objects with properties name, and value. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 9},
416
- {'fieldName' => 'requestScript', 'fieldLabel' => 'Request Script', 'type' => 'code-editor', 'description' => "Create a js script to prepare the request. Return a data object as the body for a post, and return an array containing properties name and value for a get. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 10},
417
-
368
+ {'dependsOnCode' => 'optionTypeList.type:api', 'fieldName' => 'apiType', 'fieldLabel' => 'Option List', 'type' => 'select', 'optionSource' => 'apiOptionLists', 'required' => true, 'description' => 'The code of the api list to use, eg. clouds, servers, etc.', 'displayOrder' => 9},
369
+ {'dependsOnCode' => 'optionTypeList.type:ldap', 'fieldName' => 'sourceUsername', 'fieldLabel' => 'Source Username', 'type' => 'text', 'description' => "An LDAP Username for use when type is 'ldap'.", 'displayOrder' => 10},
370
+ {'dependsOnCode' => 'optionTypeList.type:ldap', 'fieldName' => 'sourcePassword', 'fieldLabel' => 'Source Username', 'type' => 'text', 'description' => "An LDAP Password for use when type is 'ldap'.", 'displayOrder' => 11},
371
+ {'dependsOnCode' => 'optionTypeList.type:ldap', 'fieldName' => 'ldapQuery', 'fieldLabel' => 'LDAP Query', 'type' => 'text', 'description' => "LDAP Queries are standard LDAP formatted queries where different objects can be searched. Dependent parameters can be loaded into the query using the <%=phrase%> syntax.", 'displayOrder' => 12},
372
+ {'dependsOnCode' => 'optionTypeList.type:rest|api|manual', 'fieldName' => 'initialDataset', 'fieldLabel' => 'Initial Dataset', 'type' => 'code-editor', 'description' => "Create an initial json dataset to be used as the collection for this option list. It should be a list containing objects with properties 'name', and 'value'. However, if there is a translation script, that will also be passed through.", 'displayOrder' => 13},
373
+ {'dependsOnCode' => 'optionTypeList.type:rest|api|ldap', 'fieldName' => 'translationScript', 'fieldLabel' => 'Translation Script', 'type' => 'code-editor', 'description' => "Create a js script to translate the result data object into an Array containing objects with properties name, and value. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 14},
374
+ {'dependsOnCode' => 'optionTypeList.type:rest|api', 'fieldName' => 'requestScript', 'fieldLabel' => 'Request Script', 'type' => 'code-editor', 'description' => "Create a js script to prepare the request. Return a data object as the body for a post, and return an array containing properties name and value for a get. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 15},
418
375
  ]
419
- elsif list_type.to_s.downcase == 'api'
420
- [
421
- {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
422
- {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
423
- #{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Rest', 'value' => 'rest'}, {'name' => 'Manual', 'value' => 'manual'}], 'defaultValue' => 'rest', 'required' => true, 'displayOrder' => 3},
424
- {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 3},
425
- {'fieldName' => 'apiType', 'fieldLabel' => 'Option List', 'type' => 'select', 'optionSource' => 'apiOptionLists', 'required' => true, 'description' => 'The code of the api list to use, eg. clouds, servers, etc.', 'displayOrder' => 6},
426
- {'fieldName' => 'translationScript', 'fieldLabel' => 'Translation Script', 'type' => 'code-editor', 'description' => "Create a js script to translate the result data object into an Array containing objects with properties name, and value. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 9},
427
- {'fieldName' => 'requestScript', 'fieldLabel' => 'Request Script', 'type' => 'code-editor', 'description' => "Create a js script to prepare the request. Return a data object as the body for a post, and return an array containing properties name and value for a get. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 10},
428
- ]
429
- elsif list_type.to_s.downcase == 'manual'
430
- [
431
- {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
432
- {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
433
- #{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Rest', 'value' => 'rest'}, {'name' => 'Manual', 'value' => 'manual'}], 'defaultValue' => 'rest', 'required' => true, 'displayOrder' => 3},
434
- {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 3},
435
- {'fieldName' => 'initialDataset', 'fieldLabel' => 'Dataset', 'type' => 'code-editor', 'required' => true, 'description' => "Create an initial JSON or CSV dataset to be used as the collection for this option list. It should be a list containing objects with properties 'name', and 'value'.", 'displayOrder' => 4},
436
- ]
437
- else
438
- print_red_alert "Unknown Option List type '#{list_type}'"
439
- exit 1
440
- end
376
+
441
377
  end
442
378
 
443
- def update_option_type_list_option_types(list_type='rest')
444
- list = new_option_type_list_option_types(list_type)
379
+ def update_option_type_list_option_types()
380
+ list = new_option_type_list_option_types()
445
381
  list.each {|it|
446
382
  it.delete('required')
447
383
  it.delete('defaultValue')
@@ -65,8 +65,8 @@ class Morpheus::Cli::LibraryOptionTypesCommand
65
65
  fieldLabel: option_type['fieldLabel'],
66
66
  fieldName: option_type['fieldName'],
67
67
  default: option_type['defaultValue'],
68
- required: option_type['required'] ? 'yes' : 'no',
69
- export: option_type['exportMeta'] ? 'yes' : 'no'
68
+ required: (option_type['required'].nil? ? '' : format_boolean(option_type['required'])),
69
+ export: (option_type['exportMeta'].nil? ? '' : format_boolean(option_type['exportMeta']))
70
70
  }
71
71
  end
72
72
  print cyan
@@ -170,6 +170,8 @@ class Morpheus::Cli::LibraryOptionTypesCommand
170
170
  payload = {}
171
171
  payload.deep_merge!({'optionType' => parse_passed_options(options)})
172
172
  option_type_payload = Morpheus::Cli::OptionTypes.prompt(new_option_type_option_types, options[:options], @api_client)
173
+ # tweak payload for API
174
+ option_type_payload['optionList'] = {'id' => option_type_payload['optionList'].to_i} if option_type_payload['optionList'].is_a?(String) || option_type_payload['optionList'].is_a?(Numeric)
173
175
  option_type_payload['required'] = ['on','true'].include?(option_type_payload['required'].to_s) if option_type_payload.key?('required')
174
176
  option_type_payload['exportMeta'] = ['on','true'].include?(option_type_payload['exportMeta'].to_s) if option_type_payload.key?('exportMeta')
175
177
  payload.deep_merge!({'optionType' => option_type_payload})
@@ -213,6 +215,8 @@ class Morpheus::Cli::LibraryOptionTypesCommand
213
215
  payload = {}
214
216
  payload.deep_merge!({'optionType' => parse_passed_options(options)})
215
217
  option_type_payload = Morpheus::Cli::OptionTypes.no_prompt(update_option_type_option_types, options[:options], @api_client)
218
+ # tweak payload for API
219
+ option_type_payload['optionList'] = {'id' => option_type_payload['optionList'].to_i} if option_type_payload['optionList'].is_a?(String) || option_type_payload['optionList'].is_a?(Numeric)
216
220
  option_type_payload['required'] = ['on','true'].include?(option_type_payload['required'].to_s) if option_type_payload.key?('required')
217
221
  option_type_payload['exportMeta'] = ['on','true'].include?(option_type_payload['exportMeta'].to_s) if option_type_payload.key?('exportMeta')
218
222
  payload.deep_merge!({'optionType' => option_type_payload})
@@ -285,13 +289,14 @@ class Morpheus::Cli::LibraryOptionTypesCommand
285
289
  [
286
290
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
287
291
  {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
288
- {'fieldName' => 'fieldName', 'fieldLabel' => 'Field Name', 'type' => 'text', 'required' => true, 'description' => 'This is the input fieldName property that the value gets assigned to.', 'displayOrder' => 3},
289
- {'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Text', 'value' => 'text'}, {'name' => 'Password', 'value' => 'password'}, {'name' => 'Number', 'value' => 'number'}, {'name' => 'Checkbox', 'value' => 'checkbox'}, {'name' => 'Select', 'value' => 'select'}, {'name' => 'Hidden', 'value' => 'hidden'}], 'defaultValue' => 'text', 'required' => true, 'displayOrder' => 4},
290
- {'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.', 'displayOrder' => 5},
291
- {'fieldName' => 'placeHolder', 'fieldLabel' => 'Placeholder', 'type' => 'text', 'displayOrder' => 6},
292
- {'fieldName' => 'defaultValue', 'fieldLabel' => 'Default Value', 'type' => 'text', 'displayOrder' => 7},
293
- {'fieldName' => 'required', 'fieldLabel' => 'Required', 'type' => 'checkbox', 'defaultValue' => 'off', 'displayOrder' => 8},
294
- {'fieldName' => 'exportMeta', 'fieldLabel' => 'Export As Tag', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'Export as Tag.', 'displayOrder' => 9},
292
+ {'fieldName' => 'fieldName', 'fieldLabel' => 'Field Name', 'type' => 'text', 'required' => true, 'description' => 'This is the input property that the value gets assigned to.', 'displayOrder' => 3},
293
+ {'code' => 'optionType.type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Text', 'value' => 'text'}, {'name' => 'Password', 'value' => 'password'}, {'name' => 'Number', 'value' => 'number'}, {'name' => 'Checkbox', 'value' => 'checkbox'}, {'name' => 'Select', 'value' => 'select'}, {'name' => 'Hidden', 'value' => 'hidden'}], 'defaultValue' => 'text', 'required' => true, 'displayOrder' => 4},
294
+ {'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'.", 'displayOrder' => 5},
295
+ {'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.', 'displayOrder' => 6},
296
+ {'fieldName' => 'placeHolder', 'fieldLabel' => 'Placeholder', 'type' => 'text', 'displayOrder' => 7},
297
+ {'fieldName' => 'defaultValue', 'fieldLabel' => 'Default Value', 'type' => 'text', 'displayOrder' => 8},
298
+ {'fieldName' => 'required', 'fieldLabel' => 'Required', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 9},
299
+ {'fieldName' => 'exportMeta', 'fieldLabel' => 'Export As Tag', 'type' => 'checkbox', 'defaultValue' => false, 'description' => 'Export as Tag.', 'displayOrder' => 10},
295
300
  ]
296
301
  end
297
302
 
@@ -502,4 +502,36 @@ module Morpheus::Cli::LibraryHelper
502
502
  return {success:true, data: spec_template_ids}
503
503
  end
504
504
 
505
+ def find_option_type_list_by_name_or_id(val)
506
+ if val.to_s =~ /\A\d{1,}\Z/
507
+ return find_option_type_list_by_id(val)
508
+ else
509
+ return find_option_type_list_by_name(val)
510
+ end
511
+ end
512
+
513
+ def find_option_type_list_by_id(id)
514
+ begin
515
+ json_response = @option_type_lists_interface.get(id.to_i)
516
+ return json_response['optionTypeList']
517
+ rescue RestClient::Exception => e
518
+ if e.response && e.response.code == 404
519
+ print_red_alert "Option List not found by id #{id}"
520
+ exit 1
521
+ else
522
+ raise e
523
+ end
524
+ end
525
+ end
526
+
527
+ def find_option_type_list_by_name(name)
528
+ json_results = @option_type_lists_interface.list({name: name.to_s})
529
+ if json_results['optionTypeLists'].empty?
530
+ print_red_alert "Option List not found by name #{name}"
531
+ exit 1
532
+ end
533
+ option_type_list = json_results['optionTypeLists'][0]
534
+ return option_type_list
535
+ end
536
+
505
537
  end
@@ -550,10 +550,10 @@ module Morpheus::Cli::PrintHelper
550
550
  # label_width, justify = 0, "none"
551
551
  out = ""
552
552
  value = value.to_s
553
- if do_wrap && value && Morpheus::Cli::PrintHelper.terminal_width
553
+ if do_wrap && value && value.include?(" ") && Morpheus::Cli::PrintHelper.terminal_width
554
554
  value_width = Morpheus::Cli::PrintHelper.terminal_width - label_width
555
555
  if value_width > 0 && value.gsub(/\e\[(\d+)m/, '').to_s.size > value_width
556
- wrap_indent = label_width + 1 # plus 1 needs to go away
556
+ wrap_indent = label_width + 1
557
557
  value = wrap(value, value_width, wrap_indent)
558
558
  end
559
559
  end
@@ -571,7 +571,7 @@ module Morpheus::Cli::PrintHelper
571
571
  # truncate_string truncates a string and appends the suffix "..."
572
572
  # @param value [String] the string to pad
573
573
  # @param width [Integer] the length to truncate to
574
- # @param pad_char [String] the character to pad with. Default is ' '
574
+ # @param suffix [String] the character to pad right side with. Default is '...'
575
575
  def truncate_string(value, width, suffix="...")
576
576
  value = value.to_s
577
577
  # JD: hack alerty.. this sux, but it's a best effort to preserve values containing ascii coloring codes
@@ -603,6 +603,41 @@ module Morpheus::Cli::PrintHelper
603
603
  end
604
604
  end
605
605
 
606
+ # truncate_string truncates a string and appends the prefix "..."
607
+ # @param value [String] the string to pad
608
+ # @param width [Integer] the length to truncate to
609
+ # @param prefix [String] the character to pad left side with. Default is '...'
610
+ def truncate_string_right(value, width, prefix="...")
611
+ value = value.to_s
612
+ # JD: hack alerty.. this sux, but it's a best effort to preserve values containing ascii coloring codes
613
+ # it stops working when there are words separated by ascii codes, eg. two diff colors
614
+ # plus this is probably pretty slow...
615
+ uncolored_value = Term::ANSIColor.coloring? ? Term::ANSIColor.uncolored(value.to_s) : value.to_s
616
+ if uncolored_value != value
617
+ trimmed_value = nil
618
+ if uncolored_value.size > width
619
+ if prefix
620
+ trimmed_value = prefix + uncolored_value[(uncolored_value.size - width - prefix.size)..-1]
621
+ else
622
+ trimmed_value = uncolored_value[(uncolored_value.size - width)..-1]
623
+ end
624
+ return value.gsub(uncolored_value, trimmed_value)
625
+ else
626
+ return value
627
+ end
628
+ else
629
+ if value.size > width
630
+ if prefix
631
+ return prefix + value[(value.size - width - prefix.size)..-1]
632
+ else
633
+ return value[(value.size - width)..-1]
634
+ end
635
+ else
636
+ return value
637
+ end
638
+ end
639
+ end
640
+
606
641
  # justified returns a left, center, or right aligned string.
607
642
  # @param value [String] the string to pad
608
643
  # @param width [Integer] the length to truncate to
@@ -872,13 +907,7 @@ module Morpheus::Cli::PrintHelper
872
907
  out << color if color
873
908
  rows.each do |row|
874
909
  value = row[:value].to_s
875
- if do_wrap
876
- if value_width && value_width < value.size
877
- wrap_indent = label_width + 1
878
- value = wrap(value, value_width, wrap_indent)
879
- end
880
- end
881
- out << format_dt_dd(row[:label], value, label_width, justify) + "\n"
910
+ out << format_dt_dd(row[:label], value, label_width, justify, do_wrap) + "\n"
882
911
  end
883
912
  out << reset if color
884
913
  return out
@@ -47,7 +47,9 @@ module Morpheus
47
47
  end
48
48
  end
49
49
  # puts "Options Prompt #{options}"
50
- option_types.sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.each do |option_type|
50
+ # only sort if displayOrder is set
51
+ sorted_option_types = (option_types[0] && option_types[0]['displayOrder']) ? option_types.sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i } : option_types
52
+ sorted_option_types.each do |option_type|
51
53
  context_map = results
52
54
  value = nil
53
55
  value_found=false
@@ -71,17 +73,26 @@ module Morpheus
71
73
 
72
74
  # respect optionType.dependsOnCode
73
75
  if option_type['dependsOnCode'] && option_type['dependsOnCode'] != ""
74
- # optionTypes can have this setting in the format code=value or code:value
76
+ # support formats code=value or code:value OR code:(value|value2|value3)
75
77
  parts = option_type['dependsOnCode'].include?("=") ? option_type['dependsOnCode'].split("=") : option_type['dependsOnCode'].split(":")
76
78
  depends_on_code = parts[0]
77
- depends_on_value = parts[1]
79
+ depends_on_value = parts[1].to_s.strip
80
+ depends_on_values = []
81
+ if depends_on_value.size > 0
82
+ # strip parenthesis
83
+ if depends_on_value[0] && depends_on_value[0].chr == "("
84
+ depends_on_value = depends_on_value[1..-1]
85
+ end
86
+ depends_on_value.chomp(")")
87
+ depends_on_values = depends_on_value.split("|").collect { |it| it.strip }
88
+ end
78
89
  depends_on_option_type = option_types.find {|it| it["code"] == depends_on_code }
79
90
  # could not find the dependent option type, proceed and prompt
80
91
  if !depends_on_option_type.nil?
81
92
  # dependent option type has a different value
82
93
  depends_on_field_key = depends_on_option_type['fieldContext'] ? "#{depends_on_option_type['fieldContext']}.#{depends_on_option_type['fieldName']}" : "#{depends_on_option_type['fieldName']}"
83
94
  found_dep_value = get_object_value(results, depends_on_field_key) || get_object_value(options, depends_on_field_key)
84
- if depends_on_value && depends_on_value != found_dep_value
95
+ if depends_on_values.size > 0 && !depends_on_values.include?(found_dep_value)
85
96
  next
86
97
  end
87
98
  end