hot-glue 0.6.10 → 0.6.12
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 +5 -3
- data/README.md +128 -1
- data/app/helpers/hot_glue_helper.rb +8 -5
- data/lib/generators/hot_glue/field_factory.rb +2 -0
- data/lib/generators/hot_glue/fields/association_field.rb +33 -12
- data/lib/generators/hot_glue/fields/boolean_field.rb +3 -4
- data/lib/generators/hot_glue/fields/date_time_field.rb +1 -1
- data/lib/generators/hot_glue/fields/related_set_field.rb +1 -1
- data/lib/generators/hot_glue/markup_templates/erb.rb +11 -9
- data/lib/generators/hot_glue/scaffold_generator.rb +26 -11
- data/lib/generators/hot_glue/templates/controller.rb.erb +17 -6
- data/lib/generators/hot_glue/templates/erb/_edit.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/_list.erb +7 -0
- data/lib/generators/hot_glue/templates/erb/_show.erb +6 -1
- data/lib/generators/hot_glue/templates/erb/edit.erb +6 -1
- data/lib/generators/hot_glue/templates/typeahead_controller.rb.erb +27 -1
- data/lib/generators/hot_glue/typeahead_generator.rb +23 -0
- 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: 1eacfaf1cc09c6a40597a8a0f3f2bda37e156f5ed63be68ff842de01a707dc5d
|
4
|
+
data.tar.gz: 20b3c4134a1443c2c5d134a5f5bcdecfb2e13c749c856a1620ecb43209245e68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c38593db0539b7259b05b3d3e86062f550d54f969c9a30ad9e2ffa035513c035e154a02ed3f9427def36a025929d0679b66ff0423fc7fdf4ae01623ffb2f540
|
7
|
+
data.tar.gz: 6c661dff1800dc911b23681622992fe4e7ac5d554c107e32aa5577f94250022bfbd07be78d33b9c6acab4149aacc2e2ce1047b8f5fd3f728c49139f1db07a4c2
|
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.12)
|
5
5
|
ffaker (~> 2.16)
|
6
6
|
kaminari (~> 1.2)
|
7
7
|
rails (> 5.1)
|
@@ -76,6 +76,7 @@ GEM
|
|
76
76
|
tzinfo (~> 2.0)
|
77
77
|
addressable (2.8.1)
|
78
78
|
public_suffix (>= 2.0.2, < 6.0)
|
79
|
+
base64 (0.2.0)
|
79
80
|
bcrypt (3.1.18)
|
80
81
|
builder (3.2.4)
|
81
82
|
byebug (11.1.3)
|
@@ -139,7 +140,7 @@ GEM
|
|
139
140
|
mini_mime (1.1.2)
|
140
141
|
mini_portile2 (2.8.4)
|
141
142
|
minitest (5.16.3)
|
142
|
-
net-imap (0.5.
|
143
|
+
net-imap (0.5.5)
|
143
144
|
date
|
144
145
|
net-protocol
|
145
146
|
net-pop (0.1.2)
|
@@ -245,7 +246,8 @@ GEM
|
|
245
246
|
warden (1.2.9)
|
246
247
|
rack (>= 2.0.9)
|
247
248
|
websocket (1.2.9)
|
248
|
-
websocket-driver (0.7.
|
249
|
+
websocket-driver (0.7.7)
|
250
|
+
base64
|
249
251
|
websocket-extensions (>= 0.1.0)
|
250
252
|
websocket-extensions (0.1.5)
|
251
253
|
xpath (3.2.0)
|
data/README.md
CHANGED
@@ -987,6 +987,13 @@ Omits controller.
|
|
987
987
|
|
988
988
|
Omits list views.
|
989
989
|
|
990
|
+
`--new-button-position` (above, below; default: above)
|
991
|
+
Show the new button above or below the list.
|
992
|
+
|
993
|
+
`--downnest-shows-headings` (default: false)
|
994
|
+
Show headings above downnested portals.
|
995
|
+
|
996
|
+
|
990
997
|
### `--big-edit`
|
991
998
|
|
992
999
|
If you do not want inline editing of your list items but instead want to fallback to full-page style behavior for your edit views, use `--big-edit`.
|
@@ -1106,7 +1113,16 @@ Use `before` to make the labels come before or `after` to make them come after.
|
|
1106
1113
|
|
1107
1114
|
Omits the heading of column names that appears above the 1st row of data.
|
1108
1115
|
|
1116
|
+
### `--include-object-names`
|
1117
|
+
|
1118
|
+
When you are "Editing X" we specify that X is a ___ (author, book, room, etc)
|
1109
1119
|
|
1120
|
+
e.g. "Editing author Edgar Allan Poe" vs "Editing Edgar Allan Poe"
|
1121
|
+
|
1122
|
+
Can also be specified globally in `config/hot_glue.yml`
|
1123
|
+
|
1124
|
+
|
1125
|
+
### Code insertions
|
1110
1126
|
|
1111
1127
|
`--code-before-create`
|
1112
1128
|
`--code-after-create`
|
@@ -1585,6 +1601,76 @@ puts the value into the search box and the id into a hidden field.
|
|
1585
1601
|
|
1586
1602
|
You need to making a selection *and* click "Save" to update the record.
|
1587
1603
|
|
1604
|
+
The typeahead itself can be both namespaced and nested. (Remember, all controllers are generated at the namespace.)
|
1605
|
+
|
1606
|
+
Pay close attention to a nested typeahead: When generating the typeahead scaffold use both `--namespace=aaa` and `--nested=bbb/ccc`
|
1607
|
+
|
1608
|
+
In this example, the typeahead controller will operate at a namespace of `aaa` with two parents: `bbb` and `ccc`
|
1609
|
+
|
1610
|
+
Combined with `--auth-identifier`, you can load only objects that are related from the `ccc` thing that gets loaded off the `bbb` thing that gets loaded off the current_user.
|
1611
|
+
|
1612
|
+
This scopes the list returned by the typeahead.
|
1613
|
+
|
1614
|
+
You need to specify this twice: Once when specifying the typehead scaffold, and also any place in a regular scaffold that uses typeahead:
|
1615
|
+
|
1616
|
+
For example, assuming we have a reciprocal has_many through for Accounts & Users
|
1617
|
+
|
1618
|
+
user.rb
|
1619
|
+
```
|
1620
|
+
has_many :account_users
|
1621
|
+
has_many :accounts, through: :account_users
|
1622
|
+
```
|
1623
|
+
|
1624
|
+
|
1625
|
+
account.rb
|
1626
|
+
```
|
1627
|
+
has_many :account_users
|
1628
|
+
has_many :users, through: :account_users
|
1629
|
+
```
|
1630
|
+
|
1631
|
+
|
1632
|
+
`bin/rails generate hot_glue:scaffold Member --auth='current_user' --auth-identifier='user' --auth-identifier=user --modify='user_id{typeahead}[account]'`
|
1633
|
+
|
1634
|
+
in our routes.rb file, we have
|
1635
|
+
```
|
1636
|
+
namespace :account_dashboard do
|
1637
|
+
resources :accounts do
|
1638
|
+
resources :users_typeahead
|
1639
|
+
resources :rooms do
|
1640
|
+
resources :members
|
1641
|
+
end
|
1642
|
+
end
|
1643
|
+
end
|
1644
|
+
```
|
1645
|
+
|
1646
|
+
Notice that the scaffold with the references to users is 2 levels deep: accounts -> rooms -> members (and is also in a namespace)
|
1647
|
+
|
1648
|
+
Notice also that the *users typeahead* operates only one level deep in the same namespace.
|
1649
|
+
|
1650
|
+
This means that to find users within the search, the essential piece of information is the account, because we want to scope the result set to the users belong to that account.
|
1651
|
+
|
1652
|
+
• The account must belong to the current_user (notice the account uses nested account provided by the route)
|
1653
|
+
• Any users found by the typeahead must belong to the account
|
1654
|
+
|
1655
|
+
```
|
1656
|
+
def account
|
1657
|
+
@account ||= current_user.accounts.find(params[:account_id])
|
1658
|
+
end
|
1659
|
+
|
1660
|
+
def index
|
1661
|
+
authorize User, :typeahead?
|
1662
|
+
query = params[:query]
|
1663
|
+
@typeahead_identifier = params[:typeahead_identifier]
|
1664
|
+
@users = account.users.where("LOWER(email) LIKE ? ", "%#{query.downcase}%").limit(10)
|
1665
|
+
render layout: false
|
1666
|
+
end
|
1667
|
+
```
|
1668
|
+
|
1669
|
+
|
1670
|
+
|
1671
|
+
--
|
1672
|
+
|
1673
|
+
|
1588
1674
|
### TinyMCE
|
1589
1675
|
1. `bundle add tinymce-rails` to add it to your Gemfile
|
1590
1676
|
|
@@ -1658,11 +1744,52 @@ If you have a partial in your view folder called `_list_after_each_row_heading`,
|
|
1658
1744
|
|
1659
1745
|
The `within` partials should do operations within the form (like hidden fields), and the `after` partials should do entirely unrelated operations, like a different form entirely.
|
1660
1746
|
|
1661
|
-
These automatic pickups for partials are detected at
|
1747
|
+
These automatic pickups for partials are detected at build time. This means that if you add these partials later, you must rebuild your scaffold.
|
1662
1748
|
|
1663
1749
|
|
1664
1750
|
# VERSION HISTORY
|
1665
1751
|
|
1752
|
+
#### 2025-02-19 - v0.6.12
|
1753
|
+
• adds decimal field type (displays as float-- there is no special handling for decimal on the UI)
|
1754
|
+
• guard against polymorphic belongs_to -- not a full implementation for polymorphic fields, just hides the fields on the form; on the list uses to_label always
|
1755
|
+
• fixes heading with multiword names on downnested portals to display nicely capitalized
|
1756
|
+
• removes open struct
|
1757
|
+
|
1758
|
+
#### 2025-01-28 v0.6.11
|
1759
|
+
|
1760
|
+
• Typeahead now can use --auth, --auth-identifier, --namespace, and --nested
|
1761
|
+
• Works similar to how same flags work on scaffold generator. (Notice that the typeahead generator is a completely separate generator).
|
1762
|
+
• When using nested, your results are scoped the parent objects in the nest chain (which is the last one)
|
1763
|
+
|
1764
|
+
e.g.
|
1765
|
+
`bin/rails generate hot_glue:scaffold Member --auth='current_user' --auth-identifier='user' --auth-identifier=user --modify='user_id{typeahead}[account]'`
|
1766
|
+
|
1767
|
+
here the user_id field on members will use a typeahead that is built in the namespace `account_dashboard` under 1 parent: `account`
|
1768
|
+
|
1769
|
+
This would be used in conjunction with a typeahead built using the same namespace and nesting that matches:
|
1770
|
+
|
1771
|
+
```
|
1772
|
+
bin/rails generate hot_glue:typeahead User --namespace='account_dashboard' --nested='account' --auth-identifier='user' --auth='current_user'
|
1773
|
+
```
|
1774
|
+
|
1775
|
+
(See 'typeahead' section for details)
|
1776
|
+
|
1777
|
+
`--include-object-names`
|
1778
|
+
|
1779
|
+
When you are "Editing X" we specify that X is a ___ (author, book, room, etc)
|
1780
|
+
|
1781
|
+
e.g. "Editing author Edgar Allan Poe" vs "Editing Edgar Allan Poe"
|
1782
|
+
|
1783
|
+
Can also be specified globally in `config/hot_glue.yml`
|
1784
|
+
|
1785
|
+
|
1786
|
+
`--new-button-position` (above, below; default: above)
|
1787
|
+
Show the new button above or below the list.
|
1788
|
+
|
1789
|
+
`--downnest-shows-headings` (default: false)
|
1790
|
+
Show headings above downnested portals.
|
1791
|
+
|
1792
|
+
|
1666
1793
|
#### 2024-12-25 v0.6.10
|
1667
1794
|
• adds `--no-nav-menu` option to supress writing to the _nav template
|
1668
1795
|
• the _nav template itself can now end with either .html.erb or .erb
|
@@ -1,10 +1,13 @@
|
|
1
1
|
module HotGlueHelper
|
2
|
-
|
3
|
-
|
2
|
+
class KVObject
|
3
|
+
attr_accessor :key, :value
|
4
|
+
def initialize(key: , value: )
|
5
|
+
@key = key
|
6
|
+
@value = value
|
7
|
+
end
|
8
|
+
end
|
4
9
|
|
5
10
|
def enum_to_collection_select(hash)
|
6
|
-
hash.collect{|k,v|
|
7
|
-
|
11
|
+
hash.collect{|k,v| KVObject.new(key: k, value: v)}
|
8
12
|
end
|
9
|
-
|
10
13
|
end
|
@@ -24,17 +24,18 @@ class AssociationField < Field
|
|
24
24
|
raise(HotGlue::Error, exit_message)
|
25
25
|
end
|
26
26
|
|
27
|
-
|
27
|
+
if ! eval("#{class_name}.reflect_on_association(:#{assoc}).polymorphic?")
|
28
|
+
@assoc_class = eval(assoc_model.try(:class_name))
|
28
29
|
|
29
|
-
|
30
|
+
name_list = [:name, :to_label, :full_name, :display_name, :email]
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
if assoc_class && name_list.collect{ |field|
|
33
|
+
assoc_class.respond_to?(field.to_s) || assoc_class.instance_methods.include?(field)
|
34
|
+
}.none?
|
35
|
+
exit_message = "Oops: Missing a label for `#{assoc_class}`. Can't find any column to use as the display label for the #{@assoc_name} association on the #{class_name} model. TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name 5) email. You can implement any of these directly on your`#{assoc_class}` model (can be database fields or model methods) or alias them to field you want to use as your display label. Then RERUN THIS GENERATOR. (Field used will be chosen based on rank here.)"
|
36
|
+
raise(HotGlue::Error, exit_message)
|
37
|
+
end
|
36
38
|
end
|
37
|
-
|
38
39
|
end
|
39
40
|
|
40
41
|
def assoc_label
|
@@ -110,7 +111,15 @@ class AssociationField < Field
|
|
110
111
|
# else
|
111
112
|
# end
|
112
113
|
elsif modify_as && modify_as[:typeahead]
|
113
|
-
search_url = "#{namespace ? namespace + "_" : ""}
|
114
|
+
search_url = "#{namespace ? namespace + "_" : ""}" +
|
115
|
+
modify_as[:nested].join("_") + ("_" if modify_as[:nested].any?) +
|
116
|
+
+ "#{assoc.class_name.downcase.pluralize}_typeahead_index_url"
|
117
|
+
|
118
|
+
|
119
|
+
if @modify_as[:nested].any?
|
120
|
+
search_url << "(" + modify_as[:nested].collect{|x| "#{x}"}.join(",") + ")"
|
121
|
+
end
|
122
|
+
|
114
123
|
"<div class='typeahead typeahead--#{assoc.name}_id'
|
115
124
|
data-controller='typeahead'
|
116
125
|
data-typeahead-url-value='<%= #{search_url} %>'
|
@@ -132,7 +141,12 @@ class AssociationField < Field
|
|
132
141
|
|
133
142
|
is_owner = name == ownership_field
|
134
143
|
assoc_class_name = assoc.class_name.to_s
|
135
|
-
|
144
|
+
if assoc_class
|
145
|
+
display_column = HotGlue.derrive_reference_name(assoc_class_name)
|
146
|
+
else
|
147
|
+
# polymorphic
|
148
|
+
display_column = "name"
|
149
|
+
end
|
136
150
|
|
137
151
|
if hawk_keys[assoc.foreign_key.to_sym]
|
138
152
|
hawk_definition = hawk_keys[assoc.foreign_key.to_sym]
|
@@ -170,9 +184,16 @@ class AssociationField < Field
|
|
170
184
|
|
171
185
|
def line_field_output
|
172
186
|
|
173
|
-
display_column = HotGlue.derrive_reference_name(assoc_class.to_s)
|
174
187
|
|
175
|
-
|
188
|
+
if assoc_class
|
189
|
+
display_column = HotGlue.derrive_reference_name(assoc_class.to_s)
|
190
|
+
|
191
|
+
"<%= #{singular}.#{assoc}.try(:#{display_column}) || '<span class=\"content \">MISSING</span>'.html_safe %>"
|
192
|
+
else
|
193
|
+
"<%= #{singular}.#{assoc}.try(:to_label) || '<span class=\"content \">MISSING</span>'.html_safe %>"
|
194
|
+
|
195
|
+
end
|
196
|
+
|
176
197
|
end
|
177
198
|
|
178
199
|
|
@@ -40,19 +40,18 @@ class BooleanField < Field
|
|
40
40
|
if display_boolean_as.nil?
|
41
41
|
|
42
42
|
end
|
43
|
-
"<
|
43
|
+
"<span class='#{@layout_strategy.form_checkbox_wrapper_class} #{'form-switch' if display_boolean_as == 'switch'}'>\n" +
|
44
44
|
(if display_boolean_as == 'radio'
|
45
45
|
radio_button_display
|
46
46
|
elsif display_boolean_as == 'checkbox'
|
47
47
|
checkbox_display
|
48
48
|
elsif display_boolean_as == 'switch'
|
49
49
|
switch_display
|
50
|
-
end) + "</
|
50
|
+
end) + "</span> \n"
|
51
51
|
end
|
52
52
|
|
53
53
|
def form_field_output
|
54
|
-
|
55
|
-
form_field_display + (form_labels_position == 'after' ? " <br />" : "")
|
54
|
+
form_field_display
|
56
55
|
end
|
57
56
|
|
58
57
|
def line_field_output
|
@@ -40,7 +40,7 @@ class DateTimeField < Field
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def form_field_output
|
43
|
-
"<%= f.datetime_field( :#{name}, value: #{singular}.#{name} && #{singular}.#{name}.
|
43
|
+
"<%= f.datetime_field( :#{name}, value: #{singular}.#{name} && #{singular}.#{name}.in_time_zone(current_timezone), class: '#{@layout_strategy.form_input_class}' ) %><%= current_timezone %>"
|
44
44
|
end
|
45
45
|
|
46
46
|
def viewable_output
|
@@ -3,7 +3,7 @@ class RelatedSetField < Field
|
|
3
3
|
attr_accessor :assoc_name, :assoc_class, :assoc
|
4
4
|
|
5
5
|
def initialize( class_name: , default_boolean_display:, display_as: ,
|
6
|
-
name: , singular: ,
|
6
|
+
name: , singular: , plural:,
|
7
7
|
alt_lookup: ,
|
8
8
|
update_show_only: ,
|
9
9
|
hawk_keys: , auth: , sample_file_path:, ownership_field: ,
|
@@ -156,18 +156,20 @@ module HotGlue
|
|
156
156
|
"<% if @action == 'new' && policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
|
157
157
|
|
158
158
|
# show only on the update action overrides any pundit policy
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
159
|
+
elsif @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
|
160
|
+
"<% if policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
|
161
|
+
else
|
162
|
+
columns_map[col].form_field_output
|
163
|
+
end
|
164
|
+
|
164
165
|
|
165
166
|
@tinymce_stimulus_controller = (columns_map[col].modify_as == {tinymce: 1} ? "data-controller='tiny-mce' " : "")
|
167
|
+
|
166
168
|
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" +
|
167
|
-
add_spaces_each_line( (form_labels_position == 'before' ? the_label || "" : "") +
|
168
|
-
+
|
169
|
-
(form_labels_position == 'after' ? the_label : "")
|
170
|
-
"\n </span>\n
|
169
|
+
add_spaces_each_line( (form_labels_position == 'before' ? (the_label || "") + "<br />\n" : "") +
|
170
|
+
+ field_result +
|
171
|
+
(form_labels_position == 'after' ? "<br />\n" + (the_label || "") : "") , 4) +
|
172
|
+
"\n </span>\n ", 2)
|
171
173
|
|
172
174
|
}.join("") + "\n </div>"
|
173
175
|
}.join("\n")
|
@@ -28,7 +28,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
28
28
|
:layout_strategy, :form_placeholder_labels,
|
29
29
|
:form_labels_position, :no_nav_menu, :pundit,
|
30
30
|
:self_auth, :namespace_value, :record_scope, :related_sets,
|
31
|
-
:search_clear_button, :search_autosearch
|
31
|
+
:search_clear_button, :search_autosearch, :include_object_names
|
32
32
|
# important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
|
33
33
|
# so we use namespace_value instead
|
34
34
|
|
@@ -81,7 +81,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
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)
|
84
|
-
class_option :inline_list_labels, default:
|
84
|
+
class_option :inline_list_labels, default: nil # default is set below
|
85
85
|
class_option :factory_creation, default: ''
|
86
86
|
class_option :alt_foreign_key_lookup, default: '' #
|
87
87
|
class_option :attachments, default: ''
|
@@ -98,7 +98,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
98
98
|
class_option :code_after_update, default: nil
|
99
99
|
class_option :record_scope, default: nil
|
100
100
|
class_option :no_nav_menu, type: :boolean, default: false # suppress writing to _nav template
|
101
|
-
|
101
|
+
class_option :include_object_names, type: :boolean, default: false
|
102
|
+
class_option :new_button_position, type: :string, default: 'above'
|
103
|
+
class_option :downnest_shows_headings, type: :boolean, default: nil
|
102
104
|
|
103
105
|
|
104
106
|
# SEARCH OPTIONS
|
@@ -260,7 +262,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
260
262
|
elsif $2 == "tinymce"
|
261
263
|
@modify_as[key.to_sym] = {tinymce: 1, badges: $3}
|
262
264
|
elsif $2 == "typeahead"
|
263
|
-
|
265
|
+
if !$3.nil?
|
266
|
+
nested = $3.split("/")
|
267
|
+
else
|
268
|
+
nested = []
|
269
|
+
end
|
270
|
+
@modify_as[key.to_sym] = {typeahead: 1, nested: nested}
|
264
271
|
elsif $2 == "timezone"
|
265
272
|
@modify_as[key.to_sym] = {timezone: 1, badges: $3}
|
266
273
|
elsif $2 == "none"
|
@@ -300,7 +307,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
300
307
|
|
301
308
|
setup_hawk_keys
|
302
309
|
@form_placeholder_labels = options['form_placeholder_labels'] # true or false
|
303
|
-
@inline_list_labels = options['inline_list_labels'] || 'omit' # 'before','after','omit'
|
310
|
+
@inline_list_labels = options['inline_list_labels'] || get_default_from_config(key: :inline_list_labels) || 'omit' # 'before','after','omit'
|
304
311
|
|
305
312
|
@form_labels_position = options['form_labels_position']
|
306
313
|
if !['before', 'after', 'omit'].include?(@form_labels_position)
|
@@ -337,6 +344,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
337
344
|
|
338
345
|
@smart_layout = options['smart_layout']
|
339
346
|
@record_scope = options['record_scope']
|
347
|
+
@downnest_shows_headings = options['downnest_shows_headings']
|
348
|
+
@new_button_position = options['new_button_position']
|
349
|
+
|
340
350
|
|
341
351
|
@pundit = options['pundit']
|
342
352
|
|
@@ -361,6 +371,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
361
371
|
@downnest_object = HotGlue.construct_downnest_object(@downnest)
|
362
372
|
end
|
363
373
|
|
374
|
+
@include_object_names = options['include_object_names'] || get_default_from_config(key: :include_object_names)
|
375
|
+
|
376
|
+
|
377
|
+
|
364
378
|
if @god
|
365
379
|
# @auth = nil
|
366
380
|
end
|
@@ -463,6 +477,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
463
477
|
identify_object_owner
|
464
478
|
setup_fields
|
465
479
|
|
480
|
+
|
466
481
|
if (@columns - @show_only - (@ownership_field ? [@ownership_field.to_sym] : [])).empty?
|
467
482
|
@no_field_form = true
|
468
483
|
end
|
@@ -1069,7 +1084,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1069
1084
|
HotGlue.optionalized_ternary(namespace: @namespace,
|
1070
1085
|
target: @controller_build_folder,
|
1071
1086
|
nested_set: @nested_set,
|
1072
|
-
with_params:
|
1087
|
+
with_params: false,
|
1073
1088
|
top_level: false)
|
1074
1089
|
end
|
1075
1090
|
|
@@ -1077,7 +1092,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1077
1092
|
HotGlue.optionalized_ternary(namespace: @namespace,
|
1078
1093
|
target: @singular,
|
1079
1094
|
nested_set: @nested_set,
|
1080
|
-
with_params:
|
1095
|
+
with_params: false,
|
1081
1096
|
put_form: true,
|
1082
1097
|
top_level: false)
|
1083
1098
|
end
|
@@ -1086,7 +1101,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1086
1101
|
HotGlue.optionalized_ternary(namespace: @namespace,
|
1087
1102
|
target: @singular,
|
1088
1103
|
nested_set: @nested_set,
|
1089
|
-
with_params:
|
1104
|
+
with_params: false,
|
1090
1105
|
put_form: true)
|
1091
1106
|
end
|
1092
1107
|
|
@@ -1095,7 +1110,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1095
1110
|
target: @singular,
|
1096
1111
|
nested_set: @nested_set,
|
1097
1112
|
modifier: "edit_",
|
1098
|
-
with_params:
|
1113
|
+
with_params: false,
|
1099
1114
|
put_form: true)
|
1100
1115
|
end
|
1101
1116
|
|
@@ -1124,7 +1139,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1124
1139
|
target: singular,
|
1125
1140
|
nested_set: @nested_set,
|
1126
1141
|
modifier: "new_",
|
1127
|
-
with_params:
|
1142
|
+
with_params: false)
|
1128
1143
|
end
|
1129
1144
|
|
1130
1145
|
def nested_assignments
|
@@ -1222,7 +1237,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1222
1237
|
path: HotGlue.optionalized_ternary( namespace: @namespace,
|
1223
1238
|
target: @singular,
|
1224
1239
|
nested_set: @nested_set,
|
1225
|
-
with_params:
|
1240
|
+
with_params: false,
|
1226
1241
|
put_form: true),
|
1227
1242
|
big_edit: @big_edit,
|
1228
1243
|
singular: singular,
|
@@ -72,13 +72,14 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
72
72
|
params[:per] || 10
|
73
73
|
end<% end %>
|
74
74
|
<% unless @no_list %>
|
75
|
-
def load_all_<%= plural %>
|
75
|
+
def load_all_<%= plural %><% if @search == "set" %>
|
76
|
+
@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 %>
|
76
77
|
<%= load_all_code %>
|
77
78
|
end
|
78
79
|
|
79
|
-
def index
|
80
|
-
|
81
|
-
|
80
|
+
def index
|
81
|
+
load_all_<%= plural %>
|
82
|
+
<% if @search_fields %>
|
82
83
|
<%= @search_fields.collect{|field_name| @columns_map[field_name.to_sym].code_to_reset_match_if_search_is_blank}.compact.join(" \n") %><% end %>
|
83
84
|
load_all_<%= plural %><% if @pundit %><% if @pundit %>
|
84
85
|
authorize @<%= plural_name %><% end %>
|
@@ -131,8 +132,18 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
131
132
|
<% unless @display_edit_after_create %>render :create, status: :unprocessable_entity<% else %>render :new , status: :unprocessable_entity<% end %>
|
132
133
|
end<% if @pundit %>
|
133
134
|
rescue Pundit::NotAuthorizedError => e
|
135
|
+
flash[:alert] = "Not authorized."
|
134
136
|
@<%= singular %>.errors.add(:base, e.message)
|
135
|
-
render :create, status: :unprocessable_entity<%
|
137
|
+
<% unless @display_edit_after_create %>render :create, status: :unprocessable_entity<% else %>redirect_to <%= HotGlue.optionalized_ternary(namespace: @namespace,
|
138
|
+
top_level: true,
|
139
|
+
target: @singular,
|
140
|
+
nested_set: @nested_set,
|
141
|
+
modifier: 'edit_',
|
142
|
+
with_params: true,
|
143
|
+
instance_last_item: true,
|
144
|
+
put_form: true).gsub("(#{singular}", "(@#{singular}") %><% end %>
|
145
|
+
|
146
|
+
<% end %>
|
136
147
|
end
|
137
148
|
|
138
149
|
<% end %>
|
@@ -154,7 +165,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
154
165
|
@action = 'edit'
|
155
166
|
render :edit<% if @pundit %>
|
156
167
|
rescue Pundit::NotAuthorizedError
|
157
|
-
flash[:notice] = "Editing
|
168
|
+
flash[:notice] = "Editing <%= singular + ' ' if @include_object_names %>#{@<%= singular %>.<%= display_class %>} not authorized."
|
158
169
|
render :index <% end %>
|
159
170
|
end
|
160
171
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<\% if <%= singular %>.errors.any? %>
|
4
4
|
<\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: <%= singular %> }) %>
|
5
5
|
<\% end %>
|
6
|
-
<h2>Editing
|
6
|
+
<h2>Editing <%= singular + " " if @include_object_names %><\%= <%= singular %>.<%= display_class %> %></h2>
|
7
7
|
<\%= form_with model: <%= singular %>, url: <%= form_path_edit_helper %><%= ", html: {'data-turbo': false}" if @big_edit %> do |f| %>
|
8
8
|
<\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {:<%= singular %> => <%= singular %>, f: f}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> \%>
|
9
9
|
<% if @edit_within_form_partial %><\%= render partial: "edit_within_form", locals: {f: f, <%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
|
@@ -7,7 +7,9 @@
|
|
7
7
|
</h4><% end %>
|
8
8
|
<% end %>
|
9
9
|
|
10
|
+
<% if @new_button_position == 'above' %>
|
10
11
|
<% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + @controller_build_folder + '/new_button", locals: {}' + @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join() + ' %\>'.gsub('\\',"") %><br /><% end %>
|
12
|
+
<% end %>
|
11
13
|
|
12
14
|
<% unless @no_list %>
|
13
15
|
<% unless @no_list_heading %>
|
@@ -66,5 +68,10 @@
|
|
66
68
|
<% end %>
|
67
69
|
<%= @no_paginate ? "" : paginate %>
|
68
70
|
<% end %>
|
71
|
+
|
72
|
+
|
73
|
+
<% if @new_button_position == 'below' %>
|
74
|
+
<% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + @controller_build_folder + '/new_button", locals: {}' + @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join() + ' %\>'.gsub('\\',"") %><br /><% end %>
|
75
|
+
<% end %>
|
69
76
|
</div>
|
70
77
|
<\% end %>
|
@@ -12,7 +12,12 @@
|
|
12
12
|
<% downnest_object_name = eval("#{downnest_class}.table_name") %>
|
13
13
|
<% downnest_style = @layout_strategy.downnest_style %>
|
14
14
|
<% if !@stacked_downnesting %><div class="<%= @layout_strategy.downnest_portal_column_width(downnest) %> scaffold-downnest" <%= downnest_style %> ><% end %>
|
15
|
-
|
15
|
+
<% if @downnest_shows_headings %>
|
16
|
+
<h3>
|
17
|
+
<%= downnest_object_name.pluralize.humanize %>
|
18
|
+
</h3>
|
19
|
+
<% end %>
|
20
|
+
<\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {
|
16
21
|
<%= @singular %>: <%= @singular %>,
|
17
22
|
<%= downnest_object_name %>: <%= @singular %>.<%= downnest %>
|
18
23
|
}
|
@@ -11,6 +11,7 @@
|
|
11
11
|
|
12
12
|
|
13
13
|
<% if @downnest_children.any? && @big_edit %>
|
14
|
+
<hr />
|
14
15
|
<% each_downnest_width = @downnest_children.count == 1 ? 33 : (53/@downnest_children.count).floor %>
|
15
16
|
<% @downnest_object.each do |downnest, size| %>
|
16
17
|
<div class="row">
|
@@ -20,7 +21,11 @@
|
|
20
21
|
<% downnest_class = downnest_object.class_name %>
|
21
22
|
<% downnest_object_name = eval("#{downnest_class}.table_name") %>
|
22
23
|
<% downnest_style = @layout_strategy.downnest_style %>
|
23
|
-
|
24
|
+
<% if @downnest_shows_headings %>
|
25
|
+
<h3>
|
26
|
+
<%= downnest_class.titlecase.pluralize %>
|
27
|
+
</h3>
|
28
|
+
<% end %>
|
24
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 %> } \%>
|
25
30
|
|
26
31
|
</div>
|
@@ -4,12 +4,38 @@ class <%= ((@namespace.titleize.gsub(" ", "") + "::" if @namespace) || "") + @pl
|
|
4
4
|
<% end %># <%= regenerate_me_code %><% if defined?(RuboCop) %>
|
5
5
|
# rubocop:enable Layout/LineLength <% end %>
|
6
6
|
|
7
|
+
|
8
|
+
<% @nested_set.each do |nest| %>before_action :<%= nest[:singular] %>
|
9
|
+
def <%= nest[:singular] %>
|
10
|
+
@<%= nest[:singular] %> ||= current_user.accounts.find(params[:account_id])
|
11
|
+
end
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<% nest_chain = [] %>
|
15
|
+
<% @nested_set.each { |arg|
|
16
|
+
if @auth_identifier == arg[:singular]
|
17
|
+
this_scope = auth_object
|
18
|
+
elsif nest_chain.empty?
|
19
|
+
this_scope = "#{@auth ? @auth : class_name}.#{arg[:plural]}"
|
20
|
+
else
|
21
|
+
this_scope = "#{nest_chain.last}.#{arg[:plural]}"
|
22
|
+
end
|
23
|
+
nest_chain << arg
|
24
|
+
}%>
|
25
|
+
|
7
26
|
def index
|
8
27
|
<% if @pundit %>authorize <%= @class_name %>, :typeahead? <% end %>
|
9
28
|
query = params[:query]
|
10
29
|
@typeahead_identifier = params[:typeahead_identifier]
|
11
|
-
@<%= @plural %> = <%= @singular.titleize.gsub(" ", "") %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
|
12
30
|
|
31
|
+
|
32
|
+
<% if @nested_set.none? %>
|
33
|
+
@<%= @plural %> = <%= @singular.titleize.gsub(" ", "") %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
|
34
|
+
<% else %>
|
35
|
+
<% @nested_set.each do |arg| %>
|
36
|
+
@<%= @plural %> = <%= @nested_set.last[:singular] %>.<%= @plural %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
|
37
|
+
<% end %>
|
38
|
+
<% end %>
|
13
39
|
render layout: false
|
14
40
|
end
|
15
41
|
end
|
@@ -5,6 +5,10 @@ module HotGlue
|
|
5
5
|
source_root File.expand_path('templates', __dir__)
|
6
6
|
class_option :namespace, type: :string, default: nil
|
7
7
|
class_option :search_by, type: :string, default: nil
|
8
|
+
class_option :nested, type: :string, default: nil
|
9
|
+
class_option :auth, type: :string, default: nil
|
10
|
+
class_option :auth_identifier, type: :string, default: nil
|
11
|
+
|
8
12
|
|
9
13
|
include DefaultConfigLoader
|
10
14
|
def filepath_prefix
|
@@ -28,6 +32,25 @@ module HotGlue
|
|
28
32
|
@class_name = args.first
|
29
33
|
@plural = args.first.tableize.pluralize
|
30
34
|
@namespace = options['namespace']
|
35
|
+
@nested = options['nested'] if options['nested']
|
36
|
+
|
37
|
+
if !@nested.nil?
|
38
|
+
@nested_set = @nested.split("/").collect { |arg|
|
39
|
+
is_optional = arg.start_with?("~")
|
40
|
+
arg.gsub!("~", "")
|
41
|
+
{
|
42
|
+
singular: arg,
|
43
|
+
plural: arg.pluralize,
|
44
|
+
optional: is_optional
|
45
|
+
}
|
46
|
+
}
|
47
|
+
puts "NESTING: #{@nested_set}"
|
48
|
+
else
|
49
|
+
@nested_set = []
|
50
|
+
end
|
51
|
+
|
52
|
+
@auth = options['auth'] || "current_user"
|
53
|
+
@auth_identifier = options['auth_identifier'] || "user"
|
31
54
|
|
32
55
|
if options['search_by']
|
33
56
|
@search_by = options['search_by'].split(",")
|
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.12
|
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:
|
11
|
+
date: 2025-02-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|