kaui 4.0.4 → 4.0.6
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/app/assets/javascripts/kaui/kaui_override.js +5 -2
- data/app/controllers/kaui/admin_allowed_users_controller.rb +4 -0
- data/app/controllers/kaui/home_controller.rb +1 -1
- data/app/controllers/kaui/invoices_controller.rb +9 -0
- data/app/controllers/kaui/payments_controller.rb +1 -0
- data/app/helpers/kaui/admin_allowed_users_helper.rb +14 -0
- data/app/helpers/kaui/plugin_helper.rb +2 -0
- data/app/views/kaui/account_timelines/_multi_functions_bar.html.erb +1 -1
- data/app/views/kaui/accounts/_billing_details.html.erb +4 -6
- data/app/views/kaui/admin_allowed_users/index.html.erb +12 -17
- data/app/views/kaui/admin_allowed_users/show.html.erb +17 -15
- data/app/views/kaui/admin_tenants/new_catalog.html.erb +69 -0
- data/app/views/kaui/audit_logs/_multi_functions_bar.html.erb +1 -1
- data/app/views/kaui/components/dashboard/_card.html.erb +2 -1
- data/app/views/kaui/invoices/_invoice_table.html.erb +12 -1
- data/app/views/kaui/invoices/_multi_functions_bar.html.erb +1 -1
- data/app/views/kaui/payments/_multi_functions_bar.html.erb +1 -1
- data/lib/kaui/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7e6e1d8f1969609b1eb958efa90c3f1afed414dbb9a754e88e9624716997eec
|
|
4
|
+
data.tar.gz: f42f2106b4c9f9687b267b2d9475820d390aa6a78cd20605341853ada294981b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 314ac1bb0b060b413aa68ec04183eb39f8df63b94fbe68b1c938b1e726e19733f45986278227f5101884aca3e37ec80d7e86b58348c098350138277e7529de1e
|
|
7
|
+
data.tar.gz: 45d12ccbc5d09cc0c77450e5b5dce0476be99b658078123148c6335854e9c3690e834fa7df800de0b91bd4623c96b0603e68ba8a8826a91347ec1973d74e00cb
|
|
@@ -439,7 +439,7 @@ function setObjectIdPopover(){
|
|
|
439
439
|
// Custom tooltip function for object IDs
|
|
440
440
|
// attributes:
|
|
441
441
|
// data-id = content of the tooltip, object id; required
|
|
442
|
-
// title = title of the tooltip; not required
|
|
442
|
+
// data-title = title of the tooltip; not required
|
|
443
443
|
function setObjectIdTooltip() {
|
|
444
444
|
// Remove any existing tooltips
|
|
445
445
|
$(".custom-tooltip").remove();
|
|
@@ -476,6 +476,9 @@ function showCustomTooltip(element, objectId) {
|
|
|
476
476
|
var position = $element.offset();
|
|
477
477
|
var elementHeight = $element.outerHeight();
|
|
478
478
|
var elementWidth = $element.outerWidth();
|
|
479
|
+
|
|
480
|
+
// Get custom title from data-title attribute or default to "Subscription ID"
|
|
481
|
+
var tooltipTitle = $element.data("title") || "Subscription ID";
|
|
479
482
|
|
|
480
483
|
// Create tooltip content with header and custom SVG icon
|
|
481
484
|
var svgIcon =
|
|
@@ -485,7 +488,7 @@ function showCustomTooltip(element, objectId) {
|
|
|
485
488
|
"</svg>";
|
|
486
489
|
|
|
487
490
|
var tooltipContent =
|
|
488
|
-
'<div class="tooltip-header">
|
|
491
|
+
'<div class="tooltip-header">' + tooltipTitle + '</div>' +
|
|
489
492
|
'<div class="tooltip-content">' +
|
|
490
493
|
'<span class="tooltip-id">' +
|
|
491
494
|
objectId +
|
|
@@ -14,7 +14,7 @@ module Kaui
|
|
|
14
14
|
@max_records = {}
|
|
15
15
|
%w[account payment invoice].each do |type|
|
|
16
16
|
model = "Kaui::#{type.capitalize}".constantize
|
|
17
|
-
@max_records[type.to_sym] = model.list_or_search(nil, 0, 0, options_for_klient).pagination_max_nb_records
|
|
17
|
+
@max_records[type.to_sym] = model.list_or_search(nil, 0, 0, options_for_klient).pagination_max_nb_records
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -36,6 +36,15 @@ module Kaui
|
|
|
36
36
|
Kaui::Invoice.list_or_search(query_string, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient.merge(params: kb_params))
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
if start_date && end_date
|
|
40
|
+
invoices = invoices.select do |invoice|
|
|
41
|
+
start_date_parsed = Date.parse(start_date)
|
|
42
|
+
end_date_parsed = Date.parse(end_date)
|
|
43
|
+
invoice_date = Date.parse(invoice.invoice_date)
|
|
44
|
+
invoice_date.between?(start_date_parsed, end_date_parsed)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
39
48
|
csv_string = CSV.generate(headers: true) do |csv|
|
|
40
49
|
csv << columns
|
|
41
50
|
|
|
@@ -24,6 +24,7 @@ module Kaui
|
|
|
24
24
|
|
|
25
25
|
if all_fields_checked
|
|
26
26
|
columns = KillBillClient::Model::PaymentAttributes.instance_variable_get('@json_attributes') - %w[transactions audit_logs]
|
|
27
|
+
columns += %w[payment_date status] # additional fields not part of the model
|
|
27
28
|
csv_headers = columns.dup
|
|
28
29
|
Kaui::Payment::REMAPPING_FIELDS.each do |k, v|
|
|
29
30
|
index = csv_headers.index(k)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kaui
|
|
4
|
+
module AdminAllowedUsersHelper
|
|
5
|
+
# Check if a user can be deleted
|
|
6
|
+
# Returns false if the user is an admin or the current logged-in user
|
|
7
|
+
def can_delete_user?(user, user_roles)
|
|
8
|
+
is_admin = user_roles.include?('admin') || user.kb_username == Kaui.root_username
|
|
9
|
+
is_current_user = user.kb_username == current_user.kb_username
|
|
10
|
+
|
|
11
|
+
!is_admin && !is_current_user
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<path d="M2.5 8.3335H17.5" stroke="#A4A7AE" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
44
44
|
</svg>
|
|
45
45
|
</label>
|
|
46
|
-
<input type="text" class="form-control center-input" id="startDate" placeholder="All
|
|
46
|
+
<input type="text" class="form-control center-input" id="startDate" placeholder="All Account Timelines" name="startDate">
|
|
47
47
|
<div id="dash" class="dash">–</div>
|
|
48
48
|
<input type="text" class="form-control right-input" id="endDate" placeholder="" name="endDate">
|
|
49
49
|
<div id="toggle-wrapper" class="position-absolute" style="width: 100%; height: 100%;" onclick="document.getElementById('single-toggle').click()"></div>
|
|
@@ -117,12 +117,10 @@
|
|
|
117
117
|
<% end %>
|
|
118
118
|
</div>
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
</div>
|
|
125
|
-
<% end %>
|
|
120
|
+
<div class="info-item">
|
|
121
|
+
<b>Next invoice date</b>
|
|
122
|
+
<p id='next-invoice-date'>N/A</p>
|
|
123
|
+
</div>
|
|
126
124
|
</div>
|
|
127
125
|
|
|
128
126
|
<!-- Right Column -->
|
|
@@ -60,23 +60,16 @@
|
|
|
60
60
|
<td><%= link_to u.kb_username, admin_allowed_user_path(u.id) %></td>
|
|
61
61
|
<td><%= u.description %></td>
|
|
62
62
|
<td class="text-end">
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
method: "delete",
|
|
74
|
-
turbo: false,
|
|
75
|
-
"url": kaui_engine.admin_allowed_user_path(u.id)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
} %>
|
|
79
|
-
<%= link_to kaui_engine.edit_admin_allowed_user_path(u.id), :class => '' do %>
|
|
63
|
+
<% user_roles = @roles_by_user[u.kb_username] || [] %>
|
|
64
|
+
<% if can_delete_user?(u, user_roles) %>
|
|
65
|
+
<%= form_tag kaui_engine.admin_allowed_user_path(u.id), method: :delete, class: 'd-inline', onsubmit: "return confirm('Are you sure?');" do %>
|
|
66
|
+
<%= button_tag type: 'submit', class: 'btn btn-outline-secondary d-inline-flex align-items-center gap-1 kaui-button delete-button custom-hover' do %>
|
|
67
|
+
Delete
|
|
68
|
+
<% end %>
|
|
69
|
+
<% end %>
|
|
70
|
+
<% end %>
|
|
71
|
+
|
|
72
|
+
<%= link_to kaui_engine.edit_admin_allowed_user_path(u.id), class: 'text-decoration-none' do %>
|
|
80
73
|
<%= render "kaui/components/button/button", {
|
|
81
74
|
label: "Edit",
|
|
82
75
|
variant: "outline-secondary d-inline-flex align-items-center gap-1",
|
|
@@ -154,6 +147,8 @@
|
|
|
154
147
|
$header.find('.sort-' + direction).addClass('active');
|
|
155
148
|
}
|
|
156
149
|
|
|
150
|
+
} catch (e) {
|
|
151
|
+
console.error('Error initializing DataTable:', e);
|
|
157
152
|
}
|
|
158
153
|
}, 100);
|
|
159
154
|
});
|
|
@@ -6,21 +6,23 @@
|
|
|
6
6
|
<h2>User details</h2>
|
|
7
7
|
</div>
|
|
8
8
|
<span>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
<% if can_delete_user?(@allowed_user, @roles) %>
|
|
10
|
+
<%= render "kaui/components/button/button", {
|
|
11
|
+
label: 'Delete',
|
|
12
|
+
variant: "outline-secondary d-inline-flex align-items-center gap-1",
|
|
13
|
+
type: "button",
|
|
14
|
+
html_class: "kaui-button delete-button custom-hover",
|
|
15
|
+
html_options: {
|
|
16
|
+
data: {
|
|
17
|
+
confirm: "Are you sure?",
|
|
18
|
+
method: "delete",
|
|
19
|
+
turbo: false, # Optional: disable Turbo if using Rails Turbo
|
|
20
|
+
"url": kaui_engine.admin_allowed_user_path(@allowed_user.id)
|
|
21
|
+
},
|
|
22
|
+
onclick: "if (confirm(this.dataset.confirm)) { Rails.ajax({ url: this.dataset.url, type: this.dataset.method }); }"
|
|
23
|
+
}
|
|
24
|
+
} %>
|
|
25
|
+
<% end %>
|
|
24
26
|
|
|
25
27
|
<%= link_to kaui_engine.edit_admin_allowed_user_path(@allowed_user.id),
|
|
26
28
|
:class => '' do %>
|
|
@@ -246,6 +246,8 @@ function switch_basic_config() {
|
|
|
246
246
|
$(document).ready(function() {
|
|
247
247
|
switch_basic_config();
|
|
248
248
|
|
|
249
|
+
// jQuery UI autocomplete interferes with HTML5 validation
|
|
250
|
+
// So we keep the custom JS validation
|
|
249
251
|
$('#simple_plan_product_name').autocomplete({
|
|
250
252
|
source: function(query, process) {
|
|
251
253
|
process(known_products());
|
|
@@ -261,8 +263,75 @@ $(document).ready(function() {
|
|
|
261
263
|
$('#simple_plan_product_name').on('mouseleave', function() {
|
|
262
264
|
recompute_available_base_products_for_ao();
|
|
263
265
|
});
|
|
266
|
+
|
|
267
|
+
// Realtime validation function
|
|
268
|
+
function validateField(field) {
|
|
269
|
+
var pattern = /^[a-zA-Z_][\w\.-]*$/;
|
|
270
|
+
var value = field.val().trim();
|
|
271
|
+
var fieldName = field.attr('id') === 'simple_plan_product_name' ? 'Product Name' : 'Plan Name';
|
|
272
|
+
|
|
273
|
+
if (value === '') {
|
|
274
|
+
showError(field, fieldName + ' is required');
|
|
275
|
+
return false;
|
|
276
|
+
} else if (!pattern.test(value)) {
|
|
277
|
+
showError(field, fieldName + ' must start with a letter or underscore, and can only contain letters, digits, underscores, hyphens, and periods');
|
|
278
|
+
return false;
|
|
279
|
+
} else {
|
|
280
|
+
clearError(field);
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Realtime validation on input
|
|
286
|
+
$('#simple_plan_product_name, #simple_plan_plan_id').on('input', function() {
|
|
287
|
+
validateField($(this));
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Validation on blur (when user leaves the field)
|
|
291
|
+
$('#simple_plan_product_name, #simple_plan_plan_id').on('blur', function() {
|
|
292
|
+
validateField($(this));
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Custom validation on form submit
|
|
296
|
+
$('#catalog_simple form').on('submit', function(e) {
|
|
297
|
+
var isValid = true;
|
|
298
|
+
|
|
299
|
+
// Validate Product Name
|
|
300
|
+
if (!validateField($('#simple_plan_product_name'))) {
|
|
301
|
+
isValid = false;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Validate Plan Name
|
|
305
|
+
if (!validateField($('#simple_plan_plan_id'))) {
|
|
306
|
+
isValid = false;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (!isValid) {
|
|
310
|
+
e.preventDefault();
|
|
311
|
+
e.stopPropagation();
|
|
312
|
+
// Scroll to first error
|
|
313
|
+
$('.error-message:first').get(0)?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return true;
|
|
318
|
+
});
|
|
264
319
|
});
|
|
265
320
|
|
|
321
|
+
function showError(field, message) {
|
|
322
|
+
clearError(field);
|
|
323
|
+
field.addClass('error-field');
|
|
324
|
+
field.css('border-color', '#dc3545');
|
|
325
|
+
var errorDiv = $('<div class="error-message" style="color: #dc3545; font-size: 0.875rem; margin-top: 0.25rem;"></div>').text(message);
|
|
326
|
+
field.parent().append(errorDiv);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function clearError(field) {
|
|
330
|
+
field.removeClass('error-field');
|
|
331
|
+
field.css('border-color', '');
|
|
332
|
+
field.parent().find('.error-message').remove();
|
|
333
|
+
}
|
|
334
|
+
|
|
266
335
|
document.querySelectorAll('.toggle-option').forEach(el => {
|
|
267
336
|
el.addEventListener('click', () => {
|
|
268
337
|
document.querySelectorAll('.toggle-option').forEach(opt => opt.classList.remove('active-btn'));
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<path d="M2.5 8.3335H17.5" stroke="#A4A7AE" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
44
44
|
</svg>
|
|
45
45
|
</label>
|
|
46
|
-
<input type="text" class="form-control center-input" id="startDate" placeholder="All
|
|
46
|
+
<input type="text" class="form-control center-input" id="startDate" placeholder="All Logs" name="startDate">
|
|
47
47
|
<div id="dash" class="dash">–</div>
|
|
48
48
|
<input type="text" class="form-control right-input" id="endDate" placeholder="" name="endDate">
|
|
49
49
|
<div id="toggle-wrapper" class="position-absolute" style="width: 100%; height: 100%;" onclick="document.getElementById('single-toggle').click()"></div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<% count_text = count.nil? ? "20k+" : count.to_i %>
|
|
1
2
|
<div class="col-md-4">
|
|
2
3
|
<div class="dashboard-card border rounded-4 d-flex flex-column justify-content-between h-100">
|
|
3
4
|
<div class="d-flex px-4 py-3 align-items-center gap-3">
|
|
@@ -6,7 +7,7 @@
|
|
|
6
7
|
</div>
|
|
7
8
|
<div>
|
|
8
9
|
<h6 class="mb-0 fw-600 text-black-900"><%= title %></h6>
|
|
9
|
-
<p class="text-muted fw-normal text-tertiary small mb-0"><%=
|
|
10
|
+
<p class="text-muted fw-normal text-tertiary small mb-0"><%= count_text %></p>
|
|
10
11
|
</div>
|
|
11
12
|
</div>
|
|
12
13
|
<div class="w-full dashboard-card-divider"></div>
|
|
@@ -91,7 +91,11 @@
|
|
|
91
91
|
|
|
92
92
|
</td>
|
|
93
93
|
<% end %>
|
|
94
|
-
<td onClick="hightlightLinkedItems('<%= item.invoice_item_id %>', '<%= item.linked_invoice_item_id %>'); return false;"
|
|
94
|
+
<td onClick="hightlightLinkedItems('<%= item.invoice_item_id %>', '<%= item.linked_invoice_item_id %>'); return false;">
|
|
95
|
+
<span id="<%= item.invoice_item_id %>-popover" class="object-id-popover" data-id="<%= item.invoice_item_id %>" data-title="Invoice Item ID">
|
|
96
|
+
<%= item.pretty_plan_name.blank? || !item.item_type.in?(%w{USAGE RECURRING}) ? item.description : item.pretty_plan_name %>
|
|
97
|
+
</span>
|
|
98
|
+
</td>
|
|
95
99
|
<td onClick="hightlightLinkedItems('<%= item.invoice_item_id %>', '<%= item.linked_invoice_item_id %>'); return false;"><%= item.start_date.html_safe if item.start_date %></td>
|
|
96
100
|
<td onClick="hightlightLinkedItems('<%= item.invoice_item_id %>', '<%= item.linked_invoice_item_id %>'); return false;"><%= item.end_date.html_safe if item.end_date %></td>
|
|
97
101
|
<td onClick="hightlightLinkedItems('<%= item.invoice_item_id %>', '<%= item.linked_invoice_item_id %>'); return false;"><%= item.subscription_id %></td>
|
|
@@ -149,4 +153,11 @@
|
|
|
149
153
|
}
|
|
150
154
|
});
|
|
151
155
|
}
|
|
156
|
+
|
|
157
|
+
$(document).ready(function() {
|
|
158
|
+
// Initialize tooltips for invoice item IDs
|
|
159
|
+
if (typeof setObjectIdTooltip === 'function') {
|
|
160
|
+
setObjectIdTooltip();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
152
163
|
</script>
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
<path d="M2.5 8.3335H17.5" stroke="#A4A7AE" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
92
92
|
</svg>
|
|
93
93
|
</label>
|
|
94
|
-
<input type="text" class="form-control center-input" id="startDate" placeholder="All
|
|
94
|
+
<input type="text" class="form-control center-input" id="startDate" placeholder="All Invoices" name="startDate">
|
|
95
95
|
<div id="dash" class="dash">–</div>
|
|
96
96
|
<input type="text" class="form-control right-input" id="endDate" placeholder="" name="endDate">
|
|
97
97
|
<div id="toggle-wrapper" class="position-absolute" style="width: 100%; height: 100%;" onclick="document.getElementById('single-toggle').click()"></div>
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
<path d="M2.5 8.3335H17.5" stroke="#A4A7AE" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
91
91
|
</svg>
|
|
92
92
|
</label>
|
|
93
|
-
<input type="text" class="form-control center-input" id="startDate" placeholder="All
|
|
93
|
+
<input type="text" class="form-control center-input" id="startDate" placeholder="All Payments" name="startDate">
|
|
94
94
|
<div id="dash" class="dash">–</div>
|
|
95
95
|
<input type="text" class="form-control right-input" id="endDate" placeholder="" name="endDate">
|
|
96
96
|
<div id="toggle-wrapper" class="position-absolute" style="width: 100%; height: 100%;" onclick="document.getElementById('single-toggle').click()"></div>
|
data/lib/kaui/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kaui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kill Bill core team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-12-
|
|
11
|
+
date: 2025-12-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: actionpack
|
|
@@ -454,6 +454,7 @@ files:
|
|
|
454
454
|
- app/controllers/kaui/tenants_controller.rb
|
|
455
455
|
- app/controllers/kaui/transactions_controller.rb
|
|
456
456
|
- app/helpers/kaui/account_helper.rb
|
|
457
|
+
- app/helpers/kaui/admin_allowed_users_helper.rb
|
|
457
458
|
- app/helpers/kaui/application_helper.rb
|
|
458
459
|
- app/helpers/kaui/date_helper.rb
|
|
459
460
|
- app/helpers/kaui/exception_helper.rb
|