hot-glue 0.6.25 → 0.6.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 484a64a521f4d21dbb5b437ce26950d218e5a7ea5917261eb0fbb59119bc19d5
4
- data.tar.gz: 8d4570fcf5fc850c1bee98868fa19bd2805f794fa6a94425876c2bc9d4bc94af
3
+ metadata.gz: 077bb2e61017931d3db8f961922f3af0d4440bfd9900cc56f86bfa26aeb2e188
4
+ data.tar.gz: 3feecb2d560274cab61e7cb5f673175cf426fd6d7cef09112612e72f88e74038
5
5
  SHA512:
6
- metadata.gz: 49bc8ddab30ed9cb637dbbe9da496fd47836239c9f260a61b03b81ef23ef3dab864aba2c84a634dad6004720cb6a9697afed9cbbdcb2ff3de76324bc42ab760e
7
- data.tar.gz: 3145730b0c6510dcf6d813ff59acca04b867c248fb4f8107cae496c6a9405cf29260c6a8bde3e644aadf4e9853275fc55ba741409ef30014ac48fdd6fc12c2ef
6
+ metadata.gz: e2add6dcc569806f8953976332a63f29ea4cfa309ced3b8fdeb97b5c9108d030711d01a39fde8029bbfcacdde8fd7b0229861647258a40e340d1deeacfed13f8
7
+ data.tar.gz: 0c36945b6007e22bd672822bd206f842a1cd7eea54e819652fce71d613c66d8791b3902c51cb7c177f1c743a6e7a7241679b19e274e34e12bafe1dd06acbc187
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.6.25)
4
+ hot-glue (0.6.26)
5
5
  ffaker (~> 2.16)
6
6
  kaminari (~> 1.2)
7
7
  rails (> 5.1)
data/README.md CHANGED
@@ -1620,20 +1620,20 @@ bin/rails generate hot_glue:set_search_interface_install
1620
1620
  ```
1621
1621
 
1622
1622
  _Additional search option for Set Search_
1623
- ##### `--search-fields=aaa,bbb,ccc,ddd,eee`
1623
+ ### `--search-fields=aaa,bbb,ccc,ddd,eee`
1624
1624
  to specify which fields you want to be searchable.
1625
1625
 
1626
1626
 
1627
- ##### `--search-query-fields=aaa,ddd`
1627
+ ### `--search-query-fields=aaa,ddd`
1628
1628
  to specify a list of strings only which will be taken out of the search set and presented in a singular query box (allowing search across multiple string fields)
1629
1629
 
1630
- ##### `--search-position=vertical`
1630
+ ### `--search-position=vertical`
1631
1631
  to specify vertical or horizontal (default: horizontal)
1632
1632
 
1633
- ##### `--search-clear-button` (no option)
1633
+ ### `--search-clear-button` (no option)
1634
1634
  to specify whether to show a clear button to clear the whole search form at once (default: false)
1635
1635
 
1636
- ##### `--search-autosearch` (no option)
1636
+ ### `--search-autosearch` (no option)
1637
1637
  to specify whether to automatically search when the user exit or changes any field (default: false)
1638
1638
 
1639
1639
  examples:
@@ -1657,12 +1657,56 @@ Here's how you would add a search interface to Example #1 in the [Hot Glue Tutor
1657
1657
  bin/rails generate Book --include=name,author_id --search=set --search-fields=name,author_id
1658
1658
  ```
1659
1659
 
1660
+ ### `--phantom-search='{type}_{name}[All|choice A:scope_a|choice B:scope_b]`
1661
+
1662
+ A phantom search is a search we are doing on this result set that doesn't correspond to a single field. Currently, the only available implementation is for scopes with no arguments, as in the example below. It is called 'phantom' because it could be (probably is) querying fields within the scope, but the search doesn't match up with a single field on your model. (So it's like creating 'phantom' criteria.). Only RADIO type is implemented, dropdown & checkboxes an a way to input a search value passed into the scope as an argument is TBD.
1663
+
1664
+ {type} is any of: radio, dropdown, checkboxes
1665
+
1666
+ {name} is a designation for this phantom search. Should NOT match any field name on your table. This should describe the kind of categorization we are performing.
1667
+
1668
+ Your phantom search selector will be appended to the search fields and will be treated like a first-class search input, able to be combined with any of the other fields specified in a set search.
1669
+
1670
+ Note that multiple phantom searched can be specified by separating them by comma (`,`), like so:
1671
+
1672
+ `--phantom-search='radio_xxxx[All|choice A:scope_a|choice B:scope_b],radio_yyyy[All|choice W:scope_w|choice Z:scope_z|]`
1673
+ (this creates two phantom searches: `xxxx` and `yyyy` both radio selection lists)
1674
+
1675
+ After the type & name, comes a block marked by square braces [ ... ]
1676
+
1677
+ Within the square braces, each search option is separated by a pipe (|) character.
1678
+
1679
+ Within each option is a label and ruby scope, separated by a colon (:).
1680
+
1681
+ The label comes before the colon the ruby scope. The ruby scope should be specified here without a dot. Each ruby scope must be defined on your model. If there is no scope specified, we assume "all", but we still need to specify a label for "All", which is why in the example above "All" has no colon after it.
1682
+
1683
+ example
1684
+
1685
+ `--phantom-search='radio_status[Pending:pending|Rejected:rejected|Accepted:accepted|All]'`
1686
+
1687
+ On my model, I have these scopes defined:
1688
+
1689
+ scope :pending_review, -> { not_approved.not_rejected }
1690
+ scope :approved, -> { where.not(approved_at: nil) }
1691
+ scope :rejected, -> { where.not(rejected_at: nil) }
1692
+ scope :not_rejected, -> { where(rejected_at: nil) }
1693
+ scope :not_approved, -> { where(approved_at: nil) }
1694
+
1695
+ This produces a search interface with four options listed as radio buttons:
1696
+ ° Pending
1697
+ ° Approved
1698
+ ° Rejected
1699
+ ° All
1700
+
1701
+ (Notice that my search options are called 'approved' and 'rejected' but the field names are slightly different: approved_at, rejected_at)
1702
+
1703
+ The pending, approved, and rejected options will return search results with the corresponding scopes applied. The 'All' option will behave as a no-op, leaving the root search intact (giving all of the other modifications that Hot glue provides in different functionality).
1704
+
1660
1705
  #### Predicate Search
1661
1706
  NOT IMPLEMENTED YET
1662
1707
  TODO: implement me
1663
1708
 
1664
1709
 
1665
-
1666
1710
  ### `--stimmify` or `--stimmify=xyz`
1667
1711
 
1668
1712
  Automatically build the new and edit form with `data-controller='xyz'` to attach stimulus
@@ -2166,6 +2210,25 @@ These automatic pickups for partials are detected at build time. This means that
2166
2210
 
2167
2211
 
2168
2212
  # VERSION HISTORY
2213
+ #### 2025-09-16 - v0.6.26
2214
+ • Phantom Searching
2215
+ `--phantom-search='{type}_{name}[All|choice A:scope_a|choice B:scope_b],radio_yyyy[choice C:scope_c|]`
2216
+
2217
+ A phantom search is a search we are doing on this result set that doesn't correspond to a single field. Currently, the only available implementation is for scopes with no arguments, as in the example below. It is called 'phantom' because it could be (probably is) querying fields within the scope, but the search doesn't match up with a single field on your model. (So it's like creating 'phantom' criteria.). Only RADIO type is implemented, dropdown & checkboxes an a way to input a search value passed into the scope as an argument is TBD.
2218
+
2219
+ {type} is any of: radio, dropdown, checkboxes
2220
+
2221
+ {name} is a designation for this phantom search. Should NOT match any field name on your table. This should describe the kind of categorization we are performing.
2222
+ see `--phantom-search` above for details.
2223
+
2224
+ • Fixing duplicitous creation of Stimulus JS files when installing the search features
2225
+
2226
+
2227
+ #### 2025-08-31 - v0.6.25
2228
+ - very small fix to typeahead controller supporting typeaheads and nested routes
2229
+ - updates documentation for typeaheads
2230
+
2231
+
2169
2232
  #### 2025-08-22 - v0.6.24
2170
2233
  `--related-sets` fixes issue with related sets due to ruby syntax
2171
2234
 
@@ -12,7 +12,7 @@ module HotGlue
12
12
  :search, :search_fields, :search_query_fields, :search_position,
13
13
  :form_path, :layout_object, :search_clear_button, :search_autosearch,
14
14
  :stimmify, :stimmify_camel, :hidden_create, :hidden_update, :invisible_create,
15
- :invisible_update, :plural
15
+ :invisible_update, :plural, :phantom_search
16
16
 
17
17
 
18
18
  def initialize(singular:, singular_class: ,
@@ -25,7 +25,7 @@ module HotGlue
25
25
  search:, search_fields:, search_query_fields: , search_position:,
26
26
  search_clear_button:, search_autosearch:, layout_object:,
27
27
  form_path: , stimmify: , stimmify_camel:, hidden_create:, hidden_update: ,
28
- invisible_create:, invisible_update: , plural: )
28
+ invisible_create:, invisible_update: , plural: , phantom_search:)
29
29
 
30
30
 
31
31
  @form_path = form_path
@@ -65,6 +65,7 @@ module HotGlue
65
65
  @update_show_only = update_show_only
66
66
  @attachments = attachments
67
67
  @related_sets = related_sets
68
+ @phantom_search = phantom_search
68
69
  end
69
70
 
70
71
  def add_spaces_each_line(text, num_spaces)
@@ -130,18 +131,43 @@ module HotGlue
130
131
  search_field_result = columns_map[col].search_field_output
131
132
 
132
133
  add_spaces_each_line( "\n <span class='' >\n" +
133
- add_spaces_each_line( (form_labels_position == 'before' ? the_label || "" : "") +
134
- + " <br />\n" + search_field_result +
135
- (form_labels_position == 'after' ? the_label : "") , 4) +
134
+ add_spaces_each_line( (form_labels_position == 'before' ? the_label || "" : "") +
135
+ + " <br />\n" + search_field_result +
136
+ (form_labels_position == 'after' ? the_label : "") , 4) +
136
137
  "\n </span>\n <br />", 2)
137
138
  end
138
139
  }.compact.join("\n")
139
140
 
141
+
142
+
140
143
  size = layout_object[:columns][:bootstrap_column_width][columns.index(column)]
141
144
  " <div class='#{layout_strategy.column_classes_for_form_fields(size)} search-cell--#{singular}--#{column.join("-")}' >" +
142
145
  cols_result + "</div>"
143
146
 
144
147
  }.join("\n")
148
+
149
+ # phantom searches
150
+ @phantom_search.each_key do |search_field|
151
+ data = @phantom_search[search_field]
152
+ if data[:type] == "radio"
153
+ res << "<div>"
154
+
155
+ res << "<label>#{data[:name]}</label><br />"
156
+
157
+ data[:choices].each do |choice|
158
+ res << "\n<input type='radio'
159
+ id='#{search_field}_search__#{choice[:label]}'
160
+ name='q[0][#{search_field}_search]' value='#{choice[:label]}'
161
+ <%= 'checked' if @q['0'][:#{search_field}_search] == \"#{choice[:label]}\" %> />"
162
+ res << "\n<label for='#{search_field}_search__#{choice[:label]}'>#{choice[:label]}</label> <br/>"
163
+ end
164
+
165
+ res << "</div>"
166
+
167
+ end
168
+ end
169
+
170
+
145
171
  res << "</div>"
146
172
  res << "<div class='#{layout_strategy.column_classes_for_form_fields(nil)}'>"
147
173
  if @search_clear_button
@@ -134,6 +134,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
134
134
  # TDB
135
135
 
136
136
 
137
+ class_option :phantom_search, default: nil
138
+
139
+
140
+
137
141
  def initialize(*meta_args)
138
142
  super
139
143
 
@@ -449,6 +453,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
449
453
  end
450
454
 
451
455
 
456
+
457
+
452
458
  @include_object_names = options['include_object_names'] || get_default_from_config(key: :include_object_names)
453
459
 
454
460
 
@@ -699,11 +705,56 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
699
705
  end
700
706
  end
701
707
 
708
+
709
+ if options['phantom_search']
710
+ ps_input = options['phantom_search']
711
+
712
+ ps_input =~ /(.*)\[(.*)\]/
713
+ type_and_label, settings = $1, $2
714
+
715
+
716
+ type = type_and_label.split("_")[0]
717
+ label = type_and_label.split("_")[1]
718
+
719
+ @phantom_search = {}
720
+ choices = settings.split("|")
721
+
722
+
723
+ @phantom_search[label.to_sym] = {
724
+ type: type,
725
+ name: label.humanize,
726
+ choices: []
727
+ }
728
+
729
+ choices.each do |choice|
730
+ choice_label = choice.split(":")[0]
731
+ choice_scope = choice.split(":")[1]
732
+ if choice_scope.nil?
733
+ choice_scope = "all"
734
+ end
735
+
736
+ choice_scope = ".#{choice_scope}" if !choice_scope.start_with?(".")
737
+ @phantom_search[label.to_sym][:choices] << {
738
+ label: choice_label,
739
+ scope: choice_scope,
740
+ }
741
+ end
742
+ puts "phantom search #{@phantom_search}"
743
+ else
744
+ @phantom_search = {}
745
+ end
746
+
702
747
  # search
703
748
  @search = options['search']
749
+
704
750
  if @search == 'set'
705
751
  if options['search_fields'].nil?
706
- @search_fields = @columns
752
+ if !@phantom_search
753
+ puts "Since you did not specify search fields or phantom search fields I am including all columns in search"
754
+ @search_fields = @columns
755
+ else
756
+ @search_fields = []
757
+ end
707
758
  else
708
759
  @search_fields = options['search_fields'].split(',')
709
760
  end
@@ -715,12 +766,6 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
715
766
 
716
767
  @search_fields = @search_fields - @search_query_fields
717
768
 
718
- @search_fields.each do |field|
719
- if !@columns.include?(field.to_sym)
720
- raise "You specified a search field for #{field} but that field is not in the list of columns"
721
- end
722
- end
723
-
724
769
  @search_clear_button = !!options['search_clear_button']
725
770
  @search_autosearch = !!options['search_autosearch']
726
771
 
@@ -728,22 +773,24 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
728
773
 
729
774
  end
730
775
 
776
+ if @search_fields
777
+ @search_fields.each do |field|
778
+ if !@columns.include?(field.to_sym) && !@phantom_search.include?(field.to_sym)
779
+ raise "You specified a search field for #{field} but that field is not in the list of columns"
780
+ end
781
+ end
782
+ end
783
+
731
784
  builder = HotGlue::Layout::Builder.new(generator: self,
732
785
  include_setting: options['include'],
733
786
  buttons_width: buttons_width)
734
787
 
735
788
  @layout_object = builder.construct
736
789
 
737
-
738
-
739
790
  # syntax should be xyz_id{xyz_email},abc_id{abc_email}
740
791
  # instead of a drop-down for the foreign entity, a text field will be presented
741
792
  # You must ALSO use a factory that contains a parameter of the same name as the 'value' (for example, `xyz_email`)
742
793
 
743
-
744
-
745
-
746
-
747
794
  # create the template object
748
795
 
749
796
 
@@ -780,6 +827,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
780
827
  hidden_update: @hidden_update,
781
828
  invisible_create: @invisible_create,
782
829
  invisible_update: @invisible_update,
830
+ phantom_search: @phantom_search
783
831
  )
784
832
  elsif @markup == "slim"
785
833
  raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
@@ -1741,12 +1789,11 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1741
1789
  if !@columns_map[field.to_sym].load_all_query_statement.empty?
1742
1790
  @columns_map[field.to_sym].load_all_query_statement
1743
1791
  end
1744
- }.compact.join("\n" + spaces(4))
1745
- res << "\n"
1792
+ }.compact.join("\n" + spaces(4)) + "\n"
1746
1793
  end
1747
1794
 
1748
1795
  if pundit
1749
- res << " @#{ plural_name } = policy_scope(#{ object_scope })#{record_scope}.page(params[:page])#{ n_plus_one_includes }#{ ".per(per)" if @paginate_per_page_selector }"
1796
+ res << " @#{ plural_name } = policy_scope(#{ object_scope })#{record_scope}\n"
1750
1797
  else
1751
1798
  if !@self_auth
1752
1799
 
@@ -1760,22 +1807,38 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1760
1807
  end
1761
1808
  }.compact.join
1762
1809
  end
1763
- res << ".page(params[:page])#{ '.per(per)' if @paginate_per_page_selector }"
1810
+
1811
+
1812
+
1813
+ # res << "\n @#{plural} = @#{plural}.page(params[:page])#{ '.per(per)' if @paginate_per_page_selector }"
1764
1814
 
1765
1815
  elsif @nested_set[0] && @nested_set[0][:optional]
1766
1816
  res << "@#{ plural_name } = #{ class_name }.#{record_scope}.all"
1767
1817
  else
1768
1818
  res << "@#{ plural_name } = #{ class_name }.#{record_scope}.where(id: #{ auth_object.gsub("@",'') }.id)#{ n_plus_one_includes }"
1769
1819
 
1770
- res << "#{record_scope}.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
1820
+ # res << "#{record_scope}"
1771
1821
  end
1822
+ res << "\n"
1823
+
1772
1824
  end
1773
- res << "\n"
1774
1825
  if @search_fields
1826
+ res << "\n"
1775
1827
  res << @search_fields.collect{ |field|
1776
1828
  spaces(4) + "@#{plural_name} = @#{plural_name}" + @columns_map[field.to_sym].where_query_statement + " if #{field}_query"
1777
- }.join("\n")
1829
+ }.join("\n") + "\n"
1830
+ end
1831
+
1832
+ @phantom_search.each do |phantom_key, phantom_data|
1833
+ phantom_data[:choices].each do |choice|
1834
+ unless choice[:scope] == ".all"
1835
+ res << "\n @#{plural} = @#{plural}#{choice[:scope]} if @q['0'][:#{phantom_key}_search] == \"#{choice[:label]}\""
1836
+ end
1837
+ end
1838
+ res << "\n"
1778
1839
  end
1840
+
1841
+ res << " @#{plural} = @#{plural}.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
1779
1842
  res
1780
1843
  end
1781
1844
 
@@ -1830,4 +1893,22 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1830
1893
  res
1831
1894
  }.join("\n")
1832
1895
  end
1896
+
1897
+
1898
+ def search_default
1899
+ default_fields = @search_fields.collect{ |foo|
1900
+ { "#{foo}_match".to_sym =>
1901
+ (@columns_map[foo.to_sym].modify_as && @columns_map[foo.to_sym].modify_as[:binary]) ? "-1" : "", "#{foo}_search".to_sym => ""
1902
+ }
1903
+ }.reduce({}, :merge)
1904
+
1905
+ phantom_search_fields = @phantom_search.collect{| k,v|
1906
+ default = v[:choices][0]
1907
+ {
1908
+ "#{k}_match".to_sym => "",
1909
+ "#{k}_search".to_sym => "#{default[:label]}"
1910
+ }
1911
+ }.reduce({}, :merge)
1912
+ return {"0" => (default_fields.merge(phantom_search_fields))}
1913
+ end
1833
1914
  end
@@ -12,10 +12,14 @@ module HotGlue
12
12
  def initialize(*args) #:nodoc:
13
13
  super
14
14
 
15
- ['date_range_picker','time_range_picker','search_form'].each do |file|
15
+ ['date_range_picker',
16
+ 'time_range_picker',
17
+ 'search_form'].each do |file|
18
+
19
+
16
20
  system("./bin/rails generate stimulus #{file.titlecase.gsub(" ", "")}")
17
- copy_file "javascript/#{file}_controller.js", "#{filepath_prefix}app/javascript/controllers/#{file}.js"
18
- puts "HOT GLUE --> copying #{file} stimulus controller into app/javascript/controllers/#{file}.js"
21
+ copy_file "javascript/#{file}_controller.js", "#{filepath_prefix}app/javascript/controllers/#{file}_controller.js"
22
+ puts "HOT GLUE --> copying #{file} stimulus controller into app/javascript/controllers/#{file}_controller.js"
19
23
 
20
24
  end
21
25
  end
@@ -75,8 +75,8 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
75
75
  end<% end %>
76
76
  <% unless @no_list %>
77
77
  def load_all_<%= plural %><% if @search == "set" %>
78
- @q = params[:q] || <%= {"0" => @search_fields.collect{|foo| {"#{foo}_match".to_sym => ((@columns_map[foo.to_sym].modify_as && @columns_map[foo.to_sym].modify_as[:binary]) ? "-1" : ""), "#{foo}_search".to_sym => ""}}.reduce({}, :merge) } %> <% end %>
79
- <%= load_all_code %>
78
+ @q = params[:q] || <%= search_default %> <% end %>
79
+ <%= load_all_code %>
80
80
  end
81
81
 
82
82
  def index
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.6.25'
3
+ CURRENT = '0.6.26.1'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot-glue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.25
4
+ version: 0.6.26.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Fleetwood-Boldt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-31 00:00:00.000000000 Z
11
+ date: 2025-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails