hot-glue 0.4.9.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -2
- data/Gemfile.lock +1 -1
- data/README.md +135 -65
- data/app/helpers/hot_glue/controller_helper.rb +5 -23
- data/lib/generators/hot_glue/install_generator.rb +1 -6
- data/lib/generators/hot_glue/markup_templates/erb.rb +135 -89
- data/lib/generators/hot_glue/scaffold_generator.rb +35 -10
- data/lib/generators/hot_glue/templates/controller.rb.erb +10 -5
- data/lib/generators/hot_glue/templates/erb/_list.erb +2 -2
- data/lib/hotglue/version.rb +1 -1
- metadata +3 -4
- data/lib/generators/hot_glue/templates/confirmable.js +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fe06433ca491d353bbc997003fdbc3735fd3bdf35692c35a25237fcaedf73db
|
4
|
+
data.tar.gz: 42b4b9077a245b75d0878e4bb84e866e8c5b7b61b4f9efd9ea1213678e7def7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 657b12337809a015a32567497a6564afa738e2e29ca4cd4aff142a8d9e5718f15237a69b49b708b164f71d9f98f2b7ed7f21cc1130e45f78306dea4e9a93b00a
|
7
|
+
data.tar.gz: ac4aed4acb2c70df780f248f024834bf4b055aff18f8438d63415498616a2e8363ff489898f001ee8fbb7885ba99c926d80dbbb659b82f442f6a709bebbaafda
|
data/.github/FUNDING.yml
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
custom: ["https://heliosdev.shop/p/hot-glue?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link"
|
2
|
-
"https://jfbcodes.com/p/hot-glue-in-depth-tutorial?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link"]
|
1
|
+
custom: ["https://heliosdev.shop/p/hot-glue/","https://jfbcodes.com/p/hot-glue-in-depth-tutorial?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link"]
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,24 +3,24 @@
|
|
3
3
|
|
4
4
|
Hot Glue is a Rails scaffold builder for the Turbo era. It is an evolution of the admin-interface style scaffolding systems of the 2010s ([activeadmin](https://github.com/activeadmin/activeadmin), [rails_admin](https://github.com/sferik/rails_admin), and [active_scaffold](https://github.com/activescaffold/active_scaffold)).
|
5
5
|
|
6
|
-
Using Turbo-Rails and Hotwire (default in Rails 7) you get a lightning-fast out-of-the-box CRUD
|
6
|
+
Using Turbo-Rails and Hotwire (default in Rails 7) you get a lightning-fast out-of-the-box CRUD-building experience.
|
7
7
|
|
8
|
-
Every page displays only a list view: new and edit operations happen as 'edit-in-place'
|
8
|
+
Every page displays only a list view: new and edit operations happen as 'edit-in-place,' so the user never leaves the page.
|
9
9
|
|
10
|
-
Because all page navigation is Turbo's
|
10
|
+
Because all page navigation is Turbo's responsibility, everything plugs & plays nicely into a Turbo-backed Rails app.
|
11
11
|
|
12
|
-
Alternatively, you can use this tool to create a Turbo-backed *section* of your Rails app--
|
12
|
+
Alternatively, you can use this tool to create a Turbo-backed *section* of your Rails app -- such as an admin interface -- while still treating the rest of the Rails app as an API or building out other features by hand.
|
13
13
|
|
14
|
-
It will read your relationships and field types to generate your code for you, leaving you with a 'sourdough starter' to work from. If you modify the generated code, you're on your own if you want to preserve your changes and also re-generate
|
14
|
+
It will read your relationships and field types to generate your code for you, leaving you with a 'sourdough starter' to work from. If you modify the generated code, you're on your own if you want to preserve your changes and also re-generate scaffolding after adding fields.
|
15
15
|
|
16
16
|
By default, it generates code that gives users full control over objects they 'own' and by default it spits out functionality giving access to all fields.
|
17
17
|
|
18
|
-
Hot Glue generates functionality that
|
18
|
+
Hot Glue generates functionality that is quick and dirty. It lets you be crafty. As with a real glue gun, use it with caution.
|
19
19
|
|
20
20
|
* Build plug-and-play scaffolding mixing generated ERB with the power of Hotwire and Turbo-Rails
|
21
|
-
* Everything edits-in-place (unless you use `--big-edit
|
22
|
-
* Automatically
|
23
|
-
* Excellent for CREATE-READ-UPDATE-DELETE (CRUD), lists with pagination
|
21
|
+
* Everything edits-in-place (unless you use `--big-edit`)
|
22
|
+
* Automatically reads your models (make them AND migrate your database before building your scaffolding!)
|
23
|
+
* Excellent for CREATE-READ-UPDATE-DELETE (CRUD), lists with pagination
|
24
24
|
* Great for prototyping, but you should learn Rails fundamentals first.
|
25
25
|
* 'Packaged' with Devise, Kaminari, Rspec, FontAwesome
|
26
26
|
* Create system specs automatically along with the generated code.
|
@@ -37,8 +37,19 @@ Hot Glue generates functionality that's quick and dirty. It lets you be crafty.
|
|
37
37
|
| ![Teachable-225x225](https://user-images.githubusercontent.com/59002/147857335-a919e095-e6de-4718-8513-736d1f283a0b.png) | Now avaiale on [Teachable](https://jfb.teachable.com/courses/hot-glue-in-depth-tutorial/?utm_source=github.com&utm_campaign=github_hot_glue_readme_page) |
|
38
38
|
|
39
39
|
|
40
|
+
---
|
41
|
+
|
42
|
+
|
43
|
+
## NEW GETTING STARTED VIDEO
|
44
|
+
The getting started video is newly updated with an explanation of the options for **`jsbundling-rails`/`cssbudling-rails`** when creating a new Rails 7 app.
|
40
45
|
|
46
|
+
Check it out on Youtube at https://www.youtube.com/watch?v=bKjKHMTvzZc
|
41
47
|
|
48
|
+
While you're over there could you give my Youtube channel a 'Subscribe'? (look for the RED SUBSCRIBE BUTTON) Thanks so much!
|
49
|
+
|
50
|
+
|
51
|
+
---
|
52
|
+
|
42
53
|
|
43
54
|
## HOW EASY?
|
44
55
|
|
@@ -68,9 +79,9 @@ Confirm that both Stimulus and Turbo are working.
|
|
68
79
|
|
69
80
|
**If using JSBundling, make sure to use the new `bin/dev rails` instead of the old `rails server` or else your Webpack will not compile.**
|
70
81
|
|
71
|
-
For the quick step-by-step to help you confirm that both Stimulus and Turbo are working for your new JSBundling-Rails/CSSBunlding-Rails setup [see this post](https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-new-app-with-js-bundling-css-bundling/).
|
82
|
+
For the quick step-by-step guide to help you confirm that both Stimulus and Turbo are working for your new JSBundling-Rails/CSSBunlding-Rails setup [see this post](https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-new-app-with-js-bundling-css-bundling/).
|
72
83
|
|
73
|
-
(Note that Bootstrap is optional for Hot Glue. Here, I am just showing you the default
|
84
|
+
(Note that Bootstrap is optional for Hot Glue. Here, I am just showing you the default installation for simplicity.)
|
74
85
|
|
75
86
|
For the old method of installing Bootstrap [see this post](https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-bootstrap/)
|
76
87
|
|
@@ -92,18 +103,20 @@ gem 'ffaker'
|
|
92
103
|
## 3. HOTGLUE INSTALLER
|
93
104
|
Add `gem 'hot-glue'` to your Gemfile & `bundle install`
|
94
105
|
|
95
|
-
Purchase a license at https://heliosdev.shop/hot-glue
|
106
|
+
Purchase a license at https://heliosdev.shop/p/hot-glue
|
96
107
|
|
97
108
|
During in installation, you MUST supply a `--layout` flag.
|
98
109
|
|
99
|
-
### `--layout` flag (
|
110
|
+
### `--layout` flag (only two options: `hotglue` or `bootstrap`; default is `bootstrap`)
|
100
111
|
Here you will set up and install Hot Glue for the first time.
|
101
112
|
|
102
113
|
It will install a config file that will save two preferences: layout (`hotglue` or `bootstrap`)
|
103
114
|
|
104
115
|
The installer will create `config/hot_glue.yml`.
|
105
116
|
|
106
|
-
|
117
|
+
|
118
|
+
### `--theme` flag
|
119
|
+
During the installation, **if** your `--layout` flag is set to `hotglue` you must also pass `--theme` flag.
|
107
120
|
|
108
121
|
the themes are:
|
109
122
|
• like_mountain_view (Google)
|
@@ -112,15 +125,16 @@ the themes are:
|
|
112
125
|
• dark_knight (_The Dark Night_ (2008) inspired)
|
113
126
|
• like_cupertino (modern Apple-UX inspired)
|
114
127
|
|
115
|
-
### `--markup` flag
|
116
128
|
|
117
|
-
|
129
|
+
### `--markup` flag (NOTE: haml and slim are no longer supported at this time)
|
130
|
+
|
131
|
+
default is `erb`. IMPORTANT: As of right now, HAML and SLIM are not currently supported so the only option is also the default `erb`.
|
118
132
|
|
119
133
|
|
120
134
|
### example installing ERB using Bootstrap layout:
|
121
135
|
`rails generate hot_glue:install --markup=erb --layout=bootstrap`
|
122
136
|
|
123
|
-
### Example installing
|
137
|
+
### Example installing using Hot Glue layout and the 'like_mountain_view' (Gmail-inspired) theme:
|
124
138
|
`rails generate hot_glue:install --markup=erb --layout=hotglue --theme=like_mountain_view`
|
125
139
|
|
126
140
|
The Hot Glue installer did several things for you in this step. Examine the git diffs or see 'Hot Glue Installer Notes' below.
|
@@ -140,11 +154,11 @@ https://github.com/FortAwesome/font-awesome-sass
|
|
140
154
|
|
141
155
|
Add to your Gemfile
|
142
156
|
|
143
|
-
As of
|
157
|
+
As of now, Devise for Rails 7 is still not released so you must use **main branch**, like so:
|
144
158
|
|
145
159
|
`gem 'devise', branch: 'main', git: 'https://github.com/heartcombo/devise.git'`
|
146
160
|
|
147
|
-
(If you are on Rails 6, you must do ALL of the steps in the Legacy Setup steps. Be sure not to skip **Legacy Step #5**
|
161
|
+
(If you are on Rails 6, you must do ALL of the steps in the Legacy Setup steps. Be sure not to skip **Legacy Step #5** below)
|
148
162
|
|
149
163
|
For Rails 7, be sure you are on the main branch of devise above and your logins should work. (The previously necessary step of disabling turbo shown in Legacy Step #5 is no longer needed. )
|
150
164
|
|
@@ -205,7 +219,7 @@ this may not have been automatically applied by the installer.
|
|
205
219
|
#### Hot Glue switched Capybara from RACK-TEST to HEADLESS CHROME
|
206
220
|
|
207
221
|
- By default Capybara is installed with :rack_test as its driver.
|
208
|
-
- This does not support Javascript
|
222
|
+
- This does not support Javascript. Hot Glue is not targeted for fallback browsers.
|
209
223
|
- From the [Capybara docs](https://github.com/teamcapybara/capybara#drivers):
|
210
224
|
```
|
211
225
|
By default, Capybara uses the :rack_test driver, which is fast but limited: it does not support JavaScript
|
@@ -300,7 +314,7 @@ end
|
|
300
314
|
|
301
315
|
### `--nested=`
|
302
316
|
|
303
|
-
This object is nested within another tree of objects, and there is a nested route in your `routes.rb` file. When specifying the parent(s), be sure to use **singular case**.
|
317
|
+
This object is nested within another tree of objects, and there is a nested route in your `routes.rb` file with the specified parent controllers above this controller. When specifying the parent(s), be sure to use **singular case**.
|
304
318
|
|
305
319
|
#### Example #1: One-level Nesting
|
306
320
|
Invoice `has_many :lines` and a Line `belongs_to :invoice`
|
@@ -364,11 +378,11 @@ This is "starfish access control" or "poor man's access control." It works when
|
|
364
378
|
|
365
379
|
#### Optionalized Nested Parents
|
366
380
|
|
367
|
-
Add `~` in front of any nested parameter (any parent in the `--
|
381
|
+
Add `~` in front of any nested parameter (any parent in the `--nested` list) you want to make optional. This creates a two-headed controller: It can operate with or without that optionalized parameter.
|
368
382
|
|
369
|
-
This is an advanced feature
|
383
|
+
This is an advanced feature. To use, **make duplicative routes to the same controller**. You can only use this feature with Gd controller.
|
370
384
|
|
371
|
-
Specify your controller *twice* in your routes.rb. Then, in your `--
|
385
|
+
Specify your controller *twice* in your routes.rb. Then, in your `--nested` setting, add `~` to any nested parent you want to **make optional**. "Make optional" means the controller will behave as-if it exists in two places: once, at the normal nest level. Then the same controller will 'exist' again one-level up in your routes. **If the route has sub-routes, you'll need to re-specify the entire subtree also**.
|
372
386
|
```
|
373
387
|
namespace :admin
|
374
388
|
resources :users do
|
@@ -378,15 +392,15 @@ namespace :admin
|
|
378
392
|
end
|
379
393
|
```
|
380
394
|
|
381
|
-
Even though we have two routes pointed to invoices
|
395
|
+
Even though we have two routes pointed to **invoices**, both will go to the same controller (`app/controllers/admin/invoices_controller.rb`)
|
382
396
|
|
383
397
|
```
|
384
|
-
rails generate hot_glue:scaffold User --namespace=admin --gd
|
385
|
-
rails generate hot_glue:scaffold Invoice --namespace=admin --gd --
|
398
|
+
rails generate hot_glue:scaffold User --namespace=admin --gd
|
399
|
+
rails generate hot_glue:scaffold Invoice --namespace=admin --gd --nested=~users
|
386
400
|
```
|
387
401
|
Notice for the Invoice build, the parent user is *optionalized* (not 'optional'-- optionalized: to be made so it can be made optional).
|
388
402
|
|
389
|
-
The Invoices controller, which is a Gd controller, will load the User if a user is specified in the route (`/admin/users/:user_id/invoices/`). It will ALSO work at `/admin/invoices` and will switch back into loading directly from the base class when routed
|
403
|
+
The Invoices controller, which is a Gd controller, will load the User if a user is specified in the route (`/admin/users/:user_id/invoices/`). It will ALSO work at `/admin/invoices` and will switch back into loading directly from the base class when routed without the parent user.
|
390
404
|
|
391
405
|
|
392
406
|
|
@@ -394,11 +408,11 @@ The Invoices controller, which is a Gd controller, will load the User if a user
|
|
394
408
|
|
395
409
|
By default, it will be assumed you have a `current_user` for your user authentication. This will be treated as the "authentication root" for the "poor man's auth" explained above.
|
396
410
|
|
397
|
-
The poor man's auth presumes that object graphs have only one natural way to traverse them (that is, one primary way to traverse them), and that all relationships infer that a set of things or their descendants are granted access to me for reading, writing, updating, and deleting.
|
411
|
+
The poor man's auth presumes that object graphs have only one natural way to traverse them (that is, one primary way to traverse them), and that all relationships infer that a set of things or their descendants are granted access to "me" for reading, writing, updating, and deleting.
|
398
412
|
|
399
413
|
Of course this is a sloppy way to do access control, and can easily leave open endpoints your real users shouldn't have access to.
|
400
414
|
|
401
|
-
When you display anything built with the scaffolding,
|
415
|
+
When you display anything built with the scaffolding, Hot Glue assumes the `current_user` will have `has_many` association that matches the pluralized name of the scaffold. In the case of nesting, we will automatically find the nested objects first, then continue down the nest chain to find the target object. This is how Hot Glue assumes all object are 'anchored' to the logged-in user. (As explained in the `--nested` section.)
|
402
416
|
|
403
417
|
If you use Devise, you probably already have a `current_user` method available in your controllers. If you don't use Devise, you can implement it in your ApplicationController.
|
404
418
|
|
@@ -444,6 +458,8 @@ The default (do not pass `auth_identifier=`) will match the `auth` (So if you us
|
|
444
458
|
|
445
459
|
|
446
460
|
`rails generate hot_glue:scaffold Thing --auth=current_account --auth_identifier=login`
|
461
|
+
|
462
|
+
|
447
463
|
In this example, the controller produced with:
|
448
464
|
```
|
449
465
|
before_action :authenticate_login!
|
@@ -454,11 +470,12 @@ However, the object graph anchors would continue to start from current_account.
|
|
454
470
|
```
|
455
471
|
|
456
472
|
Use empty string to **turn this method off**:
|
473
|
+
|
457
474
|
`rails generate hot_glue:scaffold Thing --auth=current_account --auth_identifier=''`
|
458
475
|
|
459
476
|
In this case a controller would be generated that would have NO before_action to authenticate the account, but it would still treat the current_account as the auth root for the purpose of loading the objects.
|
460
477
|
|
461
|
-
Please note that this example would
|
478
|
+
Please note that this example would produce non-functional code, so you would need to manually fix your controllers to make sure `current_account` is available to the controller.
|
462
479
|
|
463
480
|
|
464
481
|
### `--plural=`
|
@@ -466,17 +483,24 @@ Please note that this example would product non-functional code, so you would ne
|
|
466
483
|
You don't need this if the pluralized version is just + "s" of the singular version. Only use for non-standard plurlizations, and be sure to pass it as TitleCase (as if you pluralized the model name which is non-standard for Rails)
|
467
484
|
|
468
485
|
|
486
|
+
### `--form-labels-position` (default: `after`; options are **before**, **after**, and **omit**)
|
487
|
+
By default form labels appear after the form inputs. To make them appear before or omit them, use this flag.
|
488
|
+
|
489
|
+
See also `--form-placeholder-labels` to use placeolder labels.
|
490
|
+
|
491
|
+
|
492
|
+
|
469
493
|
### `--exclude=`
|
470
494
|
(separate field names by COMMA)
|
471
495
|
|
472
|
-
By default, all fields are included unless they are on the exclude list. (The default
|
496
|
+
By default, all fields are included unless they are on the default exclude list. (The default exclude list is `id`, `created_at`, `updated_at`, `encrypted_password`, `reset_password_token`, `reset_password_sent_at`, `remember_created_at`, `confirmation_token`, `confirmed_at`, `confirmation_sent_at`, `unconfirmed_email`.)
|
473
497
|
|
474
|
-
If you specify
|
498
|
+
If you specify any exclude list, those excluded **and** the default exclude list will be excluded. (If you need any of the fields on the default exclude list, you must use `--include` instead.)
|
475
499
|
|
476
500
|
|
477
501
|
`rails generate hot_glue:scaffold Account --exclude=password`
|
478
502
|
|
479
|
-
(The default excluded list is:
|
503
|
+
(The default excluded list is: If you want to edit any fields with the same name, you must use the include flag instead.)
|
480
504
|
|
481
505
|
|
482
506
|
### `--include=`
|
@@ -488,42 +512,46 @@ If you specify an include list, it will be treated as a whitelist: no fields wil
|
|
488
512
|
|
489
513
|
You may not specify both include and exclude.
|
490
514
|
|
491
|
-
Include setting is affected by both specified grouping and
|
515
|
+
Include setting is affected by both specified grouping mode and smart layouts, explained below.
|
492
516
|
|
493
517
|
|
494
518
|
#### Specified Grouping Mode
|
495
519
|
|
496
520
|
To specify grouped columns, separate COLUMNS by a COLON, then separate fields with commas. Specified groupings work like smart layouts (see below), except you drive which groupings make up the columns.
|
497
521
|
|
498
|
-
(
|
522
|
+
(Smart layouts, below, achieves the same effect but automatically group your fields into a smart number of columns.)
|
499
523
|
|
500
524
|
If you want to group up fields together into columns, use a COLON (`:`) character to specify columns.
|
501
525
|
|
502
526
|
Your input **may** have a COLON at the end of it, but otherwise your columns will made **flush left**.
|
503
527
|
|
504
|
-
Without specified grouping (and not using smart layout), no
|
505
|
-
|
506
|
-
|
507
|
-
With a trailing colon you would be specifying the grouping. You're telling Hot Glue to make the two fields into column #1. (There is no other column.)
|
508
|
-
`--include=api_id,api_key:`
|
528
|
+
Without specified grouping (and not using smart layout), no grouping will happen. So these two fields would display in two (small, 1-column Bootstrap) columns:
|
529
|
+
|
530
|
+
`--include=first,last`
|
509
531
|
|
532
|
+
With a **trailing colon** you switch Hot Glue into specified grouping mode. You're telling Hot Glue to make the two fields into column #1. (There is no other column.)
|
533
|
+
`--include=first,last:`
|
510
534
|
|
511
|
-
|
512
|
-
`--include=name:api_id,api_key`
|
535
|
+
Hot Glue also happens to know that, for example, when you say "one column" you really want _one visual_ column made up of the available Bootstrap columns. For example, with 1 child portal (4) + the default edit/create buttons (2), you would have 6 remaining bootstrap columns (2+4+6=12). With 6 remaining Bootstrap columns Hot Glue will make 1 _visual colum_ into a 6-column Bootstrap column.
|
513
536
|
|
537
|
+
If, for example, you wanted to put the `email` field into column #1 and then the `first` and `last` into column #2, you would use:
|
538
|
+
`--include=email:first,last`
|
514
539
|
|
540
|
+
Assuming we have the same number of columns as the above example (6), Hot Glue knows that you now have 2 _visual columns_. It then gives each visual column 3-colum bootstrap columns, which makes your layout into a 3+3+4+2=12 Bootstrap layout.
|
515
541
|
|
516
|
-
Specifying any colon in your include syntax switches the builder into specified grouping mode
|
542
|
+
**Specifying any colon in your include syntax switches the builder into specified grouping mode.**
|
543
|
+
|
544
|
+
The effect will be that the fields will be stacked together into nicely fit columns. (This will look confusing if your end-user is expecting an Excel-like interface.)
|
517
545
|
|
518
|
-
With
|
546
|
+
With Hot Glue in specified grouping or smart layout mode, it automatically attempts to fit everything into Bootstrap 12-columns.
|
519
547
|
|
520
|
-
Using Bootstrap with neither specified grouping nor smart layouts may make 12 columns, which will produce strange
|
548
|
+
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.)
|
521
549
|
|
522
550
|
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.
|
523
551
|
|
524
552
|
|
525
553
|
|
526
|
-
### `--smart-layout`
|
554
|
+
### `--smart-layout` (also known as automatic grouping)
|
527
555
|
|
528
556
|
Smart layouts are like specified grouping but Hot Glue does the work of figuring out how many fields you want in each column.
|
529
557
|
|
@@ -535,7 +563,7 @@ The effect will be that the fields will be stacked together into nicely fit colu
|
|
535
563
|
|
536
564
|
**If your customer is used to Excel, this feature will confuse them.**
|
537
565
|
|
538
|
-
Also, this feature will **probably not** be supported by the SORTING (not yet implemented
|
566
|
+
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.)
|
539
567
|
|
540
568
|
The layout builder works from right-to-left and starts with 12, the number of Bootstrap's columns.
|
541
569
|
|
@@ -547,7 +575,7 @@ If you're keeping track, that means we may have used 6 to 8 out of our Bootstrap
|
|
547
575
|
|
548
576
|
If we have 2 downnested portals and only the default buttons, that uses 10 out of 12 Bootstrap columns, leaving only 2 bootstrap columns for the fields.
|
549
577
|
|
550
|
-
The layout builder takes the number of columns
|
578
|
+
The layout builder takes the number of columns remaining and then distributes the feilds 'evenly' among them. However, note that order specified translates to up-to-down within the column, and then left-to-right across the columns, like so:
|
551
579
|
|
552
580
|
A D G
|
553
581
|
|
@@ -557,7 +585,7 @@ C F I
|
|
557
585
|
|
558
586
|
This is what would happen if 9 fields, specified in the order A,B,C,D,E,F,G,H,I, were distributed across 3 columns.
|
559
587
|
|
560
|
-
(If you had a number of fields that wasn't easily divisible by the number of columns, it would leave the final column a few fields short of the others.)
|
588
|
+
(If you had a number of fields that wasn't easily divisible by the number of columns, it would leave the final column one or a few fields short of the others.)
|
561
589
|
|
562
590
|
|
563
591
|
|
@@ -658,39 +686,58 @@ Omits pagination. (All list views have pagination by default.)
|
|
658
686
|
|
659
687
|
### `--no-list`
|
660
688
|
|
661
|
-
Omits list action. Only makes sense to use this if
|
689
|
+
Omits list action. Only makes sense to use this if want to create a view where you only want the create button or to navigate to the update screen alternative ways. (The new/create still appears, as well the edit, update & destroy actions are still created even though there is no natural way to navigate to them.)
|
662
690
|
|
663
691
|
|
664
|
-
### `--no-list-
|
692
|
+
### `--no-list-label`
|
665
693
|
|
666
|
-
Omits list
|
694
|
+
Omits list LABEL itself above the list. (Do not confuse with the list heading which contains the field labels.)
|
667
695
|
|
668
|
-
|
696
|
+
(Note that on a per model basis, you can also globally omit the label or set a unique label value using
|
697
|
+
`@@table_label_singular` and `@@table_label_plural` on your model objects.)
|
669
698
|
|
670
|
-
|
699
|
+
Note that list labels may be automatically omitted on downnested scaffolds.
|
671
700
|
|
672
|
-
|
673
|
-
|
701
|
+
### `--form-placeholder-labels` (default: false)
|
702
|
+
|
703
|
+
When set to true, fields, numbers, and text areas will have placeholder labels.
|
704
|
+
Will not apply to dates, times, datetimes, dropdowns (enums + foreign keys), or booleans.
|
705
|
+
|
706
|
+
See also setting `--form-labels-position` to control position or omit normal labels.
|
707
|
+
|
708
|
+
### `--inline-list-labels` (before, after, omit; default: omit)
|
709
|
+
|
710
|
+
Determines if field label will appear on the LIST VIEW. NOoe that because Hot Glue has no sparate show route or page,
|
711
|
+
this affects the `_show` template which is rendered as a partial from the LIST view.
|
712
|
+
|
713
|
+
Because the labels are already in the heading, this `omit` by default. (Use with `--no-list-heading` to omit the labels in the list heading.)
|
714
|
+
|
715
|
+
Use `before` to make the labels come before or `after` to make them come after. See Version 0.5.1 release notes for an example.
|
716
|
+
|
717
|
+
|
718
|
+
### `--no-list-heading`
|
719
|
+
|
720
|
+
Omits the heading of column names that appears above the 1st row of data.
|
674
721
|
|
675
722
|
### `--no-create`
|
676
723
|
|
677
|
-
Omits create
|
724
|
+
Omits new & create actions.
|
678
725
|
|
679
726
|
### `--no-delete`
|
680
727
|
|
681
|
-
Omits delete action.
|
728
|
+
Omits delete button & destroy action.
|
682
729
|
|
683
730
|
### `--big-edit`
|
684
731
|
|
685
|
-
If you do not want inline editing of your list items but instead to fall back to full page style behavior for your edit views, use `--big-edit`. Turbo still handles the page interactions, but the user is taken to a full-screen edit page instead of an edit-in-place interaction.
|
732
|
+
If you do not want inline editing of your list items but instead want to fall back to full page style behavior for your edit views, use `--big-edit`. Turbo still handles the page interactions, but the user is taken to a full-screen edit page instead of an edit-in-place interaction.
|
686
733
|
|
687
|
-
### `--display-list-after-update`
|
734
|
+
### `--display-list-after-update`
|
688
735
|
|
689
736
|
After an update-in-place normally only the edit view is swapped out for the show view of the record you just edited.
|
690
737
|
|
691
738
|
Sometimes you might want to redisplay the entire list after you make an update (for example, if your action removes that record from the result set).
|
692
739
|
|
693
|
-
To do this, use flag `--
|
740
|
+
To do this, use flag `--display-list-after-update`. The update will behave like delete and re-fetch all the records in the result and tell Turbo to swap out the entire list.
|
694
741
|
|
695
742
|
|
696
743
|
|
@@ -700,14 +747,14 @@ To do this, use flag `--display_list_after_update`. The update will behave like
|
|
700
747
|
|
701
748
|
HotGlue will copy a file named base_controller.rb to the same folder where it tries to create any controller, unless such a file exists there already.
|
702
749
|
|
703
|
-
|
750
|
+
The created controller will always have this base controller as its subclass. You are encouraged to implement functionality common to the *namespace* (shared between the controllers in the namespace) using this technique.
|
704
751
|
|
705
752
|
## Special Table Labels
|
706
753
|
|
707
754
|
If your object is very wordy (like MyGreatHook) and you want it to display in the UI as something shorter,
|
708
|
-
add `@@table_label_plural = "
|
755
|
+
add `@@table_label_plural = "Hooks"` and `@@table_label_singular = "Hook"`.
|
709
756
|
|
710
|
-
Hot Glue will use this as the
|
757
|
+
Hot Glue will use this as the **list heading** and **New record label**, respectively. This affects only the UI only.
|
711
758
|
|
712
759
|
You can also set these to `nil` to omit the labels completely.
|
713
760
|
|
@@ -727,10 +774,33 @@ Child portals have the headings omitted automatically (there is a heading identi
|
|
727
774
|
- Time: displayed as HTML5 time picker
|
728
775
|
- Boolean: displayed radio buttons yes/ no
|
729
776
|
- Enum - displayed as a drop-down list (defined the enum values on your model). For Rails 6 see https://jasonfleetwoodboldt.com/courses/stepping-up-rails/enumerated-types-in-rails-and-postgres/
|
777
|
+
- AFAIK, you must specify the enum definition both in your model and also in your database migration for both Rails 6 + Rails 7
|
730
778
|
|
731
779
|
|
732
780
|
# VERSION HISTORY
|
733
781
|
|
782
|
+
#### 2022-03-12 - v0.5.1 - Inline list Labels
|
783
|
+
|
784
|
+
`--inline-list-labels` (default: `after`; options are **before**, **after**, and **omit**)
|
785
|
+
|
786
|
+
Determines if field label will appear on the LIST VIEW. Note that because Hot Glue has no separate show route or page, this affects the `_show` template which is rendered as a partial from the LIST view.
|
787
|
+
|
788
|
+
Because the labels are already in the heading, this `omit` by default. (Use with `--no-list-heading` to omit the labels in the list heading.)
|
789
|
+
|
790
|
+
Use `before` to make the labels come before or `after` to make them come after. See Version 0.5.1 release notes for an example.
|
791
|
+
|
792
|
+
#### 2022-03-06 - v0.5.0 - Label options before or after or with placeholder labels
|
793
|
+
`--form-labels-position` (default: `after`; options are **before**, **after**, and **omit**)
|
794
|
+
By default, form labels appear after the form inputs. To make them appear before or omit them, use this flag.
|
795
|
+
|
796
|
+
`--form-placeholder-labels` (default: false)
|
797
|
+
|
798
|
+
When this flag is set, fields, numbers, and text areas will have placeholder labels.
|
799
|
+
Will not apply to dates, times, datetimes, dropdowns (enums + foreign keys), or booleans.
|
800
|
+
|
801
|
+
For example see the [release notes](https://github.com/jasonfb/hot-glue/releases/tag/v0.5.0)
|
802
|
+
|
803
|
+
|
734
804
|
#### 2022-02-14 - v0.4.9
|
735
805
|
• Fixed issue building models with namespaced class names (e.g. `Fruits::Apple` and `Fruits::Bannana`).
|
736
806
|
You can now build against these kinds of models natively (be sure to pass the full model name, with double-colon syntax).
|
@@ -8,43 +8,25 @@ module HotGlue
|
|
8
8
|
|
9
9
|
|
10
10
|
def datetime_field_localized(form_object, field_name, value, label, timezone = nil )
|
11
|
-
|
12
|
-
field_name,
|
13
|
-
class: 'small form-text text-muted')
|
14
|
-
|
15
|
-
res << form_object.text_field(field_name, class: 'form-control',
|
11
|
+
form_object.text_field(field_name, class: 'form-control',
|
16
12
|
type: 'datetime-local',
|
17
13
|
value: date_to_current_timezone(value, timezone))
|
18
|
-
|
19
|
-
res << timezonize(timezone)
|
20
|
-
res
|
14
|
+
+ timezonize(timezone)
|
21
15
|
end
|
22
16
|
|
23
17
|
|
24
18
|
def date_field_localized(form_object, field_name, value, label, timezone = nil )
|
25
|
-
|
26
|
-
res = form_object.label(label,
|
27
|
-
field_name,
|
28
|
-
class: 'small form-text text-muted')
|
29
|
-
|
30
|
-
res << form_object.text_field(field_name, class: 'form-control',
|
19
|
+
form_object.text_field(field_name, class: 'form-control',
|
31
20
|
type: 'date',
|
32
21
|
value: value )
|
33
|
-
|
34
|
-
res
|
35
22
|
end
|
36
23
|
|
37
24
|
def time_field_localized(form_object, field_name, value, label, timezone = nil )
|
38
|
-
|
39
|
-
field_name,
|
40
|
-
class: 'small form-text text-muted')
|
41
|
-
|
42
|
-
res << form_object.text_field(field_name, class: 'form-control',
|
25
|
+
form_object.text_field(field_name, class: 'form-control',
|
43
26
|
type: 'time',
|
44
27
|
value: date_to_current_timezone(value, timezone))
|
28
|
+
+ timezonize(timezone)
|
45
29
|
|
46
|
-
res << timezonize(timezone)
|
47
|
-
res
|
48
30
|
end
|
49
31
|
|
50
32
|
def current_timezone
|
@@ -38,7 +38,7 @@ module HotGlue
|
|
38
38
|
require 'open-uri'
|
39
39
|
|
40
40
|
# ask HeliosDev.shop if this email is good
|
41
|
-
stream = URI.open("https://heliosdev.shop/check_licenses/hot-glue
|
41
|
+
stream = URI.open("https://heliosdev.shop/check_licenses/hot-glue?email=#{license_email}")
|
42
42
|
resp = JSON.parse(stream.read)
|
43
43
|
|
44
44
|
if resp['status'] == 'success'
|
@@ -87,11 +87,6 @@ module HotGlue
|
|
87
87
|
|
88
88
|
end
|
89
89
|
|
90
|
-
if Rails.version.split(".")[0].to_i >= 7
|
91
|
-
copy_file "confirmable.js", "#{'spec/dummy/' if Rails.env.test?}app/javascript/controllers/confirmable.js"
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
90
|
begin
|
96
91
|
if Rails.version.split(".")[0].to_i == 6
|
97
92
|
app_js_contents = File.read("app/javascript/packs/application.js")
|
@@ -1,23 +1,19 @@
|
|
1
1
|
module HotGlue
|
2
2
|
class ErbTemplate < TemplateBase
|
3
3
|
|
4
|
-
|
4
|
+
attr_accessor :path, :singular, :singular_class,
|
5
|
+
:magic_buttons, :small_buttons,
|
6
|
+
:show_only, :column_width, :layout, :perc_width,
|
7
|
+
:ownership_field, :form_labels_position,
|
8
|
+
:inline_list_labels,
|
9
|
+
:columns, :column_width, :col_identifier, :singular,
|
10
|
+
:form_placeholder_labels
|
5
11
|
|
6
12
|
def add_spaces_each_line(text, num_spaces)
|
7
13
|
add_spaces = " " * num_spaces
|
8
14
|
text.lines.collect{|line| add_spaces + line}.join("")
|
9
15
|
end
|
10
16
|
|
11
|
-
|
12
|
-
# include GeneratorHelper
|
13
|
-
attr_accessor :singular
|
14
|
-
|
15
|
-
def field_output(col, type = nil, width, col_identifier )
|
16
|
-
" <%= f.text_field :#{col}, value: @#{@singular}.#{col}, autocomplete: 'off', size: #{width}, class: 'form-control', type: '#{type}' %>\n "+
|
17
|
-
"\n"
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
17
|
def magic_button_output(*args)
|
22
18
|
path = args[0][:path]
|
23
19
|
# path_helper_singular = args[0][:path_helper_singular]
|
@@ -34,20 +30,13 @@ module HotGlue
|
|
34
30
|
}.join("\n")
|
35
31
|
end
|
36
32
|
|
37
|
-
def text_area_output(col, field_length, col_identifier )
|
38
|
-
lines = field_length % 40
|
39
|
-
if lines > 5
|
40
|
-
lines = 5
|
41
|
-
end
|
42
33
|
|
43
|
-
"<%= f.text_area :#{col}, class: 'form-control', autocomplete: 'off', cols: 40, rows: '#{lines}' %>"
|
44
|
-
end
|
45
34
|
|
46
35
|
def list_column_headings(*args)
|
47
|
-
|
48
|
-
column_width = args[0][:column_width]
|
49
|
-
col_identifier = args[0][:col_identifier]
|
50
|
-
layout = args[0][:layout]
|
36
|
+
@columns = args[0][:columns]
|
37
|
+
@column_width = args[0][:column_width]
|
38
|
+
@col_identifier = args[0][:col_identifier]
|
39
|
+
@layout = args[0][:layout]
|
51
40
|
|
52
41
|
if layout == "hotglue"
|
53
42
|
col_style = " style='flex-basis: #{column_width}%'"
|
@@ -55,23 +44,29 @@ module HotGlue
|
|
55
44
|
col_style = ""
|
56
45
|
end
|
57
46
|
|
58
|
-
result =
|
47
|
+
result = columns.map{ |column|
|
59
48
|
"<div class='#{col_identifier}'" + col_style + ">" + column.map(&:to_s).map{|col_name| "#{col_name.humanize}"}.join("<br />") + "</div>"
|
60
49
|
}.join("\n")
|
61
50
|
return result
|
62
51
|
end
|
63
52
|
|
64
53
|
|
54
|
+
################################################################
|
55
|
+
|
56
|
+
# THE FORM
|
57
|
+
|
65
58
|
def all_form_fields(*args)
|
66
|
-
|
67
|
-
show_only = args[0][:show_only]
|
68
|
-
singular_class = args[0][:singular_class]
|
69
|
-
col_identifier = args[0][:col_identifier]
|
70
|
-
ownership_field = args[0][:ownership_field]
|
59
|
+
@columns = args[0][:columns]
|
60
|
+
@show_only = args[0][:show_only]
|
61
|
+
@singular_class = args[0][:singular_class]
|
62
|
+
@col_identifier = args[0][:col_identifier]
|
63
|
+
@ownership_field = args[0][:ownership_field]
|
64
|
+
@form_labels_position = args[0][:form_labels_position]
|
65
|
+
@form_placeholder_labels = args[0][:form_placeholder_labels]
|
71
66
|
|
72
67
|
@singular = args[0][:singular]
|
73
68
|
singular = @singular
|
74
|
-
result =
|
69
|
+
result = columns.map{ |column|
|
75
70
|
" <div class='#{col_identifier}' >" +
|
76
71
|
column.map { |col|
|
77
72
|
field_result =
|
@@ -84,41 +79,11 @@ module HotGlue
|
|
84
79
|
|
85
80
|
case type
|
86
81
|
when :integer
|
87
|
-
|
88
|
-
if col.to_s.ends_with?("_id")
|
89
|
-
assoc_name = col.to_s.gsub("_id","")
|
90
|
-
assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
|
91
|
-
if assoc.nil?
|
92
|
-
exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
|
93
|
-
exit
|
94
|
-
end
|
95
|
-
|
96
|
-
is_owner = col == ownership_field
|
97
|
-
assoc_class_name = assoc.active_record.name
|
98
|
-
display_column = HotGlue.derrive_reference_name(assoc_class_name)
|
99
|
-
|
100
|
-
(is_owner ? "<% unless @#{assoc_name} %>\n" : "") +
|
101
|
-
" <%= f.collection_select(:#{col}, #{assoc.class_name}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col} }, class: 'form-control') %>\n" +
|
102
|
-
(is_owner ? "<% else %>\n <%= @#{assoc_name}.#{display_column} %>" : "") +
|
103
|
-
(is_owner ? "\n<% end %>" : "")
|
104
|
-
|
105
|
-
else
|
106
|
-
"<%= f.text_field :#{col}, value: #{singular}.#{col}, class: 'form-control', size: 4, type: 'number' %>"
|
107
|
-
|
108
|
-
end
|
82
|
+
integer_result(col)
|
109
83
|
when :string
|
110
|
-
|
111
|
-
field_output(col, nil, limit || 40, col_identifier)
|
112
|
-
else
|
113
|
-
text_area_output(col, 65536, col_identifier)
|
114
|
-
end
|
115
|
-
|
84
|
+
string_result(col, sql_type, limit)
|
116
85
|
when :text
|
117
|
-
|
118
|
-
field_output(col, nil, limit, col_identifier)
|
119
|
-
else
|
120
|
-
text_area_output(col, 65536, col_identifier)
|
121
|
-
end
|
86
|
+
text_result(col, sql_type, limit)
|
122
87
|
when :float
|
123
88
|
field_output(col, nil, 5, col_identifier)
|
124
89
|
when :datetime
|
@@ -128,18 +93,10 @@ module HotGlue
|
|
128
93
|
when :time
|
129
94
|
"<%= time_field_localized(f, :#{col}, #{singular}.#{col}, '#{ col.to_s.humanize }', #{@auth ? @auth+'.timezone' : 'nil'}) %>"
|
130
95
|
when :boolean
|
131
|
-
|
132
|
-
" <span>#{col.to_s.humanize}</span>" +
|
133
|
-
" <%= f.radio_button(:#{col}, '0', checked: #{singular}.#{col} ? '' : 'checked') %>\n" +
|
134
|
-
" <%= f.label(:#{col}, value: 'No', for: '#{singular}_#{col}_0') %>\n" +
|
135
|
-
" <%= f.radio_button(:#{col}, '1', checked: #{singular}.#{col} ? 'checked' : '') %>\n" +
|
136
|
-
" <%= f.label(:#{col}, value: 'Yes', for: '#{singular}_#{col}_1') %>\n" +
|
137
|
-
""
|
96
|
+
boolean_result(col)
|
138
97
|
when :enum
|
139
|
-
|
140
|
-
"<%= f.collection_select(:#{col}, enum_to_collection_select( #{singular_class}.defined_enums['#{enum_type}']), :key, :value, {selected: @#{singular}.#{col} }, class: 'form-control') %>"
|
98
|
+
enum_result(col)
|
141
99
|
end
|
142
|
-
|
143
100
|
end
|
144
101
|
|
145
102
|
if (type == :integer) && col.to_s.ends_with?("_id")
|
@@ -148,16 +105,93 @@ module HotGlue
|
|
148
105
|
field_error_name = col
|
149
106
|
end
|
150
107
|
|
151
|
-
|
152
|
-
|
108
|
+
the_label = "\n<label class='small form-text text-muted'>#{col.to_s.humanize}</label>"
|
109
|
+
add_spaces_each_line( "\n <span class='<%= \"alert-danger\" if #{singular}.errors.details.keys.include?(:#{field_error_name}) %>' #{'style="display: inherit;"'} >\n" +
|
110
|
+
add_spaces_each_line( (@form_labels_position == 'before' ? the_label : "") +
|
111
|
+
field_result + (@form_labels_position == 'after' ? the_label : "") , 4) +
|
153
112
|
"\n </span>\n <br />", 2)
|
154
113
|
|
114
|
+
|
155
115
|
}.join("") + "\n </div>"
|
156
116
|
}.join("\n")
|
157
117
|
return result
|
158
118
|
end
|
159
119
|
|
160
120
|
|
121
|
+
def integer_result(col)
|
122
|
+
# look for a belongs_to on this object
|
123
|
+
if col.to_s.ends_with?("_id")
|
124
|
+
assoc_name = col.to_s.gsub("_id","")
|
125
|
+
assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
|
126
|
+
if assoc.nil?
|
127
|
+
exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
|
128
|
+
exit
|
129
|
+
end
|
130
|
+
|
131
|
+
is_owner = col == ownership_field
|
132
|
+
assoc_class_name = assoc.active_record.name
|
133
|
+
display_column = HotGlue.derrive_reference_name(assoc_class_name)
|
134
|
+
|
135
|
+
(is_owner ? "<% unless @#{assoc_name} %>\n" : "") +
|
136
|
+
" <%= f.collection_select(:#{col}, #{assoc.class_name}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col} }, class: 'form-control') %>\n" +
|
137
|
+
(is_owner ? "<% else %>\n <%= @#{assoc_name}.#{display_column} %>" : "") +
|
138
|
+
(is_owner ? "\n<% end %>" : "")
|
139
|
+
|
140
|
+
else
|
141
|
+
" <%= f.text_field :#{col}, value: #{@singular}.#{col}, autocomplete: 'off', size: 4, class: 'form-control', type: 'number'" + (@form_placeholder_labels ? ", placeholder: '#{col.to_s.humanize}'" : "") + " %>\n " + "\n"
|
142
|
+
|
143
|
+
# field_output(col, nil, 4, col_identifier)
|
144
|
+
#
|
145
|
+
# # "<%= f.text_field :#{col}, value: #{singular}.#{col}, class: 'form-control', size: 4, type: 'number' %>"
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def string_result(col, sql_type, limit)
|
151
|
+
if sql_type == "varchar" || sql_type == "character varying"
|
152
|
+
field_output(col, nil, limit || 40, col_identifier)
|
153
|
+
else
|
154
|
+
text_area_output(col, 65536, col_identifier)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
def text_result(col, sql_type, limit)
|
160
|
+
if sql_type == "varchar"
|
161
|
+
field_output(col, nil, limit, col_identifier)
|
162
|
+
else
|
163
|
+
text_area_output(col, 65536, col_identifier)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def field_output(col, type = nil, width, col_identifier )
|
168
|
+
" <%= f.text_field :#{col}, value: #{@singular}.#{col}, autocomplete: 'off', size: #{width}, class: 'form-control', type: '#{type}'" + (@form_placeholder_labels ? ", placeholder: '#{col.to_s.humanize}'" : "") + " %>\n " + "\n"
|
169
|
+
end
|
170
|
+
|
171
|
+
def text_area_output(col, field_length, col_identifier )
|
172
|
+
lines = field_length % 40
|
173
|
+
if lines > 5
|
174
|
+
lines = 5
|
175
|
+
end
|
176
|
+
|
177
|
+
"<%= f.text_area :#{col}, class: 'form-control', autocomplete: 'off', cols: 40, rows: '#{lines}'" + ( @form_placeholder_labels ? ", placeholder: '#{col.to_s.humanize}'" : "") + " %>"
|
178
|
+
end
|
179
|
+
|
180
|
+
def boolean_result(col)
|
181
|
+
" <br />" +
|
182
|
+
" <%= f.radio_button(:#{col}, '0', checked: #{singular}.#{col} ? '' : 'checked') %>\n" +
|
183
|
+
" <%= f.label(:#{col}, value: 'No', for: '#{singular}_#{col}_0') %>\n" +
|
184
|
+
" <%= f.radio_button(:#{col}, '1', checked: #{singular}.#{col} ? 'checked' : '') %>\n" +
|
185
|
+
" <%= f.label(:#{col}, value: 'Yes', for: '#{singular}_#{col}_1') %>\n" +
|
186
|
+
""
|
187
|
+
end
|
188
|
+
|
189
|
+
def enum_result(col)
|
190
|
+
enum_type = eval("#{singular_class}.columns.select{|x| x.name == '#{col}'}[0].sql_type")
|
191
|
+
"<%= f.collection_select(:#{col}, enum_to_collection_select( #{singular_class}.defined_enums['#{enum_type}']), :key, :value, {selected: @#{singular}.#{col} }, class: 'form-control') %>"
|
192
|
+
end
|
193
|
+
|
194
|
+
################################################################
|
161
195
|
|
162
196
|
def paginate(*args)
|
163
197
|
plural = args[0][:plural]
|
@@ -165,18 +199,24 @@ module HotGlue
|
|
165
199
|
"<% if #{plural}.respond_to?(:total_pages) %><%= paginate(#{plural}) %> <% end %>"
|
166
200
|
end
|
167
201
|
|
168
|
-
def all_line_fields(*args)
|
169
|
-
layout_columns = args[0][:columns]
|
170
|
-
show_only = args[0][:show_only]
|
171
|
-
singular_class = args[0][:singular_class]
|
172
|
-
singular = args[0][:singular]
|
173
|
-
perc_width = args[0][:perc_width]
|
174
|
-
layout = args[0][:layout]
|
175
|
-
col_identifier = args[0][:col_identifier] || (layout == "bootstrap" ? "col-md-2" : "scaffold-cell")
|
176
202
|
|
177
203
|
|
178
|
-
|
179
|
-
|
204
|
+
|
205
|
+
################################################################
|
206
|
+
|
207
|
+
|
208
|
+
def all_line_fields(*args)
|
209
|
+
@columns = args[0][:columns]
|
210
|
+
@show_only = args[0][:show_only]
|
211
|
+
@singular_class = args[0][:singular_class]
|
212
|
+
@singular = args[0][:singular]
|
213
|
+
@perc_width = args[0][:perc_width]
|
214
|
+
@layout = args[0][:layout]
|
215
|
+
@col_identifier = args[0][:col_identifier] || (layout == "bootstrap" ? "col-md-2" : "scaffold-cell")
|
216
|
+
@inline_list_labels = args[0][:inline_list_labels] || 'omit'
|
217
|
+
|
218
|
+
columns_count = columns.count + 1
|
219
|
+
perc_width = (@perc_width).floor
|
180
220
|
|
181
221
|
if layout == "bootstrap"
|
182
222
|
style_with_flex_basis = ""
|
@@ -184,7 +224,7 @@ module HotGlue
|
|
184
224
|
style_with_flex_basis = " style='flex-basis: #{perc_width}%'"
|
185
225
|
end
|
186
226
|
|
187
|
-
result =
|
227
|
+
result = columns.map{ |column|
|
188
228
|
"<div class='#{col_identifier}'#{style_with_flex_basis}>" +
|
189
229
|
|
190
230
|
|
@@ -193,7 +233,7 @@ module HotGlue
|
|
193
233
|
limit = eval("#{singular_class}.columns_hash['#{col}']").limit
|
194
234
|
sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
|
195
235
|
|
196
|
-
case type
|
236
|
+
field_output = case type
|
197
237
|
when :integer
|
198
238
|
# look for a belongs_to on this object
|
199
239
|
if col.ends_with?("_id")
|
@@ -262,9 +302,15 @@ module HotGlue
|
|
262
302
|
<%= #{singular_class}.defined_enums['#{enum_type}'][#{singular}.#{col}] %>
|
263
303
|
<% end %>
|
264
304
|
|
265
|
-
|
266
|
-
|
267
|
-
|
305
|
+
"
|
306
|
+
end #end of switch
|
307
|
+
|
308
|
+
|
309
|
+
label = "<br/><label class='small form-text text-muted'>#{col.to_s.humanize}</label>"
|
310
|
+
|
311
|
+
(inline_list_labels == 'before' ? label : "") + field_output +
|
312
|
+
(inline_list_labels == 'after' ? label : "")
|
313
|
+
}.join( "<br />") + "</div>"
|
268
314
|
}.join("\n")
|
269
315
|
end
|
270
316
|
end
|
@@ -97,7 +97,6 @@ module HotGlue
|
|
97
97
|
class_option :nest, type: :string, default: nil # DEPRECATED —— DO NOT USE
|
98
98
|
class_option :nested, type: :string, default: ""
|
99
99
|
|
100
|
-
|
101
100
|
class_option :namespace, type: :string, default: nil
|
102
101
|
class_option :auth, type: :string, default: nil
|
103
102
|
class_option :auth_identifier, type: :string, default: nil
|
@@ -105,6 +104,7 @@ module HotGlue
|
|
105
104
|
class_option :include, type: :string, default: ""
|
106
105
|
class_option :god, type: :boolean, default: false
|
107
106
|
class_option :gd, type: :boolean, default: false # alias for god
|
107
|
+
|
108
108
|
class_option :specs_only, type: :boolean, default: false
|
109
109
|
class_option :no_specs, type: :boolean, default: false
|
110
110
|
class_option :no_delete, type: :boolean, default: false
|
@@ -116,24 +116,31 @@ module HotGlue
|
|
116
116
|
class_option :show_only, type: :string, default: ""
|
117
117
|
|
118
118
|
class_option :ujs_syntax, type: :boolean, default: nil
|
119
|
-
|
120
119
|
class_option :downnest, type: :string, default: nil
|
121
120
|
class_option :magic_buttons, type: :string, default: nil
|
122
121
|
class_option :small_buttons, type: :boolean, default: nil
|
123
|
-
|
124
122
|
class_option :display_list_after_update, type: :boolean, default: false
|
125
123
|
class_option :smart_layout, type: :boolean, default: false
|
126
124
|
class_option :markup, type: :string, default: nil # deprecated -- use in app config instead
|
127
125
|
class_option :layout, type: :string, default: nil # if used here it will override what is in the config
|
128
|
-
|
126
|
+
|
127
|
+
class_option :no_list_label, type: :boolean, default: false
|
128
|
+
|
129
129
|
class_option :no_list_heading, type: :boolean, default: false
|
130
130
|
|
131
|
-
|
131
|
+
|
132
|
+
# determines if the labels show up BEFORE or AFTER on the NEW/EDIT (form)
|
133
|
+
class_option :form_labels_position, default: 'after' # choices are before, after, omit
|
134
|
+
class_option :form_placeholder_labels, default: false # puts the field names into the placeholder labels
|
135
|
+
|
136
|
+
|
137
|
+
# NOT YET IMPLEMENTED
|
138
|
+
# determines if labels appear within the rows of the VIEWABLE list (does NOT affect the list heading)
|
139
|
+
class_option :inline_list_labels, default: 'omit' # choices are before, after, omit
|
132
140
|
|
133
141
|
def initialize(*meta_args)
|
134
142
|
super
|
135
143
|
|
136
|
-
|
137
144
|
begin
|
138
145
|
@the_object = eval(class_name)
|
139
146
|
rescue StandardError => e
|
@@ -165,7 +172,6 @@ module HotGlue
|
|
165
172
|
if !options['markup'].nil?
|
166
173
|
message = "Using --markup flag in the generator is deprecated; instead, use a file at config/hot_glue.yml with a key markup set to `erb` or `haml`"
|
167
174
|
raise(HotGlue::Error, message)
|
168
|
-
|
169
175
|
end
|
170
176
|
|
171
177
|
if !options['markup'].nil?
|
@@ -264,9 +270,24 @@ module HotGlue
|
|
264
270
|
|
265
271
|
@no_edit = options['no_edit'] || false
|
266
272
|
@no_list = options['no_list'] || false
|
267
|
-
@
|
273
|
+
@no_list_label = options['no_list_label'] || false
|
268
274
|
@no_list_heading = options['no_list_heading'] || false
|
269
275
|
|
276
|
+
@form_labels_position = options['form_labels_position']
|
277
|
+
if !['before','after','omit'].include?(@form_labels_position)
|
278
|
+
raise "You passed '#{@form_labels_position}' as the setting for --form-labels-position but the only allowed options are before, after (default), and omit"
|
279
|
+
end
|
280
|
+
|
281
|
+
@form_placeholder_labels = options['form_placeholder_labels'] # true or false
|
282
|
+
@inline_list_labels = options['inline_list_labels'] || 'omit' # 'before','after','omit'
|
283
|
+
|
284
|
+
|
285
|
+
if !['before','after','omit'].include?(@inline_list_labels)
|
286
|
+
raise "You passed '#{@inline_list_labels}' as the setting for --inline-list-labels but the only allowed options are before, after, and omit (default)"
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
|
270
291
|
@display_list_after_update = options['display_list_after_update'] || false
|
271
292
|
@smart_layout = options['smart_layout']
|
272
293
|
|
@@ -915,7 +936,9 @@ module HotGlue
|
|
915
936
|
singular_class: singular_class,
|
916
937
|
singular: singular,
|
917
938
|
col_identifier: col_identifier,
|
918
|
-
ownership_field: @ownership_field
|
939
|
+
ownership_field: @ownership_field,
|
940
|
+
form_labels_position: @form_labels_position,
|
941
|
+
form_placeholder_labels: @form_placeholder_labels
|
919
942
|
)
|
920
943
|
end
|
921
944
|
|
@@ -969,7 +992,9 @@ module HotGlue
|
|
969
992
|
singular_class: singular_class,
|
970
993
|
singular: singular,
|
971
994
|
layout: @layout,
|
972
|
-
col_identifier: col_identifier
|
995
|
+
col_identifier: col_identifier,
|
996
|
+
inline_list_labels: @inline_list_labels
|
997
|
+
|
973
998
|
)
|
974
999
|
end
|
975
1000
|
|
@@ -40,12 +40,17 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
40
40
|
@<%= @nested_set[0][:singular] %> ||= <%= root_object %> <% else %>
|
41
41
|
@<%= @nested_set[0][:singular] %> ||= <%= root_object %>.find(params[:<%= @nested_set[0][:singular] %>_id])<%= " if params.include?(:#{@nested_set[0][:singular]}_id)" if @nested_set[0][:optional] %> <% end %>
|
42
42
|
end
|
43
|
-
<% end %><% if any_nested? %><% nest_chain = [@nested_set[0][:singular]]; this_scope = @nested_set[0][:plural]; %>
|
44
|
-
|
45
|
-
|
43
|
+
<% end %><% if any_nested? %><% nest_chain = [@nested_set[0][:singular]]; this_scope = @nested_set[0][:plural]; %>
|
44
|
+
<% for index in 0..(@nested_set.count - 1) do
|
45
|
+
arg = @nested_set[index]
|
46
|
+
last_arg = (index == 0 ? nil : @nested_set[index-1])
|
47
|
+
|
48
|
+
this_scope = "#{nest_chain.last}.#{arg[:plural]}"
|
49
|
+
nest_chain << arg %>
|
46
50
|
def <%= arg[:singular] %>
|
47
|
-
@<%= arg[:singular] %> ||= (<%= this_scope %>.find(params[:<%= arg[:singular] %>_id])<%= " if params.include?(:#{
|
48
|
-
|
51
|
+
@<%= arg[:singular] %> ||= (<%= this_scope %>.find(params[:<%= arg[:singular] %>_id])<%= " if params.include?(:#{last_arg[:singular]}_id)" if last_arg && @god && last_arg[:optional] %>)
|
52
|
+
<% if @god && (last_arg[:optional] ) %>@<%= arg[:singular] %> ||= (<%= collect_objects[index-1] %>.find(params[:<%= arg[:singular] %>_id]) if params.include?(:<%= arg[:singular] %>_id) ) <% end %>
|
53
|
+
end<% end %> <% end %> <% if !@self_auth %>
|
49
54
|
|
50
55
|
def load_<%= singular_name %>
|
51
56
|
@<%= singular_name %> = (<%= object_scope.gsub("@",'') %>.find(params[:id])<%= " if params.include?(:#{@nested_set.last[:singular]}_id)" if @nested_set[0] && @nested_set[0][:optional] %>)<% if @nested_set[0] && @nested_set[0][:optional] %> || <%= class_name %>.find(params[:id])<% end %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<\%= turbo_frame_tag "<%= plural %>-list" <%= nested_for_turbo_id_list_constructor %> do %>
|
2
2
|
<div class="<%= @container_name %> scaffold-list">
|
3
|
-
<% unless @no_list
|
3
|
+
<% unless @no_list || @no_list_label || (@nested_set.any? && !@nested_set.collect{|x| x[:optional]}.any?) %>
|
4
4
|
<% unless list_label.nil? %><h4>
|
5
5
|
<%= list_label %>
|
6
6
|
</h4><% end %>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<% 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 %>
|
10
10
|
|
11
11
|
<% unless @no_list %>
|
12
|
-
<% unless @
|
12
|
+
<% unless @no_list_heading %>
|
13
13
|
<div class="row scaffold-heading-row">
|
14
14
|
<%= list_column_headings %>
|
15
15
|
<% if @downnest_object.any? %>
|
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.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Fleetwood-Boldt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -85,7 +85,6 @@ files:
|
|
85
85
|
- lib/generators/hot_glue/scaffold_generator.rb
|
86
86
|
- lib/generators/hot_glue/templates/base_controller.rb.erb
|
87
87
|
- lib/generators/hot_glue/templates/capybara_login.rb
|
88
|
-
- lib/generators/hot_glue/templates/confirmable.js
|
89
88
|
- lib/generators/hot_glue/templates/controller.rb.erb
|
90
89
|
- lib/generators/hot_glue/templates/erb/_errors.erb
|
91
90
|
- lib/generators/hot_glue/templates/erb/_flash_notices.erb
|
@@ -149,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
148
|
- !ruby/object:Gem::Version
|
150
149
|
version: '0'
|
151
150
|
requirements: []
|
152
|
-
rubygems_version: 3.1.
|
151
|
+
rubygems_version: 3.1.6
|
153
152
|
signing_key:
|
154
153
|
specification_version: 4
|
155
154
|
summary: A gem to build Tubro Rails scaffolding.
|
@@ -1,14 +0,0 @@
|
|
1
|
-
import { Controller } from "@hotwired/stimulus"
|
2
|
-
|
3
|
-
console.log("defining Confirmable....")
|
4
|
-
export default class extends Controller {
|
5
|
-
static values = { message: String }
|
6
|
-
|
7
|
-
confirm(event) {
|
8
|
-
|
9
|
-
if(!window.confirm(this.message)) {
|
10
|
-
event.preventDefault();
|
11
|
-
event.stopPropagation()
|
12
|
-
}
|
13
|
-
}
|
14
|
-
}
|