morpheus-cli 5.0.0 → 5.0.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.
- checksums.yaml +4 -4
 - data/Dockerfile +1 -1
 - data/lib/morpheus/api/api_client.rb +12 -0
 - data/lib/morpheus/api/billing_interface.rb +1 -0
 - data/lib/morpheus/api/deploy_interface.rb +1 -1
 - data/lib/morpheus/api/deployments_interface.rb +20 -1
 - data/lib/morpheus/api/forgot_password_interface.rb +17 -0
 - data/lib/morpheus/api/instances_interface.rb +7 -0
 - data/lib/morpheus/api/search_interface.rb +13 -0
 - data/lib/morpheus/api/servers_interface.rb +7 -0
 - data/lib/morpheus/api/usage_interface.rb +18 -0
 - data/lib/morpheus/cli.rb +4 -1
 - data/lib/morpheus/cli/cli_command.rb +26 -9
 - data/lib/morpheus/cli/commands/standard/curl_command.rb +3 -5
 - data/lib/morpheus/cli/commands/standard/history_command.rb +3 -1
 - data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
 - data/lib/morpheus/cli/deploy.rb +199 -90
 - data/lib/morpheus/cli/deployments.rb +341 -28
 - data/lib/morpheus/cli/deploys.rb +206 -41
 - data/lib/morpheus/cli/error_handler.rb +7 -0
 - data/lib/morpheus/cli/forgot_password.rb +133 -0
 - data/lib/morpheus/cli/health_command.rb +2 -2
 - data/lib/morpheus/cli/hosts.rb +169 -32
 - data/lib/morpheus/cli/instances.rb +83 -32
 - data/lib/morpheus/cli/invoices_command.rb +33 -16
 - data/lib/morpheus/cli/logs_command.rb +9 -6
 - data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -2
 - data/lib/morpheus/cli/mixins/print_helper.rb +0 -21
 - data/lib/morpheus/cli/mixins/provisioning_helper.rb +24 -4
 - data/lib/morpheus/cli/option_types.rb +266 -17
 - data/lib/morpheus/cli/remote.rb +35 -10
 - data/lib/morpheus/cli/reports_command.rb +99 -30
 - data/lib/morpheus/cli/search_command.rb +182 -0
 - data/lib/morpheus/cli/setup.rb +1 -1
 - data/lib/morpheus/cli/shell.rb +33 -11
 - data/lib/morpheus/cli/tasks.rb +20 -21
 - data/lib/morpheus/cli/usage_command.rb +64 -11
 - data/lib/morpheus/cli/version.rb +1 -1
 - data/lib/morpheus/cli/virtual_images.rb +280 -199
 - data/lib/morpheus/cli/whoami.rb +6 -6
 - data/lib/morpheus/cli/workflows.rb +33 -40
 - data/lib/morpheus/formatters.rb +22 -0
 - data/lib/morpheus/terminal.rb +6 -2
 - metadata +7 -2
 
| 
         @@ -25,16 +25,19 @@ class Morpheus::Cli::InvoicesCommand 
     | 
|
| 
       25 
25 
     | 
    
         
             
                options = {}
         
     | 
| 
       26 
26 
     | 
    
         
             
                params = {}
         
     | 
| 
       27 
27 
     | 
    
         
             
                ref_ids = []
         
     | 
| 
       28 
     | 
    
         
            -
                query_tags = {}
         
     | 
| 
       29 
28 
     | 
    
         
             
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         
     | 
| 
       30 
29 
     | 
    
         
             
                  opts.banner = subcommand_usage()
         
     | 
| 
       31 
30 
     | 
    
         
             
                  opts.on('-a', '--all', "Display all details, costs and prices." ) do
         
     | 
| 
       32 
31 
     | 
    
         
             
                    options[:show_all] = true
         
     | 
| 
      
 32 
     | 
    
         
            +
                    options[:show_dates] = true
         
     | 
| 
       33 
33 
     | 
    
         
             
                    options[:show_estimates] = true
         
     | 
| 
       34 
34 
     | 
    
         
             
                    # options[:show_costs] = true
         
     | 
| 
       35 
35 
     | 
    
         
             
                    options[:show_prices] = true
         
     | 
| 
       36 
36 
     | 
    
         
             
                    # options[:show_raw_data] = true
         
     | 
| 
       37 
37 
     | 
    
         
             
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  opts.on('--dates', "Display Ref Start, Ref End, etc.") do |val|
         
     | 
| 
      
 39 
     | 
    
         
            +
                    options[:show_dates] = true
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
       38 
41 
     | 
    
         
             
                  opts.on('--estimates', '--estimates', "Display all estimated costs, from usage info: Compute, Storage, Network, Extra" ) do
         
     | 
| 
       39 
42 
     | 
    
         
             
                    options[:show_estimates] = true
         
     | 
| 
       40 
43 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -107,9 +110,12 @@ class Morpheus::Cli::InvoicesCommand 
     | 
|
| 
       107 
110 
     | 
    
         
             
                    params['accountId'] = val
         
     | 
| 
       108 
111 
     | 
    
         
             
                  end
         
     | 
| 
       109 
112 
     | 
    
         
             
                  opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
         
     | 
| 
       110 
     | 
    
         
            -
                     
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
      
 113 
     | 
    
         
            +
                    val.split(",").each do |value_pair|
         
     | 
| 
      
 114 
     | 
    
         
            +
                      k,v = value_pair.strip.split("=")
         
     | 
| 
      
 115 
     | 
    
         
            +
                      options[:tags] ||= {}
         
     | 
| 
      
 116 
     | 
    
         
            +
                      options[:tags][k] ||= []
         
     | 
| 
      
 117 
     | 
    
         
            +
                      options[:tags][k] << (v || '')
         
     | 
| 
      
 118 
     | 
    
         
            +
                    end
         
     | 
| 
       113 
119 
     | 
    
         
             
                  end
         
     | 
| 
       114 
120 
     | 
    
         
             
                  opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
         
     | 
| 
       115 
121 
     | 
    
         
             
                    options[:show_raw_data] = true
         
     | 
| 
         @@ -169,8 +175,8 @@ class Morpheus::Cli::InvoicesCommand 
     | 
|
| 
       169 
175 
     | 
    
         
             
                end
         
     | 
| 
       170 
176 
     | 
    
         
             
                params['rawData'] = true if options[:show_raw_data]
         
     | 
| 
       171 
177 
     | 
    
         
             
                params['refId'] = ref_ids unless ref_ids.empty?
         
     | 
| 
       172 
     | 
    
         
            -
                if  
     | 
| 
       173 
     | 
    
         
            -
                   
     | 
| 
      
 178 
     | 
    
         
            +
                if options[:tags] && !options[:tags].empty?
         
     | 
| 
      
 179 
     | 
    
         
            +
                  options[:tags].each do |k,v|
         
     | 
| 
       174 
180 
     | 
    
         
             
                    params['tags.' + k] = v
         
     | 
| 
       175 
181 
     | 
    
         
             
                  end
         
     | 
| 
       176 
182 
     | 
    
         
             
                end
         
     | 
| 
         @@ -203,6 +209,7 @@ class Morpheus::Cli::InvoicesCommand 
     | 
|
| 
       203 
209 
     | 
    
         
             
                      {"INVOICE ID" => lambda {|it| it['id'] } },
         
     | 
| 
       204 
210 
     | 
    
         
             
                      {"TYPE" => lambda {|it| format_invoice_ref_type(it) } },
         
     | 
| 
       205 
211 
     | 
    
         
             
                      {"REF ID" => lambda {|it| it['refId'] } },
         
     | 
| 
      
 212 
     | 
    
         
            +
                      {"REF UUID" => lambda {|it| it['refUuid'] } },
         
     | 
| 
       206 
213 
     | 
    
         
             
                      {"REF NAME" => lambda {|it| 
         
     | 
| 
       207 
214 
     | 
    
         
             
                        if options[:show_all]
         
     | 
| 
       208 
215 
     | 
    
         
             
                          it['refName']
         
     | 
| 
         @@ -218,9 +225,11 @@ class Morpheus::Cli::InvoicesCommand 
     | 
|
| 
       218 
225 
     | 
    
         
             
                      {"PERIOD" => lambda {|it| format_invoice_period(it) } },
         
     | 
| 
       219 
226 
     | 
    
         
             
                      {"START" => lambda {|it| format_date(it['startDate']) } },
         
     | 
| 
       220 
227 
     | 
    
         
             
                      {"END" => lambda {|it| format_date(it['endDate']) } },
         
     | 
| 
       221 
     | 
    
         
            -
                    ] + (options[:show_all] ? [
         
     | 
| 
      
 228 
     | 
    
         
            +
                    ] + ((options[:show_dates] || options[:show_all]) ? [
         
     | 
| 
       222 
229 
     | 
    
         
             
                      {"REF START" => lambda {|it| format_dt(it['refStart']) } },
         
     | 
| 
       223 
230 
     | 
    
         
             
                      {"REF END" => lambda {|it| format_dt(it['refEnd']) } },
         
     | 
| 
      
 231 
     | 
    
         
            +
                      # {"LAST COST DATE" => lambda {|it| format_local_dt(it['lastCostDate']) } },
         
     | 
| 
      
 232 
     | 
    
         
            +
                      # {"LAST ACTUAL DATE" => lambda {|it| format_local_dt(it['lastActualDate']) } },
         
     | 
| 
       224 
233 
     | 
    
         
             
                    ] : []) + [
         
     | 
| 
       225 
234 
     | 
    
         
             
                      {"COMPUTE" => lambda {|it| format_money(it['computeCost'], 'usd', {sigdig:options[:sigdig]}) } },
         
     | 
| 
       226 
235 
     | 
    
         
             
                      # {"MEMORY" => lambda {|it| format_money(it['memoryCost']) } },
         
     | 
| 
         @@ -272,9 +281,15 @@ class Morpheus::Cli::InvoicesCommand 
     | 
|
| 
       272 
281 
     | 
    
         
             
                      {"PROJECT TAGS" => lambda {|it| it['project'] ? truncate_string(format_metadata(it['project']['tags']), 50) : '' } },
         
     | 
| 
       273 
282 
     | 
    
         
             
                    ]
         
     | 
| 
       274 
283 
     | 
    
         
             
                    end
         
     | 
| 
      
 284 
     | 
    
         
            +
                    if options[:show_dates]
         
     | 
| 
      
 285 
     | 
    
         
            +
                      columns += [
         
     | 
| 
      
 286 
     | 
    
         
            +
                        {"LAST COST DATE" => lambda {|it| format_local_dt(it['lastCostDate']) } },
         
     | 
| 
      
 287 
     | 
    
         
            +
                        {"LAST ACTUAL DATE" => lambda {|it| format_local_dt(it['lastActualDate']) } },
         
     | 
| 
      
 288 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 289 
     | 
    
         
            +
                    end
         
     | 
| 
       275 
290 
     | 
    
         
             
                    columns += [
         
     | 
| 
       276 
291 
     | 
    
         
             
                      {"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
         
     | 
| 
       277 
     | 
    
         
            -
                      {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } }
         
     | 
| 
      
 292 
     | 
    
         
            +
                      {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } },
         
     | 
| 
       278 
293 
     | 
    
         
             
                    ]
         
     | 
| 
       279 
294 
     | 
    
         
             
                    if options[:show_raw_data]
         
     | 
| 
       280 
295 
     | 
    
         
             
                      columns += [{"RAW DATA" => lambda {|it| truncate_string(it['rawData'].to_s, 10) } }]
         
     | 
| 
         @@ -656,7 +671,6 @@ EOT 
     | 
|
| 
       656 
671 
     | 
    
         
             
                options = {}
         
     | 
| 
       657 
672 
     | 
    
         
             
                params = {}
         
     | 
| 
       658 
673 
     | 
    
         
             
                ref_ids = []
         
     | 
| 
       659 
     | 
    
         
            -
                query_tags = {}
         
     | 
| 
       660 
674 
     | 
    
         
             
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         
     | 
| 
       661 
675 
     | 
    
         
             
                  opts.banner = subcommand_usage()
         
     | 
| 
       662 
676 
     | 
    
         
             
                  opts.on('-a', '--all', "Display all details, costs and prices." ) do
         
     | 
| 
         @@ -744,11 +758,14 @@ EOT 
     | 
|
| 
       744 
758 
     | 
    
         
             
                  opts.on('--tenant ID', String, "View invoice line items for a tenant. Default is your own account.") do |val|
         
     | 
| 
       745 
759 
     | 
    
         
             
                    params['accountId'] = val
         
     | 
| 
       746 
760 
     | 
    
         
             
                  end
         
     | 
| 
       747 
     | 
    
         
            -
                   
     | 
| 
       748 
     | 
    
         
            -
             
     | 
| 
       749 
     | 
    
         
            -
             
     | 
| 
       750 
     | 
    
         
            -
             
     | 
| 
       751 
     | 
    
         
            -
             
     | 
| 
      
 761 
     | 
    
         
            +
                  opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
         
     | 
| 
      
 762 
     | 
    
         
            +
                    val.split(",").each do |value_pair|
         
     | 
| 
      
 763 
     | 
    
         
            +
                      k,v = value_pair.strip.split("=")
         
     | 
| 
      
 764 
     | 
    
         
            +
                      options[:tags] ||= {}
         
     | 
| 
      
 765 
     | 
    
         
            +
                      options[:tags][k] ||= []
         
     | 
| 
      
 766 
     | 
    
         
            +
                      options[:tags][k] << (v || '')
         
     | 
| 
      
 767 
     | 
    
         
            +
                    end
         
     | 
| 
      
 768 
     | 
    
         
            +
                  end
         
     | 
| 
       752 
769 
     | 
    
         
             
                  opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
         
     | 
| 
       753 
770 
     | 
    
         
             
                    options[:show_raw_data] = true
         
     | 
| 
       754 
771 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -808,8 +825,8 @@ EOT 
     | 
|
| 
       808 
825 
     | 
    
         
             
                end
         
     | 
| 
       809 
826 
     | 
    
         
             
                params['rawData'] = true if options[:show_raw_data]
         
     | 
| 
       810 
827 
     | 
    
         
             
                params['refId'] = ref_ids unless ref_ids.empty?
         
     | 
| 
       811 
     | 
    
         
            -
                if  
     | 
| 
       812 
     | 
    
         
            -
                   
     | 
| 
      
 828 
     | 
    
         
            +
                if options[:tags] && !options[:tags].empty?
         
     | 
| 
      
 829 
     | 
    
         
            +
                  options[:tags].each do |k,v|
         
     | 
| 
       813 
830 
     | 
    
         
             
                    params['tags.' + k] = v
         
     | 
| 
       814 
831 
     | 
    
         
             
                  end
         
     | 
| 
       815 
832 
     | 
    
         
             
                end
         
     | 
| 
         @@ -34,7 +34,7 @@ class Morpheus::Cli::LogsCommand 
     | 
|
| 
       34 
34 
     | 
    
         
             
                options = {}
         
     | 
| 
       35 
35 
     | 
    
         
             
                params = {}
         
     | 
| 
       36 
36 
     | 
    
         
             
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         
     | 
| 
       37 
     | 
    
         
            -
                  opts.banner = subcommand_usage("[ 
     | 
| 
      
 37 
     | 
    
         
            +
                  opts.banner = subcommand_usage("[search]")
         
     | 
| 
       38 
38 
     | 
    
         
             
                  opts.on('--hosts HOSTS', String, "Filter logs to specific Host ID(s)") do |val|
         
     | 
| 
       39 
39 
     | 
    
         
             
                    params['servers'] = val.to_s.split(",").collect {|it| it.to_s.strip }.select {|it| it }.compact
         
     | 
| 
       40 
40 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -72,18 +72,21 @@ class Morpheus::Cli::LogsCommand 
     | 
|
| 
       72 
72 
     | 
    
         
             
                    options[:details] = true
         
     | 
| 
       73 
73 
     | 
    
         
             
                  end
         
     | 
| 
       74 
74 
     | 
    
         
             
                  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
         
     | 
| 
       75 
     | 
    
         
            -
                  opts.footer = "List logs for  
     | 
| 
       76 
     | 
    
         
            -
                                "[id] is required. This is the id of a container."
         
     | 
| 
      
 75 
     | 
    
         
            +
                  opts.footer = "List logs for all hosts and containers."
         
     | 
| 
       77 
76 
     | 
    
         
             
                end
         
     | 
| 
       78 
77 
     | 
    
         
             
                optparse.parse!(args)
         
     | 
| 
       79 
     | 
    
         
            -
                if args.count  
     | 
| 
       80 
     | 
    
         
            -
                   
     | 
| 
      
 78 
     | 
    
         
            +
                if args.count > 0
         
     | 
| 
      
 79 
     | 
    
         
            +
                  options[:phrase] = args.join(" ")
         
     | 
| 
       81 
80 
     | 
    
         
             
                end
         
     | 
| 
       82 
81 
     | 
    
         
             
                connect(options)
         
     | 
| 
       83 
82 
     | 
    
         
             
                begin
         
     | 
| 
       84 
83 
     | 
    
         
             
                  params['level'] = params['level'].collect {|it| it.to_s.upcase }.join('|') if params['level'] # api works with INFO|WARN
         
     | 
| 
       85 
84 
     | 
    
         
             
                  params.merge!(parse_list_options(options))
         
     | 
| 
       86 
     | 
    
         
            -
                   
     | 
| 
      
 85 
     | 
    
         
            +
                  if params['phrase']
         
     | 
| 
      
 86 
     | 
    
         
            +
                    options.delete(:phrase)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    search_phrase = params.delete('phrase')
         
     | 
| 
      
 88 
     | 
    
         
            +
                    params['query'] = search_phrase
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
       87 
90 
     | 
    
         
             
                  params['order'] = params['direction'] unless params['direction'].nil? # old api version expects order instead of direction
         
     | 
| 
       88 
91 
     | 
    
         
             
                  params['startMs'] = (options[:start].to_i * 1000) if options[:start]
         
     | 
| 
       89 
92 
     | 
    
         
             
                  params['endMs'] = (options[:end].to_i * 1000) if options[:end]
         
     | 
| 
         @@ -51,9 +51,10 @@ module Morpheus::Cli::DeploymentsHelper 
     | 
|
| 
       51 
51 
     | 
    
         
             
                  return nil
         
     | 
| 
       52 
52 
     | 
    
         
             
                elsif deployments.size > 1
         
     | 
| 
       53 
53 
     | 
    
         
             
                  print_red_alert "#{deployments.size} deployments found by name '#{name}'"
         
     | 
| 
      
 54 
     | 
    
         
            +
                  print_error "\n"
         
     | 
| 
       54 
55 
     | 
    
         
             
                  puts_error as_pretty_table(deployments, [:id, :name], {color:red})
         
     | 
| 
       55 
56 
     | 
    
         
             
                  print_red_alert "Try using ID instead"
         
     | 
| 
       56 
     | 
    
         
            -
                   
     | 
| 
      
 57 
     | 
    
         
            +
                  print_error reset,"\n"
         
     | 
| 
       57 
58 
     | 
    
         
             
                  return nil
         
     | 
| 
       58 
59 
     | 
    
         
             
                else
         
     | 
| 
       59 
60 
     | 
    
         
             
                  return deployments[0]
         
     | 
| 
         @@ -122,13 +123,41 @@ module Morpheus::Cli::DeploymentsHelper 
     | 
|
| 
       122 
123 
     | 
    
         
             
                  return nil
         
     | 
| 
       123 
124 
     | 
    
         
             
                elsif deployment_versions.size > 1
         
     | 
| 
       124 
125 
     | 
    
         
             
                  print_red_alert "#{deployment_versions.size} deployment versions found by version '#{name}'"
         
     | 
| 
      
 126 
     | 
    
         
            +
                  print_error "\n"
         
     | 
| 
       125 
127 
     | 
    
         
             
                  puts_error as_pretty_table(deployment_versions, {"ID" => 'id', "VERSION" => 'userVersion'}, {color:red})
         
     | 
| 
       126 
128 
     | 
    
         
             
                  print_red_alert "Try using ID instead"
         
     | 
| 
       127 
     | 
    
         
            -
                   
     | 
| 
      
 129 
     | 
    
         
            +
                  print_error reset,"\n"
         
     | 
| 
       128 
130 
     | 
    
         
             
                  return nil
         
     | 
| 
       129 
131 
     | 
    
         
             
                else
         
     | 
| 
       130 
132 
     | 
    
         
             
                  return deployment_versions[0]
         
     | 
| 
       131 
133 
     | 
    
         
             
                end
         
     | 
| 
       132 
134 
     | 
    
         
             
              end
         
     | 
| 
       133 
135 
     | 
    
         | 
| 
      
 136 
     | 
    
         
            +
              def format_deployment_version_number(deployment_version)
         
     | 
| 
      
 137 
     | 
    
         
            +
                if deployment_version
         
     | 
| 
      
 138 
     | 
    
         
            +
                  deployment_version['userVersion'] || deployment_version['version'] || ''
         
     | 
| 
      
 139 
     | 
    
         
            +
                else
         
     | 
| 
      
 140 
     | 
    
         
            +
                  ''
         
     | 
| 
      
 141 
     | 
    
         
            +
                end
         
     | 
| 
      
 142 
     | 
    
         
            +
              end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
              def format_app_deploy_status(status, return_color=cyan)
         
     | 
| 
      
 145 
     | 
    
         
            +
                out = ""
         
     | 
| 
      
 146 
     | 
    
         
            +
                s = status.to_s.downcase
         
     | 
| 
      
 147 
     | 
    
         
            +
                if s == 'deployed' || s == 'committed'
         
     | 
| 
      
 148 
     | 
    
         
            +
                  out << "#{green}#{s.upcase}#{return_color}"
         
     | 
| 
      
 149 
     | 
    
         
            +
                elsif s == 'open' || s == 'archived'
         
     | 
| 
      
 150 
     | 
    
         
            +
                  out << "#{cyan}#{s.upcase}#{return_color}"
         
     | 
| 
      
 151 
     | 
    
         
            +
                elsif s == 'failed'
         
     | 
| 
      
 152 
     | 
    
         
            +
                  out << "#{red}#{s.upcase}#{return_color}"
         
     | 
| 
      
 153 
     | 
    
         
            +
                else
         
     | 
| 
      
 154 
     | 
    
         
            +
                  out << "#{yellow}#{s.upcase}#{return_color}"
         
     | 
| 
      
 155 
     | 
    
         
            +
                end
         
     | 
| 
      
 156 
     | 
    
         
            +
                out
         
     | 
| 
      
 157 
     | 
    
         
            +
              end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
              def format_deploy_type(val)
         
     | 
| 
      
 160 
     | 
    
         
            +
                return val
         
     | 
| 
      
 161 
     | 
    
         
            +
              end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
       134 
163 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1151,27 +1151,6 @@ module Morpheus::Cli::PrintHelper 
     | 
|
| 
       1151 
1151 
     | 
    
         
             
                out
         
     | 
| 
       1152 
1152 
     | 
    
         
             
              end
         
     | 
| 
       1153 
1153 
     | 
    
         | 
| 
       1154 
     | 
    
         
            -
              def format_list(items, conjunction="and", limit=nil)
         
     | 
| 
       1155 
     | 
    
         
            -
                items = items ? items.clone : []
         
     | 
| 
       1156 
     | 
    
         
            -
                if limit
         
     | 
| 
       1157 
     | 
    
         
            -
                  items = items.first(limit)
         
     | 
| 
       1158 
     | 
    
         
            -
                end
         
     | 
| 
       1159 
     | 
    
         
            -
                last_item = items.pop
         
     | 
| 
       1160 
     | 
    
         
            -
                if items.empty?
         
     | 
| 
       1161 
     | 
    
         
            -
                  return "#{last_item}"
         
     | 
| 
       1162 
     | 
    
         
            -
                else
         
     | 
| 
       1163 
     | 
    
         
            -
                  return items.join(", ") + (conjunction.to_s.empty? ? ", " : " #{conjunction} ") + "#{last_item}" + ((limit && limit < (items.size+1)) ? " ..." : "")
         
     | 
| 
       1164 
     | 
    
         
            -
                end
         
     | 
| 
       1165 
     | 
    
         
            -
              end
         
     | 
| 
       1166 
     | 
    
         
            -
             
     | 
| 
       1167 
     | 
    
         
            -
              def anded_list(items, limit=nil)
         
     | 
| 
       1168 
     | 
    
         
            -
                format_list(items, "and", limit)
         
     | 
| 
       1169 
     | 
    
         
            -
              end
         
     | 
| 
       1170 
     | 
    
         
            -
             
     | 
| 
       1171 
     | 
    
         
            -
              def ored_list(items, limit=nil)
         
     | 
| 
       1172 
     | 
    
         
            -
                format_list(items, "or", limit)
         
     | 
| 
       1173 
     | 
    
         
            -
              end
         
     | 
| 
       1174 
     | 
    
         
            -
             
     | 
| 
       1175 
1154 
     | 
    
         
             
              def sleep_with_dots(sleep_seconds, dots=3, dot_chr=".")
         
     | 
| 
       1176 
1155 
     | 
    
         
             
                dot_interval = (sleep_seconds.to_f / dots.to_i)
         
     | 
| 
       1177 
1156 
     | 
    
         
             
                dots.to_i.times do |dot_index|
         
     | 
| 
         @@ -596,11 +596,13 @@ module Morpheus::Cli::ProvisioningHelper 
     | 
|
| 
       596 
596 
     | 
    
         
             
                v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments()}], options[:options])
         
     | 
| 
       597 
597 
     | 
    
         
             
                payload['instance']['instanceContext'] = v_prompt['environment'] if !v_prompt['environment'].empty?
         
     | 
| 
       598 
598 
     | 
    
         | 
| 
       599 
     | 
    
         
            -
                # Labels (tags)
         
     | 
| 
       600 
     | 
    
         
            -
                 
     | 
| 
       601 
     | 
    
         
            -
             
     | 
| 
      
 599 
     | 
    
         
            +
                # Labels (Provisioning API still refers to these as tags)
         
     | 
| 
      
 600 
     | 
    
         
            +
                # and tags (metadata tags) is called metadata.
         
     | 
| 
      
 601 
     | 
    
         
            +
                # todo: switch this from 'tags' to labels' when the api changes
         
     | 
| 
      
 602 
     | 
    
         
            +
                if options[:labels]
         
     | 
| 
      
 603 
     | 
    
         
            +
                  payload['instance']['tags'] = options[:labels].is_a?(Array) ? options[:labels] : options[:labels].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
         
     | 
| 
       602 
604 
     | 
    
         
             
                else
         
     | 
| 
       603 
     | 
    
         
            -
                  v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => ' 
     | 
| 
      
 605 
     | 
    
         
            +
                  v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false}], options[:options])
         
     | 
| 
       604 
606 
     | 
    
         
             
                  payload['instance']['tags'] = v_prompt['tags'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['tags'].empty?
         
     | 
| 
       605 
607 
     | 
    
         
             
                end
         
     | 
| 
       606 
608 
     | 
    
         | 
| 
         @@ -976,6 +978,9 @@ module Morpheus::Cli::ProvisioningHelper 
     | 
|
| 
       976 
978 
     | 
    
         
             
                    metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
         
     | 
| 
       977 
979 
     | 
    
         
             
                    metadata_list = metadata_list.collect do |it|
         
     | 
| 
       978 
980 
     | 
    
         
             
                      metadata_pair = it.split(":")
         
     | 
| 
      
 981 
     | 
    
         
            +
                      if metadata_pair.size < 2 && it.include?("=")
         
     | 
| 
      
 982 
     | 
    
         
            +
                        metadata_pair = it.split("=")
         
     | 
| 
      
 983 
     | 
    
         
            +
                      end
         
     | 
| 
       979 
984 
     | 
    
         
             
                      row = {}
         
     | 
| 
       980 
985 
     | 
    
         
             
                      row['name'] = metadata_pair[0].to_s.strip
         
     | 
| 
       981 
986 
     | 
    
         
             
                      row['value'] = metadata_pair[1].to_s.strip
         
     | 
| 
         @@ -2200,4 +2205,19 @@ module Morpheus::Cli::ProvisioningHelper 
     | 
|
| 
       2200 
2205 
     | 
    
         
             
                  return type_code.to_s.downcase
         
     | 
| 
       2201 
2206 
     | 
    
         
             
                end
         
     | 
| 
       2202 
2207 
     | 
    
         
             
              end
         
     | 
| 
      
 2208 
     | 
    
         
            +
             
     | 
| 
      
 2209 
     | 
    
         
            +
              def format_snapshot_status(snapshot, return_color=cyan)
         
     | 
| 
      
 2210 
     | 
    
         
            +
                out = ""
         
     | 
| 
      
 2211 
     | 
    
         
            +
                status_string = snapshot['status'].to_s
         
     | 
| 
      
 2212 
     | 
    
         
            +
                if status_string == 'complete'
         
     | 
| 
      
 2213 
     | 
    
         
            +
                  out << "#{green}#{status_string.upcase}#{return_color}"
         
     | 
| 
      
 2214 
     | 
    
         
            +
                elsif status_string == 'creating'
         
     | 
| 
      
 2215 
     | 
    
         
            +
                  out << "#{cyan}#{status_string.upcase}#{return_color}"
         
     | 
| 
      
 2216 
     | 
    
         
            +
                elsif status_string == 'failed'
         
     | 
| 
      
 2217 
     | 
    
         
            +
                  out << "#{red}#{status_string.upcase}#{return_color}"
         
     | 
| 
      
 2218 
     | 
    
         
            +
                else
         
     | 
| 
      
 2219 
     | 
    
         
            +
                  out << "#{yellow}#{status_string.upcase}#{return_color}"
         
     | 
| 
      
 2220 
     | 
    
         
            +
                end
         
     | 
| 
      
 2221 
     | 
    
         
            +
                out
         
     | 
| 
      
 2222 
     | 
    
         
            +
              end
         
     | 
| 
       2203 
2223 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,6 +5,7 @@ module Morpheus 
     | 
|
| 
       5 
5 
     | 
    
         
             
              module Cli
         
     | 
| 
       6 
6 
     | 
    
         
             
                module OptionTypes
         
     | 
| 
       7 
7 
     | 
    
         
             
                  include Term::ANSIColor
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # include Morpheus::Cli::PrintHelper
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
10 
     | 
    
         
             
                  def self.confirm(message,options={})
         
     | 
| 
       10 
11 
     | 
    
         
             
                    if options[:yes] == true
         
     | 
| 
         @@ -72,9 +73,15 @@ module Morpheus 
     | 
|
| 
       72 
73 
     | 
    
         
             
                      field_name = namespaces.pop
         
     | 
| 
       73 
74 
     | 
    
         | 
| 
       74 
75 
     | 
    
         
             
                      # respect optionType.dependsOnCode
         
     | 
| 
       75 
     | 
    
         
            -
                       
     | 
| 
      
 76 
     | 
    
         
            +
                      # i guess this switched to visibleOnCode, respect one or the other
         
     | 
| 
      
 77 
     | 
    
         
            +
                      visible_option_check_value = option_type['dependsOnCode']
         
     | 
| 
      
 78 
     | 
    
         
            +
                      if !option_type['visibleOnCode'].to_s.empty?
         
     | 
| 
      
 79 
     | 
    
         
            +
                        visible_option_check_value = option_type['visibleOnCode']
         
     | 
| 
      
 80 
     | 
    
         
            +
                      end
         
     | 
| 
      
 81 
     | 
    
         
            +
                      if !visible_option_check_value.to_s.empty?
         
     | 
| 
       76 
82 
     | 
    
         
             
                        # support formats code=value or code:value OR code:(value|value2|value3)
         
     | 
| 
       77 
     | 
    
         
            -
                         
     | 
| 
      
 83 
     | 
    
         
            +
                        # OR fieldContext.fieldName=value
         
     | 
| 
      
 84 
     | 
    
         
            +
                        parts = visible_option_check_value.include?("=") ? visible_option_check_value.split("=") : visible_option_check_value.split(":")
         
     | 
| 
       78 
85 
     | 
    
         
             
                        depends_on_code = parts[0]
         
     | 
| 
       79 
86 
     | 
    
         
             
                        depends_on_value = parts[1].to_s.strip
         
     | 
| 
       80 
87 
     | 
    
         
             
                        depends_on_values = []
         
     | 
| 
         @@ -87,14 +94,29 @@ module Morpheus 
     | 
|
| 
       87 
94 
     | 
    
         
             
                          depends_on_values = depends_on_value.split("|").collect { |it| it.strip }
         
     | 
| 
       88 
95 
     | 
    
         
             
                        end
         
     | 
| 
       89 
96 
     | 
    
         
             
                        depends_on_option_type = option_types.find {|it| it["code"] == depends_on_code }
         
     | 
| 
       90 
     | 
    
         
            -
                         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 97 
     | 
    
         
            +
                        if !depends_on_option_type
         
     | 
| 
      
 98 
     | 
    
         
            +
                          depends_on_option_type = option_types.find {|it| 
         
     | 
| 
      
 99 
     | 
    
         
            +
                            (it['fieldContext'] ? "#{it['fieldContext']}.#{it['fieldName']}" : it['fieldName']) == depends_on_code
         
     | 
| 
      
 100 
     | 
    
         
            +
                          }
         
     | 
| 
      
 101 
     | 
    
         
            +
                        end
         
     | 
| 
      
 102 
     | 
    
         
            +
                        if depends_on_option_type
         
     | 
| 
       92 
103 
     | 
    
         
             
                          # dependent option type has a different value
         
     | 
| 
       93 
104 
     | 
    
         
             
                          depends_on_field_key = depends_on_option_type['fieldContext'] ? "#{depends_on_option_type['fieldContext']}.#{depends_on_option_type['fieldName']}" : "#{depends_on_option_type['fieldName']}"
         
     | 
| 
       94 
105 
     | 
    
         
             
                          found_dep_value = get_object_value(results, depends_on_field_key) || get_object_value(options, depends_on_field_key)
         
     | 
| 
       95 
     | 
    
         
            -
                          if depends_on_values.size > 0 
     | 
| 
       96 
     | 
    
         
            -
                             
     | 
| 
      
 106 
     | 
    
         
            +
                          if depends_on_values.size > 0
         
     | 
| 
      
 107 
     | 
    
         
            +
                            # must be in the specified values
         
     | 
| 
      
 108 
     | 
    
         
            +
                            # todo: uhh this actually needs to change to parse regex
         
     | 
| 
      
 109 
     | 
    
         
            +
                            if !depends_on_values.include?(found_dep_value)
         
     | 
| 
      
 110 
     | 
    
         
            +
                              next
         
     | 
| 
      
 111 
     | 
    
         
            +
                            end
         
     | 
| 
      
 112 
     | 
    
         
            +
                          else
         
     | 
| 
      
 113 
     | 
    
         
            +
                            # no value found
         
     | 
| 
      
 114 
     | 
    
         
            +
                            if found_dep_value.to_s.empty?
         
     | 
| 
      
 115 
     | 
    
         
            +
                              next
         
     | 
| 
      
 116 
     | 
    
         
            +
                            end
         
     | 
| 
       97 
117 
     | 
    
         
             
                          end
         
     | 
| 
      
 118 
     | 
    
         
            +
                        else
         
     | 
| 
      
 119 
     | 
    
         
            +
                          # could not find the dependent option type, proceed and prompt
         
     | 
| 
       98 
120 
     | 
    
         
             
                        end
         
     | 
| 
       99 
121 
     | 
    
         
             
                      end
         
     | 
| 
       100 
122 
     | 
    
         | 
| 
         @@ -115,7 +137,7 @@ module Morpheus 
     | 
|
| 
       115 
137 
     | 
    
         
             
                      # use the value passed in the options map
         
     | 
| 
       116 
138 
     | 
    
         
             
                      if cur_namespace.respond_to?('key?') && cur_namespace.key?(field_name)
         
     | 
| 
       117 
139 
     | 
    
         
             
                        value = cur_namespace[field_name]
         
     | 
| 
       118 
     | 
    
         
            -
                        input_value = ['select', 'multiSelect'].include?(option_type['type']) && option_type['fieldInput'] ? cur_namespace[option_type['fieldInput']] : nil
         
     | 
| 
      
 140 
     | 
    
         
            +
                        input_value = ['select', 'multiSelect','typeahead', 'multiTypeahead'].include?(option_type['type']) && option_type['fieldInput'] ? cur_namespace[option_type['fieldInput']] : nil
         
     | 
| 
       119 
141 
     | 
    
         
             
                        if option_type['type'] == 'number'
         
     | 
| 
       120 
142 
     | 
    
         
             
                          value = value.to_s.include?('.') ? value.to_f : value.to_i
         
     | 
| 
       121 
143 
     | 
    
         
             
                        # these select prompts should just fall down through below, with the extra params no_prompt, use_value
         
     | 
| 
         @@ -130,7 +152,17 @@ module Morpheus 
     | 
|
| 
       130 
152 
     | 
    
         
             
                            select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, (api_params || {}).merge(results), true)
         
     | 
| 
       131 
153 
     | 
    
         
             
                          end
         
     | 
| 
       132 
154 
     | 
    
         
             
                          value = select_value_list
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
      
 155 
     | 
    
         
            +
                        elsif option_type['type'] == 'typeahead'
         
     | 
| 
      
 156 
     | 
    
         
            +
                          value = typeahead_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, (api_params || {}).merge(results), true)
         
     | 
| 
      
 157 
     | 
    
         
            +
                        elsif option_type['type'] == 'multiTypeahead'
         
     | 
| 
      
 158 
     | 
    
         
            +
                          # support value as csv like "thing1, thing2"
         
     | 
| 
      
 159 
     | 
    
         
            +
                          value_list = value.is_a?(String) ? value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [value].flatten
         
     | 
| 
      
 160 
     | 
    
         
            +
                          input_value_list = input_value.is_a?(String) ? input_value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [input_value].flatten
         
     | 
| 
      
 161 
     | 
    
         
            +
                          select_value_list = []
         
     | 
| 
      
 162 
     | 
    
         
            +
                          value_list.each_with_index do |v, i|
         
     | 
| 
      
 163 
     | 
    
         
            +
                            select_value_list << typeahead_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, (api_params || {}).merge(results), true)
         
     | 
| 
      
 164 
     | 
    
         
            +
                          end
         
     | 
| 
      
 165 
     | 
    
         
            +
                          value = select_value_list
         
     | 
| 
       134 
166 
     | 
    
         
             
                        end
         
     | 
| 
       135 
167 
     | 
    
         
             
                        if options[:always_prompt] != true
         
     | 
| 
       136 
168 
     | 
    
         
             
                          value_found = true
         
     | 
| 
         @@ -147,7 +179,7 @@ module Morpheus 
     | 
|
| 
       147 
179 
     | 
    
         
             
                      no_prompt = no_prompt || options[:no_prompt]
         
     | 
| 
       148 
180 
     | 
    
         
             
                      if no_prompt
         
     | 
| 
       149 
181 
     | 
    
         
             
                        if !value_found
         
     | 
| 
       150 
     | 
    
         
            -
                          if option_type['defaultValue'] != nil && !['select', 'multiSelect'].include?(option_type['type'])
         
     | 
| 
      
 182 
     | 
    
         
            +
                          if option_type['defaultValue'] != nil && !['select', 'multiSelect','typeahead','multiTypeahead'].include?(option_type['type'])
         
     | 
| 
       151 
183 
     | 
    
         
             
                            value = option_type['defaultValue']
         
     | 
| 
       152 
184 
     | 
    
         
             
                            value_found = true
         
     | 
| 
       153 
185 
     | 
    
         
             
                          end
         
     | 
| 
         @@ -158,6 +190,10 @@ module Morpheus 
     | 
|
| 
       158 
190 
     | 
    
         
             
                              value = select_prompt(option_type, api_client, (api_params || {}).merge(results), true)
         
     | 
| 
       159 
191 
     | 
    
         
             
                              value_found = !!value
         
     | 
| 
       160 
192 
     | 
    
         
             
                            end
         
     | 
| 
      
 193 
     | 
    
         
            +
                            if ['typeahead', 'multiTypeahead'].include?(option_type['type'])
         
     | 
| 
      
 194 
     | 
    
         
            +
                              value = typeahead_prompt(option_type, api_client, (api_params || {}).merge(results), true)
         
     | 
| 
      
 195 
     | 
    
         
            +
                              value_found = !!value
         
     | 
| 
      
 196 
     | 
    
         
            +
                            end
         
     | 
| 
       161 
197 
     | 
    
         
             
                            if !value_found
         
     | 
| 
       162 
198 
     | 
    
         
             
                              if option_type['required']
         
     | 
| 
       163 
199 
     | 
    
         
             
                                print Term::ANSIColor.red, "\nMissing Required Option\n\n", Term::ANSIColor.reset
         
     | 
| 
         @@ -203,6 +239,18 @@ module Morpheus 
     | 
|
| 
       203 
239 
     | 
    
         
             
                              end
         
     | 
| 
       204 
240 
     | 
    
         
             
                            end
         
     | 
| 
       205 
241 
     | 
    
         
             
                          end
         
     | 
| 
      
 242 
     | 
    
         
            +
                        elsif ['typeahead', 'multiTypeahead'].include?(option_type['type'])
         
     | 
| 
      
 243 
     | 
    
         
            +
                          value = typeahead_prompt(option_type, api_client, (api_params || {}).merge(results), options[:no_prompt], nil, paging_enabled)
         
     | 
| 
      
 244 
     | 
    
         
            +
                          if value && option_type['type'] == 'multiTypeahead'
         
     | 
| 
      
 245 
     | 
    
         
            +
                            value = [value]
         
     | 
| 
      
 246 
     | 
    
         
            +
                            while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => false}) do
         
     | 
| 
      
 247 
     | 
    
         
            +
                              if addn_value = typeahead_prompt(option_type, api_client, (api_params || {}).merge(results), options[:no_prompt], nil, paging_enabled)
         
     | 
| 
      
 248 
     | 
    
         
            +
                                value << addn_value
         
     | 
| 
      
 249 
     | 
    
         
            +
                              else
         
     | 
| 
      
 250 
     | 
    
         
            +
                                break
         
     | 
| 
      
 251 
     | 
    
         
            +
                              end
         
     | 
| 
      
 252 
     | 
    
         
            +
                            end
         
     | 
| 
      
 253 
     | 
    
         
            +
                          end
         
     | 
| 
       206 
254 
     | 
    
         
             
                        elsif option_type['type'] == 'hidden'
         
     | 
| 
       207 
255 
     | 
    
         
             
                          value = option_type['defaultValue']
         
     | 
| 
       208 
256 
     | 
    
         
             
                          input = value
         
     | 
| 
         @@ -310,11 +358,12 @@ module Morpheus 
     | 
|
| 
       310 
358 
     | 
    
         
             
                    value_field = (option_type['config'] ? option_type['config']['valueField'] : nil) || 'value'
         
     | 
| 
       311 
359 
     | 
    
         
             
                    default_value = option_type['defaultValue']
         
     | 
| 
       312 
360 
     | 
    
         
             
                    default_value = default_value['id'] if default_value && default_value.is_a?(Hash) && !default_value['id'].nil?
         
     | 
| 
      
 361 
     | 
    
         
            +
                    api_params ||= {}
         
     | 
| 
       313 
362 
     | 
    
         
             
                    # local array of options
         
     | 
| 
       314 
363 
     | 
    
         
             
                    if option_type['selectOptions']
         
     | 
| 
       315 
364 
     | 
    
         
             
                      # calculate from inline lambda
         
     | 
| 
       316 
365 
     | 
    
         
             
                      if option_type['selectOptions'].is_a?(Proc)
         
     | 
| 
       317 
     | 
    
         
            -
                        select_options = option_type['selectOptions'].call()
         
     | 
| 
      
 366 
     | 
    
         
            +
                        select_options = option_type['selectOptions'].call(api_client, grails_params(api_params || {}))
         
     | 
| 
       318 
367 
     | 
    
         
             
                      else
         
     | 
| 
       319 
368 
     | 
    
         
             
                        # todo: better type validation
         
     | 
| 
       320 
369 
     | 
    
         
             
                        select_options = option_type['selectOptions']
         
     | 
| 
         @@ -325,7 +374,7 @@ module Morpheus 
     | 
|
| 
       325 
374 
     | 
    
         
             
                        select_options = option_type['optionSource'].call(api_client, grails_params(api_params || {}))
         
     | 
| 
       326 
375 
     | 
    
         
             
                      elsif option_type['optionSource'] == 'list'
         
     | 
| 
       327 
376 
     | 
    
         
             
                        # /api/options/list is a special action for custom OptionTypeLists, just need to pass the optionTypeId parameter
         
     | 
| 
       328 
     | 
    
         
            -
                        select_options = load_source_options(option_type['optionSource'], api_client, {'optionTypeId' => option_type['id']})
         
     | 
| 
      
 377 
     | 
    
         
            +
                        select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}).merge({'optionTypeId' => option_type['id']}))
         
     | 
| 
       329 
378 
     | 
    
         
             
                      else
         
     | 
| 
       330 
379 
     | 
    
         
             
                        # remote optionSource aka /api/options/$optionSource?
         
     | 
| 
       331 
380 
     | 
    
         
             
                        select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}))
         
     | 
| 
         @@ -345,7 +394,7 @@ module Morpheus 
     | 
|
| 
       345 
394 
     | 
    
         
             
                        print Term::ANSIColor.red, "  * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
         
     | 
| 
       346 
395 
     | 
    
         
             
                        if select_options && select_options.size > 10
         
     | 
| 
       347 
396 
     | 
    
         
             
                          display_select_options(option_type, select_options.first(10))
         
     | 
| 
       348 
     | 
    
         
            -
                          puts " (#{select_options.size- 
     | 
| 
      
 397 
     | 
    
         
            +
                          puts " (#{select_options.size-10} more)"
         
     | 
| 
       349 
398 
     | 
    
         
             
                        else
         
     | 
| 
       350 
399 
     | 
    
         
             
                          display_select_options(option_type, select_options)
         
     | 
| 
       351 
400 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -388,7 +437,7 @@ module Morpheus 
     | 
|
| 
       388 
437 
     | 
    
         
             
                          print Term::ANSIColor.red, "  * #{option_type['fieldLabel']} [-O #{help_field_key}=] - #{option_type['description']}\n", Term::ANSIColor.reset
         
     | 
| 
       389 
438 
     | 
    
         
             
                          if select_options && select_options.size > 10
         
     | 
| 
       390 
439 
     | 
    
         
             
                            display_select_options(option_type, select_options.first(10))
         
     | 
| 
       391 
     | 
    
         
            -
                            puts " (#{select_options.size- 
     | 
| 
      
 440 
     | 
    
         
            +
                            puts " (#{select_options.size-10} more)"
         
     | 
| 
       392 
441 
     | 
    
         
             
                          else
         
     | 
| 
       393 
442 
     | 
    
         
             
                            display_select_options(option_type, select_options)
         
     | 
| 
       394 
443 
     | 
    
         
             
                          end
         
     | 
| 
         @@ -458,6 +507,154 @@ module Morpheus 
     | 
|
| 
       458 
507 
     | 
    
         
             
                    value
         
     | 
| 
       459 
508 
     | 
    
         
             
                  end
         
     | 
| 
       460 
509 
     | 
    
         | 
| 
      
 510 
     | 
    
         
            +
                  # this works like select_prompt, but refreshes options with ?query=value between inputs
         
     | 
| 
      
 511 
     | 
    
         
            +
                  # paging_enabled is ignored right now
         
     | 
| 
      
 512 
     | 
    
         
            +
                  def self.typeahead_prompt(option_type,api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false)
         
     | 
| 
      
 513 
     | 
    
         
            +
                    select_options = []
         
     | 
| 
      
 514 
     | 
    
         
            +
                    field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
         
     | 
| 
      
 515 
     | 
    
         
            +
                    help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
         
     | 
| 
      
 516 
     | 
    
         
            +
                    input = ""
         
     | 
| 
      
 517 
     | 
    
         
            +
                    value_found = false
         
     | 
| 
      
 518 
     | 
    
         
            +
                    value = nil
         
     | 
| 
      
 519 
     | 
    
         
            +
                    value_field = (option_type['config'] ? option_type['config']['valueField'] : nil) || 'value'
         
     | 
| 
      
 520 
     | 
    
         
            +
                    default_value = option_type['defaultValue']
         
     | 
| 
      
 521 
     | 
    
         
            +
                    default_value = default_value['id'] if default_value && default_value.is_a?(Hash) && !default_value['id'].nil?
         
     | 
| 
      
 522 
     | 
    
         
            +
             
     | 
| 
      
 523 
     | 
    
         
            +
                    while !value_found do
         
     | 
| 
      
 524 
     | 
    
         
            +
                      # ok get input, refresh options and see if it matches
         
     | 
| 
      
 525 
     | 
    
         
            +
                      # if matches one, cool otherwise print matches and reprompt or error
         
     | 
| 
      
 526 
     | 
    
         
            +
                      if use_value
         
     | 
| 
      
 527 
     | 
    
         
            +
                        input = use_value
         
     | 
| 
      
 528 
     | 
    
         
            +
                      elsif no_prompt
         
     | 
| 
      
 529 
     | 
    
         
            +
                        input = default_value
         
     | 
| 
      
 530 
     | 
    
         
            +
                      else
         
     | 
| 
      
 531 
     | 
    
         
            +
                        Readline.completion_append_character = ""
         
     | 
| 
      
 532 
     | 
    
         
            +
                        Readline.basic_word_break_characters = ''
         
     | 
| 
      
 533 
     | 
    
         
            +
                        Readline.completion_proc = proc {|s| 
         
     | 
| 
      
 534 
     | 
    
         
            +
                          matches = []
         
     | 
| 
      
 535 
     | 
    
         
            +
                          available_options = (select_options || [])
         
     | 
| 
      
 536 
     | 
    
         
            +
                          available_options.each{|option| 
         
     | 
| 
      
 537 
     | 
    
         
            +
                            if option['name'] && option['name'] =~ /^#{Regexp.escape(s)}/
         
     | 
| 
      
 538 
     | 
    
         
            +
                              matches << option['name']
         
     | 
| 
      
 539 
     | 
    
         
            +
                            # elsif option['id'] && option['id'].to_s =~ /^#{Regexp.escape(s)}/
         
     | 
| 
      
 540 
     | 
    
         
            +
                            elsif option[value_field] && option[value_field].to_s == s
         
     | 
| 
      
 541 
     | 
    
         
            +
                              matches << option['name']
         
     | 
| 
      
 542 
     | 
    
         
            +
                            end
         
     | 
| 
      
 543 
     | 
    
         
            +
                          }
         
     | 
| 
      
 544 
     | 
    
         
            +
                          matches
         
     | 
| 
      
 545 
     | 
    
         
            +
                        }
         
     | 
| 
      
 546 
     | 
    
         
            +
                        # prompt for typeahead input value
         
     | 
| 
      
 547 
     | 
    
         
            +
                        input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!default_value.to_s.empty? ? ' ['+default_value.to_s+']' : ''} ['?' for options]: ", false).to_s
         
     | 
| 
      
 548 
     | 
    
         
            +
                        input = input.chomp.strip
         
     | 
| 
      
 549 
     | 
    
         
            +
                      end
         
     | 
| 
      
 550 
     | 
    
         
            +
             
     | 
| 
      
 551 
     | 
    
         
            +
                      # just hit enter, use [default] if set
         
     | 
| 
      
 552 
     | 
    
         
            +
                      if input.empty? && default_value
         
     | 
| 
      
 553 
     | 
    
         
            +
                        input = default_value.to_s
         
     | 
| 
      
 554 
     | 
    
         
            +
                      end
         
     | 
| 
      
 555 
     | 
    
         
            +
                      
         
     | 
| 
      
 556 
     | 
    
         
            +
                      # not required and no value? ok proceed
         
     | 
| 
      
 557 
     | 
    
         
            +
                      if input.to_s == "" && option_type['required'] != true
         
     | 
| 
      
 558 
     | 
    
         
            +
                        value_found = true
         
     | 
| 
      
 559 
     | 
    
         
            +
                        value = nil # or "" # hmm
         
     | 
| 
      
 560 
     | 
    
         
            +
                        #next
         
     | 
| 
      
 561 
     | 
    
         
            +
                        break
         
     | 
| 
      
 562 
     | 
    
         
            +
                      end
         
     | 
| 
      
 563 
     | 
    
         
            +
             
     | 
| 
      
 564 
     | 
    
         
            +
                      # required and no value? you need help
         
     | 
| 
      
 565 
     | 
    
         
            +
                      # if input.to_s == "" && option_type['required'] == true
         
     | 
| 
      
 566 
     | 
    
         
            +
                      #   help_prompt(option_type)
         
     | 
| 
      
 567 
     | 
    
         
            +
                      #   display_select_options(option_type, select_options) unless select_options.empty?
         
     | 
| 
      
 568 
     | 
    
         
            +
                      #   next
         
     | 
| 
      
 569 
     | 
    
         
            +
                      # end
         
     | 
| 
      
 570 
     | 
    
         
            +
             
     | 
| 
      
 571 
     | 
    
         
            +
                      # looking for help with this input
         
     | 
| 
      
 572 
     | 
    
         
            +
                      if input == '?'
         
     | 
| 
      
 573 
     | 
    
         
            +
                        help_prompt(option_type)
         
     | 
| 
      
 574 
     | 
    
         
            +
                        display_select_options(option_type, select_options) unless select_options.empty?
         
     | 
| 
      
 575 
     | 
    
         
            +
                        next
         
     | 
| 
      
 576 
     | 
    
         
            +
                      end
         
     | 
| 
      
 577 
     | 
    
         
            +
             
     | 
| 
      
 578 
     | 
    
         
            +
                      # just hit enter? scram
         
     | 
| 
      
 579 
     | 
    
         
            +
                      # looking for help with this input
         
     | 
| 
      
 580 
     | 
    
         
            +
                      # if input == ""
         
     | 
| 
      
 581 
     | 
    
         
            +
                      #   help_prompt(option_type)
         
     | 
| 
      
 582 
     | 
    
         
            +
                      #   display_select_options(option_type, select_options)
         
     | 
| 
      
 583 
     | 
    
         
            +
                      #   next
         
     | 
| 
      
 584 
     | 
    
         
            +
                      # end
         
     | 
| 
      
 585 
     | 
    
         
            +
             
     | 
| 
      
 586 
     | 
    
         
            +
                      # this is how typeahead works, it keeps refreshing the options with a new ?query={value}
         
     | 
| 
      
 587 
     | 
    
         
            +
                      # query_value = (value || use_value || default_value || '')
         
     | 
| 
      
 588 
     | 
    
         
            +
                      query_value = (input || '')
         
     | 
| 
      
 589 
     | 
    
         
            +
                      api_params ||= {}
         
     | 
| 
      
 590 
     | 
    
         
            +
                      api_params['query'] = query_value
         
     | 
| 
      
 591 
     | 
    
         
            +
                      # skip refresh if you just hit enter
         
     | 
| 
      
 592 
     | 
    
         
            +
                      if !query_value.empty?
         
     | 
| 
      
 593 
     | 
    
         
            +
                        select_options = load_options(option_type, api_client, api_params, query_value)
         
     | 
| 
      
 594 
     | 
    
         
            +
                      end
         
     | 
| 
      
 595 
     | 
    
         
            +
             
     | 
| 
      
 596 
     | 
    
         
            +
                      # match input to option name or value
         
     | 
| 
      
 597 
     | 
    
         
            +
                      # actually that is redundant, it should already be filtered to matches
         
     | 
| 
      
 598 
     | 
    
         
            +
                      # and can just do this:
         
     | 
| 
      
 599 
     | 
    
         
            +
                      # select_option = select_options.size == 1 ? select_options[0] : nil
         
     | 
| 
      
 600 
     | 
    
         
            +
                      select_option = select_options.find{|b| (b[value_field] && (b[value_field].to_s == input.to_s)) || ((b[value_field].nil? || b[value_field].empty?) && (input == "")) }
         
     | 
| 
      
 601 
     | 
    
         
            +
                      if select_option.nil?
         
     | 
| 
      
 602 
     | 
    
         
            +
                        select_option = select_options.find{|b| b['name'] && b['name'] == input }
         
     | 
| 
      
 603 
     | 
    
         
            +
                      end
         
     | 
| 
      
 604 
     | 
    
         
            +
             
     | 
| 
      
 605 
     | 
    
         
            +
                      # found matching value, else did not find a value, show matching options and prompt again or error
         
     | 
| 
      
 606 
     | 
    
         
            +
                      if select_option
         
     | 
| 
      
 607 
     | 
    
         
            +
                        value = select_option[value_field]
         
     | 
| 
      
 608 
     | 
    
         
            +
                        set_last_select(select_option)
         
     | 
| 
      
 609 
     | 
    
         
            +
                        value_found = true
         
     | 
| 
      
 610 
     | 
    
         
            +
                      else
         
     | 
| 
      
 611 
     | 
    
         
            +
                        if use_value || no_prompt
         
     | 
| 
      
 612 
     | 
    
         
            +
                          # todo: make this nicer
         
     | 
| 
      
 613 
     | 
    
         
            +
                          # help_prompt(option_type)
         
     | 
| 
      
 614 
     | 
    
         
            +
                          print Term::ANSIColor.red, "\nMissing Required Option\n\n", Term::ANSIColor.reset
         
     | 
| 
      
 615 
     | 
    
         
            +
                          print Term::ANSIColor.red, "  * #{option_type['fieldLabel']} [-O #{help_field_key}=] - #{option_type['description']}\n", Term::ANSIColor.reset
         
     | 
| 
      
 616 
     | 
    
         
            +
                          if select_options && select_options.size > 10
         
     | 
| 
      
 617 
     | 
    
         
            +
                            display_select_options(option_type, select_options.first(10))
         
     | 
| 
      
 618 
     | 
    
         
            +
                            puts " (#{select_options.size-10} more)"
         
     | 
| 
      
 619 
     | 
    
         
            +
                          else
         
     | 
| 
      
 620 
     | 
    
         
            +
                            display_select_options(option_type, select_options)
         
     | 
| 
      
 621 
     | 
    
         
            +
                          end
         
     | 
| 
      
 622 
     | 
    
         
            +
                          print "\n"
         
     | 
| 
      
 623 
     | 
    
         
            +
                          if select_options.empty?
         
     | 
| 
      
 624 
     | 
    
         
            +
                            print "The value '#{input}' matched 0 options.\n"
         
     | 
| 
      
 625 
     | 
    
         
            +
                            # print "Please try again.\n"
         
     | 
| 
      
 626 
     | 
    
         
            +
                          else
         
     | 
| 
      
 627 
     | 
    
         
            +
                            print "The value '#{input}' matched #{select_options.size()} options.\n"
         
     | 
| 
      
 628 
     | 
    
         
            +
                            print "Perhaps you meant one of these? #{ored_list(select_options.collect {|i|i['name']}, 3)}\n"
         
     | 
| 
      
 629 
     | 
    
         
            +
                            # print "Please try again.\n"
         
     | 
| 
      
 630 
     | 
    
         
            +
                          end
         
     | 
| 
      
 631 
     | 
    
         
            +
                          print "\n"
         
     | 
| 
      
 632 
     | 
    
         
            +
                          exit 1
         
     | 
| 
      
 633 
     | 
    
         
            +
                        else
         
     | 
| 
      
 634 
     | 
    
         
            +
                          #help_prompt(option_type)
         
     | 
| 
      
 635 
     | 
    
         
            +
                          display_select_options(option_type, select_options)
         
     | 
| 
      
 636 
     | 
    
         
            +
                          print "\n"
         
     | 
| 
      
 637 
     | 
    
         
            +
                          if select_options.empty?
         
     | 
| 
      
 638 
     | 
    
         
            +
                            print "The value '#{input}' matched 0 options.\n"
         
     | 
| 
      
 639 
     | 
    
         
            +
                            print "Please try again.\n"
         
     | 
| 
      
 640 
     | 
    
         
            +
                          else
         
     | 
| 
      
 641 
     | 
    
         
            +
                            print "The value '#{input}' matched #{select_options.size()} options.\n"
         
     | 
| 
      
 642 
     | 
    
         
            +
                            print "Perhaps you meant one of these? #{ored_list(select_options.collect {|i|i['name']}, 3)}\n"
         
     | 
| 
      
 643 
     | 
    
         
            +
                            print "Please try again.\n"
         
     | 
| 
      
 644 
     | 
    
         
            +
                          end
         
     | 
| 
      
 645 
     | 
    
         
            +
                          print "\n"
         
     | 
| 
      
 646 
     | 
    
         
            +
                          # reprompting now...
         
     | 
| 
      
 647 
     | 
    
         
            +
                        end
         
     | 
| 
      
 648 
     | 
    
         
            +
                      end
         
     | 
| 
      
 649 
     | 
    
         
            +
                    end # end while !value_found
         
     | 
| 
      
 650 
     | 
    
         
            +
             
     | 
| 
      
 651 
     | 
    
         
            +
                    # wrap in object when using fieldInput
         
     | 
| 
      
 652 
     | 
    
         
            +
                    if value && !option_type['fieldInput'].nil?
         
     | 
| 
      
 653 
     | 
    
         
            +
                      value = {option_type['fieldName'].split('.').last => value, option_type['fieldInput'] => (no_prompt ? option_type['defaultInputValue'] : field_input_prompt(option_type))}
         
     | 
| 
      
 654 
     | 
    
         
            +
                    end
         
     | 
| 
      
 655 
     | 
    
         
            +
                    value
         
     | 
| 
      
 656 
     | 
    
         
            +
                  end
         
     | 
| 
      
 657 
     | 
    
         
            +
             
     | 
| 
       461 
658 
     | 
    
         
             
                  # this is a funky one, the user is prompted for yes/no
         
     | 
| 
       462 
659 
     | 
    
         
             
                  # but the return value is 'on','off',nil
         
     | 
| 
       463 
660 
     | 
    
         
             
                  # todo: maybe make this easier to use, and have the api's be flexible too..
         
     | 
| 
         @@ -544,6 +741,9 @@ module Morpheus 
     | 
|
| 
       544 
741 
     | 
    
         
             
                      # value = input.empty? ? option_type['defaultValue'] : input
         
     | 
| 
       545 
742 
     | 
    
         
             
                      if input == '?' && value.nil?
         
     | 
| 
       546 
743 
     | 
    
         
             
                        help_prompt(option_type)
         
     | 
| 
      
 744 
     | 
    
         
            +
                      elsif input.chomp == '' && value.nil?
         
     | 
| 
      
 745 
     | 
    
         
            +
                        # just hit enter right away to skip this
         
     | 
| 
      
 746 
     | 
    
         
            +
                        value_found = true
         
     | 
| 
       547 
747 
     | 
    
         
             
                      elsif input.chomp == 'EOF'
         
     | 
| 
       548 
748 
     | 
    
         
             
                        value_found = true
         
     | 
| 
       549 
749 
     | 
    
         
             
                      else
         
     | 
| 
         @@ -682,6 +882,42 @@ module Morpheus 
     | 
|
| 
       682 
882 
     | 
    
         
             
                    return file_params
         
     | 
| 
       683 
883 
     | 
    
         
             
                  end
         
     | 
| 
       684 
884 
     | 
    
         | 
| 
      
 885 
     | 
    
         
            +
                  def self.load_options(option_type, api_client, api_params, query_value=nil)
         
     | 
| 
      
 886 
     | 
    
         
            +
                    select_options = []
         
     | 
| 
      
 887 
     | 
    
         
            +
                    # local array of options
         
     | 
| 
      
 888 
     | 
    
         
            +
                    if option_type['selectOptions']
         
     | 
| 
      
 889 
     | 
    
         
            +
                      # calculate from inline lambda
         
     | 
| 
      
 890 
     | 
    
         
            +
                      if option_type['selectOptions'].is_a?(Proc)
         
     | 
| 
      
 891 
     | 
    
         
            +
                        select_options = option_type['selectOptions'].call(api_client, grails_params(api_params || {}))
         
     | 
| 
      
 892 
     | 
    
         
            +
                      else
         
     | 
| 
      
 893 
     | 
    
         
            +
                        select_options = option_type['selectOptions']
         
     | 
| 
      
 894 
     | 
    
         
            +
                      end
         
     | 
| 
      
 895 
     | 
    
         
            +
                      # filter options ourselves
         
     | 
| 
      
 896 
     | 
    
         
            +
                      if query_value.to_s != ""
         
     | 
| 
      
 897 
     | 
    
         
            +
                        filtered_options = select_options.select { |it| it['value'].to_s == query_value.to_s }
         
     | 
| 
      
 898 
     | 
    
         
            +
                        if filtered_options.empty?
         
     | 
| 
      
 899 
     | 
    
         
            +
                          filtered_options = select_options.select { |it| it['name'].to_s == query_value.to_s }
         
     | 
| 
      
 900 
     | 
    
         
            +
                        end
         
     | 
| 
      
 901 
     | 
    
         
            +
                        select_options = filtered_options
         
     | 
| 
      
 902 
     | 
    
         
            +
                      end
         
     | 
| 
      
 903 
     | 
    
         
            +
                    elsif option_type['optionSource']
         
     | 
| 
      
 904 
     | 
    
         
            +
                      # calculate from inline lambda
         
     | 
| 
      
 905 
     | 
    
         
            +
                      if option_type['optionSource'].is_a?(Proc)
         
     | 
| 
      
 906 
     | 
    
         
            +
                        select_options = option_type['optionSource'].call(api_client, grails_params(api_params || {}))
         
     | 
| 
      
 907 
     | 
    
         
            +
                      elsif option_type['optionSource'] == 'list'
         
     | 
| 
      
 908 
     | 
    
         
            +
                        # /api/options/list is a special action for custom OptionTypeLists, just need to pass the optionTypeId parameter
         
     | 
| 
      
 909 
     | 
    
         
            +
                        select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}).merge({'optionTypeId' => option_type['id']}))
         
     | 
| 
      
 910 
     | 
    
         
            +
                      else
         
     | 
| 
      
 911 
     | 
    
         
            +
                        # remote optionSource aka /api/options/$optionSource?
         
     | 
| 
      
 912 
     | 
    
         
            +
                        select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}))
         
     | 
| 
      
 913 
     | 
    
         
            +
                      end
         
     | 
| 
      
 914 
     | 
    
         
            +
                    else
         
     | 
| 
      
 915 
     | 
    
         
            +
                      raise "option '#{field_key}' is type: 'typeahead' and missing selectOptions or optionSource!"
         
     | 
| 
      
 916 
     | 
    
         
            +
                    end
         
     | 
| 
      
 917 
     | 
    
         
            +
             
     | 
| 
      
 918 
     | 
    
         
            +
                    return select_options
         
     | 
| 
      
 919 
     | 
    
         
            +
                  end
         
     | 
| 
      
 920 
     | 
    
         
            +
             
     | 
| 
       685 
921 
     | 
    
         
             
                  def self.help_prompt(option_type)
         
     | 
| 
       686 
922 
     | 
    
         
             
                    field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
         
     | 
| 
       687 
923 
     | 
    
         
             
                    help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
         
     | 
| 
         @@ -691,6 +927,11 @@ module Morpheus 
     | 
|
| 
       691 
927 
     | 
    
         
             
                    else
         
     | 
| 
       692 
928 
     | 
    
         
             
                      print Term::ANSIColor.green,"  * #{option_type['fieldLabel']} [-O #{help_field_key}=] - ", Term::ANSIColor.reset , "#{option_type['description']}\n"
         
     | 
| 
       693 
929 
     | 
    
         
             
                    end
         
     | 
| 
      
 930 
     | 
    
         
            +
                    if option_type['type'].to_s == 'typeahead'
         
     | 
| 
      
 931 
     | 
    
         
            +
                      print "This is a typeahead input. Enter the name or value of an option.\n"
         
     | 
| 
      
 932 
     | 
    
         
            +
                      print "If the specified input matches more than one option, they will be printed and you will be prompted again.\n"
         
     | 
| 
      
 933 
     | 
    
         
            +
                      print "the matching options will be shown and you can try again.\n"
         
     | 
| 
      
 934 
     | 
    
         
            +
                    end
         
     | 
| 
       694 
935 
     | 
    
         
             
                  end
         
     | 
| 
       695 
936 
     | 
    
         | 
| 
       696 
937 
     | 
    
         | 
| 
         @@ -698,7 +939,8 @@ module Morpheus 
     | 
|
| 
       698 
939 
     | 
    
         
             
                    api_client.options.options_for_source(source,params)['data']
         
     | 
| 
       699 
940 
     | 
    
         
             
                  end
         
     | 
| 
       700 
941 
     | 
    
         | 
| 
       701 
     | 
    
         
            -
                  def self. 
     | 
| 
      
 942 
     | 
    
         
            +
                  def self.format_select_options_help(opt, select_options = [], paging = nil)
         
     | 
| 
      
 943 
     | 
    
         
            +
                    out = ""
         
     | 
| 
       702 
944 
     | 
    
         
             
                    header = opt['fieldLabel'] ? "#{opt['fieldLabel']} Options" : "Options"
         
     | 
| 
       703 
945 
     | 
    
         
             
                    if paging
         
     | 
| 
       704 
946 
     | 
    
         
             
                      offset = paging[:cur_page] * paging[:page_size]
         
     | 
| 
         @@ -706,11 +948,18 @@ module Morpheus 
     | 
|
| 
       706 
948 
     | 
    
         
             
                      header = "#{header} (#{offset+1}-#{limit+1} of #{paging[:total]})"
         
     | 
| 
       707 
949 
     | 
    
         
             
                      select_options = select_options[(offset)..(limit)]
         
     | 
| 
       708 
950 
     | 
    
         
             
                    end
         
     | 
| 
       709 
     | 
    
         
            -
                     
     | 
| 
       710 
     | 
    
         
            -
                     
     | 
| 
      
 951 
     | 
    
         
            +
                    out = ""
         
     | 
| 
      
 952 
     | 
    
         
            +
                    out << "\n"
         
     | 
| 
      
 953 
     | 
    
         
            +
                    out << "#{header}\n"
         
     | 
| 
      
 954 
     | 
    
         
            +
                    out << "===============\n"
         
     | 
| 
       711 
955 
     | 
    
         
             
                    select_options.each do |option|
         
     | 
| 
       712 
     | 
    
         
            -
                       
     | 
| 
      
 956 
     | 
    
         
            +
                      out << " * #{option['name']} [#{option['value']}]\n"
         
     | 
| 
       713 
957 
     | 
    
         
             
                    end
         
     | 
| 
      
 958 
     | 
    
         
            +
                    return out
         
     | 
| 
      
 959 
     | 
    
         
            +
                  end
         
     | 
| 
      
 960 
     | 
    
         
            +
             
     | 
| 
      
 961 
     | 
    
         
            +
                  def self.display_select_options(opt, select_options = [], paging = nil)
         
     | 
| 
      
 962 
     | 
    
         
            +
                    puts format_select_options_help(opt, select_options, paging)
         
     | 
| 
       714 
963 
     | 
    
         
             
                  end
         
     | 
| 
       715 
964 
     | 
    
         | 
| 
       716 
965 
     | 
    
         
             
                  def self.format_option_types_help(option_types, opts={})
         
     |