hot-glue 0.6.14 → 0.6.16
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/Gemfile.lock +3 -3
- data/README.md +57 -0
- data/app/helpers/hot_glue/controller_helper.rb +11 -1
- data/lib/generators/hot_glue/field_factory.rb +3 -2
- data/lib/generators/hot_glue/fields/association_field.rb +8 -0
- data/lib/generators/hot_glue/fields/enum_field.rb +1 -0
- data/lib/generators/hot_glue/fields/field.rb +5 -0
- data/lib/generators/hot_glue/layout/builder.rb +19 -7
- data/lib/generators/hot_glue/layout_strategy/bootstrap.rb +6 -6
- data/lib/generators/hot_glue/layout_strategy/hot_glue.rb +3 -3
- data/lib/generators/hot_glue/layout_strategy/tailwind.rb +3 -3
- data/lib/generators/hot_glue/markup_templates/erb.rb +21 -15
- data/lib/generators/hot_glue/scaffold_generator.rb +24 -9
- data/lib/generators/hot_glue/templates/controller.rb.erb +36 -18
- data/lib/generators/hot_glue/templates/erb/create.turbo_stream.erb +3 -3
- data/lib/generators/hot_glue/templates/erb/edit.erb +23 -13
- data/lib/hotglue/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09ebf223206d1bf224f02aaafe2796774bfa6b3d61c6892c1b0144ec2a8dd0f3'
|
4
|
+
data.tar.gz: 1fd04b5e1909ebcf2ecc9eeb5c4e212f7a6878d49c0fe918305e43e441cd73d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c01e39699fe999a7024850b9d738d5e205b4e5abe8c39d3619d10efa74fbed2384ac6cadfa4010d52c0a9fdea3878ae599aa23002cd439d323701f4b8524c3eb
|
7
|
+
data.tar.gz: 79c20e1f78772f79e396cecfc81990a70b3a0d17988962baebd6c2ea0b10eabedea59ebd8624f34d0ad7ce864d59bf7ad7be2afb8c712ef01f605ab06e272fce
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hot-glue (0.6.
|
4
|
+
hot-glue (0.6.15)
|
5
5
|
ffaker (~> 2.16)
|
6
6
|
kaminari (~> 1.2)
|
7
7
|
rails (> 5.1)
|
@@ -140,14 +140,14 @@ GEM
|
|
140
140
|
mini_mime (1.1.2)
|
141
141
|
mini_portile2 (2.8.4)
|
142
142
|
minitest (5.16.3)
|
143
|
-
net-imap (0.5.
|
143
|
+
net-imap (0.5.6)
|
144
144
|
date
|
145
145
|
net-protocol
|
146
146
|
net-pop (0.1.2)
|
147
147
|
net-protocol
|
148
148
|
net-protocol (0.2.2)
|
149
149
|
timeout
|
150
|
-
net-smtp (0.5.
|
150
|
+
net-smtp (0.5.1)
|
151
151
|
net-protocol
|
152
152
|
nio4r (2.5.8)
|
153
153
|
nokogiri (1.13.9)
|
data/README.md
CHANGED
@@ -790,6 +790,23 @@ end
|
|
790
790
|
Because Hot Glue detects the `*_able?` methods at build time, if you add them to your policy, you will have to rebuild your scaffold.
|
791
791
|
|
792
792
|
|
793
|
+
### `--pundit-policy-override`
|
794
|
+
if you use the flag `--pundit-policy-override` your controller operations will bypass the invisible (pundit provided) access control and use the pundit policy you specify.
|
795
|
+
|
796
|
+
example
|
797
|
+
|
798
|
+
`rails generate hot_glue:scaffold Invoice --gd --pundit-policy-override='UniqueInvoicePolicy'`
|
799
|
+
|
800
|
+
You will implement a Pundit policy for `UniqueInvoicePolicy` and it should implement actions with question mark `?` endings corresponding to the same actions you are building, `new?`, `create?`, `edit?`, `update?`, and `destroy?`
|
801
|
+
|
802
|
+
If provided, the output code looks something like (in this example, showing the `edit?` method)
|
803
|
+
|
804
|
+
```
|
805
|
+
skip_authorization
|
806
|
+
raise Pundit::NotAuthorizedError if ! UniqueInvoicePolicy.edit?
|
807
|
+
```
|
808
|
+
|
809
|
+
|
793
810
|
### `--show-only=`
|
794
811
|
(separate field names by COMMA)
|
795
812
|
|
@@ -1751,6 +1768,46 @@ These automatic pickups for partials are detected at build time. This means that
|
|
1751
1768
|
|
1752
1769
|
# VERSION HISTORY
|
1753
1770
|
|
1771
|
+
#### 2025-03-31 v0.6.16
|
1772
|
+
|
1773
|
+
• Bootstrap Tab Panes For Downnested Portals
|
1774
|
+
Downnested portals are now built with bootstrap tab panes (always) and are no longer stacked on top of one another.
|
1775
|
+
|
1776
|
+
It looks like this:
|
1777
|
+
https://getbootstrap.com/docs/5.0/components/navs-tabs/#javascript-behavior
|
1778
|
+
|
1779
|
+
• inline_list_labels can be set in hot_glue.yml
|
1780
|
+
• typeaheads nested inside of routes are fixed
|
1781
|
+
• switches back to current_timezone implementation, displaying times relative to the user's set timezone
|
1782
|
+
• load all code now sets query parameters
|
1783
|
+
|
1784
|
+
• Pundit Policy Override
|
1785
|
+
if you use the flag `--pundit-policy-override` your controller operations will bypass the invisible (pundit provided) access control and use the pundit policy you specify.
|
1786
|
+
|
1787
|
+
example
|
1788
|
+
|
1789
|
+
`rails generate hot_glue:scaffold Invoice --gd --pundit-policy-override='UniqueInvoicePolicy'`
|
1790
|
+
|
1791
|
+
Implement `UniqueInvoicePolicy` using actions with question mark `?` endings corresponding to the same actions you are building, `new?`, `create?`, `edit?`, `update?`, and `destroy?`
|
1792
|
+
|
1793
|
+
|
1794
|
+
• Bootstrap column builder has been changed.
|
1795
|
+
The bootstrap column bulder previously defaulted all real columns to col-sm-2 (or whichever bootstrap column with you set)
|
1796
|
+
|
1797
|
+
The builder has been refactored to allow for a per-column width generated automatically by the builder. If there are unused bootstrap columns, the builder will add width to the first columns in your layout, making them wider.
|
1798
|
+
|
1799
|
+
|
1800
|
+
|
1801
|
+
|
1802
|
+
|
1803
|
+
|
1804
|
+
#### 2025-03-17 - v0.6.15
|
1805
|
+
|
1806
|
+
• now store on your current_user model (this is automatically passed into the method modify_date_inputs_on_params). HG will set user-inputted values correctly to daylight savings time during April-Nov months only (#195)
|
1807
|
+
• fixes issue with turbo frame name after create is rendered (#194)
|
1808
|
+
• removes vestigates of optionalized partents
|
1809
|
+
|
1810
|
+
|
1754
1811
|
#### 2025-02-28 - v0.6.14
|
1755
1812
|
|
1756
1813
|
• fixes bug in association field involving scaffolds built without nesting
|
@@ -68,8 +68,16 @@ module HotGlue
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def is_dst_now?
|
72
|
+
Time.now.utc.month > 3 && Time.now.month < 11 ||
|
73
|
+
(Time.now.utc.month == 3 && Time.now.day >= (14 - Time.now.utc.wday)) ||
|
74
|
+
(Time.now.utc.month == 11 && Time.now.utc.day < (7 - Time.now.utc.wday))
|
75
|
+
end
|
76
|
+
|
71
77
|
def modify_date_inputs_on_params(modified_params, current_user_object = nil, field_list = nil)
|
72
78
|
use_timezone = (current_user_object.try(:timezone)) || Time.zone
|
79
|
+
uses_dst = (current_user_object.try(:locale_uses_dst)) || false
|
80
|
+
|
73
81
|
modified_params = modified_params.tap do |params|
|
74
82
|
params.keys.each{|k|
|
75
83
|
|
@@ -88,7 +96,9 @@ module HotGlue
|
|
88
96
|
# if they already exist in your database, you should zero them out
|
89
97
|
# or apply .change(sec: 0) when displaying them as output in the form
|
90
98
|
# this will prevent seconds from being added by the browser
|
91
|
-
|
99
|
+
parsed_time = Time.strptime(parse_date, "%Y-%m-%d %H:%M %Z")
|
100
|
+
parsed_time = parsed_time.to_time - 60.minutes if uses_dst && is_dst_now?
|
101
|
+
params[k] = parsed_time
|
92
102
|
end
|
93
103
|
end
|
94
104
|
}
|
@@ -12,8 +12,6 @@ require_relative "fields/uuid_field"
|
|
12
12
|
require_relative "fields/attachment_field"
|
13
13
|
require_relative "fields/related_set_field"
|
14
14
|
|
15
|
-
|
16
|
-
|
17
15
|
class FieldFactory
|
18
16
|
attr_accessor :field, :class_name
|
19
17
|
def initialize(type: , name: , generator: )
|
@@ -51,6 +49,9 @@ class FieldFactory
|
|
51
49
|
end
|
52
50
|
@class_name = class_name
|
53
51
|
|
52
|
+
if field_class.nil?
|
53
|
+
raise "Field type could be identified #{name} "
|
54
|
+
end
|
54
55
|
|
55
56
|
@field = field_class.new(name: name,
|
56
57
|
layout_strategy: generator.layout_strategy,
|
@@ -155,6 +155,7 @@ class AssociationField < Field
|
|
155
155
|
hawked_association = "#{assoc.class_name}.all"
|
156
156
|
end
|
157
157
|
|
158
|
+
|
158
159
|
(is_owner ? "<% unless @#{assoc_name} %>\n" : "") +
|
159
160
|
" <%= f.collection_select(:#{name}, #{hawked_association}, :id, :#{display_column}, {prompt: true, selected: #{singular}.#{name} }, class: 'form-control') %>\n" +
|
160
161
|
(is_owner ? "<% else %>\n <%= @#{assoc_name}.#{display_column} %>" : "") +
|
@@ -253,6 +254,13 @@ class AssociationField < Field
|
|
253
254
|
# "\n "
|
254
255
|
end
|
255
256
|
|
257
|
+
def newline_after_field?
|
258
|
+
if modify_as && modify_as[:typeahead]
|
259
|
+
false
|
260
|
+
else
|
261
|
+
true
|
262
|
+
end
|
263
|
+
end
|
256
264
|
|
257
265
|
def where_query_statement
|
258
266
|
".where(*#{name}_query)"
|
@@ -32,6 +32,7 @@ class EnumField < Field
|
|
32
32
|
|
33
33
|
def form_field_output
|
34
34
|
enum_type = eval("#{class_name}.columns.select{|x| x.name == '#{name}'}[0].sql_type")
|
35
|
+
|
35
36
|
if eval("defined? #{class_name}.#{enum_type}_labels") == "method"
|
36
37
|
enum_definer = "#{class_name}.#{enum_type}_labels"
|
37
38
|
else
|
@@ -40,7 +40,8 @@ module HotGlue
|
|
40
40
|
layout_object = {
|
41
41
|
columns: {
|
42
42
|
size_each: smart_layout ? bootstrap_column_width : (specified_grouping_mode ? nil : 1),
|
43
|
-
container: [] # array of arrays
|
43
|
+
container: [] , # array of arrays,
|
44
|
+
bootstrap_column_width: []
|
44
45
|
},
|
45
46
|
portals: {
|
46
47
|
|
@@ -99,7 +100,7 @@ module HotGlue
|
|
99
100
|
}
|
100
101
|
layout_object[:columns][:container] = (0..available_columns-1).collect { |x| [columns[x]] }
|
101
102
|
layout_object[:columns][:container].reject!{|x| x == [nil]}
|
102
|
-
layout_object[:columns][:size_each] = bootstrap_column_width
|
103
|
+
# layout_object[:columns][:size_each] = bootstrap_column_width
|
103
104
|
end
|
104
105
|
elsif ! specified_grouping_mode
|
105
106
|
# not smart and no specified grouping
|
@@ -117,22 +118,33 @@ module HotGlue
|
|
117
118
|
# input control
|
118
119
|
|
119
120
|
user_layout_columns = @include_setting.split(":")
|
120
|
-
size_each = (bootstrap_columns / user_layout_columns.count).floor # this is the bootstrap size
|
121
121
|
|
122
|
-
|
122
|
+
extra_columns = available_columns - user_layout_columns.size
|
123
|
+
# size_each = (bootstrap_columns / user_layout_columns.count).floor # this is the bootstrap size
|
124
|
+
#
|
125
|
+
# layout_object[:columns][:size_each] = size_each
|
123
126
|
|
124
|
-
if user_layout_columns.size > available_columns
|
125
|
-
|
126
|
-
end
|
127
|
+
# if user_layout_columns.size > available_columns
|
128
|
+
# raise "Your include statement #{@include_setting } has #{user_layout_columns.size} columns, but I can only construct up to #{available_columns}"
|
129
|
+
# end
|
127
130
|
user_layout_columns.each_with_index do |column,i|
|
128
131
|
layout_object[:columns][:container][i] = column.split(",").collect(&:to_sym)
|
132
|
+
|
133
|
+
default_col_width = 1
|
134
|
+
if extra_columns > 0
|
135
|
+
default_col_width += 1
|
136
|
+
extra_columns -= 1
|
137
|
+
end
|
138
|
+
layout_object[:columns][:bootstrap_column_width][i] = default_col_width
|
129
139
|
end
|
130
140
|
|
131
141
|
if user_layout_columns.size < layout_object[:columns][:container].size
|
132
142
|
layout_object[:columns][:container].reject!{|x| x == []}
|
133
143
|
end
|
144
|
+
|
134
145
|
end
|
135
146
|
|
147
|
+
|
136
148
|
puts "*** constructed smart layout columns #{layout_object.inspect}"
|
137
149
|
layout_object
|
138
150
|
end
|
@@ -17,20 +17,20 @@ class LayoutStrategy::Bootstrap < LayoutStrategy::Base
|
|
17
17
|
end
|
18
18
|
|
19
19
|
|
20
|
-
def column_classes_for_form_fields
|
21
|
-
"col-md-#{builder.layout_object[:columns][:size_each]}"
|
20
|
+
def column_classes_for_form_fields(size = nil)
|
21
|
+
"col-md-#{size || builder.layout_object[:columns][:size_each]}"
|
22
22
|
end
|
23
23
|
|
24
|
-
def column_classes_for_column_headings
|
25
|
-
column_classes_for_line_fields
|
24
|
+
def column_classes_for_column_headings(size = nil)
|
25
|
+
column_classes_for_line_fields(size)
|
26
26
|
end
|
27
27
|
|
28
28
|
def container_name
|
29
29
|
"container"
|
30
30
|
end
|
31
31
|
|
32
|
-
def column_classes_for_line_fields
|
33
|
-
"col-sm-#{builder.layout_object[:columns][:size_each]}"
|
32
|
+
def column_classes_for_line_fields(size = nil)
|
33
|
+
"col-sm-#{size || builder.layout_object[:columns][:size_each]}"
|
34
34
|
end
|
35
35
|
|
36
36
|
def column_width
|
@@ -39,18 +39,18 @@ class LayoutStrategy::HotGlue < LayoutStrategy::Base
|
|
39
39
|
"scaffold-row"
|
40
40
|
end
|
41
41
|
|
42
|
-
def column_classes_for_form_fields
|
42
|
+
def column_classes_for_form_fields(size = nil)
|
43
43
|
"scaffold-cell"
|
44
44
|
end
|
45
45
|
|
46
46
|
def row_heading_classes
|
47
47
|
"scaffold-heading-row"
|
48
48
|
end
|
49
|
-
def column_classes_for_line_fields
|
49
|
+
def column_classes_for_line_fields(size = nil)
|
50
50
|
"scaffold-cell"
|
51
51
|
end
|
52
52
|
|
53
|
-
def column_classes_for_column_headings
|
53
|
+
def column_classes_for_column_headings(size = nil)
|
54
54
|
"scaffold-cell"
|
55
55
|
end
|
56
56
|
|
@@ -6,9 +6,9 @@ class LayoutStrategy::Tailwind < LayoutStrategy::Base
|
|
6
6
|
def button_style ; ""; end
|
7
7
|
def column_headings_col_style; "" ; end
|
8
8
|
def column_width; ""; end
|
9
|
-
def column_classes_for_line_fields; ""; end
|
10
|
-
def column_classes_for_form_fields; ""; end
|
11
|
-
def column_classes_for_column_headings; ""; end
|
9
|
+
def column_classes_for_line_fields(size = nil); ""; end
|
10
|
+
def column_classes_for_form_fields(size = nil); ""; end
|
11
|
+
def column_classes_for_column_headings(size = nil); ""; end
|
12
12
|
def col_width; 100; end
|
13
13
|
def container_name; ""; end
|
14
14
|
def downnest_style ; ""; end
|
@@ -76,13 +76,14 @@ module HotGlue
|
|
76
76
|
}.join("\n")
|
77
77
|
end
|
78
78
|
|
79
|
-
def list_column_headings(
|
80
|
-
column_width:, singular: )
|
79
|
+
def list_column_headings(column_width:, singular: )
|
81
80
|
col_style = @layout_strategy.column_headings_col_style
|
82
81
|
|
83
82
|
columns = layout_object[:columns][:container]
|
84
|
-
result = columns.map{ |column|
|
85
|
-
|
83
|
+
result = columns.map.with_index{ |column,i|
|
84
|
+
|
85
|
+
size = layout_object[:columns][:bootstrap_column_width][i]
|
86
|
+
"<div class='#{layout_strategy.column_classes_for_column_headings(size)} hg-heading-row heading--#{singular}--#{column.join("-")}' " + col_style + ">" +
|
86
87
|
column.map(&:to_s).map{|col_name| "#{col_name.humanize}"}.join("<br />") + "</div>"
|
87
88
|
}.join("\n")
|
88
89
|
return result
|
@@ -95,7 +96,6 @@ module HotGlue
|
|
95
96
|
|
96
97
|
def search_input_area
|
97
98
|
columns = layout_object[:columns][:container]
|
98
|
-
column_classes = layout_strategy.column_classes_for_form_fields
|
99
99
|
|
100
100
|
res =+ "<\%= form_with url: #{form_path}, method: :get, html: {'data-turbo-action': 'advance', 'data-controller': 'search-form'} do |f| %>"
|
101
101
|
res << "<div class=\"#{@layout_strategy.row_classes} search--#{@plural}\">"
|
@@ -116,12 +116,13 @@ module HotGlue
|
|
116
116
|
end
|
117
117
|
}.compact.join("\n")
|
118
118
|
|
119
|
-
|
119
|
+
size = layout_object[:columns][:bootstrap_column_width][columns.index(column)]
|
120
|
+
" <div class='#{layout_strategy.column_classes_for_form_fields(size)} search-cell--#{singular}--#{column.join("-")}' >" +
|
120
121
|
cols_result + "</div>"
|
121
122
|
|
122
123
|
}.join("\n")
|
123
124
|
res << "</div>"
|
124
|
-
res << "<div class='#{
|
125
|
+
res << "<div class='#{layout_strategy.column_classes_for_form_fields(nil)}'>"
|
125
126
|
if @search_clear_button
|
126
127
|
res << "<\%= f.button \"Clear\", name: nil, 'data-search-form-target': 'clearButton', class: 'btn btn-sm btn-secondary' %>"
|
127
128
|
end
|
@@ -132,11 +133,12 @@ module HotGlue
|
|
132
133
|
|
133
134
|
|
134
135
|
def all_form_fields(layout_strategy:)
|
135
|
-
column_classes = layout_strategy.column_classes_for_form_fields
|
136
136
|
columns = layout_object[:columns][:container]
|
137
137
|
|
138
138
|
result = columns.map{ |column|
|
139
|
-
|
139
|
+
size = layout_object[:columns][:bootstrap_column_width][columns.index(column)]
|
140
|
+
|
141
|
+
" <div class='#{layout_strategy.column_classes_for_form_fields(size)} cell--#{singular}--#{column.join("-")}' >" +
|
140
142
|
column.map { |col|
|
141
143
|
|
142
144
|
field_error_name = columns_map[col].field_error_name
|
@@ -158,6 +160,8 @@ module HotGlue
|
|
158
160
|
# show only on the update action overrides any pundit policy
|
159
161
|
elsif @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
|
160
162
|
"<% if policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
|
163
|
+
elsif update_show_only.include?(col)
|
164
|
+
"<% if @action == 'edit' %>" + columns_map[col].form_show_only_output + "<% else %>" + columns_map[col].form_field_output + "<% end %>"
|
161
165
|
else
|
162
166
|
columns_map[col].form_field_output
|
163
167
|
end
|
@@ -168,7 +172,7 @@ module HotGlue
|
|
168
172
|
add_spaces_each_line( "\n <span #{@tinymce_stimulus_controller}class='<%= \"alert alert-danger\" if #{singular}.errors.details.keys.include?(:#{field_error_name}) %>' #{'style="display: inherit;"'} >\n" +
|
169
173
|
add_spaces_each_line( (form_labels_position == 'before' ? (the_label || "") + "<br />\n" : "") +
|
170
174
|
+ field_result +
|
171
|
-
(form_labels_position == 'after' ? "<br />\n" + (the_label || "") : "") , 4) +
|
175
|
+
(form_labels_position == 'after' ? ( columns_map[col].newline_after_field? ? "<br />\n" : "") + (the_label || "") : "") , 4) +
|
172
176
|
"\n </span>\n ", 2)
|
173
177
|
|
174
178
|
}.join("") + "\n </div>"
|
@@ -190,10 +194,8 @@ module HotGlue
|
|
190
194
|
################################################################
|
191
195
|
|
192
196
|
def all_line_fields(layout_strategy:,
|
193
|
-
perc_width
|
194
|
-
col_identifier: nil)
|
197
|
+
perc_width:)
|
195
198
|
|
196
|
-
@col_identifier = layout_strategy.column_classes_for_line_fields
|
197
199
|
|
198
200
|
inline_list_labels = @inline_list_labels || 'omit'
|
199
201
|
columns = layout_object[:columns][:container]
|
@@ -203,9 +205,11 @@ module HotGlue
|
|
203
205
|
|
204
206
|
style_with_flex_basis = layout_strategy.style_with_flex_basis(perc_width)
|
205
207
|
|
206
|
-
result = columns.map{ |column|
|
208
|
+
result = columns.map.with_index{ |column,i|
|
209
|
+
|
210
|
+
size = layout_object[:columns][:bootstrap_column_width][i]
|
207
211
|
|
208
|
-
"<div class='hg-col #{
|
212
|
+
"<div class='hg-col #{layout_strategy.column_classes_for_line_fields(size)} #{singular}--#{column.join("-")}'#{style_with_flex_basis}> " +
|
209
213
|
column.map { |col|
|
210
214
|
if eval("#{singular_class}.columns_hash['#{col}']").nil? && !attachments.keys.include?(col) && !related_sets.include?(col)
|
211
215
|
raise "Can't find column '#{col}' on #{singular_class}, are you sure that is the column name?"
|
@@ -217,6 +221,8 @@ module HotGlue
|
|
217
221
|
"#{inline_list_labels == 'before' ? label + "<br/>" : ''}#{field_output}#{inline_list_labels == 'after' ? "<br/>" + label : ''}"
|
218
222
|
}.join( "<br />") + "</div>"
|
219
223
|
}.join("\n")
|
224
|
+
return result
|
225
|
+
|
220
226
|
end
|
221
227
|
end
|
222
228
|
end
|
@@ -77,7 +77,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
77
77
|
class_option :no_list_heading, type: :boolean, default: false
|
78
78
|
|
79
79
|
# determines if the labels show up BEFORE or AFTER on the NEW/EDIT (form)
|
80
|
-
class_option :form_labels_position, type: :string
|
80
|
+
class_option :form_labels_position, type: :string # choices are before, after, omit
|
81
81
|
class_option :form_placeholder_labels, type: :boolean, default: false # puts the field names into the placeholder labels
|
82
82
|
|
83
83
|
# determines if labels appear within the rows of the VIEWABLE list (does NOT affect the list heading)
|
@@ -91,6 +91,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
91
91
|
class_option :modify, default: {}
|
92
92
|
class_option :display_as, default: {}
|
93
93
|
class_option :pundit, default: nil
|
94
|
+
class_option :pundit_policy_override, default: nil
|
94
95
|
class_option :related_sets, default: ''
|
95
96
|
class_option :code_before_create, default: nil
|
96
97
|
class_option :code_after_create, default: nil
|
@@ -310,10 +311,18 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
310
311
|
@inline_list_labels = options['inline_list_labels'] || get_default_from_config(key: :inline_list_labels) || 'omit' # 'before','after','omit'
|
311
312
|
|
312
313
|
@form_labels_position = options['form_labels_position']
|
313
|
-
if
|
314
|
-
|
314
|
+
if @form_labels_position.nil?
|
315
|
+
@form_labels_position = get_default_from_config(key: :form_labels_position)
|
316
|
+
if @form_labels_position.nil?
|
317
|
+
@form_labels_position = 'after'
|
318
|
+
end
|
319
|
+
else
|
320
|
+
if !['before', 'after', 'omit'].include?(@form_labels_position)
|
321
|
+
raise HotGlue::Error, "You passed '#{@form_labels_position}' as the setting for --form-labels-position but the only allowed options are before, after (default), and omit"
|
322
|
+
end
|
315
323
|
end
|
316
324
|
|
325
|
+
|
317
326
|
if !['before', 'after', 'omit'].include?(@inline_list_labels)
|
318
327
|
raise HotGlue::Error, "You passed '#{@inline_list_labels}' as the setting for --inline-list-labels but the only allowed options are before, after, and omit (default)"
|
319
328
|
end
|
@@ -349,6 +358,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
349
358
|
|
350
359
|
|
351
360
|
@pundit = options['pundit']
|
361
|
+
@pundit_policy_override = options['pundit_policy_override']
|
352
362
|
|
353
363
|
@no_nav_menu = options['no_nav_menu']
|
354
364
|
|
@@ -651,6 +661,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
651
661
|
@menu_file_exists = true if @nested_set.none? && File.exist?("#{Rails.root}/app/views/#{namespace_with_trailing_dash}_menu.#{@markup}")
|
652
662
|
|
653
663
|
@turbo_streams = !!options['with_turbo_streams']
|
664
|
+
|
665
|
+
puts "show only #{@show_only}"
|
666
|
+
puts "update show only #{@update_show_only}"
|
667
|
+
|
654
668
|
end
|
655
669
|
|
656
670
|
def setup_hawk_keys
|
@@ -966,7 +980,6 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
966
980
|
|
967
981
|
def list_column_headings
|
968
982
|
@template_builder.list_column_headings(
|
969
|
-
col_identifier: @layout_strategy.column_classes_for_column_headings,
|
970
983
|
column_width: @layout_strategy.column_width,
|
971
984
|
singular: @singular
|
972
985
|
)
|
@@ -1330,9 +1343,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1330
1343
|
append_text = " <li class='nav-item'>
|
1331
1344
|
<%= link_to '#{@list_label_heading.humanize}', #{path_helper_plural(@nested_set.any? ? true: false)}, class: \"nav-link \#{'active' if nav == '#{plural_name}'}\" %>
|
1332
1345
|
</li>"
|
1346
|
+
alt_append_text = " <li class='nav-item'>
|
1347
|
+
<%= link_to '#{@list_label_heading.humanize.upcase}', #{path_helper_plural(@nested_set.any? ? true: false)}, class: \"nav-link \#{'active' if nav == '#{plural_name}'}\" %>
|
1348
|
+
</li>"
|
1333
1349
|
|
1334
1350
|
text = File.read(nav_file)
|
1335
|
-
if text.include?(append_text)
|
1351
|
+
if text.include?(append_text) || text.include?(alt_append_text)
|
1336
1352
|
puts "SKIPPING: Nav link for #{singular_name} already exists in #{nav_file}"
|
1337
1353
|
else
|
1338
1354
|
puts "APPENDING: nav link for #{singular_name} #{nav_file}"
|
@@ -1427,7 +1443,6 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1427
1443
|
|
1428
1444
|
def all_line_fields
|
1429
1445
|
@template_builder.all_line_fields(
|
1430
|
-
col_identifier: @layout_strategy.column_classes_for_line_fields,
|
1431
1446
|
perc_width: @layout_strategy.each_col, # undefined method `each_col'
|
1432
1447
|
layout_strategy: @layout_strategy
|
1433
1448
|
)
|
@@ -1531,9 +1546,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1531
1546
|
if @nested_set.none?
|
1532
1547
|
"\"\""
|
1533
1548
|
else
|
1534
|
-
@nested_set.collect { |arg|
|
1535
|
-
"
|
1536
|
-
}.join(" + "
|
1549
|
+
"\"" + @nested_set.collect { |arg|
|
1550
|
+
"__#{arg[:singular]}-\#{" + "@" + arg[:singular] + ".id}"
|
1551
|
+
}.join("") + "\""
|
1537
1552
|
end
|
1538
1553
|
end
|
1539
1554
|
|
@@ -78,11 +78,12 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def index
|
81
|
-
load_all_<%= plural %>
|
82
|
-
<% if @search_fields %>
|
81
|
+
load_all_<%= plural %><% if @search_fields %>
|
83
82
|
<%= @search_fields.collect{|field_name| @columns_map[field_name.to_sym].code_to_reset_match_if_search_is_blank}.compact.join(" \n") %><% end %>
|
84
|
-
|
85
|
-
authorize @<%= plural_name %><%
|
83
|
+
<% if @pundit %><% if @pundit && !@pundit_policy_override %>
|
84
|
+
authorize @<%= plural_name %><% elsif @pundit && @pundit_policy_override %>
|
85
|
+
skip_authorization
|
86
|
+
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.index?<% end %>
|
86
87
|
rescue Pundit::NotAuthorizedError
|
87
88
|
flash[:alert] = 'You are not authorized to perform this action.'
|
88
89
|
render 'layouts/error'<% end %>
|
@@ -92,7 +93,10 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
92
93
|
@<%= singular_name %> = <%= class_name %>.new<% if eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>(<%= @object_owner_sym %>: <%= @object_owner_eval %>)<% end %><% elsif @object_owner_optional && any_nested? %>
|
93
94
|
@<%= singular_name %> = <%= class_name %>.new({}.merge(<%= @nested_set.last[:singular] %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}))<% else %>
|
94
95
|
@<%= singular_name %> = <%= class_name %>.new(<% if any_nested? %><%= @object_owner_sym %>: <%= @object_owner_eval %><% end %>)<% end %>
|
95
|
-
<% if @pundit
|
96
|
+
<% if @pundit && !@pundit_policy_override %>
|
97
|
+
authorize @<%= singular %><% elsif @pundit && @pundit_policy_override %>
|
98
|
+
skip_authorization
|
99
|
+
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.new?<% end %><% if @pundit %>
|
96
100
|
@action = 'new'
|
97
101
|
rescue Pundit::NotAuthorizedError
|
98
102
|
flash[:alert] = 'You are not authorized to perform this action.'
|
@@ -112,7 +116,10 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
112
116
|
<%= creation_syntax %>
|
113
117
|
<% if @pundit %><% @related_sets.each do |key, related_set| %>
|
114
118
|
check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :create)<% end %><% end %>
|
115
|
-
|
119
|
+
<% if @pundit && !@pundit_policy_override %>
|
120
|
+
authorize @<%= singular %><% elsif @pundit && @pundit_policy_override %>
|
121
|
+
skip_authorization
|
122
|
+
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.create?<% end %>
|
116
123
|
<%= @code_before_create ? "\n " + @code_before_create.gsub(";", "\n") : "" %>
|
117
124
|
if @<%= singular_name %>.save<%= @code_after_create ? ("\n " + @code_after_create.gsub(";", "\n")) : ""%>
|
118
125
|
flash[:notice] = "Successfully created #{@<%= singular %>.<%= display_class %>}"
|
@@ -148,8 +155,10 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
148
155
|
|
149
156
|
<% end %>
|
150
157
|
<% unless @no_edit %>
|
151
|
-
def show<% if @pundit %>
|
152
|
-
authorize @<%= singular %><%
|
158
|
+
def show<% if @pundit && !@pundit_policy_override %>
|
159
|
+
authorize @<%= singular %><% elsif @pundit && @pundit_policy_override %>
|
160
|
+
skip_authorization
|
161
|
+
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.show?<% end %>
|
153
162
|
redirect_to <%= HotGlue.optionalized_ternary(namespace: @namespace,
|
154
163
|
target: @singular,
|
155
164
|
top_level: false,
|
@@ -160,8 +169,10 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
160
169
|
put_form: true).gsub("(#{singular}", "(@#{singular}") %>
|
161
170
|
end
|
162
171
|
|
163
|
-
def edit<% if @pundit
|
164
|
-
authorize @<%=
|
172
|
+
def edit<% if @pundit && !@pundit_policy_override %>
|
173
|
+
authorize @<%= singular %><% elsif @pundit && @pundit_policy_override %>
|
174
|
+
skip_authorization
|
175
|
+
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.edit?<% end %>
|
165
176
|
@action = 'edit'
|
166
177
|
render :edit<% if @pundit %>
|
167
178
|
rescue Pundit::NotAuthorizedError
|
@@ -187,15 +198,19 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
187
198
|
|
188
199
|
<% if @hawk_keys.any? %> modified_params = hawk_params({<%= hawk_to_ruby %>}, modified_params)<% end %>
|
189
200
|
<%= controller_attachment_orig_filename_pickup_syntax %>
|
190
|
-
|
191
|
-
if @<%= singular_name %>.attributes = modified_params
|
201
|
+
<% if @pundit && !@pundit_policy_override %>
|
192
202
|
authorize @<%= singular_name %>
|
193
203
|
<%= @code_before_update ? "\n " + @code_before_update.gsub(";", "\n") : "" %>
|
194
|
-
|
195
|
-
<% else %>
|
196
|
-
<%= @code_before_update ? "\n " + @code_before_update.gsub(";", "\n") : "" %>
|
204
|
+
|
197
205
|
if @<%= singular_name %>.update(modified_params)
|
198
|
-
|
206
|
+
|
207
|
+
<% elsif @pundit && @pundit_policy_override %>
|
208
|
+
skip_authorization
|
209
|
+
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.update?
|
210
|
+
if @<%= singular_name %>.update(modified_params)
|
211
|
+
<% else %>
|
212
|
+
<%= @code_before_update ? "\n " + @code_before_update.gsub(";", "\n") : "" %>
|
213
|
+
if @<%= singular_name %>.update(modified_params)<% end %>
|
199
214
|
<%= post_action_parental_updates.compact.join("\n ") %>
|
200
215
|
<%= @code_after_update ? "\n " + @code_after_update.gsub(";", "\n") : "" %>
|
201
216
|
<% if @display_list_after_update %> load_all_<%= plural %><% end %>
|
@@ -216,11 +231,14 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
216
231
|
end
|
217
232
|
|
218
233
|
<% end %><% if destroy_action %> def destroy
|
219
|
-
<% if @pundit
|
234
|
+
<% if @pundit && !@pundit_policy_override %>
|
235
|
+
authorize @<%= singular %><% elsif @pundit && @pundit_policy_override %>
|
236
|
+
skip_authorization
|
237
|
+
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.destroy?<% end %>
|
220
238
|
begin
|
221
239
|
@<%=singular_name%>.destroy
|
222
240
|
flash[:notice] = '<%= singular_name.titlecase %> successfully deleted'
|
223
|
-
rescue
|
241
|
+
rescue ActiveRecordError => e
|
224
242
|
flash[:alert] = '<%= singular_name.titlecase %> could not be deleted'
|
225
243
|
end
|
226
244
|
<%= post_action_parental_updates.join("\n ") %>
|
@@ -1,7 +1,8 @@
|
|
1
1
|
<\% if @<%= singular %>.errors.none? %>
|
2
2
|
<\%= turbo_stream.replace "<%= @namespace %>__<%= plural %>-list" + <%= nested_for_turbo_nested_constructor %> do %>
|
3
|
-
<\%= render partial: "list", locals: {<%= plural %>: @<%= plural
|
4
|
-
|
3
|
+
<\%= render partial: "list", locals: {<%= plural %>: @<%= plural %><% if @nested_set.any? %>, <%= @nested_set.collect{|arg| "#{arg[:singular]}: @#{arg[:singular]}"}.join(", ") %>, nested_for: '<%= @nested_set.collect{|arg| "\"#{arg[:singular]}-\#{@#{arg[:singular]}.id}\""}.join("__") %>' <% end %> } %>
|
4
|
+
|
5
|
+
<\% end %>
|
5
6
|
<\% end %>
|
6
7
|
<!-- parental updated -->
|
7
8
|
<%= turbo_parental_updates %>
|
@@ -15,5 +16,4 @@
|
|
15
16
|
<\% end %>
|
16
17
|
<\%= turbo_stream.replace "flash_notices" do %>
|
17
18
|
<\%= render partial: "layouts/flash_notices", locals: {resource: @<%= singular %>} %>
|
18
|
-
|
19
19
|
<\% end %>
|
@@ -8,30 +8,40 @@
|
|
8
8
|
<% if @big_edit %>
|
9
9
|
</div>
|
10
10
|
</div>
|
11
|
+
</div>
|
12
|
+
|
11
13
|
|
12
14
|
|
13
15
|
<% if @downnest_children.any? && @big_edit %>
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
<
|
16
|
+
<div class="container" data-controller="bootstrap-tabbed-nav">
|
17
|
+
<ul class="nav nav-tabs" id="<%= singular + "_downnest_portals" %>" role="tablist">
|
18
|
+
<% @downnest_object.each_with_index do |data,index| %>
|
19
|
+
<% downnest = data[0] %>
|
20
|
+
<li class="nav-item" role="presentation">
|
21
|
+
<button class="nav-link <%= "active" if index==0 %>" id="<%= downnest %>-tab" data-bs-toggle="tab" data-bs-target="#<%= downnest %>-portal" type="button" role="tab" aria-controls="home" aria-selected="true">
|
22
|
+
<%= downnest.titlecase.pluralize %>
|
23
|
+
</button>
|
24
|
+
</li>
|
25
|
+
<% end %>
|
26
|
+
</ul>
|
27
|
+
|
28
|
+
<div class="tab-content" id="myTabContent">
|
29
|
+
<% @downnest_object.each_with_index do |data, index| %>
|
30
|
+
<% downnest = data[0] %>
|
31
|
+
<div class="tab-pane fade <%= "show active" if index==0 %>" id="<%= downnest %>-portal" role="tabpanel" aria-labelledby="<%= downnest %>-tab">
|
19
32
|
<% downnest_object = eval("#{singular_class}.reflect_on_association(:#{downnest})") %>
|
20
33
|
<% if downnest_object.nil?; raise "no relationship for downnested portal `#{downnest}` found on `#{singular_class}`; please check relationship for has_many :#{downnest}"; end; %>
|
21
34
|
<% downnest_class = downnest_object.class_name %>
|
22
35
|
<% downnest_object_name = eval("#{downnest_class}.table_name") %>
|
23
36
|
<% downnest_style = @layout_strategy.downnest_style %>
|
24
|
-
<% if @downnest_shows_headings %>
|
25
|
-
<h3>
|
26
|
-
<%= downnest_class.titlecase.pluralize %>
|
27
|
-
</h3>
|
28
|
-
<% end %>
|
29
|
-
<\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {<%= @singular %>: @<%= @singular %>, <%= downnest_object_name %>: @<%= @singular %>.<%= downnest %><% if @nested_set.any? %>, <%= @nested_set.collect{|x| "#{x[:singular]}: @#{x[:singular]}"}.join(", ") %>, nested_for: "<%= @nested_set.collect{|x| "#{x[:singular]}-" + "\#{" + "@#{x[:singular]}.id}"}.join("__") %>__<%= singular %>-#{@<%= @singular %>.id}" <% end %> } \%>
|
30
37
|
|
31
|
-
|
38
|
+
<\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {<%= @singular %>: @<%= @singular %>, <%= downnest_object_name %>: @<%= @singular %>.<%= downnest %><% if @nested_set.any? %>, <%= @nested_set.collect{|x| "#{x[:singular]}: @#{x[:singular]}"}.join(", ") %>, nested_for: "<%= @nested_set.collect{|x| "#{x[:singular]}-" + "\#{" + "@#{x[:singular]}.id}"}.join("__") %>__<%= singular %>-#{@<%= @singular %>.id}" <% end %> } \%>
|
32
39
|
</div>
|
33
40
|
<% end %>
|
34
|
-
|
41
|
+
</div>
|
42
|
+
|
35
43
|
</div>
|
36
44
|
<% end %>
|
37
45
|
|
46
|
+
|
47
|
+
<% end %>
|
data/lib/hotglue/version.rb
CHANGED
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.
|
4
|
+
version: 0.6.16
|
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-
|
11
|
+
date: 2025-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|