kaui 2.0.0 → 2.1.0

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.
Files changed (77) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +5 -29
  3. data/app/assets/javascripts/kaui/kaui.js +1 -1
  4. data/app/assets/stylesheets/kaui/account.less +9 -1
  5. data/app/assets/stylesheets/kaui/common.less +46 -3
  6. data/app/controllers/kaui/accounts_controller.rb +11 -15
  7. data/app/controllers/kaui/admin_tenants_controller.rb +77 -106
  8. data/app/controllers/kaui/audit_logs_controller.rb +3 -3
  9. data/app/controllers/kaui/bundles_controller.rb +4 -0
  10. data/app/controllers/kaui/engine_controller_util.rb +25 -17
  11. data/app/controllers/kaui/invoice_tags_controller.rb +28 -0
  12. data/app/controllers/kaui/invoices_controller.rb +65 -14
  13. data/app/controllers/kaui/payment_methods_controller.rb +14 -3
  14. data/app/controllers/kaui/sessions_controller.rb +6 -0
  15. data/app/controllers/kaui/subscriptions_controller.rb +13 -4
  16. data/app/helpers/kaui/account_helper.rb +10 -2
  17. data/app/helpers/kaui/payment_method_helper.rb +5 -3
  18. data/app/helpers/kaui/plugin_helper.rb +10 -49
  19. data/app/helpers/kaui/subscription_helper.rb +26 -9
  20. data/app/helpers/kaui/uuid_helper.rb +1 -0
  21. data/app/models/kaui/admin_tenant.rb +8 -84
  22. data/app/models/kaui/catalog.rb +28 -2
  23. data/app/models/kaui/tag.rb +1 -1
  24. data/app/views/kaui/account_emails/_form.html.erb +1 -1
  25. data/app/views/kaui/accounts/_billing_info.html.erb +4 -0
  26. data/app/views/kaui/accounts/_form.html.erb +1 -1
  27. data/app/views/kaui/accounts/_payment_methods.html.erb +3 -0
  28. data/app/views/kaui/accounts/index.html.erb +7 -4
  29. data/app/views/kaui/admin_tenants/_form_plugin_config.erb +59 -241
  30. data/app/views/kaui/admin_tenants/_show_catalog_simple.erb +2 -2
  31. data/app/views/kaui/admin_tenants/new_catalog.html.erb +16 -15
  32. data/app/views/kaui/bundles/_bundle_details.html.erb +12 -0
  33. data/app/views/kaui/bundles/index.html.erb +3 -14
  34. data/app/views/kaui/chargebacks/_form.html.erb +1 -1
  35. data/app/views/kaui/charges/_form.html.erb +1 -1
  36. data/app/views/kaui/invoice_tags/_form.html.erb +33 -0
  37. data/app/views/kaui/invoice_tags/_form_bar.html.erb +21 -0
  38. data/app/views/kaui/invoice_tags/edit.html.erb +10 -0
  39. data/app/views/kaui/invoices/_invoice_table.html.erb +30 -9
  40. data/app/views/kaui/invoices/index.html.erb +6 -4
  41. data/app/views/kaui/invoices/show.html.erb +11 -2
  42. data/app/views/kaui/layouts/kaui_flash.html.erb +8 -1
  43. data/app/views/kaui/payments/_form.html.erb +1 -1
  44. data/app/views/kaui/payments/_payment_table.html.erb +2 -2
  45. data/app/views/kaui/payments/index.html.erb +3 -1
  46. data/app/views/kaui/subscriptions/_edit_form.html.erb +1 -1
  47. data/app/views/kaui/subscriptions/_form.html.erb +1 -1
  48. data/app/views/kaui/subscriptions/_subscriptions_table.html.erb +3 -3
  49. data/config/routes.rb +6 -1
  50. data/lib/kaui.rb +55 -0
  51. data/lib/kaui/version.rb +1 -1
  52. data/test/dummy/config/database.yml +2 -2
  53. data/test/dummy/config/initializers/cookies_serializer.rb +1 -1
  54. data/test/dummy/config/initializers/money.rb +2 -0
  55. data/test/functional/kaui/account_emails_controller_test.rb +2 -2
  56. data/test/functional/kaui/account_tags_controller_test.rb +1 -1
  57. data/test/functional/kaui/accounts_controller_test.rb +4 -4
  58. data/test/functional/kaui/admin_tenants_controller_test.rb +3 -23
  59. data/test/functional/kaui/bundle_tags_controller_test.rb +1 -1
  60. data/test/functional/kaui/bundles_controller_test.rb +3 -3
  61. data/test/functional/kaui/chargebacks_controller_test.rb +2 -2
  62. data/test/functional/kaui/charges_controller_test.rb +2 -2
  63. data/test/functional/kaui/credits_controller_test.rb +5 -5
  64. data/test/functional/kaui/home_controller_test.rb +5 -5
  65. data/test/functional/kaui/invoice_items_controller_test.rb +3 -3
  66. data/test/functional/kaui/invoices_controller_test.rb +2 -2
  67. data/test/functional/kaui/refunds_controller_test.rb +2 -2
  68. data/test/functional/kaui/subscriptions_controller_test.rb +6 -6
  69. data/test/killbill_test_helper.rb +8 -6
  70. data/test/unit/helpers/kaui/payment_method_helper_test.rb +17 -0
  71. data/test/unit/kaui/account_test.rb +2 -2
  72. data/test/unit/kaui/admin_tenant_test.rb +10 -47
  73. data/test/unit/kaui/invoice_item_test.rb +1 -1
  74. data/test/unit/kaui/invoice_payment_test.rb +7 -7
  75. data/test/unit/kaui/invoice_test.rb +4 -4
  76. data/test/unit/kaui/payment_test.rb +7 -7
  77. metadata +110 -86
@@ -10,25 +10,39 @@ module Kaui
10
10
  end
11
11
 
12
12
  def humanized_product_category(product_category)
13
- if product_category == 'BASE'
13
+ if product_category.to_s == 'BASE'
14
14
  'Base'
15
- elsif product_category == 'ADD_ON'
15
+ elsif product_category.to_s == 'ADD_ON'
16
16
  'Add-on'
17
17
  else
18
- product_category.downcase.capitalize
18
+ product_category.to_s.downcase.capitalize
19
19
  end
20
20
  end
21
21
 
22
- def humanized_subscription_product_name(sub)
23
- if !sub.present? or !sub.product_name.present?
22
+ def humanized_subscription_product_name(sub, catalog = nil)
23
+ if !sub.present? || !sub.product_name.present?
24
24
  nil
25
25
  else
26
- humanized_product_name(sub.product_name)
26
+ product = catalog.nil? ? nil : catalog.products.find { |p| p.name == sub.product_name }
27
+ humanized_product_name(!product.nil? && !product.pretty_name.blank? ? product.pretty_name : sub.product_name)
28
+ end
29
+ end
30
+
31
+ def humanized_subscription_pretty_plan_name(sub, catalog = nil)
32
+ if !sub.present? || !sub.product_name.present?
33
+ nil
34
+ else
35
+ product = catalog.nil? ? nil : catalog.products.find { |p| p.name == sub.product_name }
36
+ return nil if product.nil?
37
+
38
+ plan = product.plans.find { |p| p.name == sub.plan_name }
39
+ plan.nil? || plan.pretty_name.blank? ? nil : plan.pretty_name
27
40
  end
28
41
  end
29
42
 
30
43
  def humanized_product_name(product_name)
31
- product_name.downcase.capitalize
44
+ # Don't change the casing to avoid confusions (could lead to different products with different casing)
45
+ product_name
32
46
  end
33
47
 
34
48
  def humanized_subscription_billing_period(sub)
@@ -55,8 +69,11 @@ module Kaui
55
69
  end
56
70
  end
57
71
 
58
- def humanized_subscription_full_product_name(sub)
59
- humanized_product_name = humanized_subscription_product_name(sub)
72
+ def humanized_subscription_plan_or_product_name(sub, catalog = nil)
73
+ pretty_plan_name = humanized_subscription_pretty_plan_name(sub, catalog)
74
+ return pretty_plan_name unless pretty_plan_name.nil?
75
+
76
+ humanized_product_name = humanized_subscription_product_name(sub, catalog)
60
77
  humanized_billing_period = humanized_subscription_billing_period(sub)
61
78
  humanized_price_list = humanized_subscription_price_list(sub, false)
62
79
 
@@ -6,6 +6,7 @@ module Kaui
6
6
  split = uuid.split('-')
7
7
  split[0] + '-...-' + split[4]
8
8
  end
9
+ module_function :truncate_uuid
9
10
 
10
11
  def object_id_popover(object_id, placement = 'right', title = nil)
11
12
  content_tag(:span, truncate_uuid(object_id),
@@ -26,81 +26,21 @@ class Kaui::AdminTenant < KillBillClient::Model::Tenant
26
26
  KillBillClient::Model::Tenant.upload_tenant_plugin_config(plugin_name, plugin_config, user, reason, comment, options)
27
27
  end
28
28
 
29
- def get_plugin_repository
30
- require 'open-uri'
31
- require 'yaml'
32
-
33
- source = URI.parse('https://raw.githubusercontent.com/killbill/killbill-cloud/master/kpm/lib/kpm/plugins_directory.yml').read
34
- YAML.load(source)
35
- rescue
36
- # Ignore gracefully
37
- {}
38
- end
39
-
40
- def get_oss_plugin_info(plugin_directory)
41
- # Serialize the plugin state for the view:
42
- # plugin_name#plugin_type:prop1,prop2,prop3;plugin_name#plugin_type:prop1,prop2,prop3;...
43
- #
44
- plugin_config = plugin_directory.inject({}) do |hsh, (k,v)|
45
- hsh["#{k}##{v[:type]}"] = v[:require] || []
46
- hsh
47
- end
48
- plugin_config.map { |e,v| "#{e}:#{v.join(",")}" }.join(";")
49
- end
50
-
51
- def get_tenant_plugin_config(plugin_directory, options)
52
- require 'yaml'
53
-
29
+ # Return a map of plugin_name => config
30
+ def get_tenant_plugin_config(options)
54
31
  raw_tenant_config = KillBillClient::Model::Tenant::search_tenant_config("PLUGIN_CONFIG_", options)
55
32
 
56
33
  tenant_config = raw_tenant_config.inject({}) do |hsh, e|
57
34
  # Strip prefix '/PLUGIN_CONFIG_'
58
- killbill_key = e.key.gsub!(/PLUGIN_CONFIG_/, '')
59
-
60
- # Extract killbill key for oss plugins based on convention 'killbill-KEY'
61
- plugin_key = killbill_key.gsub(/killbill-/, '') if killbill_key.start_with?('killbill-')
62
-
63
- # hack:: rewrite key, to allow the ui to find the right configuration inputs
64
- plugin_key = rewrite_plugin_key(plugin_key) unless plugin_key.nil?
65
- # If such key exists, lookup in plugin directory to see if is an official plugin
66
- is_an_official_plugin = !plugin_key.nil? && !plugin_directory[plugin_key.to_sym].blank?
67
- # Deserialize config based on string possible format, if exist in the official repository
68
- if is_an_official_plugin && is_yaml?(e.values[0])
69
- yml = YAML.load(e.values[0])
70
- # Hash of properties
71
- # is plugin key part of the yaml?
72
- if yml[plugin_key.to_sym].blank?
73
- # if not set it as raw
74
- hsh[plugin_key] = {:raw_config => e.values[0]}
75
- else
76
- hsh[plugin_key] = yml[plugin_key.to_sym]
77
- end
78
- hsh[plugin_key][:_raw] = e.values[0]
79
- elsif is_an_official_plugin && is_kv?(e.values[0])
80
- # Construct hash of properties based on java properties (k1=v1\nk2=v2\n...)
81
- hsh[plugin_key] = e.values[0].split("\n").inject({}) do |h, p0|
82
- k, v = p0.split('=');
83
- h[k] = v;
84
- h
85
- end
86
- hsh[plugin_key][:_raw] = e.values[0]
87
- else
88
- # Construct simple hash with one property :raw_config
89
- hsh[killbill_key] = {:raw_config => e.values[0], :_raw => e.values[0]}
90
- end
35
+ plugin_name = e.key.gsub!(/PLUGIN_CONFIG_/, '')
36
+
37
+ # Construct simple hash with one property (first value)
38
+ hsh[plugin_name] = e.values[0]
39
+
91
40
  hsh
92
41
  end
93
42
 
94
- # Serialize the whole thing a as string of the form:
95
- # plugin_key1::key1=value1|key2=value2|..;plugin_key2::...
96
- tenant_config.map do |plugin_key, props|
97
- serialized_props = props.inject("") do |s, (k, v)|
98
- e="#{k.to_s}=#{v.to_s}";
99
- s == "" ? s="#{e}" : s="#{s}|#{e}";
100
- s
101
- end
102
- "#{plugin_key}::#{serialized_props}"
103
- end.join(";")
43
+ tenant_config
104
44
  end
105
45
 
106
46
  def format_plugin_config(plugin_key, plugin_type, props)
@@ -142,22 +82,6 @@ class Kaui::AdminTenant < KillBillClient::Model::Tenant
142
82
  props
143
83
  end
144
84
 
145
- # hack when the plugin name after killbill is not the same as the plugin key, this mainly affects ruby plugin configuration,
146
- # as it use the key to retrieve the configuration.
147
- def rewrite_plugin_key(plugin_key)
148
- if plugin_key.start_with?('paypal')
149
- 'paypal_express'
150
- elsif plugin_key.start_with?('firstdata')
151
- 'firstdata_e4'
152
- elsif plugin_key.start_with?('bridge')
153
- 'payment_bridge'
154
- elsif plugin_key.start_with?('payu-latam')
155
- 'payu_latam'
156
- else
157
- "#{plugin_key}"
158
- end
159
- end
160
-
161
85
  # checks if string could be parse as yaml
162
86
  def is_yaml?(candidate_string)
163
87
  is_yaml = false
@@ -4,9 +4,35 @@ class Kaui::Catalog < KillBillClient::Model::Catalog
4
4
 
5
5
  class << self
6
6
 
7
- def get_catalog_json(latest, requested_date, options)
7
+ def get_account_catalog_json(account_id, requested_date = nil, options = {})
8
+ params = {}
9
+ params[:accountId] = account_id
10
+ params[:requestedDate] = requested_date if requested_date
11
+
12
+ get KillBillClient::Model::Catalog::KILLBILL_API_CATALOG_PREFIX,
13
+ params,
14
+ {
15
+ :head => {'Accept' => "application/json"},
16
+ :content_type => "application/json",
17
+
18
+ }.merge(options)
19
+ end
8
20
 
9
- catalogs = KillBillClient::Model::Catalog.get_tenant_catalog_json(requested_date, options)
21
+ def get_tenant_catalog_json(requested_date = nil, options = {})
22
+ super
23
+ rescue ::KillBillClient::API::InternalServerError => e
24
+ if !e.response.nil? && !e.response.body.nil?
25
+ error_message = JSON.parse(e.response.body) rescue nil
26
+ raise e if error_message.nil? || error_message['message'].nil?
27
+
28
+ # Hack for lack of proper Kill Bill messaging (see https://github.com/killbill/killbill-admin-ui/issues/265)
29
+ return [] if error_message['message'].starts_with?('No existing versions')
30
+ end
31
+ raise e
32
+ end
33
+
34
+ def get_catalog_json(latest, requested_date, options)
35
+ catalogs = get_tenant_catalog_json(requested_date, options)
10
36
  return catalogs.length > 0 ? catalogs[catalogs.length - 1] : nil if latest
11
37
 
12
38
  # Order by latest
@@ -9,7 +9,7 @@ class Kaui::Tag < KillBillClient::Model::Tag
9
9
  end
10
10
 
11
11
  class << self
12
- [:account, :bundle, :subscription].each do |model|
12
+ [:account, :bundle, :subscription, :invoice].each do |model|
13
13
  define_method "all_for_#{model.to_s}" do |model_id, included_deleted, audit, options|
14
14
  instance = Kaui.const_get(model.to_s.camelize).new("#{model.to_s}_id".to_sym => model_id)
15
15
  instance.tags(included_deleted, audit, options)
@@ -2,7 +2,7 @@
2
2
  <div class='form-group'>
3
3
  <%= f.label :email, 'Email', :class => 'col-sm-2 control-label' %>
4
4
  <div class="col-sm-10">
5
- <%= f.text_field :email, :class => 'form-control', :required => true %>
5
+ <%= f.email_field :email, :class => 'form-control', :required => true %>
6
6
  </div>
7
7
  </div>
8
8
  <div class="form-group">
@@ -25,6 +25,10 @@
25
25
  <%= link_to '<i class="fa fa-plus-square"></i>&nbsp;Create charge'.html_safe,
26
26
  kaui_engine.new_account_charge_path(@account.account_id, :currency => @account.currency) %>
27
27
  <% end %>
28
+ <% if deposit_plugin_available? %>
29
+ <%= link_to '<i class="fa fa-plus-square"></i>&nbsp;Create deposit'.html_safe,
30
+ deposit_engine.collection_index_path(:account_id => @account.account_id, :currency => @account.currency) %>
31
+ <% end %>
28
32
  </div>
29
33
  </div>
30
34
  </div>
@@ -38,7 +38,7 @@
38
38
  <div class="form-group">
39
39
  <%= f.label :email, 'Email', :class => 'col-sm-3 control-label' %>
40
40
  <div class="col-sm-9">
41
- <%= f.text_field :email, :class => 'form-control' %>
41
+ <%= f.email_field :email, :class => 'form-control' %>
42
42
  </div>
43
43
  </div>
44
44
  <% unless @account.persisted? %>
@@ -7,6 +7,9 @@
7
7
  <%= link_to '<i class="fa fa-plus-square"></i>'.html_safe,
8
8
  kaui_engine.new_payment_method_path(:account_id => @account.account_id),
9
9
  :class => 'btn btn-xs' %>
10
+ <%= form_tag kaui_engine.refresh_payment_methods_path(params.to_h), :method => :post, :class => 'form-force-inline form-right' do %>
11
+ <%= button_tag '<i class="fa fa-refresh"></i>'.html_safe, :class => 'btn btn-xs' %>
12
+ <% end %>
10
13
  <% end %>
11
14
  </h1>
12
15
 
@@ -13,8 +13,9 @@
13
13
  <tr>
14
14
  <th></th>
15
15
  <th>ID</th>
16
- <th>External key</th>
17
- <th>Balance</th>
16
+ <% Kaui.account_search_columns.call()[0].each do |title| %>
17
+ <th><%= title %></th>
18
+ <% end %>
18
19
  </tr>
19
20
  </thead>
20
21
  <tbody>
@@ -39,8 +40,10 @@ $(document).ready(function() {
39
40
  },
40
41
  "pageLength": <%= @limit %>,
41
42
  "displayStart": <%= @offset %>,
42
- <% unless @ordering.blank? %>
43
- "order": [[ 1, "<%= @ordering %>" ]],
43
+ <% if @search_query.blank? %>
44
+ "ordering": false,
45
+ <% elsif !@ordering.blank? %>
46
+ "order": [[ 1, "<%= @ordering %>" ]],
44
47
  <% end %>
45
48
  "processing": true,
46
49
  "serverSide": true,
@@ -17,9 +17,10 @@
17
17
 
18
18
  <div id="plugin" class="form-group">
19
19
  <%= label_tag :entered_plugin_name, 'Plugin name', :class => 'col-sm-2 control-label' %>
20
+
20
21
  <div class="col-sm-4">
21
22
  <select class="form-control" id="select_plugin_name"></select>
22
- <%= text_field_tag :entered_plugin_name, nil, :class => 'form-control', :plugin_config => @plugin_config, :tenant_plugin_config => @tenant_plugin_config %>
23
+ <%= text_field_tag :entered_plugin_name, nil, :placeholder => 'as defined in the plugin Activator file', :class => 'form-control', :tenant_plugin_config => @tenant_plugin_config.to_json %>
23
24
  <div class="text plugin-suggestion text-danger"></div>
24
25
  </div>
25
26
  <div class="col-sm-1 spinner"><i class="fa fa-cog fa-2x fa-spin"></i></div>
@@ -29,7 +30,7 @@
29
30
  <span class="slider round"></span>
30
31
  </label>
31
32
  </label>
32
- <label class="col-sm-3 control-label toggle-label text-muted">or toggle plugin name input</label>
33
+ <label class="col-sm-3 control-label toggle-label text-muted">manual entry</label>
33
34
  </div>
34
35
 
35
36
  <div id="plugin_config_properties_header" class="form-group">
@@ -41,8 +42,11 @@
41
42
  </label>
42
43
  </label>
43
44
  </div>
44
- <!-- Anchor DIV that gets thrown away when switching plugins -->
45
- <div id="plugin_config_properties" plugin_name="" class="row">
45
+ <div class="form-group">
46
+ <%= label_tag :configuration, 'Configuration', :class => 'col-sm-2 control-label' %>
47
+ <div class="col-sm-6">
48
+ <textarea name="plugin_properties[raw_config]" id="raw_config" rows="20" class="form-control"></textarea>
49
+ </div>
46
50
  </div>
47
51
 
48
52
  <div class="form-group">
@@ -54,23 +58,6 @@
54
58
  </div>
55
59
  <% end %>
56
60
 
57
- <script id="plugin_config_properties_template" type="text/template">
58
- <input type="hidden" id="plugin_key_values" value="{{data_json}}" />
59
- {{#plugin_props_with_values}}
60
- <div class="form-group">
61
- <label class="col-sm-offset-1 col-sm-2 control-label" for="{{property}}">{{property_label}}</label>
62
- <div class="col-sm-6">
63
- {{#is_raw_config}}
64
- <textarea name="plugin_properties[raw_config]" id="raw_config" rows="10" class="form-control">{{value}}</textarea>
65
- {{/is_raw_config}}
66
- {{^is_raw_config}}
67
- <input type="text" name="plugin_properties[{{property}}]" id="{{property}}" class="form-control" value="{{value}}" />
68
- {{/is_raw_config}}
69
- </div>
70
- </div>
71
- {{/plugin_props_with_values}}
72
- </script>
73
-
74
61
  <script id="plugin_name_options_template" type="text/template">
75
62
  <option></option>
76
63
  {{#plugin_repository}}
@@ -101,48 +88,54 @@
101
88
  $('#plugin_config_properties').empty();
102
89
  $('#plugin_config_properties_header').hide();
103
90
  $(".plugin-suggestion").html('');
91
+ $("#raw_config").val('');
104
92
  });
105
93
 
106
- $("#toggle_raw").on('change', function(e) {
107
- if (isBlank($('#plugin_key_values').val())) {
108
- return;
94
+ /* Intercept TAB and potentially display known properties */
95
+ $('#entered_plugin_name').keydown(function (e) {
96
+ if (e.keyCode === 9) {
97
+ $("#plugin_name").val($('#entered_plugin_name').val());
98
+ $("#plugin_key").val('');
99
+ render_plugin_key_values();
109
100
  }
101
+ });
102
+ /* Intercept mouseleave and potentially display known properties */
103
+ $('#entered_plugin_name').on('mouseleave', function() {
104
+ $("#plugin_name").val($('#entered_plugin_name').val());
105
+ $("#plugin_key").val('');
106
+ render_plugin_key_values();
107
+ });
110
108
 
111
- var plugin_key_values = JSON.parse($('#plugin_key_values').val());
112
- if ($("#toggle_raw").prop("checked")) {
113
- var raw = [];
114
- raw.push({ is_raw_config: true, property: "raw_config", property_label: "Raw Config", value: ''});
115
-
116
- var plugin_name = $('#entered_plugin_name').val();
117
- var plugin_key = $("#plugin_key").val();
118
- var existing_props = get_tenant_plugin_properties(plugin_key, plugin_name);
119
- raw[0].value = existing_props['_raw'];
120
-
121
- render_plugin_key_values(raw, plugin_key_values);
122
- } else {
123
- render_plugin_key_values(plugin_key_values, plugin_key_values);
124
- }
109
+ $("#toggle_raw").on('change', function(e) {
110
+ $("#plugin_name").val($('#entered_plugin_name').val());
111
+ $("#plugin_key").val('');
112
+ render_plugin_key_values();
125
113
  });
126
114
 
127
115
  $('#select_plugin_name').on('change', function(e) {
116
+ // User has selected a plugin from the dropdown
128
117
  var selectedOption = e.target.selectedOptions;
129
118
 
130
119
  if (selectedOption.length > 0) {
131
120
  var plugin_name = selectedOption[0].value;
132
121
  var plugin_key = selectedOption[0].text;
122
+
133
123
  $("#plugin_name").val(plugin_name);
134
124
  $("#plugin_key").val(plugin_key);
135
- $("#plugin_type").val(selectedOption[0].dataset['pluginType']);
125
+ $("#plugin_type").val(selectedOption[0].dataset['pluginType']); // java or ruby
136
126
  $('#plugin_config_properties').attr('plugin_name', '');
137
127
  $('#plugin_config_properties_header').hide();
138
128
  $("#toggle_raw").prop('checked', false);
139
- add_properties_for_plugin(plugin_key, plugin_name);
129
+
130
+ render_plugin_key_values();
140
131
  }
141
132
  });
142
133
 
143
134
  populate_plugin_name_options();
144
135
  function populate_plugin_name_options(){
145
- var plugin_repository = JSON.parse($("#plugin_repository").val());
136
+ var all_plugins = JSON.parse($("#plugin_repository").val());
137
+ // We only list installed plugins as to not confuse the user
138
+ var plugin_repository = all_plugins.filter(plugin => plugin.installed);
146
139
  for (var idx = 0, size = plugin_repository.length; idx < size; idx++) {
147
140
  if (idx == 0 && plugin_repository[idx].installed) {
148
141
  plugin_repository[idx]['start_installed'] = true;
@@ -163,225 +156,50 @@
163
156
  }
164
157
 
165
158
  var template = $("#plugin_name_options_template").html();
166
- var options_html = Mustache.render( template , { plugin_repository: plugin_repository});
159
+ var options_html = Mustache.render( template , { plugin_repository: plugin_repository });
167
160
  $("#select_plugin_name").html(options_html);
168
161
  }
169
162
 
170
163
  function get_existing_tenant_plugin_properties(entered_plugin_name) {
171
164
  var tenant_plugin_properties = $('#entered_plugin_name').attr('tenant_plugin_config');
172
- var res = {};
173
- if (tenant_plugin_properties != undefined) {
174
- $.each(tenant_plugin_properties.split(';'), function(idx, el) {
175
- var el_parts = el.split('::');
176
- var el_plugin_name = el_parts[0];
177
- var el_props = el_parts[1];
178
- if (el_plugin_name === entered_plugin_name) {
179
- if (el_props.split('=')[0] == 'raw_config') {
180
- res['raw_config'] = el_props.replace("raw_config=", "");
181
- } else {
182
- $.map(el_props.split('|'), function(el) {
183
- var parts = el.split('=');
184
- res[parts[0]] = parts.slice(1).join('=');
185
- });
186
- }
187
- return false;
188
- }
189
- });
190
- }
191
- return res;
192
- }
193
-
194
- function get_selected_plugin_info(plugin_key) {
195
- var plugin_config_str = $('#entered_plugin_name').attr('plugin_config');
196
- var res = {}
197
- /* Deserialize plugin/properties (see AdminTenant model)*/
198
- $.each(plugin_config_str.split(';'), function(idx, el) {
199
- var el_parts = el.split(':');
200
- var el_parts_key = el_parts[0].split('#');
201
- var el_plugin_name = el_parts_key[0];
202
- var el_plugin_type = el_parts_key[1];
203
- var el_plugin_props = el_parts[1];
204
- if (el_plugin_name == plugin_key) {
205
- res['type'] = el_plugin_type;
206
- res['props'] = el_plugin_props == "" ? [] : (el_plugin_type == "" ? ['raw_config'] : el_plugin_props.split(','));
207
- return false;
208
- }
209
- });
210
-
211
- if (isBlank(res['props'])) {
212
- res['type'] = '';
213
- res['props'] = ['raw_config'];
214
- }
215
-
216
- return res;
165
+ var res = JSON.parse(tenant_plugin_properties);
166
+ return res[entered_plugin_name];
217
167
  }
218
168
 
219
169
  function get_tenant_plugin_properties(plugin_key, plugin_name) {
220
170
  /* Retrieve existing plugin properties for this tenant */
221
171
  var existing_props = get_existing_tenant_plugin_properties(plugin_key);
222
172
 
223
- // try by plugin name for proprietary plugins
224
- if (isBlank(existing_props)) {
173
+ // Try by plugin name for proprietary plugins
174
+ if (isBlank(existing_props) && !isBlank(plugin_name)) {
225
175
  existing_props = get_existing_tenant_plugin_properties(plugin_name);
226
- }
227
-
228
- return existing_props;
229
- }
230
-
231
- function add_properties_for_plugin(plugin_key, plugin_name) {
232
- var plugin_info = get_selected_plugin_info(plugin_key);
233
-
234
- if (isBlank(plugin_name)) {
235
- $('#plugin_config_properties').empty();
236
- $('#plugin_config_properties').attr('plugin_name', '');
237
- return;
238
- }
239
-
240
- if ($('#plugin_config_properties').attr('plugin_name') == plugin_name) {
241
- /* Already set...*/
242
- return;
243
- }
244
-
245
- var existing_props = get_tenant_plugin_properties(plugin_key, plugin_name);
246
-
247
- var type = plugin_info['type'];
248
- var props = plugin_info['props']
249
-
250
- if (isBlank(type)) {
251
- $(".switch-half-container").hide();
252
- } else {
253
- $(".switch-half-container").show();
254
- }
255
-
256
- $('#plugin_type').val(type);
257
- /* Prune the tree to restart from scratch */
258
- $('#plugin_config_properties_header').show();
259
- $('#plugin_config_properties').empty();
260
- $('#plugin_config_properties').append('<div id="plugin_config_properties_anchor" class="col-sm-12"></div>');
261
-
262
- var merged_props_with_values = existing_props;
263
- if (props != undefined) {
264
- $.each(props, function(idx, p) {
265
- if (merged_props_with_values[p] == undefined) {
266
- merged_props_with_values[p] = '';
176
+ if (isBlank(existing_props)) {
177
+ // For proprietary plugins, the killbill- prefix likely doesn't exist (see Kaui::PluginHelper discussion)
178
+ plugin_name = plugin_name.replace('killbill-', '');
179
+ existing_props = get_existing_tenant_plugin_properties(plugin_name);
180
+ if (isBlank(existing_props)) {
181
+ // For proprietary plugins, our docs suggest acme:foo as the format for the plugin key, and often the plugin name becomes acme-foo
182
+ plugin_name = plugin_name.replace(':', '-');
183
+ existing_props = get_existing_tenant_plugin_properties(plugin_name);
267
184
  }
268
- });
269
- }
270
-
271
- add_property_form_entry(merged_props_with_values);
272
-
273
- $('#plugin_config_properties').attr('plugin_name', plugin_name);
274
- }
275
-
276
- function format_label(input) {
277
- /* Keep latest piece of a system property to keep it short */
278
- var label_name = input.split('.').pop();
279
- /* Replace underscore with comma */
280
- label_name = label_name.replace(/_/g, ',');
281
- /* Replace uppercase with comma + uppercase */
282
- label_name = label_name.replace(/([A-Z]+)/g, ",$1");
283
- /* Split name make sure each word starts with Uppercase */
284
- var tmp1 = label_name.split(',');
285
- var label_name_array = [];
286
- $.map(tmp1, function(el) { label_name_array.push(el.charAt(0).toUpperCase() + el.slice(1)) });
287
- label_name = label_name_array.join(' ');
288
- return label_name;
289
- }
290
-
291
- function add_property_form_entry(merged_props_with_values) {
292
- var plugin_props_with_values = [];
293
-
294
- $.each(merged_props_with_values, function(p, v) {
295
- if (p != '_raw') {
296
- plugin_props_with_values.push({ property_label: format_label(p), property: p, value: v, is_raw_config: p == 'raw_config'});
297
- }
298
- });
299
-
300
- render_plugin_key_values(plugin_props_with_values, plugin_props_with_values);
301
- }
302
-
303
- function render_plugin_key_values(plugin_props_with_values, original) {
304
- var template = $("#plugin_config_properties_template").html();
305
- var plugin_props_with_values_html = Mustache.render( template ,{ plugin_props_with_values: plugin_props_with_values,
306
- data_json: JSON.stringify(original)});
307
- $("#plugin_config_properties_anchor").html(plugin_props_with_values_html);
308
- }
309
-
310
- // Free text related functions and handlers
311
- init_plugin_name_handlers();
312
- function init_plugin_name_handlers() {
313
- /* Intercept ENTER and potentially display property form if plugin is know */
314
- $('#entered_plugin_name').keyup(function (e) {
315
- e.preventDefault();
316
- if (e.keyCode === 13) {
317
- suggest_plugin_name();
318
185
  }
319
- });
320
-
321
- /* Intercept mouseleave and potentially display property form if plugin is know */
322
- $('#entered_plugin_name').on('mouseleave', function() {
323
- suggest_plugin_name();
324
- });
325
- }
326
-
327
- function suggested_response(response) {
328
- $(".spinner").hide();
329
- if (!isBlank(response.suggestion)) {
330
- $(".plugin-suggestion").html(response.suggestion);
331
-
332
- $("#suggested").click(function(e) {
333
- var plugin_name = e.currentTarget.dataset['pluginName'];
334
- var plugin_key = e.currentTarget.dataset['pluginKey'];
335
-
336
- $("#entered_plugin_name").val(plugin_name);
337
- $("#plugin_key").val(plugin_key);
338
- $("#plugin_type").val(e.currentTarget.dataset['pluginType']);
339
- $("#entered_plugin_name").data("last", plugin_name);
340
-
341
- $(".plugin-suggestion").html('');
342
- add_properties_for_plugin(isBlank(plugin_key) ? plugin_name : plugin_key, plugin_name);
343
- });
344
-
345
- } else {
346
- $(".plugin-suggestion").html('');
347
186
  }
348
187
 
349
- var plugin_name = $('#entered_plugin_name').val();
350
- var plugin_key = $("#plugin_key").val();
351
- $("#plugin_name").val(plugin_name);
352
-
353
- add_properties_for_plugin(isBlank(plugin_key) ? plugin_name : plugin_key, plugin_name);
188
+ return existing_props;
354
189
  }
355
190
 
356
- function suggest_plugin_name() {
357
- var plugin_name = $("#entered_plugin_name").val();
358
- var last_plugin_name = $("#entered_plugin_name").data("last");
359
- $("#plugin_key").val(plugin_name);
360
-
361
- if (isBlank(plugin_name)) {
362
- return;
363
- }
364
-
365
- // no change
366
- if ( plugin_name == last_plugin_name) {
367
- return;
191
+ function render_plugin_key_values() {
192
+ var plugin_name = "";
193
+ var plugin_key = "";
194
+ if (isBlank($('#entered_plugin_name').val())) {
195
+ plugin_name = $("#plugin_name").val();
196
+ plugin_key = $("#plugin_key").val();
197
+ } else {
198
+ plugin_name = $("#entered_plugin_name").val();
368
199
  }
369
200
 
370
- $('#plugin_config_properties').attr('plugin_name', '');
371
- $('#plugin_config_properties').empty();
372
- $(".plugin-suggestion").html('');
373
- $("#entered_plugin_name").data("last", plugin_name);
374
- $(".spinner").show();
375
- $.ajax({
376
- url: '<%= suggest_plugin_name_path() %>',
377
- type: "GET",
378
- dataType: "json",
379
- data: {
380
- "plugin_name": plugin_name,
381
- },
382
- success: suggested_response
383
- });
201
+ var existing_props = get_tenant_plugin_properties(plugin_key, plugin_name);
202
+ $("#raw_config").val(existing_props);
384
203
  }
385
-
386
204
  });
387
- <% end %>
205
+ <% end %>