hot-glue 0.5.15 → 0.5.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a4b8f9da30750e8df7e69820c0bd934c0f8b16080bb21f5e5412d49c773dd28
4
- data.tar.gz: 66b8fa328ca3f96f12e13c7df2f6006a730ff635078dd7e109d0d42467985502
3
+ metadata.gz: b466a03ce8d764332b3f3d8673bc29b6071308cb976706632a70713b6efb53b4
4
+ data.tar.gz: 03f8580d7266c767b1bed6a1e325c515bc09a5d9886356250ed9a4d936bab452
5
5
  SHA512:
6
- metadata.gz: 45e3e6d56cf8125b67383f68985888a8d131cf2a68643d41e1015f3298b7a0175ff6752a790daed42db151f59b36f567e53b1f293240f393a64498730ee123bd
7
- data.tar.gz: 82c3d1439c5333da6f0427994de3d962a0767453432cc1edd25b7df27532c4e264b033421eb2ff8a3bb2885a1882d6495f58141eceafc3ac04848dda4f240f63
6
+ metadata.gz: 3e0b66aa6cbab6a813a810f6bee04503c0f7437f53dc2a7a2f27aadad8b09a559a1d540f7c6ce850c5a25f641ab847edeb6c5b26fc83c6b6728bb52278bbc3bb
7
+ data.tar.gz: 5bcc706e9ad0a620c33a5815fc5160fe7afef6b9468d1d920032d1daffbfc3bc304816dc661d1c359b1002fdc854d1757869844e7afe1efa2f0eb021df408827
@@ -25,7 +25,7 @@ jobs:
25
25
  steps:
26
26
  - uses: actions/checkout@v3
27
27
  - name: Set up Ruby
28
- uses: ruby/setup-ruby@v1
28
+ uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
29
29
  with:
30
30
  # Not needed with a .ruby-version file
31
31
  # runs 'bundle install' and caches installed gems automatically
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.5.14)
4
+ hot-glue (0.5.16)
5
5
  ffaker (~> 2.16)
6
6
  kaminari (~> 1.2)
7
7
  rails (> 5.1)
@@ -139,7 +139,7 @@ GEM
139
139
  mini_mime (1.1.2)
140
140
  mini_portile2 (2.8.4)
141
141
  minitest (5.16.3)
142
- net-imap (0.3.4)
142
+ net-imap (0.3.7)
143
143
  date
144
144
  net-protocol
145
145
  net-pop (0.1.2)
@@ -235,7 +235,7 @@ GEM
235
235
  stimulus-rails (1.1.1)
236
236
  railties (>= 6.0.0)
237
237
  thor (1.2.1)
238
- timeout (0.3.2)
238
+ timeout (0.4.0)
239
239
  turbo-rails (1.3.2)
240
240
  actionpack (>= 6.0.0)
241
241
  activejob (>= 6.0.0)
@@ -245,7 +245,7 @@ GEM
245
245
  warden (1.2.9)
246
246
  rack (>= 2.0.9)
247
247
  websocket (1.2.9)
248
- websocket-driver (0.7.5)
248
+ websocket-driver (0.7.6)
249
249
  websocket-extensions (>= 0.1.0)
250
250
  websocket-extensions (0.1.5)
251
251
  xpath (3.2.0)
data/README.md CHANGED
@@ -605,9 +605,7 @@ With Hot Glue in specified grouping or smart layout mode, it automatically attem
605
605
 
606
606
  Using Bootstrap with neither specified grouping nor smart layouts may make more than 12 columns, which will produce strange results. (Bootstrap is not designed to work with, for example, a 13-column layout.)
607
607
 
608
- You should typically either specify your grouping or use smart layouts when building with Bootstrap, but if your use case does not fit the stacking feature you can specify neither flag and then you may then have to deal with the over-stuffed layouts as explained.
609
-
610
-
608
+ You should typically either specify your grouping or use smart layouts when building with Bootstrap, but if your use case does not fit the stacking feature you can specify neither flag and then you may then have to deal with the over-stuffed layouts as explained.
611
609
 
612
610
  ### `--smart-layout` (also known as automatic grouping)
613
611
 
@@ -656,6 +654,39 @@ IMPORTANT: By default, all fields that begin with an underscore (`_`) are automa
656
654
 
657
655
  This is for fields you want globally non-editable by users in your app. For example, a counter cache or other field set only by a backend mechanism.
658
656
 
657
+ ### `--modify=field1{...},field2{...}`
658
+
659
+
660
+ You can apply modification to the viewable (non-edit) display of field using the `--modify` switch.
661
+
662
+ The syntax is `--modify=cost{$},price{$}`
663
+
664
+ Here, the `cost` and `price` fields will be displayed as wrapped in `number_to_currency()` when displayed on the list view and when displayed as show-only.
665
+
666
+ You can also use a binary modifier, which can apply to booleans, datetimes, times, dates or anything else. When using the binary modify, a specific value is displayed if the field is truthy and another one is display if the field is falsy.
667
+ You specify it using a pipe | character like so:
668
+
669
+ `--modify=paid_at{paid|unpaid}`
670
+
671
+ here, even though `paid_at` is a datetime field, it will display as-if it is a binary -- showing either the truthy
672
+ label or the falsy label depending on if `paid_at` is or is not null in the database.
673
+ For all fields except booleans, this affects only the viewable output —
674
+ what you see on the list page and on the edit page for show-only fields.
675
+ For booleans, it affects those outputs as well as the normal edit output:
676
+ The labels you specify are used as the labels for the radio buttons that the user can select.
677
+
678
+
679
+ You will need to separately specify them as show-only if you want them to be non-editable.
680
+
681
+ The available modifiers are:
682
+
683
+ | modifier | what it does | can be used on | | |
684
+ |---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|---|---|
685
+ | $ | wraps output in `number_to_currency()` | float, integer | | |
686
+ | truthy label\|falsy label | specify a binary switch with a pipe (\|) character if the value is truthy, it will display as "truthy label" if the value is falsy, it will display as "falsy label" | boolean, datetime, date, time | | |
687
+ | | | | | |
688
+
689
+
659
690
 
660
691
  ### `--update-show-only`
661
692
  (separate field names by COMMA)
@@ -1147,7 +1178,29 @@ Always:
1147
1178
 
1148
1179
  Don't include this last line in your factory code.
1149
1180
 
1181
+ ## Nav Templates
1182
+ At the namespace level, you can have a file called `_nav.html.erb` to create tabbed bootstrap nav (you'll need to create this file manually).
1183
+
1184
+ To create the default template, start by running
1185
+ ```
1186
+ bin/rails generate hot_glue:nav_template --namespace=xyz
1187
+
1188
+ ```
1189
+ this will append the file `_nav.html.erb` to the views folder at `views/xyz`
1190
+
1191
+ ```
1192
+ <ul class='nav nav-tabs'>
1193
+ </ul>
1194
+ ```
1195
+
1196
+ Once the file is present, any further builds in this namespace will:
1150
1197
 
1198
+ 1) Append to the `_nav.html.erb` file, adding a tab for the new built scaffold
1199
+ 2) Add render to the list view of the built scaffold to include the partial:
1200
+ ```
1201
+ <%= render partial: "owner/nav", locals: {nav: "things"} %>
1202
+ ```
1203
+ (in this example `owner/` is the namespace and `things` is the name of the scaffold being built)
1151
1204
 
1152
1205
  ## Automatic Base Controller
1153
1206
 
@@ -1253,6 +1306,41 @@ end
1253
1306
 
1254
1307
  # VERSION HISTORY
1255
1308
 
1309
+ #### 2023-08-18 - v0.5.17
1310
+
1311
+ • Nav templates (`_nav.html.erb`) are now automatically appended to if they exist. Remember nav template live in the views folder at the root of the *namespace*, which is one folder up from whatever folder is being built.
1312
+ If a file exists `_nav.html.erb`, it will get appnded to with content like this:
1313
+
1314
+ ```
1315
+ <li class="nav-item">
1316
+ <%= link_to "Domains", domains_path, class: "nav-link #{'active' if nav == 'domains'}" %>
1317
+ </li>
1318
+ ```
1319
+
1320
+ This append to the `_nav.html.erb` template happens in addition to the partial itself being included from the layout.
1321
+ (Also only if it exists, so be sure create it before running the scaffold generators for the namespace. Of course, you only need to create it once for each namespace)
1322
+
1323
+ • To create a new `_nav.html.erb` template use
1324
+
1325
+ ```
1326
+ bin/rails generate hot_glue:nav_template --namespace=xyz
1327
+ ```
1328
+
1329
+ Here, you give only the namespace. It will create an empty nav template:
1330
+ ```
1331
+ <ul class='nav nav-tabs'>
1332
+ </ul>
1333
+ ```
1334
+
1335
+ • Fixes to specs for datetimes
1336
+
1337
+ • Fixes way the flash notices where created that violated frozen string literal
1338
+
1339
+
1340
+ #### 2023-08-17 - v0.5.16
1341
+
1342
+ - Adds `--modidy` flag to turn numbers into currency and apply binary labels (see docs for `--modify` flag)
1343
+
1256
1344
  #### 2023-08-11 - v0.5.15
1257
1345
 
1258
1346
  - When using big edit, updating a child will now re-render the parent EDIT record automatically.
@@ -1263,7 +1351,6 @@ For example
1263
1351
 
1264
1352
  Whenever the line item is created, updated, or destroyed, the parent invoice record gets (edit action) re-rendered automatically. This happens for the big edit screen of the invoice.
1265
1353
 
1266
-
1267
1354
  - Refactors fields into polymoric objects
1268
1355
 
1269
1356
  - Adds test coverage for Postgres Enums
@@ -57,6 +57,7 @@ class FieldFactory
57
57
  singular: generator.singular,
58
58
  update_show_only: generator.update_show_only,
59
59
  attachment_data: generator.attachments[name.to_sym],
60
- sample_file_path: generator.sample_file_path)
60
+ sample_file_path: generator.sample_file_path,
61
+ modify: generator.modify[name.to_sym] || nil )
61
62
  end
62
63
  end
@@ -8,7 +8,7 @@ class AssociationField < Field
8
8
  def initialize(name: , class_name: , alt_lookups: , singular: , update_show_only: ,
9
9
  hawk_keys: , auth: , sample_file_path:, ownership_field: ,
10
10
  attachment_data: nil , layout_strategy: , form_placeholder_labels: nil,
11
- form_labels_position: )
11
+ form_labels_position:, modify: )
12
12
  super
13
13
 
14
14
  @assoc_model = eval("#{class_name}.reflect_on_association(:#{assoc})")
@@ -2,7 +2,7 @@ class AttachmentField < Field
2
2
  attr_accessor :attachment_data
3
3
  def initialize(name:, class_name:, alt_lookups:, singular:, update_show_only:, hawk_keys:, auth:,
4
4
  sample_file_path: nil, attachment_data:, ownership_field:, layout_strategy: ,
5
- form_placeholder_labels: , form_labels_position:)
5
+ form_placeholder_labels: , form_labels_position:, modify: )
6
6
  super
7
7
 
8
8
  @attachment_data = attachment_data
@@ -13,27 +13,36 @@ class BooleanField < Field
13
13
  end
14
14
 
15
15
  def spec_list_view_assertion
16
- " " + ["expect(page).to have_content(#{singular}#{1}.#{name} ? 'YES' : 'NO')"].join("\n ")
16
+ ["expect(page).to have_content(#{singular}#{1}.#{name} ? 'YES' : 'NO')"].join("\n ")
17
17
  end
18
18
 
19
19
 
20
20
  def form_field_output
21
21
  (form_labels_position == 'before' ? " <br />" : "") +
22
22
  " <%= f.radio_button(:#{name}, '0', checked: #{singular}.#{name} ? '' : 'checked') %>\n" +
23
- " <%= f.label(:#{name}, value: 'No', for: '#{singular}_#{name}_0') %>\n" +
24
- " <%= f.radio_button(:#{name}, '1', checked: #{singular}.#{name} ? 'checked' : '') %>\n" +
25
- " <%= f.label(:#{name}, value: 'Yes', for: '#{singular}_#{name}_1') %>\n" +
23
+ " <%= f.label(:#{name}, value: '#{modify_binary? && modify[:binary][:falsy] || 'No'}', for: '#{singular}_#{name}_0') %>\n" +
24
+ " <br /> <%= f.radio_button(:#{name}, '1', checked: #{singular}.#{name} ? 'checked' : '') %>\n" +
25
+ " <%= f.label(:#{name}, value: '#{modify_binary? && modify[:binary][:truthy] || 'Yes'}', for: '#{singular}_#{name}_1') %>\n" +
26
26
  (form_labels_position == 'after' ? " <br />" : "")
27
27
  end
28
28
 
29
29
  def line_field_output
30
- "
31
- <% if #{singular}.#{name}.nil? %>
30
+ if modify_binary?
31
+ "<% if #{singular}.#{name}.nil? %>
32
+ <span class='alert-danger'>MISSING</span>
33
+ <% elsif #{singular}.#{name} %>
34
+ #{modify[:binary][:truthy]}
35
+ <% else %>
36
+ #{modify[:binary][:falsy]}
37
+ <% end %>"
38
+ else
39
+ "<% if #{singular}.#{name}.nil? %>
32
40
  <span class='alert-danger'>MISSING</span>
33
41
  <% elsif #{singular}.#{name} %>
34
42
  YES
35
43
  <% else %>
36
44
  NO
37
45
  <% end %>"
46
+ end
38
47
  end
39
48
  end
@@ -10,7 +10,11 @@ class DateTimeField < Field
10
10
  end
11
11
 
12
12
  def spec_make_assertion
13
- "expect(page).to have_content(new_#{name}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ') + timezonize(current_timezone))"
13
+ if !modify_binary?
14
+ "expect(page).to have_content(new_#{name}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ') + timezonize(current_timezone))"
15
+ else
16
+ "expect(page).to have_content('#{modify[:binary][:truthy]}'"
17
+ end
14
18
  end
15
19
 
16
20
  def spec_setup_let_arg
@@ -18,7 +22,15 @@ class DateTimeField < Field
18
22
  end
19
23
 
20
24
  def spec_list_view_assertion
21
- "expect(page).to have_content(#{singular}#{1}.#{name}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ').gsub(' ', ' ') + timezonize(current_timezone) )"
25
+ if modify_binary?
26
+ "expect(page).to have_content('#{modify[:binary][:truthy]}')"
27
+ else
28
+ spec_list_view_natural_assertion
29
+ end
30
+ end
31
+
32
+ def spec_list_view_natural_assertion
33
+ "expect(page).to have_content(#{singular}#{1}.#{name}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ').gsub(' ', ' ') + timezonize(current_timezone) )"
22
34
  end
23
35
 
24
36
  def form_field_output
@@ -26,10 +38,14 @@ class DateTimeField < Field
26
38
  end
27
39
 
28
40
  def line_field_output
29
- "<% unless #{singular}.#{name}.nil? %>
41
+ if modify_binary?
42
+ modified_display_output
43
+ else
44
+ "<% unless #{singular}.#{name}.nil? %>
30
45
  <%= #{singular}.#{name}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ') + timezonize(current_timezone) %>
31
46
  <% else %>
32
47
  <span class='alert-danger'>MISSING</span>
33
48
  <% end %>"
49
+ end
34
50
  end
35
51
  end
@@ -1,16 +1,26 @@
1
1
  class Field
2
- attr_accessor :name, :object, :singular_class, :class_name, :singular,
2
+ attr_accessor :assoc_model, :assoc_name, :assoc_class, :associations, :alt_lookups, :auth,
3
+ :assoc_label, :class_name, :form_placeholder_labels, :form_labels_position,
4
+ :hawk_keys, :layout_strategy, :limit, :modify, :name, :object, :sample_file_path,
5
+ :singular_class, :singular, :sql_type, :ownership_field,
3
6
  :update_show_only
4
- attr_accessor :assoc_model, :assoc_name, :assoc_class, :associations, :alt_lookups, :assoc_label
5
-
6
- attr_accessor :hawk_keys, :auth, :sample_file_path, :form_placeholder_labels, :ownership_field,
7
- :sql_type, :limit, :layout_strategy, :form_labels_position
8
-
9
- def initialize(name: , class_name: , alt_lookups: , singular: , update_show_only: , form_labels_position:,
10
- form_placeholder_labels: ,
11
- auth: , ownership_field: , hawk_keys: nil, layout_strategy: ,
12
- sample_file_path: nil, attachment_data: nil )
13
7
 
8
+ def initialize(
9
+ auth: ,
10
+ alt_lookups: ,
11
+ attachment_data: nil,
12
+ class_name: ,
13
+ form_labels_position:,
14
+ form_placeholder_labels: ,
15
+ hawk_keys: nil,
16
+ layout_strategy: ,
17
+ modify: ,
18
+ name: ,
19
+ ownership_field: ,
20
+ sample_file_path: nil,
21
+ singular: ,
22
+ update_show_only:
23
+ )
14
24
  @name = name
15
25
  @layout_strategy = layout_strategy
16
26
  @alt_lookups = alt_lookups
@@ -23,7 +33,7 @@ class Field
23
33
  @form_placeholder_labels = form_placeholder_labels
24
34
  @ownership_field = ownership_field
25
35
  @form_labels_position = form_labels_position
26
-
36
+ @modify = modify
27
37
 
28
38
  # TODO: remove knowledge of subclasses from Field
29
39
  unless self.class == AttachmentField
@@ -52,28 +62,59 @@ class Field
52
62
  ""
53
63
  end
54
64
 
65
+
55
66
  def spec_make_assertion
56
- "expect(page).to have_content(new_#{name})"
67
+ if !modify_binary?
68
+ "expect(page).to have_content(new_#{name})"
69
+ else
70
+ "expect(page).to have_content('#{modify[:binary][:truthy]}'"
71
+ end
57
72
  end
58
73
 
74
+
59
75
  def spec_setup_let_arg
60
76
 
61
77
  end
62
78
 
63
- def spec_list_view_assertion
79
+ def spec_list_view_natural_assertion
64
80
  "expect(page).to have_content(#{singular}#{1}.#{name})"
65
81
  end
66
82
 
83
+ def spec_list_view_assertion
84
+ if modify_binary?
85
+ "expect(page).to have_content('#{modify[:binary][:truthy]}'"
86
+ else
87
+ spec_list_view_natural_assertion
88
+ end
89
+ end
90
+
91
+
67
92
  def spec_related_column_lets
68
93
  ""
69
94
  end
70
95
 
96
+ def line_field_output
97
+ viewable_output
98
+ end
99
+
71
100
  def form_show_only_output
72
- "<%= #{singular}.#{name} %>"
101
+ viewable_output
73
102
  end
74
103
 
75
- def line_field_output
76
- "<%= #{singular}.#{name} %>"
104
+ def viewable_output
105
+ if modify
106
+ modified_display_output
107
+ else
108
+ "<%= #{singular}.#{name} %>"
109
+ end
110
+ end
111
+
112
+ def modified_display_output
113
+ if modify[:cast] && modify[:cast] == "$"
114
+ "<%= number_to_currency(#{singular}.#{name}) %>"
115
+ elsif modify[:binary]
116
+ "<%= #{singular}.#{name} ? '#{modify[:binary][:truthy]}' : '#{modify[:binary][:falsy]}' %>"
117
+ end
77
118
  end
78
119
 
79
120
  def field_output(type = nil, width )
@@ -85,7 +126,10 @@ class Field
85
126
  if lines > 5
86
127
  lines = 5
87
128
  end
88
-
89
129
  "<%= f.text_area :#{name}, class: 'form-control', autocomplete: 'off', cols: 40, rows: '#{lines}'" + ( form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") + " %>"
90
130
  end
131
+
132
+ def modify_binary? # safe
133
+ !!(modify && modify[:binary])
134
+ end
91
135
  end
@@ -5,6 +5,7 @@ class FloatField < Field
5
5
 
6
6
  end
7
7
 
8
+
8
9
  def spec_setup_let_arg
9
10
  "#{name}: rand(1)*10000"
10
11
  end
@@ -13,8 +14,9 @@ class FloatField < Field
13
14
  field_output(nil, 5)
14
15
  end
15
16
 
16
- def line_field_output
17
- width = (limit && limit < 40) ? limit : (40)
18
- "<%= #{singular}.#{name}%>"
19
- end
17
+ # def line_field_output
18
+ # width = (limit && limit < 40) ? limit : (40)
19
+ #
20
+ # "<%= #{singular}.#{name} %>"
21
+ # end
20
22
  end
@@ -5,7 +5,7 @@ class UUIDField < AssociationField
5
5
 
6
6
  def spec_list_view_assertion
7
7
  assoc_name = name.to_s.gsub('_id','')
8
- association = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
8
+ association = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
9
9
  "expect(page).to have_content(#{singular}#{1}.#{assoc_name}.#{HotGlue.derrive_reference_name(association.class_name)})"
10
10
  end
11
11
  end
@@ -16,6 +16,7 @@ module HotGlue
16
16
 
17
17
  @generator = generator
18
18
 
19
+ @modify = generator.modify
19
20
  @columns = generator.columns
20
21
  @smart_layout = generator.smart_layout
21
22
  @stacked_downnesting = generator.stacked_downnesting || false
@@ -39,7 +40,8 @@ module HotGlue
39
40
  portals: {
40
41
 
41
42
  },
42
- buttons: { size: @buttons_width}
43
+ buttons: { size: @buttons_width},
44
+ modify: @modify
43
45
  }
44
46
 
45
47
  # downnest_object.each do |child, size|
@@ -68,7 +70,7 @@ module HotGlue
68
70
  raise "Cannot build layout -- too few columns"
69
71
  end
70
72
 
71
- # smart layout: bootstrap_column_width columns per field; 4 column for EACH downnested portals, 2 column for buttons
73
+ # smart layout: bootstrap_column_width columns per field; 4 column for EACH downnested portal, 2 column for buttons
72
74
  if smart_layout
73
75
  # automatic control
74
76
  #
@@ -0,0 +1,22 @@
1
+ module HotGlue
2
+ class NavTemplateGenerator < Rails::Generators::Base
3
+ source_root File.expand_path('templates', __dir__)
4
+ class_option :namespace, type: :string, default: nil
5
+
6
+ def filepath_prefix
7
+ # todo: inject the context
8
+ 'spec/dummy/' if $INTERNAL_SPECS
9
+ end
10
+
11
+
12
+ def initialize(*args) #:nodoc:
13
+ super
14
+ @namespace = options['namespace']
15
+ copy_file "erb/_nav.html.erb", "#{'spec/dummy/' if $INTERNAL_SPECS}app/views/#{@namespace ? @namespace + "/" : ""}_nav.html.erb"
16
+
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+