bullet_train 1.2.10 → 1.2.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/account/two_factors_controller.rb +21 -5
  3. data/app/controllers/turbo_devise_controller.rb +1 -1
  4. data/app/helpers/account/forms_helper.rb +3 -1
  5. data/app/javascript/controllers/clipboard_controller.js +1 -1
  6. data/app/javascript/controllers/connection_workflow_controller.js +7 -0
  7. data/app/javascript/controllers/desktop_menu_controller.js +26 -0
  8. data/app/javascript/controllers/index.js +4 -0
  9. data/app/javascript/index.js +2 -1
  10. data/app/javascript/support/turn.js +183 -0
  11. data/app/models/concerns/users/base.rb +1 -1
  12. data/app/views/account/invitations/_form.html.erb +2 -2
  13. data/app/views/account/memberships/_form.html.erb +2 -2
  14. data/app/views/account/memberships/_membership.html.erb +1 -1
  15. data/app/views/account/teams/_breadcrumbs.html.erb +12 -5
  16. data/app/views/account/teams/_team.html.erb +4 -4
  17. data/app/views/account/two_factors/verify.js.erb +1 -0
  18. data/app/views/devise/registrations/_two_factor.html.erb +29 -8
  19. data/app/views/devise/sessions/new.html.erb +4 -2
  20. data/app/views/layouts/docs.html.erb +7 -7
  21. data/config/locales/en/teams.en.yml +2 -0
  22. data/config/locales/en/users.en.yml +8 -1
  23. data/config/routes.rb +3 -1
  24. data/docs/action-models.md +5 -5
  25. data/docs/api/versioning.md +0 -2
  26. data/docs/api.md +4 -4
  27. data/docs/application-options.md +1 -1
  28. data/docs/billing/usage.md +94 -16
  29. data/docs/field-partials.md +20 -20
  30. data/docs/font-awesome-pro.md +1 -1
  31. data/docs/getting-started.md +3 -3
  32. data/docs/i18n.md +3 -3
  33. data/docs/indirection.md +6 -4
  34. data/docs/namespacing.md +1 -1
  35. data/docs/onboarding.md +8 -8
  36. data/docs/overriding.md +1 -1
  37. data/docs/permissions.md +1 -1
  38. data/docs/seeds.md +1 -1
  39. data/docs/testing.md +2 -1
  40. data/docs/themes.md +18 -11
  41. data/docs/tunneling.md +2 -2
  42. data/docs/upgrades.md +2 -1
  43. data/lib/bullet_train/version.rb +1 -1
  44. data/lib/bullet_train.rb +2 -1
  45. data/lib/colorizer.rb +1 -1
  46. data/lib/tasks/bullet_train_tasks.rake +29 -12
  47. metadata +20 -8
  48. data/app/views/account/invitations/_invitation.json.jbuilder +0 -7
  49. data/app/views/account/invitations/index.json.jbuilder +0 -1
  50. data/app/views/account/invitations/show.json.jbuilder +0 -1
  51. data/app/views/account/teams/_team.json.jbuilder +0 -9
  52. data/app/views/account/teams/index.json.jbuilder +0 -1
  53. data/app/views/account/teams/show.json.jbuilder +0 -1
@@ -3,7 +3,7 @@
3
3
  Action Models make it easy to scaffold and implement user-facing custom actions in your Bullet Train application and API in a RESTful way. Action Models are perfect for situations where you want one or more of the following:
4
4
 
5
5
  - Bulk actions for a model where users can select one or more objects as targets.
6
- - Long-running background tasks where you want to keep users updated on their progress in the UI or notify then after completion.
6
+ - Long-running background tasks where you want to keep users updated on their progress in the UI or notify them after completion.
7
7
  - Actions that have one or more configuration options available.
8
8
  - Tasks that can be configured now but scheduled to take place later.
9
9
  - Actions where you want to keep an in-app record of when it happened and who initiated the action.
@@ -44,11 +44,11 @@ end
44
44
 
45
45
  ### 1. Purchase Bullet Train Pro
46
46
 
47
- First, [purchase Bullet Train Pro](https://buy.stripe.com/aEU7vc4dBfHtfO89AV). Once you've completed this process, you'll be issued a private token for the Bullet Train Pro package server. The process is currently completed manually, so you may have to way a little to receive your keys.
47
+ First, [purchase Bullet Train Pro](https://buy.stripe.com/aEU7vc4dBfHtfO89AV). Once you've completed this process, you'll be issued a private token for the Bullet Train Pro package server. The process is currently completed manually, so you may have to wait a little to receive your keys.
48
48
 
49
49
  ### 2. Install the Package
50
50
 
51
- You'll need to specify both Ruby gems in your `Gemfile`, since we have to specify a private source for both:
51
+ Then you can specify the Ruby gem in your `Gemfile`:
52
52
 
53
53
  ```ruby
54
54
  source "https://YOUR_TOKEN_HERE@gem.fury.io/bullettrain" do
@@ -104,7 +104,7 @@ Because Action Models are just regular models, you can add new fields to them wi
104
104
  For example:
105
105
 
106
106
  ```
107
- rails g migration add notify_users_to_projects_archive_actions notify_users:boolean
107
+ rails g migration add_notify_users_to_projects_archive_actions notify_users:boolean
108
108
  # side quest: update the generated migration with `default: false` on the new boolean field.
109
109
  bin/super-scaffold crud-field Projects::ArchiveAction notify_users:boolean
110
110
  ```
@@ -145,4 +145,4 @@ This final type of action is available for things like importers that don't nece
145
145
 
146
146
  ### Do Action Models have to be persisted to the database?
147
147
 
148
- No. Action Models extend from `ApplicationRecord` by default, but if you're not using features that depend on persistence to the database, you can make them `include ActiveModel::API` instead. That said, it's probably not worth the trouble. As an alternative, consider just including `Actions::CleansUp` in your action to ensure it removes itself from the database after completion.
148
+ No. Action Models extend from `ApplicationRecord` by default, but if you're not using features that depend on persistence to the database, you can make them `include ActiveModel::API` instead. That said, it's probably not worth the trouble. As an alternative, consider just including `Actions::CleansUp` in your action to ensure it removes itself from the database after completion.
@@ -31,8 +31,6 @@ If you're in a situation where you know you need to bump your API version to hel
31
31
  rake bullet_train:api:bump_version
32
32
  ```
33
33
 
34
- > TODO This Rake task doesn't exist yet.
35
-
36
34
  ## What happens when you bump an API version?
37
35
  When you bump your API version, all of the files and directories that are namespaced with the API version number will be duplicated into a new namespace for the new API version number.
38
36
 
data/docs/api.md CHANGED
@@ -19,7 +19,7 @@ APIs are built using standard Rails tools like `ActiveController::API`, [Strong
19
19
  In the same way we've adopted [Devise](https://github.com/heartcombo/devise) for best-of-breed and battle-tested authentication on the browser side, we've adopted [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) for best-of-breed and battle-tested authentication on the API side.
20
20
 
21
21
  ### DRY Authorization Logic
22
- Because our API endpoints are standard Rails controllers, they're able to leverage the exact same [permissions definitions and authorization logic](https://github.com/bullet-train-co/bullet_train-base/blob/main/docs/permissions.md) as our account controllers.
22
+ Because our API endpoints are standard Rails controllers, they're able to leverage the exact same [permissions definitions and authorization logic](/docs/permissions) as our account controllers.
23
23
 
24
24
  ## Structure
25
25
  Where vanilla Rails uses a single controller in `app/controllers` for both in-browser and API requests, Bullet Train splits these into two separate controllers, one in `app/controllers/account` and another in `app/controllers/api/v1`, although a lot of logic is shared between the two.
@@ -40,7 +40,7 @@ The primary definition of Strong Parameters for a given resource is defined in t
40
40
  include strong_parameters_from_api
41
41
  ```
42
42
 
43
- > This may feel counter-intuitive to some developers and you might wonder why we don't flip this around and have the primary definition in the account controller and have the API controller delegate to it. The answer is a pragmatic one: creating and maintaining the defintion of Strong Paramters in the API controller means it gets automatically frozen in time should you ever need to [bump your API version number](/api/docs/versioning.md). We probably _could_ accomplish this if things were the other way around, but it wouldn't happen automatically.
43
+ > This may feel counter-intuitive to some developers and you might wonder why we don't flip this around and have the primary definition in the account controller and have the API controller delegate to it. The answer is a pragmatic one: creating and maintaining the defintion of Strong Paramters in the API controller means it gets automatically frozen in time should you ever need to [bump your API version number](/docs/api/versioning.md). We probably _could_ accomplish this if things were the other way around, but it wouldn't happen automatically.
44
44
 
45
45
  If by chance there are additional attributes that should be permitted or specific logic that needs to be run as part of the account controller (or inversely, only in the API controller), you can specify that in the controller like so:
46
46
 
@@ -71,7 +71,7 @@ end
71
71
  ```
72
72
 
73
73
  ## Usage Example
74
- First, provision a platform application in section titled "Your Applications" in the "Developers" menu of the application. When you create a new platform application, an access token that doesn't automatically expire will be automatically provisioned along with it. You can then use the access token to hit the API, as seen in the following Ruby-based example:
74
+ First, provision a platform application in the section titled "Your Applications" in the "Developers" menu of the application. When you create a new platform application, an access token that doesn't automatically expire will be automatically provisioned along with it. You can then use the access token to hit the API, as seen in the following Ruby-based example:
75
75
 
76
76
  ```ruby
77
77
  require 'net/http'
@@ -103,4 +103,4 @@ response = client.patch("/api/v1/teams/1", {team: team}.to_json, headers)
103
103
  - [API Versioning](/docs/api/versioning.md)
104
104
 
105
105
  ## A Note About Other Serializers and API Frameworks
106
- In early versions of Bullet Train we made the decision to adopt a specific serialization library, [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers) and in subsequent versions we went as far as to adopt an entire third-party framework ([Grape](https://github.com/ruby-grape/grape)) and a third-party API specification ([JSON:API](https://jsonapi.org)). We now consider it out-of-scope to try and make such decisions on behalf of developers. Support for them in Bullet Train applications and in Super Scaffolding could be created by third-parties.
106
+ In early versions of Bullet Train we made the decision to adopt a specific serialization library, [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers), and in subsequent versions we went as far as to adopt an entire third-party framework ([Grape](https://github.com/ruby-grape/grape)) and a third-party API specification ([JSON:API](https://jsonapi.org)). We now consider it out-of-scope to try and make such decisions on behalf of developers. Support for them in Bullet Train applications and in Super Scaffolding could be created by third-parties.
@@ -23,7 +23,7 @@ The helper methods below can also be directly invoked in your application if you
23
23
  | STRIPE_CLIENT_ID | See [Bullet Train Billing for Stripe](/docs/billing/stripe.md) for more information and related environment variables. |
24
24
  | CLOUDINARY_URL | Enables use of Cloudinary for handling images. |
25
25
  | TWO_FACTOR_ENCRYPTION_KEY | Enables two-factor authentication through Devise. |
26
- | INVITATION_KEYS | See more [Invitation Only](/docs/authentication.md) for more information. |
26
+ | INVITATION_KEYS | See [Invitation Only](/docs/authentication.md) for more information. |
27
27
  | FONTAWESOME_NPM_AUTH_TOKEN | Enables use of Font Awesome. |
28
28
  | SILENCE_LOGS | Silences Super Scaffolding logs. |
29
29
  | TESTING_PROVISION_KEY | Creates a test `Platform::Application` by accessing `/testing/provision?key=your_provision_key` |
@@ -45,7 +45,31 @@ Note this is different than how many Rails engines ask you to install migrations
45
45
  rake db:migrate
46
46
  ```
47
47
 
48
- ## Configuration
48
+ ### 2.5. Add Model Support
49
+
50
+ There are two concerns that need to be added to your application models.
51
+
52
+ The first concern is `Billing::UsageSupport` and it allows tracking of usage of verbs on the models you want to support tracking usage on. It is recommended to add this capability to all models, so you can add this.
53
+
54
+ ```
55
+ # app/models/application_record.rb
56
+
57
+ class ApplicationRecord
58
+ include Billing::Usage
59
+ end
60
+ ```
61
+
62
+ The second concern is `Billing::HasTrackers` and it allows any model to hold the usage tracking. This is usually done on the `Team` model.
63
+
64
+ ```
65
+ # app/models/team.rb
66
+
67
+ class Team
68
+ include Billing::HasTrackers
69
+ end
70
+ ```
71
+
72
+ ## Configuration
49
73
  Usage limit configuration piggybacks on your [product definitions](/docs/billing/stripe.md) in `config/models/billing/products.yml`. It may help to make reference to the [default product definitions in the Bullet Train starter repository](https://github.com/bullet-train-co/bullet_train/blob/main/config/models/billing/products.yml).
50
74
 
51
75
  ## Basic Usage Limits
@@ -63,21 +87,37 @@ basic:
63
87
  upgradable: true
64
88
  ```
65
89
 
66
- It's important to note that `have` is a special verb and represents the simple `count` of a given model on a `Team`. All _other_ verbs will be interpreted as time-based usage limits.
90
+ Any verb that your model supports can be used. It is recommended to standardize on using the action as the verb. For example, when creating a new model, use the verb _create_. When deleting a model, use the verb _delete_, and so on.
91
+
92
+ It's important to note that `have` is a special verb and represents the simple `count` of a given model on a `Team`. All _other_ verbs will be interpreted as [time-based usage limits](#time-based-usage-limits).
67
93
 
68
94
  ### Options
69
- - `enforcement` can be `hard` or `soft`.
95
+ - `enforcement` can be `hard` or `soft`.
70
96
  - When a `hard` limit is hit, the create form will be disabled.
71
97
  - When a `soft` limit is hit, users are simply notified, but can continue to surpass the limit.
72
98
  - `upgradable` indicates whether or not a user should be prompted to upgrade when they hit this limit.
73
99
 
74
100
  ### Excluding Records from `have` Usage Limits
75
- All models have an overridable `billable` scope that includes all records by default. You can override this scope to ensure that certain records are filtered out from consideration when calculating usage limits. For example, we do the following on `Membership` to exclude removed team members from contributing to any limitation put on the number of team members, like so:
101
+ All models have an overridable `billable` scope that includes all records by default. You can override this scope on any given model to ensure that certain records are filtered out from consideration when calculating usage limits. For example, we do the following on `Membership` to exclude removed team members from contributing to any limitation put on the number of team members, like so:
76
102
 
77
103
  ```ruby
78
104
  scope :billable, -> { current_and_invited }
79
105
  ```
80
106
 
107
+ Another example may be excluding "archived" items within the billable usage count such as:
108
+
109
+ ```ruby
110
+ module Archivable
111
+ extend ActiveSupport::Concern
112
+
113
+ included do
114
+ scope :billable, -> { where(archived_at: nil) }
115
+
116
+ # ...
117
+ end
118
+ end
119
+ ```
120
+
81
121
  ## Time-Based Usage Limits
82
122
 
83
123
  ### Configuring Limits
@@ -95,7 +135,7 @@ free:
95
135
  ```
96
136
 
97
137
  - `count` is how many times something can happen.
98
- - `duration` and `interval` represent the time period we'll track for, e.g. "3 days" in this case.
138
+ - `duration` and `interval` represent the time period we'll track for, e.g. "3 days" in this case.
99
139
  - Valid options for `interval` are anything you can append to an integer, e.g. `minutes`, `hours`, `days`, `weeks`, `months`, etc., both plural and singular.
100
140
 
101
141
  ### Tracking Usage
@@ -112,7 +152,7 @@ class Blogs::Post < ApplicationRecord
112
152
  end
113
153
  ```
114
154
 
115
- If you'd like to increment the usage count by more than one, you can pass a quantity like `count: 5` to this call.
155
+ It is important that you use the past tense of the verb when tracking so it is tracked appropriately. If you'd like to increment the usage count by more than one, you can pass a quantity like `count: 5` to this call.
116
156
 
117
157
  ### Cycling Trackers Regularly
118
158
  We include a Rake task you'll need to run on a regular basis in order to cycle the usage trackers that are created at a `Team` level. By default, you should probably run this every five minutes:
@@ -123,26 +163,64 @@ rake billing:cycle_usage_trackers
123
163
 
124
164
  ## Checking Usage Limits
125
165
 
166
+ ### Checking Time-Based Limits
167
+ To make decisions based on or enforce time-based `hard` limits in your views and controllers, you can use the `current_limits` helper like this:
168
+
169
+ ```ruby
170
+ current_limits.can?(:publish, Blogs::Post)
171
+ ```
172
+
173
+ (You can also pass quantities like `count: 5` as an option.)
174
+
126
175
  ### Checking Basic Limits
127
176
  For basic `have` limits, forms generated by Super Scaffolding will be automatically disabled when a `hard` limit has been hit. Index views will also alert users to a limit being hit or broken for both `hard` and `soft` limits.
128
177
 
129
178
  > If your Bullet Train application scaffolding predates this feature, you can reference the newest Tangible Things [index template](https://github.com/bullet-train-co/bullet_train-super_scaffolding/blob/main/app/views/account/scaffolding/completely_concrete/tangible_things/_index.html.erb) and [form template](https://github.com/bullet-train-co/bullet_train-super_scaffolding/blob/main/app/views/account/scaffolding/completely_concrete/tangible_things/_form.html.erb) to see how we're using the `shared/limits/index` and `shared/limits/form` partials to present and enforce usage limits, and copy this usage in your own views.
130
179
 
131
- ### Checking Time-Based Limits
132
- To make decisions based on or enforce time-based limits in your views and controllers, you can use the `current_limits` helper like this:
180
+ To make decisions in other views or within controllers, you can use the `#exhausted?` method on the `current_limits` helper to check if any basic `have` limits have been hit or exceeded.
133
181
 
134
- ```
135
- current_limits.can?(:publish, Blogs::Post)
136
- ```
182
+ ```ruby
183
+ # Inspects broken hard limits by default
184
+ current_limits.exhausted?(Blogs::Post)
137
185
 
138
- (You can also pass quantities like `count: 5` as an option.)
186
+ # Or you can specify the `enforcement` level
187
+ current_limits.exhausted?(Blogs::Post, :soft)
188
+ ```
139
189
 
140
190
  #### Presenting an Error
141
191
 
142
- If you're checking on this in a controller before taking an action and you want to present an error to the user based on their usage, you can redirect with this special flash error message key:
192
+ If you want to present an error or warning to the user based on their usage, there themed alert partials that can be displayed in your views. These partials can be rendered via the path `shared/limits/error` and `shared/limits/warning` respectively.
143
193
 
194
+ ```ruby
195
+ <%= render "shared/limits/warning", model: model.class %>
196
+
197
+ <%= render "shared/limits/error", action: :create, model: model.class, count: 1, cancel_path: cancel_path %>
144
198
  ```
145
- flash[:error] = :create_limit
146
- redirect_to [:account, @post]
199
+
200
+ These partials have various local assigns that are used to configure the partial.
201
+
202
+ * `action` - the `verb` to check the usage on the model for. Defaults to `have`.
203
+ * `color` - the `color` value to use for the alert partial. Defaults to `red` for errors and `yellow` for warnings.
204
+ * `count` - the number of objects intended to be acted upon. Defaults to 1.
205
+ * `model` - the `class` relationship as the model to inspect usage on. Defaults to `form.object.class`.
206
+
207
+ ### Changing Products
208
+ The default list of products that the limits are based off of are the products available from your Billing products, which is most likely a list of subscription plans from Stripe.
209
+
210
+ You can change this default behavior by creating your own billing limiter and overriding the `current_products` method. This method should return a list of products that all respond to a `limits` message. The rest of the behavior is encapsulated in the `Billing::Limiter::Base` concern.
211
+
212
+ ```ruby
213
+ # app/models/billing/email_limiter.rb
214
+
215
+ class Billing::EmailLimiter
216
+ include Billing::Limiter::Base
217
+
218
+ def current_products
219
+ products = Billing::Product.data
220
+
221
+ EmailService.retrieve_product_tiers.map do |tier|
222
+ add_product_limit(tier, products)
223
+ end
224
+ end
225
+ end
147
226
  ```
148
- > TODO This technically works but needs to be redone. Too limited.
@@ -40,7 +40,7 @@ Breaking down the invocation:
40
40
  - `text_field` matches the name of the native Rails form field helper we want to invoke.
41
41
  - The `form` option passes a reference to the form object the field will exist within.
42
42
  - The `method` option specifies which attribute of the model the field represents, in the same way as the first parameter of the basic Rails `text_field` helper.
43
- - The `options` option is basically a passthrough, allowing you to specify options which will passed directly to the underlying Rails form field helper.
43
+ - The `options` option is basically a passthrough, allowing you to specify options which will be passed directly to the underlying Rails form field helper.
44
44
 
45
45
  The 1:1 relationship between these field partials and their underlying Rails form helpers is an important design decision. For example, the way `options` is passed through to native Rails form field helpers means that experienced Rails developers will still be able to leverage what they remember about using Rails, while those of us who don't readily remember all the various options of those helpers can make use of [the standard Rails documentation](https://guides.rubyonrails.org/form_helpers.html) and the great wealth of Rails code examples available online and still take advantage of these field partials. That means the amount of documentation we need to maintain for these field partials is strictly for those features that are in addition to what Rails provides by default.
46
46
 
@@ -76,7 +76,7 @@ When you're including multiple fields, you can DRY up redundant settings (e.g. `
76
76
  ```
77
77
 
78
78
  ## Field partials that integrate with third-party service providers
79
- - `cloudinary` makes it trivial to upload photos and images to [Cloudinary](https://cloudinary.com) and store their resulting Cloudinary ID as an attribute of the model backing the form. To enable this field partial, sign up for Cloudinary and copy the "Cloudinary URL" they provide you with into your `config/application.yml` as `CLOUDINARY_URL`. If you use our [Heroku app.json] to provision your production environment, this will happen in that environment automatically.
79
+ - `cloudinary` makes it trivial to upload photos and images to [Cloudinary](https://cloudinary.com) and store their resulting Cloudinary ID as an attribute of the model backing the form. To enable this field partial, sign up for Cloudinary and copy the "Cloudinary URL" they provide you with into your `config/application.yml` as `CLOUDINARY_URL`. If you use our [Heroku app.json](https://github.com/bullet-train-co/bullet_train/blob/main/app.json) to provision your production environment, this will happen in that environment automatically.
80
80
 
81
81
  ## Yaml Configuration
82
82
  The localization Yaml file (where you configure label and option values for a field) is automatically generated when you run Super Scaffolding for a model. If you haven't done this yet, the localization Yaml file for `Scaffolding::CompletelyConcrete::TangibleThing` serves as a good example. Under `en.scaffolding/completely_concrete/tangible_things.fields` you'll see definitions like this:
@@ -109,23 +109,24 @@ Certain form field partials like `buttons` and `super_select` can also have thei
109
109
 
110
110
  ## Available Field Partials
111
111
 
112
- | Field Partial | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description | Commercial License Required |
113
- | --- | --- | --- | --- | --- | --- | --- |
114
- | `boolean` | `boolean` | `assign_boolean` | | | |
115
- | [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | | |
116
- | `cloudinary_image` | `string` | | | | | |
117
- | `color_picker` | | | | [pickr](https://simonwep.github.io/pickr/) | | |
118
- | `date_and_time_field` | `datetime` | | `assign_date_and_time` | [Date Range Picker](https://www.daterangepicker.com) | | |
119
- | `date_field` | `date` | | `assign_date` | [Date Range Picker](https://www.daterangepicker.com) | | |
120
- | `email_field` | `string` | | | | | |
121
- | [`file_field`](/docs/field-partials/file-field.md) | `attachment` | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | | |
122
- | `options` | `string` | Optionally | `assign_checkboxes` | | | |
123
- | `password_field` | `string` | | | | | |
124
- | `phone_field` | `string` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. | |
125
- | [`super_select`](/docs/field-partials/super-select.md) | `string` | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. | |
126
- | `text_area` | `text` | | | | | |
127
- | `text_field` | `string` | | | | | |
128
- | `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. | |
112
+ | Field Partial | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description |
113
+ |--------------------------------------------------------|--------------|------------------|-------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
114
+ | `boolean` | `boolean` | | `assign_boolean` | | |
115
+ | [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | |
116
+ | `cloudinary_image` | `string` | | | | |
117
+ | `color_picker` | | | | [pickr](https://simonwep.github.io/pickr/) | |
118
+ | `date_and_time_field` | `datetime` | | `assign_date_and_time` | [Date Range Picker](https://www.daterangepicker.com) | |
119
+ | `date_field` | `date` | | `assign_date` | [Date Range Picker](https://www.daterangepicker.com) | |
120
+ | `email_field` | `string` | | | | |
121
+ | `emoji_field` | `string` | | | [Emoji Mart](https://missiveapp.com/open/emoji-mart) | A front-end library which allows users to browse and select emojis with ease. | |
122
+ | [`file_field`](/docs/field-partials/file-field.md) | `attachment` | | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | |
123
+ | `options` | `string` | Optionally | `assign_checkboxes` | | |
124
+ | `password_field` | `string` | | | | |
125
+ | `phone_field` | `string` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. |
126
+ | [`super_select`](/docs/field-partials/super-select.md) | `string` | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. |
127
+ | `text_area` | `text` | | | | |
128
+ | `text_field` | `string` | | | | |
129
+ | `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. |
129
130
 
130
131
  ## A Note On Data Types
131
132
  Set the data type to `jsonb` whenever passing the `multiple` option to a new attribute.
@@ -138,4 +139,3 @@ Set the data type to `jsonb` whenever passing the `multiple` option to a new att
138
139
  - [`buttons`](/docs/field-partials/buttons.md)
139
140
  - [`super_select`](/docs/field-partials/super-select.md)
140
141
  - [`file_field`](/docs/field-partials/file-field.md)
141
-
@@ -18,7 +18,7 @@ Once you buy a license for Font Awesome Pro, set `FONTAWESOME_NPM_AUTH_TOKEN` in
18
18
  - Add `export FONTAWESOME_NPM_AUTH_TOKEN=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX` in `~/.zshrc`.
19
19
  - Restart your terminal.
20
20
 
21
- If you're configuring this in another type of shell, please let us know what the steps are [in a new GitHub issue](http://github.com/bullet-train-co/bullet-train-tailwind-css/issues/new) and we'll add them here for others.
21
+ If you're configuring this in another type of shell, please let us know what the steps are [in a new GitHub issue](https://github.com/bullet-train-co/bullet_train/issues/new) and we'll add them here for others.
22
22
 
23
23
  ### 2. Add `.npmrc` Configuration
24
24
 
@@ -8,7 +8,7 @@ Whether you want to build a new application with Bullet Train or contribute to B
8
8
 
9
9
  If you're using Bullet Train for the first time, begin by learning these five important techniques:
10
10
 
11
- 1. Use `rails g model` to create and `bin/super-scaffold` to scaffold a new model:
11
+ 1. Use `rails g model` to create and `bin/super-scaffold crud` to scaffold a new model:
12
12
 
13
13
  ```
14
14
  rails g model Project team:references name:string
@@ -17,7 +17,7 @@ If you're using Bullet Train for the first time, begin by learning these five im
17
17
 
18
18
  In this example, `Team` refers to the immediate parent of the `Project` resource. For more details, just run `bin/super-scaffold` or [read the documentation](/docs/super-scaffolding.md).
19
19
 
20
- 2. Use `rails g migration` and `bin/super-scaffold` to add a new field to a model you've already scaffolded:
20
+ 2. Use `rails g migration` and `bin/super-scaffold crud-field` to add a new field to a model you've already scaffolded:
21
21
 
22
22
  ```
23
23
  rails g migration add_description_to_projects description:text
@@ -32,7 +32,7 @@ If you're using Bullet Train for the first time, begin by learning these five im
32
32
  - Selecting "Inspect Element".
33
33
  - Looking for the `<!-- BEGIN ... -->` comment above the element you've selected.
34
34
 
35
- 4. Figure out the full I18N translation key of any string on the page by adding `?show_locales=true` to the URL.
35
+ 4. Figure out the full I18n translation key of any string on the page by adding `?show_locales=true` to the URL.
36
36
 
37
37
  5. Use `bin/resolve` to figure out where framework or theme things are coming from and eject them if you need to customize something locally:
38
38
 
data/docs/i18n.md CHANGED
@@ -8,7 +8,7 @@ We override the native I18n translation method to automatically include the curr
8
8
  The following are the details for David’s Membership on Your Team.
9
9
  ```
10
10
 
11
- The view can be found here in the `bullet_train-base` gem:<br/>[bullet_train-base/app/views/account/memberships/show.html.erb](https://github.com/bullet-train-co/bullet_train-base/blob/657e932cb4eb3e0c1f56c88c8365c2611de90e06/app/views/account/memberships/show.html.erb#L16)<br/>
11
+ The view can be found here in the `bullet_train` gem:<br/>[bullet_train-core/bullet_train/app/views/account/memberships/show.html.erb](https://github.com/bullet-train-co/bullet_train-core/blob/fab77efab57126c083e0041f97c0e716560a2ffe/bullet_train/app/views/account/memberships/show.html.erb#L16)<br/>
12
12
  <br/>
13
13
  Looking at the view, you can see we are only passing a key to the translation method for I18n to process:
14
14
 
@@ -16,7 +16,7 @@ Looking at the view, you can see we are only passing a key to the translation me
16
16
  <%= t('.description') %>
17
17
  ```
18
18
 
19
- However, looking at the [locale itself](https://github.com/bullet-train-co/bullet_train-base/blob/657e932cb4eb3e0c1f56c88c8365c2611de90e06/config/locales/en/memberships.en.yml#L82), you can see that the string takes two variables, `memberships_possessive` and `team_name`, to complete the string:
19
+ However, looking at the [locale itself](https://github.com/bullet-train-co/bullet_train-core/blob/fab77efab57126c083e0041f97c0e716560a2ffe/bullet_train/config/locales/en/memberships.en.yml#L82), you can see that the string takes two variables, `memberships_possessive` and `team_name`, to complete the string:
20
20
  ```yaml
21
21
  description: The following are the details for %{memberships_possessive} Membership on %{team_name}.
22
22
  ```
@@ -26,6 +26,6 @@ Usually, you would pass the variable as a keyword argument:
26
26
  t('.description', memberships_possessive: memberships_possessive, team_name: current_team.name)
27
27
  ```
28
28
 
29
- However, in Bullet Train, we override the original translation method to include variable names like this automatically in our locales. Check out the [locale helper](https://github.com/bullet-train-co/bullet_train-base/blob/main/app/helpers/account/locale_helper.rb) to get a closer look at how we handle strings for internationalization. For example, the two variables above are generated by the method `model_locales` in the locale helper.
29
+ However, in Bullet Train, we override the original translation method to include variable names like this automatically in our locales. Check out the [locale helper](https://github.com/bullet-train-co/bullet_train-core/blob/main/bullet_train/app/helpers/account/locale_helper.rb) to get a closer look at how we handle strings for internationalization. For example, the two variables above are generated by the method `model_locales` in the locale helper.
30
30
 
31
31
  You can find more information in the [indirection documentation](indirection) about using `bin/resolve` and logs to pinpoint where your locales are coming from.
data/docs/indirection.md CHANGED
@@ -61,13 +61,15 @@ Would you like to open `/Users/andrewculver/.rbenv/versions/3.1.2/lib/ruby/gems/
61
61
  y
62
62
  ```
63
63
 
64
- You may also want to consider using `bin/develop`, which will clone the Bullet Train package of your choice to `local/` within your main application's root directory. Running this command will also automatically link the package to your main application and open it in the code editor for you, so you can start using the cloned repository and make changes to your main application right away.
64
+ You may also want to consider using `bin/hack`, which will clone the Bullet Train core packages to `local/bullet_train-core` within your main application's root directory. Running this command will also automatically link the packages to your main application and open bullet_train-core in the code editor for you, so you can start using the cloned repository and make changes to your main application right away.
65
+
66
+ To revert back to using the original gems, run `bin/hack --reset`. You can link up to your local packages at any time with `bin/hack --link`.
65
67
 
66
68
  Note that in the example above, the view in question isn't actually coming from the application repository. Instead, it's being included from the `bullet_train-themes-light` package. For further instructions on how to customize it, see [Overriding Framework Defaults](/docs/overriding.md).
67
69
 
68
70
  ### Drilling Down on Translation Keys
69
71
 
70
- Even in vanilla Rails applications, extracting strings from view files into I18N translation YAML files introduces a layer of indirection. Bullet Train tries to improve the resulting DX with a couple tools that make it easier to figure out where a translation you see in your browser is coming from.
72
+ Even in vanilla Rails applications, extracting strings from view files into I18n translation YAML files introduces a layer of indirection. Bullet Train tries to improve the resulting DX with a couple of tools that make it easier to figure out where a translation you see in your browser is coming from.
71
73
 
72
74
  #### Show Translation Keys in the Browser with `?show_locales=true`
73
75
 
@@ -75,11 +77,11 @@ You can see the full translation key of any string on the page by adding `?show_
75
77
 
76
78
  #### Log Translation Keys to the Console with `?log_locales=true`
77
79
 
78
- You can also log all the translation key for anything being rendered to the console by adding `?log_locales=true` to the request URL. This can make it easier to copy and paste translation keys for strings that are rendered in non-selectable UI elements.
80
+ You can also log all the translation keys for anything being rendered to the console by adding `?log_locales=true` to the request URL. This can make it easier to copy and paste translation keys for strings that are rendered in non-selectable UI elements.
79
81
 
80
82
  #### Resolving Translation Keys with `bin/resolve`
81
83
 
82
- Once you have the full I18N translation key, you can use `bin/resolve` to figure out which package and file it's coming from. At that point, if you need to customize it, you can also use the `--eject` option to copy the the framework for customization in your local application:
84
+ Once you have the full I18n translation key, you can use `bin/resolve` to figure out which package and file it's coming from. At that point, if you need to customize it, you can also use the `--eject` option to copy the framework for customization in your local application:
83
85
 
84
86
  ```
85
87
  bin/resolve en.account.onboarding.user_details.edit.header --eject --open
data/docs/namespacing.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Namespacing in Bullet Train
2
2
 
3
3
  ## The `Account` Namespace for Controllers and Views
4
- Bullet Train comes preconfigured with an `Account` and controller and view namespace. This is the place where Super Scaffolding will, by default, put new resource views and controllers. The intention here is to ensure that in systems that have both authenticated resource workflows and public-facing resources, those two different facets of the application are served by separate resource views and controllers. (By default, public-facing resources would be in the `Public` namespace.)
4
+ Bullet Train comes preconfigured with an `Account` namespace for controllers and views. This is the place where Super Scaffolding will, by default, put new resource views and controllers. The intention here is to ensure that in systems that have both authenticated resource workflows and public-facing resources, those two different facets of the application are served by separate resource views and controllers. (By default, public-facing resources would be in the `Public` namespace.)
5
5
 
6
6
  ## Alternative Authenticated Namespaces
7
7
  In Bullet Train applications with [multiple team types](/docs/teams.md), you may find it helpful to introduce additional controller and view namespaces to represent and organize user interfaces and experiences for certain team types that vary substantially from the `Account` namespace default. In Super Scaffolding, you can specify a namespace other than `Account` with the `--namespace` option, for example:
data/docs/onboarding.md CHANGED
@@ -17,25 +17,25 @@ Each of the following files exist within their own respective Bullet Train packa
17
17
 
18
18
  ### Controllers
19
19
  - `ensure_onboarding_is_complete` in `bullet_train/app/controllers/account/application_controller.rb`
20
- - `bullet_train-base/app/controllers/account/onboarding/user_details_controller.rb`
21
- - `bullet_train-base/app/controllers/account/onboarding/user_email_controller.rb`
20
+ - `bullet_train-core/bullet_train/app/controllers/account/onboarding/user_details_controller.rb`
21
+ - `bullet_train-core/bullet_train/app/controllers/account/onboarding/user_email_controller.rb`
22
22
 
23
23
  ### Views
24
- - `bullet_train-base/app/views/account/onboarding/user_details/edit.html.erb`
25
- - `bullet_train-base/app/views/account/onboarding/user_email/edit.html.erb`
24
+ - `bullet_train-core/bullet_train/app/views/account/onboarding/user_details/edit.html.erb`
25
+ - `bullet_train-core/bullet_train/app/views/account/onboarding/user_email/edit.html.erb`
26
26
 
27
27
  ### Models
28
- - `user#details_provided?` in `bullet_train-base/app/models/concerns/users/base.rb`
28
+ - `user#details_provided?` in `bullet_train/app/models/concerns/users/base.rb`
29
29
 
30
30
  ### Routes
31
- - `namespace :onboarding` in `bullet_train-base/config/routes.rb` and `bullet_train/config/routes.rb`
31
+ - `namespace :onboarding` in `bullet_train-core/bullet_train/config/routes.rb` and `bullet_train/config/routes.rb`
32
32
 
33
33
  ## Adding Additional Steps
34
34
  Although you can implement onboarding steps from scratch, we always just copy and paste one of the existing steps as a starting point, like so:
35
35
 
36
- 1. Copy, rename, and modify of the existing onboarding controllers.
36
+ 1. Copy, rename, and modify all of the existing onboarding controllers.
37
37
  2. Copy, rename, and modify the corresponding `edit.html.erb` view.
38
- 3. Copy and rename the route entry in `bullet_train-base/config/routes.rb`.
38
+ 3. Copy and rename the route entry in `bullet_train-core/bullet_train/config/routes.rb`.
39
39
  4. Add the appropriate gating logic in `ensure_onboarding_is_complete` in `bullet_train/app/controllers/account/application_controller.rb`
40
40
 
41
41
  Onboarding steps aren't limited to targeting `User` models. It's possible to add onboarding steps to help flesh out team `Membership` records or `Team` records as well. You can use this pattern for setting up any sort of required data for either the user or the team.
data/docs/overriding.md CHANGED
@@ -18,4 +18,4 @@ class User < ApplicationRecord
18
18
  end
19
19
  ```
20
20
 
21
- In this case, for most customizations or extensions you would want to make, you don't need to eject `Users::Core` into your local repository. Instead, you can simply re-define methods from that concern in your local `User` model after the inclusion of the concern.
21
+ In this case, for most customizations or extensions you would want to make, you don't need to eject `Users::Base` into your local repository. Instead, you can simply re-define methods from that concern in your local `User` model after the inclusion of the concern.
data/docs/permissions.md CHANGED
@@ -4,7 +4,7 @@
4
4
  Bullet Train leans heavily on [CanCanCan](https://github.com/CanCanCommunity/cancancan) for implementing authorization and permissions. (We’re also proud sponsors of its ongoing maintenance.) The original CanCan library by Ryan Bates was, in our opinion, a masterpiece and a software engineering marvel that has stood the test of time. It's truly a diamond among Ruby Gems. If you're not already familiar with CanCanCan, you should [read its documentation](https://github.com/CanCanCommunity/cancancan) to get familiar with its features and DSL.
5
5
 
6
6
  ## Bullet Train Roles
7
- Over many years of successfully implementing applications with CanCanCan, it became apparent to us that a supplemental level of abstraction could help streamline and simplify the definition of many common permissions, especially in large applications. We've since extracted this functionality into [a standalone Ruby Gem](https://github.com/bullet-train-co/bullet_train-roles) and moved the documentation that used to be here into [the README for that project](https://github.com/bullet-train-co/bullet_train-roles). Should you encounter situations where this abstraction doesn't meet your specific needs, you can always implement the permissions you need using standard CanCanCan directives in `app/models/ability.rb`.
7
+ Over many years of successfully implementing applications with CanCanCan, it became apparent to us that a supplemental level of abstraction could help streamline and simplify the definition of many common permissions, especially in large applications. We've since extracted this functionality into [a standalone Ruby Gem](https://github.com/bullet-train-co/bullet_train-core/tree/main/bullet_train-roles) and moved the documentation that used to be here into [the README for that project](https://github.com/bullet-train-co/bullet_train-core/tree/main/bullet_train-roles). Should you encounter situations where this abstraction doesn't meet your specific needs, you can always implement the permissions you need using standard CanCanCan directives in `app/models/ability.rb`.
8
8
 
9
9
  ## Additional Notes
10
10
 
data/docs/seeds.md CHANGED
@@ -29,7 +29,7 @@ end
29
29
  We do this so Bullet Train applications can re-use the logic in `db/seeds.rb` for three purposes:
30
30
 
31
31
  1. Set up new local development environments.
32
- 2. Ensure the test suite has the same configuration for features whose configuration is backed by Active Record (e.g. [subscriptions](/docs/subscriptions.md) and [outgoing webhooks](/docs/webhooks/outgoing.md)).
32
+ 2. Ensure the test suite has the same configuration for features whose configuration is backed by Active Record (e.g. [outgoing webhooks](/docs/webhooks/outgoing.md)).
33
33
  3. Ensure any updates to the baseline configuration that have been tested both locally and in CI are the exact same updates being executed in production upon deploy.
34
34
 
35
35
  This makes `db/seeds.rb` a single source of truth for this sort of baseline data, instead of having this concern spread and sometimes duplicated across `db/seeds.rb`, `db/migrations/*`, and `test/fixtures`.
data/docs/testing.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # Automated Test Suite
2
2
  All of Bullet Train’s core functionality is verifiable using the provided test suite. This foundation of headless browser integration tests took a ton of time to write, but they can give you the confidence and peace of mind that you haven't broken any key functionality in your application before a deploy.
3
3
 
4
- You can run the test suite with the following command in your shell:
4
+ You can run the test suite with the following commands in your shell:
5
5
 
6
6
  ```
7
+ rails test
7
8
  rails test:system
8
9
  ```
9
10
 
data/docs/themes.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Themes
2
2
 
3
- Bullet Train has a theme subsystem designed to allow you the flexibility to either extend or completely replace the stock “Light” UI template.
3
+ Bullet Train has a theme subsystem designed to allow you the flexibility to either extend or completely replace the stock “Light” UI theme.
4
4
  To reduce duplication of code across themes, Bullet Train implements the following three packages:
5
5
  1. `bullet_train-themes`
6
6
  2. `bullet_train-themes-tailwind_css`
@@ -10,12 +10,16 @@ This is where all of Bullet Train's standard views are contained.
10
10
 
11
11
  ## Adding a New Theme (ejecting standard views)
12
12
 
13
- If you want to add a new theme, you can use the following command. This will copy all of the standard views from `bullet_train-themes-light` to `app/views/themes/` and configure your application to use the new theme. For example, let's make a new theme called "foo":
14
- `> rake bullet_train:themes:light:eject[foo]`
13
+ If you want to add a new theme, you can use the following command. For example, let's make a new theme called "foo":
14
+ ```
15
+ > rake bullet_train:themes:light:eject[foo]
16
+ ```
17
+
18
+ This will copy all of the standard views from `bullet_train-themes-light` to `app/views/themes/` and configure your application to use the new theme.
15
19
 
16
20
  After running this command, you will see that a few other files are edited to use this new theme. Whenever switching a theme, you will need to make the same changes to make sure your application is running with the theme of your choice.
17
21
 
18
- You can also pass an annotated path to a view after running `bin/resolve` to eject individual views to your application.
22
+ You can also pass an annotated path to a view after running `bin/resolve --interactive` to eject individual views to your application.
19
23
 
20
24
  ## Theme Component Usage
21
25
 
@@ -25,21 +29,24 @@ To use a theme component, simply include it from "within" `shared` like so:
25
29
  <%= render 'shared/fields/text_field', method: :text_field_value %>
26
30
  ```
27
31
 
28
- We say "within" because while a `shared` view partial directory does exist, the referenced `shared/fields/_text_field.html.erb` doesn't actually exist within it. Instead, the theme engine picks up on `shared` and also works its way through the theme directories to find the appropriate match.
32
+ We say "within" because while a `shared` view partial directory does exist, the referenced `shared/fields/_text_field.html.erb` doesn't actually exist within it. Instead, the theme engine picks up on `shared` and then works its way through the theme directories to find the appropriate match.
29
33
 
30
34
  ### Dealing with Indirection
31
35
 
32
36
  This small piece of indirection buys us an incredible amount of power in building and extending themes, but as with any indirection, it could potentially come at the cost of developer experience. That's why Bullet Train includes additional tools for smoothing over this experience. Be sure to read the section on [dealing with indirection](./indirection.md).
33
37
 
34
- ## Theme Configuration
38
+ ## Restoring Theme Configuration
35
39
 
36
- Your application will automatically be configured to use your new theme whenever you run the eject command. Run `> rake bullet_train:themes:light:install` to re-install the standard light theme.
40
+ Your application will automatically be configured to use your new theme whenever you run the eject command. You can run the below command to re-install the standard light theme.
41
+ ```
42
+ > rake bullet_train:themes:light:install
43
+ ```
37
44
 
38
45
  ## Additional Guidance and Principles
39
46
 
40
47
  ### Should you extend or replace?
41
48
 
42
- For most development projects, the likely best path for customizing the UI is to extend “Light” or another complete Bullet Train theme. It’s difficult to convey how many hours have gone into making the Bullet Train themes complete and coherent from end to end. Every type of field partial, all the third-party libraries, all the responsiveness scenarios, etc. It’s taken many hours and many invoices.
49
+ For most development projects, the likely best path for customizing the UI is to extend “Light” or another complete Bullet Train theme. It’s difficult to convey how many hours have gone into making the Bullet Train themes complete and coherent from end to end. Every type of field partial, all the third-party libraries, all the responsiveness scenarios, etc. It has taken many hours of expert time.
43
50
 
44
51
  Extending an existing theme is like retaining an option on shipping. By extending a theme that is already complete, you allow yourself to say “enough is enough” at a certain point and just living with some inherited defaults in exchange for shipping your product sooner. You can always do more UI work later, but it doesn’t look unpolished now!
45
52
 
@@ -63,11 +70,11 @@ On the other hand, if you decide to try to build a theme from the ground up, you
63
70
  <% end %>
64
71
  ```
65
72
 
66
- This allows the theme engine to resolve which theme in the inheritance chain to include the `box` partial from. For example:
73
+ This allows the theme engine to resolve which theme in the inheritance chain will include the `box` partial. For example:
67
74
 
68
- - It might come from the “Light” theme today, but if you switch to the “Bold” theme later, it’ll can start pulling it from there.
75
+ - It might come from the “Light” theme today, but if you switch to the “Bold” theme later, it’ll start pulling it from there.
69
76
  - If you start extending “Light”, you can override its `box` implementation and your application will pick up the new customized version from your theme automatically.
70
- - If (hypothetically) `box` became generalized and move into the parent “Tailwind CSS” theme, your application would pick it up from the appropriate place.
77
+ - If (hypothetically) `box` becomes generalized and moves into the parent “Tailwind CSS” theme, your application would pick it up from the appropriate place.
71
78
 
72
79
  ### Let your designer name their theme.
73
80