kaui 3.0.6 → 3.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f1640604b51f6dc5c1d70ed464a59445fd16fc830d69797bb73c18a351db03f
4
- data.tar.gz: b385394d51aed523a26d34b437a7e4f8f869de07447b18a0fcce3d81948e275f
3
+ metadata.gz: 23207942c5d84c906aa3e23e06c74e86f278b7889088efb260bbb7d591043b4b
4
+ data.tar.gz: 56df3037f7210cffd9521a410df4302d93da6e5c3989bc5717fbad37033fcb9b
5
5
  SHA512:
6
- metadata.gz: ca50c69637a9fa3e7b7bd866ad3ac638bf676e8f8a61ff8b56e68eb7591f59fefa6536739b8c326523cf7013502586b23edc7fe62a08766e586cbcc73996aa07
7
- data.tar.gz: 2ef386342bd738b4089d50dd1621c2e5e0542c37099435ef8a80f5419a30dd956d478ea3762a553b741985c5f6e1878686d502915b02b2f47f471d671ff11746
6
+ metadata.gz: 5542399f26a14547366266fd4047b78cada6204033610005d9901e8d1a8c7a2367423809e468f599d602e1e59880c0f08cfded1298deeef41bc593e4203592de
7
+ data.tar.gz: eff5e260361d301bf8cc10ac973320c25f9fb76347aa57b3792017acc6fb4d817cea4e798eb797bf6d7c575862b5e1b4bf62ceed2d036ab33611f66f62a28e15
@@ -0,0 +1,132 @@
1
+ // Function to map operators to user-friendly text
2
+ function searchFormatOperator(operator) {
3
+ var operatorMapping = {
4
+ 'eq': 'Equals',
5
+ 'neq': 'Not Equals',
6
+ 'gt': 'Greater Than',
7
+ 'gte': 'Greater Than Or Equal',
8
+ 'lt': 'Less Than',
9
+ 'lte': 'Less Than Or Equal',
10
+ 'like': 'Like'
11
+ };
12
+ return operatorMapping[operator] || operator;
13
+ }
14
+
15
+ // Function to parse URL parameters
16
+ function getUrlParams() {
17
+ var params = {};
18
+ var queryString = window.location.search.substring(1);
19
+ queryString = queryString.replace(/ac_id/g, 'account_id');
20
+ var regex = /([^&=]+)=([^&]*)/g;
21
+ var m;
22
+ while (m = regex.exec(queryString)) {
23
+ params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
24
+ }
25
+ return params;
26
+ }
27
+
28
+ // Function to populate search labels from URL parameters
29
+ function populateSearchLabelsFromUrl() {
30
+ var params = getUrlParams();
31
+ var searchLabelsContainer = $('#search-labels-container');
32
+ searchLabelsContainer.empty();
33
+
34
+ var hasBalanceFilter = window.location.search.includes('balance');
35
+
36
+ for (var key in params) {
37
+ if (params.hasOwnProperty(key)) {
38
+ var value = params[key];
39
+ value = value.replace(/%/g, '');
40
+ var match = key.match(/(.*)\[(.*)\]/);
41
+ if (match) {
42
+ var columnName = match[1].replace(/_/g, ' ').replace(/^\w/, function(l) { return l.toUpperCase(); });
43
+ var filter = searchFormatOperator(match[2]);
44
+ var label = $('<span>', {
45
+ class: 'label label-info',
46
+ text: columnName + ' [' + filter + '] ' + value
47
+ });
48
+
49
+ if (hasBalanceFilter && columnName.toLowerCase() !== 'balance') {
50
+ label.attr('class', 'label label-default');
51
+ }
52
+
53
+ searchLabelsContainer.append(label);
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ function searchQuery(account_id){
60
+ var searchFields = $('.search-field');
61
+ var searchLabelsContainer = $('#search-labels-container');
62
+ searchLabelsContainer.empty();
63
+
64
+ var searchLabels = searchFields.map(function() {
65
+ var filter = $(this).find('.search-field-filter').val();
66
+ var value = $(this).find('.search-field-value').val();
67
+ var columnName = $(this).find('.search-field-filter').attr('name').replace('Filter', '').toLowerCase().replace(/\s+/g, '_');
68
+
69
+ if (value !== '') {
70
+ if (filter === 'like') {
71
+ return columnName + encodeURIComponent('[' + filter + ']') + '=' + encodeURIComponent('%' + value + '%');
72
+ } else {
73
+ return columnName + encodeURIComponent('[' + filter + ']') + '=' + encodeURIComponent(value);
74
+ }
75
+ }
76
+ }).get().join('&');
77
+
78
+ if (account_id !== undefined && account_id !== '') {
79
+ searchLabels += '&' + encodeURIComponent('account_id[eq]') + '=' + encodeURIComponent(account_id);
80
+ }
81
+
82
+ var searchLabelString = searchLabels.length > 0 ? ('_q=1&' + searchLabels) : '';
83
+ if (searchLabelString == '') {
84
+ clearAdvanceSearch();
85
+ }
86
+ return searchLabelString;
87
+ };
88
+
89
+ function clearAdvanceSearch() {
90
+ // Clear all search fields
91
+ $('#search-fields-container').empty();
92
+
93
+ // Remove all search labels
94
+ $('#search-labels-container').empty();
95
+
96
+ // Reload the page with the original URL (no parameters)
97
+ window.location.href = window.location.pathname;
98
+
99
+ // Hide the modal
100
+ $('#advanceSearchModal').modal('hide');
101
+ }
102
+
103
+ function showAdvanceSearchModal() {
104
+ var searchLabelsContainer = $('#search-labels-container');
105
+ var searchFieldsContainer = $('#search-fields-container');
106
+ searchFieldsContainer.empty();
107
+
108
+ // Populate the search fields with the current filters
109
+ searchLabelsContainer.find('.label').each(function() {
110
+ var labelText = $(this).text();
111
+ var parts = labelText.split(' [');
112
+ var columnName = parts[0].trim();
113
+ var filterAndValue = parts[1].split('] ');
114
+ var filter = filterAndValue[0].trim();
115
+ var value = filterAndValue[1].trim();
116
+
117
+ var template = document.getElementById('search-field-template').content.cloneNode(true);
118
+ template.querySelector('.search-field-label').textContent = columnName.replace(/([A-Z])/g, ' $1').trim();
119
+ template.querySelector('.search-field-filter').name = columnName + 'Filter';
120
+ template.querySelector('.search-field-filter').value = filter;
121
+ template.querySelector('.search-field-value').name = columnName;
122
+ template.querySelector('.search-field-value').value = value;
123
+
124
+ searchFieldsContainer.append(template);
125
+ var dropdown = searchFieldsContainer.find('.search-field:last-child .search-field-filter');
126
+ dropdown.find('option').each(function() {
127
+ if ($(this).text().trim().toLowerCase() === filter.toLowerCase()) {
128
+ $(this).prop('selected', true);
129
+ }
130
+ });
131
+ });
132
+ }
@@ -146,7 +146,7 @@ module Kaui
146
146
  rescue StandardError
147
147
  nil
148
148
  end
149
- target_date >= start_date && target_date <= end_date
149
+ target_date.between?(start_date, end_date)
150
150
  end
151
151
 
152
152
  def load_bundle_name_for_timeline(bundle_key)
@@ -5,7 +5,7 @@ module Kaui
5
5
  class AccountsController < Kaui::EngineController
6
6
  def index
7
7
  @search_query = params[:q]
8
-
8
+ @advance_search_query = request.query_string
9
9
  if params[:fast] == '1' && !@search_query.blank?
10
10
  account = Kaui::Account.list_or_search(@search_query, -1, 1, options_for_klient).first
11
11
  if account.nil?
@@ -16,7 +16,7 @@ module Kaui
16
16
  end
17
17
  return
18
18
  end
19
-
19
+ @search_fields = Kaui::Account::ADVANCED_SEARCH_COLUMNS.map { |attr| [attr, attr.split('_').join(' ').capitalize] }
20
20
  @dropdown_default = default_columns(Kaui.account_search_columns.call[2], Kaui::Account::SENSIVITE_DATA_FIELDS)
21
21
 
22
22
  @ordering = params[:ordering] || (@search_query.blank? ? 'desc' : 'asc')
@@ -29,6 +29,7 @@ module Kaui
29
29
  def pagination
30
30
  cached_options_for_klient = options_for_klient
31
31
  searcher = lambda do |search_key, offset, limit|
32
+ search_key = remapping_addvanced_search_fields(search_key, Kaui::Account::ADVANCED_SEARCH_NAME_CHANGES)
32
33
  Kaui::Account.list_or_search(search_key, offset, limit, cached_options_for_klient)
33
34
  end
34
35
 
@@ -52,11 +53,18 @@ module Kaui
52
53
  start_date = params[:startDate]
53
54
  end_date = params[:endDate]
54
55
  all_fields_checked = params[:allFieldsChecked] == 'true'
56
+ query_string = params[:search]
55
57
 
56
58
  if all_fields_checked
57
59
  columns = KillBillClient::Model::AccountAttributes.instance_variable_get('@json_attributes')
60
+ csv_headers = columns.dup
61
+ Kaui::Account::REMAPPING_FIELDS.each do |k, v|
62
+ index = csv_headers.index(k)
63
+ csv_headers[index] = v if index
64
+ end
58
65
  else
59
66
  columns = params.require(:columnsString).split(',').map { |attr| attr.split.join('_').downcase }
67
+ csv_headers = columns.dup
60
68
  Kaui::Account::REMAPPING_FIELDS.each do |k, v|
61
69
  index = columns.index(v)
62
70
  columns[index] = k if index
@@ -73,10 +81,11 @@ module Kaui
73
81
  rescue StandardError
74
82
  nil
75
83
  end
76
- accounts = Kaui::Account.list_or_search(nil, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient)
84
+ query_string = remapping_addvanced_search_fields(query_string, Kaui::Account::ADVANCED_SEARCH_NAME_CHANGES)
85
+ accounts = Kaui::Account.list_or_search(query_string, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient)
77
86
 
78
87
  csv_string = CSV.generate(headers: true) do |csv|
79
- csv << columns
88
+ csv << csv_headers
80
89
  accounts.each do |account|
81
90
  change_date = Date.parse(account.reference_time)
82
91
  data = columns.map do |attr|
@@ -14,8 +14,34 @@ module Kaui
14
14
  end
15
15
  # rubocop:enable Lint/UselessAssignment, Naming/AccessorMethodName
16
16
 
17
+ # Remove this when we support balance search alongside the other search
18
+ def handle_balance_search(query_string)
19
+ return nil if query_string.blank?
20
+ return query_string unless query_string.include?('balance')
21
+
22
+ CGI.unescape(query_string)
23
+ .split('&')
24
+ .grep(/_q|balance/)
25
+ .map { |param| param.split('=') }
26
+ .map { |key, value| "#{CGI.escape(key)}=#{value}" }
27
+ .join('&')
28
+ end
29
+
30
+ def remapping_addvanced_search_fields(search_string, advanced_search_name_changes)
31
+ return search_string if search_string.blank? || !(search_string.include? '_q')
32
+
33
+ advanced_search_name_changes.each do |new_name, old_name|
34
+ search_string = search_string.gsub(new_name, old_name)
35
+ end
36
+ search_string
37
+ end
38
+
17
39
  def paginate(searcher, data_extractor, formatter, table_default_columns = [])
18
40
  search_key = (params[:search] || {})[:value].presence
41
+ advance_search_query = params[:advance_search_query].presence
42
+
43
+ search_key = advance_search_query if advance_search_query
44
+ search_key = handle_balance_search(search_key) if search_key.present?
19
45
  offset = (params[:start] || 0).to_i
20
46
  limit = (params[:length] || 10).to_i
21
47
 
@@ -5,10 +5,11 @@ module Kaui
5
5
  class InvoicesController < Kaui::EngineController
6
6
  def index
7
7
  @search_query = params[:account_id]
8
-
8
+ @advance_search_query = request.query_string
9
9
  @ordering = params[:ordering] || (@search_query.blank? ? 'desc' : 'asc')
10
10
  @offset = params[:offset] || 0
11
11
  @limit = params[:limit] || 50
12
+ @search_fields = Kaui::Invoice::ADVANCED_SEARCH_COLUMNS.map { |attr| [attr, attr.split('_').join(' ').capitalize] }
12
13
 
13
14
  @max_nb_records = @search_query.blank? ? Kaui::Invoice.list_or_search(nil, 0, 0, options_for_klient).pagination_max_nb_records : 0
14
15
  end
@@ -18,6 +19,7 @@ module Kaui
18
19
  start_date = params[:startDate]
19
20
  end_date = params[:endDate]
20
21
  all_fields_checked = params[:allFieldsChecked] == 'true'
22
+ query_string = handle_balance_search(params[:search])
21
23
  columns = if all_fields_checked
22
24
  KillBillClient::Model::InvoiceAttributes.instance_variable_get('@json_attributes') - Kaui::Invoice::TABLE_IGNORE_COLUMNS
23
25
  else
@@ -27,12 +29,12 @@ module Kaui
27
29
  kb_params = {}
28
30
  kb_params[:startDate] = Date.parse(start_date).strftime('%Y-%m-%d') if start_date
29
31
  kb_params[:endDate] = Date.parse(end_date).strftime('%Y-%m-%d') if end_date
30
- if account_id.present?
31
- account = Kaui::Account.find_by_id_or_key(account_id, false, false, options_for_klient)
32
- invoices = account.invoices(options_for_klient.merge(params: kb_params))
33
- else
34
- invoices = Kaui::Invoice.list_or_search(nil, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient.merge(params: kb_params))
35
- end
32
+ query_string = remapping_addvanced_search_fields(query_string, Kaui::Invoice::ADVANCED_SEARCH_NAME_CHANGES)
33
+ invoices = if account_id.present? && query_string.blank?
34
+ Kaui::Account.paginated_invoices(account_id, nil, nil, 'NONE', options_for_klient).map! { |invoice| Kaui::Invoice.build_from_raw_invoice(invoice) }
35
+ else
36
+ Kaui::Invoice.list_or_search(query_string, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient.merge(params: kb_params))
37
+ end
36
38
 
37
39
  csv_string = CSV.generate(headers: true) do |csv|
38
40
  csv << columns
@@ -54,6 +56,7 @@ module Kaui
54
56
  nil
55
57
  end
56
58
  if account.nil?
59
+ search_key = remapping_addvanced_search_fields(search_key, Kaui::Invoice::ADVANCED_SEARCH_NAME_CHANGES)
57
60
  Kaui::Invoice.list_or_search(search_key, offset, limit, cached_options_for_klient)
58
61
  else
59
62
  Kaui::Account.paginated_invoices(search_key, offset, limit, 'NONE', cached_options_for_klient).map! { |invoice| Kaui::Invoice.build_from_raw_invoice(invoice) }
@@ -6,10 +6,11 @@ module Kaui
6
6
  class PaymentsController < Kaui::EngineController
7
7
  def index
8
8
  @search_query = params[:q] || params[:account_id]
9
-
9
+ @advance_search_query = request.query_string
10
10
  @ordering = params[:ordering] || (@search_query.blank? ? 'desc' : 'asc')
11
11
  @offset = params[:offset] || 0
12
12
  @limit = params[:limit] || 50
13
+ @search_fields = Kaui::Payment::ADVANCED_SEARCH_COLUMNS.map { |attr| [attr, attr.split('_').join(' ').capitalize] }
13
14
 
14
15
  @max_nb_records = @search_query.blank? ? Kaui::Payment.list_or_search(nil, 0, 0, options_for_klient).pagination_max_nb_records : 0
15
16
  end
@@ -19,25 +20,34 @@ module Kaui
19
20
  start_date = params[:startDate]
20
21
  end_date = params[:endDate]
21
22
  all_fields_checked = params[:allFieldsChecked] == 'true'
23
+ query_string = params[:search]
24
+
22
25
  if all_fields_checked
23
26
  columns = KillBillClient::Model::PaymentAttributes.instance_variable_get('@json_attributes') - %w[transactions audit_logs]
27
+ csv_headers = columns.dup
28
+ Kaui::Payment::REMAPPING_FIELDS.each do |k, v|
29
+ index = csv_headers.index(k)
30
+ csv_headers[index] = v if index
31
+ end
24
32
  else
25
33
  columns = params.require(:columnsString).split(',').map { |attr| attr.split.join('_').downcase }
34
+ csv_headers = columns.dup
26
35
  Kaui::Payment::REMAPPING_FIELDS.each do |k, v|
27
36
  index = columns.index(v)
28
37
  columns[index] = k if index
29
38
  end
30
39
  end
31
-
40
+ query_string = remapping_addvanced_search_fields(query_string, Kaui::Payment::ADVANCED_SEARCH_NAME_CHANGES)
32
41
  kb_params = {}
33
42
  kb_params[:startDate] = Date.parse(start_date).strftime('%Y-%m-%d') if start_date
34
43
  kb_params[:endDate] = Date.parse(end_date).strftime('%Y-%m-%d') if end_date
35
- if account_id.present?
36
- account = Kaui::Account.find_by_id_or_key(account_id, false, false, options_for_klient)
37
- payments = account.payments(options_for_klient).map! { |payment| Kaui::Payment.build_from_raw_payment(payment) }
38
- else
39
- payments = Kaui::Payment.list_or_search(nil, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient.merge(params: kb_params))
40
- end
44
+ account = account_id.present? ? Kaui::Account.find_by_id_or_key(account_id, false, false, options_for_klient) : nil
45
+
46
+ payments = if account_id.present? && query_string.blank?
47
+ Kaui::Account.paginated_payments(account_id, nil, nil, 'NONE', options_for_klient).map! { |payment| Kaui::Payment.build_from_raw_invoice(payment) }
48
+ else
49
+ Kaui::Payment.list_or_search(query_string, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient.merge(params: kb_params))
50
+ end
41
51
 
42
52
  payments.each do |payment|
43
53
  created_date = nil
@@ -99,6 +109,7 @@ module Kaui
99
109
  end
100
110
 
101
111
  payments = if account.nil?
112
+ search_key = remapping_addvanced_search_fields(search_key, Kaui::Payment::ADVANCED_SEARCH_NAME_CHANGES)
102
113
  Kaui::Payment.list_or_search(search_key, offset, limit, options_for_klient)
103
114
  else
104
115
  account.payments(options_for_klient).map! { |payment| Kaui::Payment.build_from_raw_payment(payment) }
@@ -12,6 +12,8 @@ module Kaui
12
12
  # The sign-in flow eventually calls authenticate! from config/initializers/killbill_authenticatable.rb
13
13
 
14
14
  rescue_from(StandardError) do |exception|
15
+ Rails.logger.error(exception.message)
16
+ Rails.logger.error(exception.backtrace.join("\n")) if exception.backtrace
15
17
  @error = standardize_exception(exception)
16
18
  render 'kaui/errors/500', status: 500, layout: false
17
19
  end
@@ -5,8 +5,10 @@ module Kaui
5
5
  def standardize_exception(exception)
6
6
  if defined?(JRUBY_VERSION)
7
7
  case exception
8
- when ActiveRecord::JDBCError
8
+ when ActiveRecord::JDBCError, ActiveRecord::NoDatabaseError, ActiveRecord::DatabaseConnectionError, ActiveRecord::ConnectionNotEstablished
9
9
  return I18n.translate('errors.messages.unable_to_connect_database')
10
+ else
11
+ return exception.message
10
12
  end
11
13
  end
12
14
 
@@ -7,12 +7,15 @@ module Kaui
7
7
  SENSIVITE_DATA_FIELDS = %w[name email].freeze
8
8
  REMAPPING_FIELDS = {
9
9
  'is_payment_delegated_to_parent' => 'pay_via_parent',
10
- 'bill_cycle_day_local' => 'bcd',
11
10
  'account_balance' => 'balance',
11
+ 'bill_cycle_day_local' => 'bcd',
12
12
  'account_cba' => 'cba',
13
13
  'is_migrated' => 'migrated'
14
14
  }.freeze
15
15
 
16
+ ADVANCED_SEARCH_COLUMNS = %w[id external_key email name currency parent_account_id pay_via_parent payment_method_id time_zone country postal_code].freeze
17
+ ADVANCED_SEARCH_NAME_CHANGES = [%w[pay_via_parent is_payment_delegated_to_parent]].freeze
18
+
16
19
  def check_account_details_phone
17
20
  return true if phone =~ /\A(?:\+?\d{1,3}\s*-?)?\(?(?:\d{3})?\)?[- ]?\d{3}[- ]?\d{4}\z/i
18
21
 
@@ -3,6 +3,8 @@
3
3
  module Kaui
4
4
  class Invoice < KillBillClient::Model::Invoice
5
5
  TABLE_IGNORE_COLUMNS = %w[amount balance credit_adj refund_adj items is_parent_invoice parent_invoice_id parent_account_id audit_logs bundle_keys].freeze
6
+ ADVANCED_SEARCH_COLUMNS = %w[id account_id invoice_date target_date currency status balance].freeze
7
+ ADVANCED_SEARCH_NAME_CHANGES = [%w[ac_id account_id]].freeze
6
8
 
7
9
  def self.build_from_raw_invoice(raw_invoice)
8
10
  result = Kaui::Invoice.new
@@ -14,6 +14,8 @@ module Kaui
14
14
  'credited_amount' => 'credit',
15
15
  'refunded_amount' => 'refund'
16
16
  }.freeze
17
+ ADVANCED_SEARCH_COLUMNS = %w[id account_id payment_method_id external_key].freeze
18
+ ADVANCED_SEARCH_NAME_CHANGES = [%w[ac_id account_id]].freeze
17
19
 
18
20
  def self.build_from_raw_payment(raw_payment)
19
21
  result = Kaui::Payment.new
@@ -0,0 +1,189 @@
1
+ <div class="modal fade" id="advanceSearchModal" tabindex="-1" role="dialog" aria-labelledby="advanceSearchModalLabel" aria-hidden="true">
2
+ <div class="modal-dialog" role="document">
3
+ <div class="modal-content">
4
+ <div class="modal-header">
5
+ <h5 class="modal-title" id="advanceSearchModalLabel">Advance Search</h5>
6
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
7
+ <span aria-hidden="true">&times;</span>
8
+ </button>
9
+ </div>
10
+ <div class="modal-body">
11
+ <form id="advanceSearchForm">
12
+ <div class="form-group d-flex align-items-center">
13
+ <label for="searchFieldSelect" class="mr-2" style="width: 30%;">Search Fields:</label>
14
+ <select id="searchFieldSelect" class="form-control mr-2">
15
+ <% @search_fields.each do |value, title| %>
16
+ <option value="<%= value %>"><%= title %></option>
17
+ <% end %>
18
+ </select>
19
+ <button type="button" class="btn btn-secondary" id="addSearchField">Add</button>
20
+ </div>
21
+ <div id="search-fields-container">
22
+ </div>
23
+ </form>
24
+ </div>
25
+ <div class="modal-footer">
26
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
27
+ <button type="button" class="btn btn-primary" id="applyAdvanceSearch">Apply Search</button>
28
+ <button type="button" class="btn btn-danger" id="clearAdvanceSearch">Clear Search</button>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <template id="search-field-template">
35
+ <div class="form-group row align-items-center search-field">
36
+ <label class="col-sm-4 col-form-label search-field-label"></label>
37
+ <div class="col-sm-3">
38
+ <select class="form-control search-field-filter">
39
+ <option value="eq">Equals</option>
40
+ <option value="neq">Not Equals</option>
41
+ <option value="gt">Greater Than</option>
42
+ <option value="gte">Greater Than Or Equal</option>
43
+ <option value="lt">Less Than</option>
44
+ <option value="lte">Less Than Or Equal</option>
45
+ <option value="like">Like</option>
46
+ </select>
47
+ </div>
48
+ <div class="col-sm-4">
49
+ <input type="text" class="form-control search-field-value">
50
+ </div>
51
+ <div class="col-sm-1">
52
+ <i class="glyphicon glyphicon-remove" id=remove-search-field></i>
53
+ </div>
54
+ </div>
55
+ </template>
56
+
57
+ <style>
58
+ .form-group.row.align-items-center {
59
+ display: flex;
60
+ align-items: center;
61
+ }
62
+
63
+ .form-group.row.align-items-center label {
64
+ margin-bottom: 0; /* Remove default margin */
65
+ }
66
+
67
+ .form-group.row.align-items-center .form-control {
68
+ margin-right: 10px; /* Add some space between elements */
69
+ }
70
+
71
+ .form-group.d-flex {
72
+ display: flex;
73
+ align-items: center;
74
+ }
75
+
76
+ .form-group.d-flex label {
77
+ margin-bottom: 0; /* Remove default margin */
78
+ }
79
+
80
+ .form-group.d-flex .form-control {
81
+ margin-right: 10px; /* Add some space between the select box and the button */
82
+ }
83
+
84
+ #search-labels-container .label {
85
+ margin-left: 5px; /* Add space between labels */
86
+ margin-bottom: 5px; /* Add space below labels if they wrap to the next line */
87
+ color: white;
88
+ }
89
+
90
+ .filter-bar-container {
91
+ display: flex;
92
+ justify-content: flex-start; /* Align items to the left */
93
+ align-items: center; /* Center items vertically */
94
+ }
95
+
96
+ .filter-bar {
97
+ display: flex;
98
+ align-items: center; /* Center items vertically */
99
+ }
100
+
101
+ .filter-bar label {
102
+ margin: 10px; /* Add some space between the label and the select box */
103
+ }
104
+ </style>
105
+
106
+ <%= javascript_tag do %>
107
+ $(document).ready(function() {
108
+ populateSearchLabelsFromUrl();
109
+ var dateFields = ['Created date', 'Updated date', 'Reference time'];
110
+ // Handle the "Add" button click to add new search fields
111
+ $('#addSearchField').on('click', function() {
112
+ var selectedField = $('#searchFieldSelect option:selected').text();
113
+ var template = document.getElementById('search-field-template').content.cloneNode(true);
114
+
115
+ // Set the label and input names based on the selected field
116
+ template.querySelector('.search-field-label').textContent = selectedField.replace(/([A-Z])/g, ' $1').trim();
117
+ template.querySelector('.search-field-filter').name = selectedField + 'Filter';
118
+
119
+ // Check if the field should use a date input
120
+ if (dateFields.includes(selectedField)) {
121
+ template.querySelector('.search-field-value').type = 'date';
122
+ } else {
123
+ template.querySelector('.search-field-value').type = 'text';
124
+ }
125
+ template.querySelector('.search-field-value').name = selectedField;
126
+
127
+ // Append the new search field to the container
128
+ document.getElementById('search-fields-container').appendChild(template);
129
+ });
130
+
131
+ // Handle the "Apply Search" button click inside the modal
132
+ $('#applyAdvanceSearch').on('click', function() {
133
+ var searchFields = $('.search-field');
134
+ var searchLabelsContainer = $('#search-labels-container');
135
+ searchLabelsContainer.empty();
136
+
137
+ var table = $('#accounts-table').DataTable();
138
+ table.on('preXhr.dt', function(e, settings, data) {
139
+ data.search.value = searchQuery;
140
+ });
141
+
142
+ table.ajax.url("<%= accounts_pagination_path(:ordering => @ordering, :format => :json) %>").load();
143
+
144
+ // Update the URL with the search parameters
145
+ var searchParams = searchQuery('');
146
+ if (searchParams) {
147
+ var newUrl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + searchParams;
148
+ window.history.pushState({ path: newUrl }, '', newUrl);
149
+ }
150
+
151
+ searchFields.each(function() {
152
+ var filter = $(this).find('.search-field-filter option:selected').text();
153
+ var value = $(this).find('.search-field-value').val();
154
+ var columnName = $(this).find('.search-field-filter').attr('name').replace('Filter', '');
155
+
156
+ // Create and append the search label
157
+ if (value !== '') {
158
+ var label = $('<span>', {
159
+ class: 'label label-info',
160
+ text: columnName + ' [' + filter + '] ' + value
161
+ });
162
+ }
163
+ searchLabelsContainer.append(label);
164
+ });
165
+
166
+ $('#advanceSearchModal').modal('hide');
167
+ });
168
+
169
+ // Populate the modal with the current filters when it is shown
170
+ $('#advanceSearchModal').on('show.bs.modal', function() {
171
+ showAdvanceSearchModal();
172
+ $('#search-fields-container .search-field').each(function() {
173
+ var input = $(this).find('.search-field-value');
174
+ if (dateFields.includes(input.attr('name'))) {
175
+ input.attr('type', 'date');
176
+ }
177
+ });
178
+ });
179
+
180
+ $('#clearAdvanceSearch').on('click', function() {
181
+ clearAdvanceSearch();
182
+ });
183
+
184
+ // Handle the remove icon click event to remove search fields
185
+ $('#search-fields-container').on('click', '#remove-search-field', function() {
186
+ $(this).closest('.search-field').remove();
187
+ });
188
+ });
189
+ <% end %>