hot-glue 0.7.9 → 0.8

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: 76c922f98d4c719eebde65cdc53c37d2c8be4c77ef56790bc749332f3d65eefc
4
- data.tar.gz: 32b2ae025eae1edd8f75a702c00efb9cad09797c72f9af56343c881d0850d9b9
3
+ metadata.gz: 555bc8c92663c9e6797856debce6569ef5532f1d8f0536d862f1226b08b3e297
4
+ data.tar.gz: 2cc566882dc10083d857ebf8e254a126cf2842cde280509ff56ce37a86c4766e
5
5
  SHA512:
6
- metadata.gz: 4cb18544f2114c1633fd2c00ccfe8beecaed890a0e6fdfec5cd0bf6ebb536ef9a80d8cf586b4d5bf9baf6097afc8149380d77f85df04465b01872239f09033b7
7
- data.tar.gz: 180a70ce42a44d9bf0f6919e689762dad6589530746e51e98d6b18fe8568d3c52f699859e715b2a3045c9240813ad6537a39a0f2416f8d7e8739da3e2e2d606e
6
+ metadata.gz: 9592d760df6d8b79e41fdd71bb8e8a89f62745056c512b56cf1d31bed0174e9169146531febdec68dfb7ca2017e26e048f52055718ab04279e444c2742016482
7
+ data.tar.gz: c4e5ab6b7289ba6ac225eb4f40267bd2bb5b0163b1dc029ba43b55161552255ae4e541028a89aa4b988f6a83ea8123da7102216d4afe52a226dead4ca0e71c98
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.7.8)
4
+ hot-glue (0.7.9)
5
5
  ffaker (~> 2.16)
6
6
  rails (> 5.1)
7
7
 
@@ -134,7 +134,7 @@ GEM
134
134
  net-protocol
135
135
  net-pop (0.1.2)
136
136
  net-protocol
137
- net-protocol (0.2.2)
137
+ net-protocol (0.3.0)
138
138
  timeout
139
139
  net-smtp (0.5.1)
140
140
  net-protocol
data/README.md CHANGED
@@ -1096,8 +1096,6 @@ The effect will be that the fields will be stacked together into nicely fit colu
1096
1096
 
1097
1097
  **If your customer is used to Excel, this feature will confuse them.**
1098
1098
 
1099
- Also, this feature will **probably not** be supported by the SORTING (not yet implemented). (You will be forced to choose between the two which I think makes sense.)
1100
-
1101
1099
  The layout builder works from right-to-left and starts with 12, the number of Bootstrap's columns.
1102
1100
 
1103
1101
  It reserves 2 columns for the default buttons. Then +1 additional column for **each magic button** you have specified.
@@ -2000,6 +1998,17 @@ _Notice that Stimulus requires object registration when used in a Node environme
2000
1998
  Instead, use the generator and the registry will be updated for you automatically.
2001
1999
 
2002
2000
 
2001
+ ## Sorting
2002
+
2003
+ #### `--sortable` (true of flagged; false otherwise; does not take an argument)
2004
+ To add sorting to your columns add `--sortable` to your build
2005
+ sortable fields are integers, floats, string, text, datetime, time, dates excluding anything that is a foreign key, not UUIDs
2006
+
2007
+ #### `--sort-fields=`
2008
+ List of field names (separated by commas)
2009
+ Leave off (do not specify) to sort by all sort-eligible fields
2010
+
2011
+
2003
2012
  ## Attachments
2004
2013
 
2005
2014
  #### `--attachments=` Long form syntax with 1st and 2nd parameters
@@ -2489,6 +2498,15 @@ These automatic pickups for partials are detected at build time. This means that
2489
2498
 
2490
2499
  # VERSION HISTORY
2491
2500
 
2501
+ #### 2026-08-30 - v0.8
2502
+ - `--sortable` (true of flagged; false otherwise; does not take an argument)
2503
+ To add sorting to your columns add `--sortable` to your build
2504
+ sortable fields are integers, floats, string, text, datetime, time, dates excluding anything that is a foreign key, not UUIDs
2505
+ - `--sort-fields=`
2506
+ List of field names (separated by commas)
2507
+ Leave off (do not specify) to sort by all sort-eligible fields
2508
+
2509
+
2492
2510
  #### 2026-08-29 - v0.7.9
2493
2511
  -  Render float fields as type="number" step="any" for HTML5 validation; float fields should not be correctly validated on input
2494
2512
 
@@ -2523,12 +2541,13 @@ for example, if we have a `thing` that can belong (via parent_id and parent_type
2523
2541
 
2524
2542
  Hot glue wil convert the spaces to commas when writing the controller code.
2525
2543
 
2526
- A child controller to with a polymorphic parent:
2527
- - This special case assume that that the parent being build is not actually a polymoprh, it is a real object, but its children have foreign keys to it which are polymorphic.
2544
+ A child controller with a polymorphic parent:
2545
+
2546
+ - This special case assumes that that the parent being build is not actually a polymoprh, it is a real object, but its children have foreign keys to it which are polymorphic.
2528
2547
 
2529
- `--nested=abc(parent) `
2548
+ `--nested=abc(parent)`
2530
2549
 
2531
- Example: In my data model, targets have a polymorphic parent (parent_id and parent_type) and can belong to either Companies or Schools. Here, we are building the Companies view with a child to Targets, but notice for these targets we are using polymorphism and also using a controller prefix, so tha this child controller will be built as CompanyTargets. In the companies build, we downnest `company_targets(targets)` (`company_targets` is the name of the child controller, but it is acting on an object called `targets`, as seen in the downnest specification.)
2550
+ Example: In my data model, targets have a polymorphic parent (parent_id and parent_type) and can belong to either Companies or Schools. Here, we are building the Companies view with a child to Targets, but notice for these targets we are using polymorphism and also using a controller prefix, so that this child controller will be built as CompanyTargets. In the companies build, we downnest `company_targets(targets)` (`company_targets` is the name of the child controller, but it is acting on an object called `targets`, as seen in the downnest specification.)
2532
2551
 
2533
2552
  ```
2534
2553
  bin/rails generate hot_glue:scaffold Company --namespace='account_dashboard' --nested='account' --downnest='company_targets(targets)'
@@ -10,4 +10,36 @@ module HotGlueHelper
10
10
  def enum_to_collection_select(hash)
11
11
  hash.collect{|k,v| KVObject.new(key: k, value: v)}
12
12
  end
13
+
14
+ def sort_link(field, label)
15
+ field = field.to_s
16
+ active = params[:sort] == field
17
+ direction = active ? params[:direction] : nil
18
+
19
+ next_direction =
20
+ if !active
21
+ 'asc'
22
+ elsif direction == 'asc'
23
+ 'desc'
24
+ else
25
+ nil
26
+ end
27
+
28
+ new_params = request.query_parameters.except('sort', 'direction', 'page')
29
+ if next_direction
30
+ new_params['sort'] = field
31
+ new_params['direction'] = next_direction
32
+ end
33
+
34
+ arrow =
35
+ if active && direction == 'asc'
36
+ ' ▲'
37
+ elsif active && direction == 'desc'
38
+ ' ▼'
39
+ else
40
+ ''
41
+ end
42
+
43
+ link_to (label + arrow).html_safe, "#{request.path}?#{new_params.to_query}".chomp('?'), style: 'white-space: nowrap', 'data-turbo-action': 'advance'
44
+ end
13
45
  end
@@ -33,6 +33,10 @@ class AssociationField < Field
33
33
 
34
34
  end
35
35
 
36
+ def sortable?
37
+ false
38
+ end
39
+
36
40
  def assoc_name
37
41
  assoc
38
42
  end
@@ -52,6 +52,10 @@ class Field
52
52
  @name
53
53
  end
54
54
 
55
+ def sortable?
56
+ true
57
+ end
58
+
55
59
  def form_field_output
56
60
  raise "superclass must implement"
57
61
  end
@@ -13,7 +13,7 @@ module HotGlue
13
13
  :form_path, :layout_object, :search_clear_button, :search_autosearch,
14
14
  :stimmify, :stimmify_camel, :hidden_create, :hidden_update, :invisible_create,
15
15
  :invisible_update, :plural, :phantom_search, :pagination_style,
16
- :namespace, :controller_build_folder
16
+ :namespace, :controller_build_folder, :sortable, :sortable_fields
17
17
 
18
18
 
19
19
  def initialize(singular:, singular_class: ,
@@ -27,9 +27,12 @@ module HotGlue
27
27
  search_clear_button:, search_autosearch:, layout_object:,
28
28
  form_path: , stimmify: , stimmify_camel:, hidden_create:, hidden_update: ,
29
29
  invisible_create:, invisible_update: , plural: , phantom_search:,
30
- pagination_style:, namespace: nil, controller_build_folder: nil )
30
+ pagination_style:, namespace: nil, controller_build_folder: nil,
31
+ sortable: false, sortable_fields: [] )
31
32
 
32
33
 
34
+ @sortable = sortable
35
+ @sortable_fields = sortable_fields
33
36
  @form_path = form_path
34
37
  @search = search
35
38
  @search_fields = search_fields
@@ -106,7 +109,11 @@ module HotGlue
106
109
  "<div class='#{layout_strategy.column_classes_for_column_headings(size)} hg-heading-row heading--#{singular}--#{column.join("-")}' " + col_style + ">" +
107
110
  column.map(&:to_s).map{|col_name|
108
111
  unless col_name.starts_with?("**")
109
- the_output = "#{col_name.humanize}"
112
+ if @sortable && @sortable_fields.collect(&:to_s).include?(col_name)
113
+ the_output = "<%= sort_link(:#{col_name}, '#{col_name.humanize}') %>"
114
+ else
115
+ the_output = "#{col_name.humanize}"
116
+ end
110
117
  else
111
118
  the_output = ""
112
119
  end
@@ -34,7 +34,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
34
34
  :search_clear_button, :search_autosearch, :include_object_names,
35
35
  :stimmify, :stimmify_camel, :hidden_create, :hidden_update,
36
36
  :invisible_create, :invisible_update, :phantom_create_params,
37
- :phantom_update_params, :lazy, :back_link_to_parent, :polymorphic_parents
37
+ :phantom_update_params, :lazy, :back_link_to_parent, :polymorphic_parents,
38
+ :sortable, :sortable_fields
38
39
 
39
40
  # important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
40
41
  # so we use namespace_value instead
@@ -144,6 +145,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
144
145
 
145
146
  class_option :phantom_search, default: nil
146
147
 
148
+ # SORT OPTIONS
149
+ class_option :sortable, type: :boolean, default: false
150
+ class_option :sort_fields, default: nil # comma separated whitelist; defaults to all sortable-type fields
151
+
147
152
 
148
153
 
149
154
  def initialize(*meta_args)
@@ -752,6 +757,27 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
752
757
  @columns_map[col] = this_column_object.field
753
758
  end
754
759
 
760
+ @sortable = options['sortable']
761
+
762
+ if @sortable
763
+ if options['sort_fields']
764
+ @sortable_fields = options['sort_fields'].split(',').collect(&:to_sym)
765
+ @sortable_fields.each do |field|
766
+ if !@columns_map[field]
767
+ raise "You specified a sort field for #{field} but that field is not in the list of columns"
768
+ elsif !@columns_map[field].sortable?
769
+ raise "You specified a sort field for #{field} but that field type cannot be sorted (e.g. an association or a UUID)"
770
+ end
771
+ end
772
+ else
773
+ @sortable_fields = @columns_map.select { |col, field| field.sortable? }.keys
774
+ end
775
+
776
+ warn_about_unindexed_sortable_fields
777
+ else
778
+ @sortable_fields = []
779
+ end
780
+
755
781
 
756
782
  @columns_map.each do |key, field|
757
783
  if field.is_a?(AssociationField)
@@ -928,7 +954,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
928
954
  phantom_search: @phantom_search,
929
955
  pagination_style: @pagination_style,
930
956
  namespace: @namespace,
931
- controller_build_folder: @controller_build_folder
957
+ controller_build_folder: @controller_build_folder,
958
+ sortable: @sortable,
959
+ sortable_fields: @sortable_fields
932
960
  )
933
961
  elsif @markup == "slim"
934
962
  raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
@@ -1997,6 +2025,17 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1997
2025
  end
1998
2026
 
1999
2027
 
2028
+ def warn_about_unindexed_sortable_fields
2029
+ indexed_columns = @the_object.connection.indexes(@the_object.table_name).collect { |index| index.columns.first }
2030
+ unindexed = @sortable_fields.reject { |field| indexed_columns.include?(field.to_s) }
2031
+ return if unindexed.empty?
2032
+
2033
+ puts "********************"
2034
+ puts "WARNING: The following fields are sortable but have no database index, which may cause slow queries as the table grows: #{unindexed.join(', ')}"
2035
+ puts "Consider adding indexes, e.g.: " + unindexed.collect { |field| "add_index :#{plural}, :#{field}" }.join("; ")
2036
+ puts "********************"
2037
+ end
2038
+
2000
2039
  def load_all_code
2001
2040
  # the inner method definition of the load_all_* method
2002
2041
  res = +""
@@ -2068,6 +2107,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
2068
2107
  res << "\n"
2069
2108
  end
2070
2109
 
2110
+ if @sortable
2111
+ res << "\n"
2112
+ res << " if SORTABLE_FIELDS.include?(params[:sort]) && %w[asc desc].include?(params[:direction])\n"
2113
+ res << " @#{plural} = @#{plural}.order(params[:sort] => params[:direction].to_sym)\n"
2114
+ res << " end"
2115
+ end
2071
2116
 
2072
2117
  if @pagination_style == "kaminari"
2073
2118
  res << " @#{plural} = @#{plural}.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
@@ -77,6 +77,8 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
77
77
  params[:per] || 10
78
78
  end<% end %>
79
79
  <% unless @no_list %>
80
+ <% if @sortable %> SORTABLE_FIELDS = %w[<%= @sortable_fields.join(' ') %>].freeze
81
+ <% end %>
80
82
  def load_all_<%= plural %><% if @search == "set" %>
81
83
  @q = params[:q] || <%= search_default %> <% end %>
82
84
  <%= load_all_code %>
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.7.9'
3
+ CURRENT = '0.8'
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.7.9
4
+ version: '0.8'
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: 2026-08-29 00:00:00.000000000 Z
11
+ date: 2026-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails