kaui 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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 %>