bullet_train 1.2.20 → 1.2.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/concerns/invitations/base.rb +2 -5
  3. data/app/models/concerns/memberships/base.rb +1 -1
  4. data/app/models/concerns/records/base.rb +1 -5
  5. data/app/views/account/invitations/new.html.erb +5 -10
  6. data/app/views/account/invitations/show.html.erb +3 -3
  7. data/app/views/account/memberships/_index.html.erb +5 -5
  8. data/app/views/account/memberships/_menu_item.html.erb +2 -2
  9. data/app/views/account/memberships/_tombstones.html.erb +4 -4
  10. data/app/views/account/memberships/edit.html.erb +9 -15
  11. data/app/views/account/memberships/index.html.erb +3 -3
  12. data/app/views/account/memberships/show.html.erb +11 -14
  13. data/app/views/account/onboarding/user_details/edit.html.erb +3 -3
  14. data/app/views/account/onboarding/user_email/edit.html.erb +3 -3
  15. data/app/views/account/teams/_menu_item.html.erb +2 -2
  16. data/app/views/account/teams/_team.html.erb +2 -2
  17. data/app/views/account/teams/edit.html.erb +5 -10
  18. data/app/views/account/teams/index.html.erb +4 -6
  19. data/app/views/account/teams/new.html.erb +3 -3
  20. data/app/views/account/users/edit.html.erb +9 -12
  21. data/app/views/devise/passwords/edit.html.erb +3 -3
  22. data/app/views/devise/passwords/new.html.erb +3 -3
  23. data/app/views/devise/registrations/_two_factor.html.erb +5 -6
  24. data/app/views/devise/registrations/new.html.erb +3 -3
  25. data/app/views/devise/sessions/new.html.erb +4 -8
  26. data/app/views/layouts/docs.html.erb +33 -33
  27. data/docs/application-options.md +2 -0
  28. data/docs/field-partials.md +1 -1
  29. data/docs/super-scaffolding/sortable.md +2 -2
  30. data/lib/bullet_train/resolver.rb +10 -7
  31. data/lib/bullet_train/version.rb +1 -1
  32. data/lib/bullet_train.rb +9 -0
  33. data/lib/tasks/bullet_train_tasks.rake +25 -7
  34. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4561ddbfaa81217ae48ea15b210025cb0390f3acecb2a7be5f0cd239eb0ec731
4
- data.tar.gz: 610569262d3a98cf8778a702202f21c0739b62e4e68691befa83b90b1800fab2
3
+ metadata.gz: d03b4bc2028c88dac20f3223cd1cd6ef395cae53b6cf84377360b0b068a0c0e8
4
+ data.tar.gz: 3524f24af8fd64c3be1ae14ddf99562fd9ba251faed18e88f35800ff11c3a7f2
5
5
  SHA512:
6
- metadata.gz: 2a2a672f5278fa428754aeee9f17a4115e4bf0b9420b9768790bd3d7e9a29c2a98dfeec7ce82b6d33338cd61674fc7ebf4074a7b4b7f3f239733a3e20ef8e194
7
- data.tar.gz: 4dc593a08ee2e2137a807038ca554be019b1a3fb8362e691be55f4e9834be6636a9475947b51e272205968b5665306261bc8bc63aec9e4cc6f4dbab23c9361f3
6
+ metadata.gz: 7da1cc8e9a9acaef9fa0eeeab6c135f7d3c7d6261c2518c4b29c572711fe2e347ce3da8e7476a6fd2f8515af6d6c442df77f1d7566b7d9ba95c9dc0f59026078
7
+ data.tar.gz: 622671f75556fe2358107f3acdba1f917da32347df64b325514ad670c09044b85baad4e56ed3d7edc45ae761e4bf07cac91170cbeb5ea73254e3d0f124bb3985
@@ -11,9 +11,10 @@ module Invitations::Base
11
11
 
12
12
  validates :email, presence: true
13
13
 
14
- before_create :generate_uuid
15
14
  after_create :set_added_by_membership
16
15
  after_create :send_invitation_email
16
+
17
+ attribute :uuid, default: -> { SecureRandom.hex }
17
18
  end
18
19
 
19
20
  def set_added_by_membership
@@ -24,10 +25,6 @@ module Invitations::Base
24
25
  UserMailer.invited(uuid).deliver_later
25
26
  end
26
27
 
27
- def generate_uuid
28
- self.uuid = SecureRandom.hex
29
- end
30
-
31
28
  def accept_for(user)
32
29
  User.transaction do
33
30
  user.memberships << membership
@@ -128,7 +128,7 @@ module Memberships::Base
128
128
 
129
129
  def last_initial
130
130
  return nil unless last_name.present?
131
- "#{last_name}."
131
+ "#{last_name[0]}."
132
132
  end
133
133
 
134
134
  def first_name_last_initial
@@ -73,11 +73,7 @@ module Records::Base
73
73
  end
74
74
 
75
75
  def seeding?
76
- rake_tasks = ObjectSpace.each_object(Rake::Task)
77
- return false if rake_tasks.count.zero?
78
-
79
- db_seed_task = rake_tasks.find { |task| task.name.match?(/^db:seed$/) }
80
- db_seed_task.already_invoked
76
+ Rake::Task.task_defined?("db:seed") && Rake::Task["db:seed"].already_invoked
81
77
  end
82
78
 
83
79
  # TODO This should really be in the API package and included from there.
@@ -1,12 +1,7 @@
1
- <%= render 'account/shared/page' do |p| %>
2
- <% p.content_for :title, t('.section') %>
3
- <% p.content_for :body do %>
4
- <%= render 'account/shared/box', divider: true do |p| %>
5
- <% p.content_for :title, t('.header') %>
6
- <% p.content_for :description, t('.description') %>
7
- <% p.content_for :body do %>
8
- <%= render 'form', invitation: @invitation %>
9
- <% end %>
10
- <% end %>
1
+ <%= render 'account/shared/page' do |page| %>
2
+ <% page.title t('.section') %>
3
+ <% page.body.render 'account/shared/box', divider: true do |box| %>
4
+ <% box.t :description, title: '.header' %>
5
+ <% box.body.render 'form', invitation: @invitation %>
11
6
  <% end %>
12
7
  <% end %>
@@ -1,6 +1,6 @@
1
- <%= render 'account/shared/workflow/box' do |p| %>
2
- <% p.content_for :title, t(".join_team") %>
3
- <% p.content_for :body do %>
1
+ <%= render 'account/shared/workflow/box' do |box| %>
2
+ <% box.title t(".join_team") %>
3
+ <% box.body do %>
4
4
  <div class="space-y">
5
5
  <% if !@invitation.is_for?(current_user) %>
6
6
  <p><%= raw t('.has_invited', user_name: @invitation.from_membership.name) %></p>
@@ -3,14 +3,14 @@
3
3
  <% hide_back ||= false %>
4
4
 
5
5
  <%= updates_for context, :memberships do %>
6
- <%= render 'account/shared/box' do |p| %>
7
- <% p.content_for :title, t(".contexts.#{context.class.name.underscore}.header") %>
8
- <% p.content_for :description do %>
6
+ <%= render 'account/shared/box' do |box| %>
7
+ <% box.title t(".contexts.#{context.class.name.underscore}.header") %>
8
+ <% box.description do %>
9
9
  <%= raw t(".contexts.#{context.class.name.underscore}.#{@memberships.any? ? 'description' : 'description_empty'}") %>
10
10
  <%= render "shared/limits/index", model: @memberships.model %>
11
11
  <% end %>
12
12
 
13
- <% p.content_for :table do %>
13
+ <% box.table do %>
14
14
  <% if @memberships.any? %>
15
15
  <table class="table">
16
16
  <thead>
@@ -29,7 +29,7 @@
29
29
  <% end %>
30
30
 
31
31
  <% unless hide_actions %>
32
- <% p.content_for :actions do %>
32
+ <% box.actions do %>
33
33
  <%= link_to t('invitations.buttons.new'), new_account_team_invitation_path(@team, cancel_path: account_team_memberships_path(@team)), class: "#{first_button_primary}" %>
34
34
  <%= link_to t('global.buttons.back'), [:account, context], class: "#{first_button_primary} back" unless hide_back %>
35
35
  <% end %>
@@ -1,8 +1,8 @@
1
1
  <%= render 'account/shared/menu/item', {
2
2
  url: main_app.polymorphic_path([:account, current_team, :memberships]),
3
3
  label: t('memberships.navigation.label'),
4
- } do |p| %>
5
- <% p.content_for :icon do %>
4
+ } do |item| %>
5
+ <% item.icon do %>
6
6
  <i class="<%= t('memberships.navigation.icon') %>"></i>
7
7
  <% end %>
8
8
  <% end %>
@@ -1,13 +1,13 @@
1
1
  <% context ||= @team %>
2
2
  <% hide_actions ||= false %>
3
3
 
4
- <%= render 'account/shared/box' do |p| %>
5
- <% p.content_for :title, t("memberships.tombstones.contexts.#{context.class.name.underscore}.header") %>
6
- <% p.content_for :description do %>
4
+ <%= render 'account/shared/box' do |box| %>
5
+ <% box.title t("memberships.tombstones.contexts.#{context.class.name.underscore}.header") %>
6
+ <% box.description do %>
7
7
  <%= raw t("memberships.tombstones.contexts.#{context.class.name.underscore}.#{memberships.any? ? 'description' : 'description_empty'}") %>
8
8
  <% end %>
9
9
 
10
- <% p.content_for :body do %>
10
+ <% box.body do %>
11
11
  <% if memberships.any? %>
12
12
  <table class="table">
13
13
  <thead>
@@ -1,21 +1,15 @@
1
- <%= render 'account/shared/page' do |p| %>
2
- <% p.content_for :title, t('.section') %>
3
- <% p.content_for :body do %>
4
- <%= render 'account/shared/box', divider: true do |p| %>
5
- <% p.content_for :title, t('.header') %>
6
- <% p.content_for :description, t('.description') %>
7
- <% p.content_for :body do %>
8
- <%= render 'form', membership: @membership %>
9
- <% end %>
1
+ <%= render 'account/shared/page' do |page| %>
2
+ <% page.title t('.section') %>
3
+ <% page.body do %>
4
+ <%= render 'account/shared/box', divider: true do |box| %>
5
+ <% box.t :description, title: '.header' %>
6
+ <% box.body.render 'form', membership: @membership %>
10
7
  <% end %>
11
8
 
12
9
  <% if can? :destroy, @membership %>
13
- <%= render 'account/shared/box', divider: true do |p| %>
14
- <% p.content_for :title, t('.remove_header') %>
15
- <% p.content_for :description, t('.remove_description') %>
16
- <% p.content_for :body do %>
17
- <%= button_to t('.buttons.destroy'), [:account, @membership], method: :delete, data: { confirm: t('.buttons.confirmations.destroy') }, class: 'button' %>
18
- <% end %>
10
+ <%= render 'account/shared/box', divider: true do |box| %>
11
+ <% box.t title: '.remove_header', description: '.remove_description' %>
12
+ <% box.body.button_to t('.buttons.destroy'), [:account, @membership], method: :delete, data: { confirm: t('.buttons.confirmations.destroy') }, class: 'button' %>
19
13
  <% end %>
20
14
  <% end %>
21
15
  <% end %>
@@ -1,6 +1,6 @@
1
- <%= render 'account/shared/page' do |p| %>
2
- <% p.content_for :title, t('.section') %>
3
- <% p.content_for :body do %>
1
+ <%= render 'account/shared/page' do |page| %>
2
+ <% page.title t('.section') %>
3
+ <% page.body do %>
4
4
  <% if @memberships.current_and_invited.any? %>
5
5
  <%= render 'index' do %>
6
6
  <%= render @memberships.current_and_invited.includes(:user) %>
@@ -1,8 +1,8 @@
1
- <%= render 'account/shared/page' do |p| %>
2
- <% p.content_for :title, t('.section') %>
3
- <% p.content_for :body do %>
4
- <%= render 'account/shared/box', divider: true do |p| %>
5
- <% p.content_for :title do %>
1
+ <%= render 'account/shared/page' do |page| %>
2
+ <% page.title t('.section') %>
3
+ <% page.body do %>
4
+ <%= render 'account/shared/box', divider: true do |box| %>
5
+ <% box.title do %>
6
6
  <% if @membership.unclaimed? %>
7
7
  <%= t('.invitation_header') %>
8
8
  <% elsif @membership.tombstone? %>
@@ -12,16 +12,14 @@
12
12
  <% end %>
13
13
  <% end %>
14
14
 
15
- <% p.content_for :description do %>
16
- <%= t('.description') %>
17
- <% end %>
15
+ <% box.t :description %>
18
16
 
19
- <% p.content_for :body do %>
17
+ <% box.body do %>
20
18
  <% with_attribute_settings object: @membership, strategy: :label do %>
21
19
  <%= render 'shared/attributes/text', attribute: :name %>
22
- <%= render 'shared/attributes/base' do |p| %>
23
- <% p.content_for :heading, t('.fields.role_ids.heading') %>
24
- <% p.content_for :body do %>
20
+ <%= render 'shared/attributes/base' do |base| %>
21
+ <% base.heading t('.fields.role_ids.heading') %>
22
+ <% base.body do %>
25
23
  <% if @membership.assignable_roles.any? %>
26
24
  <%= @membership.assignable_roles.map { |role| t(".fields.role_ids.options.#{role.key}.label") }.to_sentence %>
27
25
  <% else %>
@@ -33,7 +31,7 @@
33
31
  <%# 🚅 super scaffolding will insert new fields above this line. %>
34
32
  <% end %>
35
33
 
36
- <% p.content_for :actions do %>
34
+ <% box.actions do %>
37
35
  <% if @membership.tombstone? %>
38
36
  <%= link_to t('.buttons.reinvite'), [:reinvite, :account, @membership], class: first_button_primary, method: :post, data: {confirm: t('.buttons.confirmations.reinvite', membership_name: @membership.name)} if can? :edit, @membership %>
39
37
  <% end %>
@@ -53,7 +51,6 @@
53
51
 
54
52
  <%= link_to t('global.buttons.back'), [:account, @team, :memberships], class: first_button_primary %>
55
53
  <% end %>
56
-
57
54
  <% end %>
58
55
 
59
56
  <%= render 'account/scaffolding/completely_concrete/tangible_things/index', tangible_things: @membership.scaffolding_completely_concrete_tangible_things, context: @membership if @membership.scaffolding_completely_concrete_tangible_things.any? %>
@@ -1,8 +1,8 @@
1
1
  <% @title = t('.header') %>
2
2
 
3
- <%= render 'account/shared/workflow/box' do |p| %>
4
- <% p.content_for :title, @title %>
5
- <% p.content_for :body do %>
3
+ <%= render 'account/shared/workflow/box' do |box| %>
4
+ <% box.title @title %>
5
+ <% box.body do %>
6
6
  <% within_fields_namespace(:self) do %>
7
7
  <%= form_for @user, url: account_onboarding_user_detail_path(@user), method: :put, html: {class: 'form'} do |f| %>
8
8
  <%= render 'account/shared/forms/errors', form: f %>
@@ -1,8 +1,8 @@
1
1
  <% @title = t('.header') %>
2
2
 
3
- <%= render 'account/shared/workflow/box' do |p| %>
4
- <% p.content_for :title, @title %>
5
- <% p.content_for :body do %>
3
+ <%= render 'account/shared/workflow/box' do |box| %>
4
+ <% box.title @title %>
5
+ <% box.body do %>
6
6
  <% within_fields_namespace(:self) do %>
7
7
  <%= form_for @user, url: account_onboarding_user_email_path(@user), method: :put, html: {class: 'form'} do |f| %>
8
8
  <% if @email_taken %>
@@ -1,8 +1,8 @@
1
1
  <%= render 'account/shared/menu/item', {
2
2
  url: main_app.polymorphic_path([:account, current_team]),
3
3
  label: t('menus.main.labels.dashboard'),
4
- } do |p| %>
5
- <% p.content_for :icon do %>
4
+ } do |item| %>
5
+ <% item.icon do %>
6
6
  <i class="fal fa-home-lg-alt ti ti-home"></i>
7
7
  <% end %>
8
8
  <% end %>
@@ -1,3 +1,3 @@
1
- <%= render 'account/shared/team', link_url: [:account, team], memberships: team.memberships.current_and_invited.first(10) do |p| %>
2
- <% p.content_for :name, team.name %>
1
+ <%= render 'account/shared/team', link_url: [:account, team], memberships: team.memberships.current_and_invited.first(10) do |p| %>
2
+ <% p.name team.name %>
3
3
  <% end %>
@@ -1,12 +1,7 @@
1
- <%= render 'account/shared/page' do |p| %>
2
- <% p.content_for :title, t('.section') %>
3
- <% p.content_for :body do %>
4
- <%= render 'account/shared/box', divider: true do |p| %>
5
- <% p.content_for :title, t('.header') %>
6
- <% p.content_for :description, t('.description') %>
7
- <% p.content_for :body do %>
8
- <%= render 'form', team: @team %>
9
- <% end %>
10
- <% end %>
1
+ <%= render 'account/shared/page' do |page| %>
2
+ <% page.title t('.section') %>
3
+ <% page.body.render 'account/shared/box', divider: true do |box| %>
4
+ <% box.t :description, title: '.header' %>
5
+ <% box.body.render 'form', team: @team %>
11
6
  <% end %>
12
7
  <% end %>
@@ -1,8 +1,6 @@
1
- <%= render 'account/shared/page' do |p| %>
2
- <% p.content_for :title, t('.section') %>
3
- <% p.content_for :body do %>
4
- <%= render 'index', creative_concepts: @creative_concepts do %>
5
- <%= render @teams %>
6
- <% end %>
1
+ <%= render 'account/shared/page' do |page| %>
2
+ <% page.title t('.section') %>
3
+ <% page.body.render 'index', creative_concepts: @creative_concepts do %>
4
+ <%= render @teams %>
7
5
  <% end %>
8
6
  <% end %>
@@ -6,9 +6,9 @@ else
6
6
  end
7
7
  %>
8
8
 
9
- <%= render 'account/shared/workflow/box' do |p| %>
10
- <% p.content_for :title, @title %>
11
- <% p.content_for :body do %>
9
+ <%= render 'account/shared/workflow/box' do |box| %>
10
+ <% box.title @title %>
11
+ <% box.body do %>
12
12
  <%= form_with model: @team, url: [:account, @team], local: true, class: 'form' do |form| %>
13
13
  <%= render 'account/shared/notices' %>
14
14
  <%= render 'account/shared/forms/errors', form: form %>
@@ -1,18 +1,15 @@
1
- <%= render 'account/shared/page' do |p| %>
2
- <% p.content_for :title, t('.section') %>
3
- <% p.content_for :body do %>
1
+ <%= render 'account/shared/page' do |page| %>
2
+ <% page.title t('.section') %>
3
+ <% page.body do %>
4
4
  <%= form_for [:account, @user] do |form| %>
5
5
  <%= render 'account/shared/forms/errors', form: form %>
6
6
  <% end if @user.errors.any? %>
7
7
 
8
8
  <div class="grid grid-cols-1 gap-y gap-x-8 lg:grid-cols-2">
9
9
  <div class="xl:col-span-1 space-y-8">
10
- <%= render 'account/shared/box', divider: true do |p| %>
11
- <% p.content_for :title, t('.profile.header') %>
12
- <% p.content_for :description, t('.profile.description') %>
13
- <% p.content_for :body do %>
14
- <%= render "account/users/form", user: @user %>
15
- <% end %>
10
+ <%= render 'account/shared/box', divider: true do |box| %>
11
+ <% box.t title: '.profile.header', description: '.profile.description' %>
12
+ <% box.body.render "account/users/form", user: @user %>
16
13
  <% end %>
17
14
 
18
15
  <% if two_factor_authentication_enabled? %>
@@ -25,9 +22,9 @@
25
22
  <div class="xl:col-span-1 space-y-8">
26
23
  <%= render 'account/users/oauth' %>
27
24
 
28
- <%= render 'account/shared/box', divider: true do |p| %>
29
- <% p.content_for :title, t('.password.header') %>
30
- <% p.content_for :body do %>
25
+ <%= render 'account/shared/box', divider: true do |box| %>
26
+ <% box.title t('.password.header') %>
27
+ <% box.body do %>
31
28
  <% within_fields_namespace(:update_self) do %>
32
29
  <%= form_for [:account, @user], html: {id: dom_id(@user, :password), class: 'form'} do |form| %>
33
30
  <% with_field_settings form: form do %>
@@ -1,7 +1,7 @@
1
1
  <% @title = t('devise.headers.change_password') %>
2
- <%= render 'account/shared/workflow/box' do |p| %>
3
- <% p.content_for :title, @title %>
4
- <% p.content_for :body do %>
2
+ <%= render 'account/shared/workflow/box' do |box| %>
3
+ <% box.title @title %>
4
+ <% box.body do %>
5
5
  <% within_fields_namespace(:update_self) do %>
6
6
  <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { class: 'form', method: :put }) do |f| %>
7
7
  <%= f.hidden_field :reset_password_token %>
@@ -1,6 +1,6 @@
1
- <%= render 'account/shared/workflow/box' do |p| %>
2
- <% p.content_for :title, t('devise.titles.reset_password') %>
3
- <% p.content_for :body do %>
1
+ <%= render 'account/shared/workflow/box' do |box| %>
2
+ <% box.title t('devise.titles.reset_password') %>
3
+ <% box.body do %>
4
4
  <% within_fields_namespace(:sign_up) do %>
5
5
  <%= form_for resource, as: resource_name, url: password_path(resource_name), html: {method: :post, class: 'form'} do |f| %>
6
6
  <%= render 'account/shared/forms/errors', form: f %>
@@ -1,10 +1,9 @@
1
- <%= render 'account/shared/box', divider: @backup_codes do |p| %>
2
- <% p.content_for :title, t("users.edit.two_factor.header") %>
3
- <% p.content_for :description, t("users.edit.two_factor.description_#{@user.otp_required_for_login? ? 'enabled' : 'disabled'}") %>
1
+ <%= render 'account/shared/box', divider: @backup_codes do |box| %>
2
+ <% box.title t("users.edit.two_factor.header") %>
3
+ <% box.description t("users.edit.two_factor.description_#{@user.otp_required_for_login? ? 'enabled' : 'disabled'}") %>
4
4
  <% if current_user.otp_secret %>
5
5
  <% if @backup_codes %>
6
- <% p.content_for :body do %>
7
-
6
+ <% box.body do %>
8
7
  <%= render 'account/shared/alert' do %>
9
8
  <%= t('users.edit.two_factor.warning').html_safe %>
10
9
  <% end %>
@@ -38,7 +37,7 @@
38
37
  <% end %>
39
38
  <% end %>
40
39
  <% end %>
41
- <% p.content_for :actions do %>
40
+ <% box.actions do %>
42
41
  <div class="<%= 'hidden' if @backup_codes %> space-y">
43
42
  <% if local_assigns.has_key? :verified %>
44
43
  <% if verified %>
@@ -1,6 +1,6 @@
1
- <%= render 'account/shared/workflow/box' do |p| %>
2
- <% p.content_for :title, t('devise.headers.create_account') %>
3
- <% p.content_for :body do %>
1
+ <%= render 'account/shared/workflow/box' do |box| %>
2
+ <% box.title t('devise.headers.create_account') %>
3
+ <% box.body do %>
4
4
  <% within_fields_namespace(:sign_up) do %>
5
5
  <%= form_for resource, as: resource_name, url: registration_path(resource_name), html: {class: 'form'} do |f| %>
6
6
  <%= render 'account/shared/notices' %>
@@ -1,6 +1,6 @@
1
- <%= render 'account/shared/workflow/box' do |p| %>
2
- <% p.content_for :title, t('devise.headers.sign_in') %>
3
- <% p.content_for :body do %>
1
+ <%= render 'account/shared/workflow/box' do |box| %>
2
+ <% box.title t('devise.headers.sign_in') %>
3
+ <% box.body do %>
4
4
  <% within_fields_namespace(:self) do %>
5
5
  <%# TODO: Turbo is set to `false` for now, but we may want to only bypass Turbo for JavaScript-based requests in the future. %>
6
6
  <%= form_for resource, as: resource_name, url: two_factor_authentication_enabled? ? users_pre_otp_path : session_path(resource_name), remote: two_factor_authentication_enabled?, html: {class: 'form'}, authenticity_token: true, data: {turbo: false} do |form| %>
@@ -44,11 +44,7 @@
44
44
  </div>
45
45
 
46
46
  <% if devise_mapping.rememberable? %>
47
- <% # TODO This needs to be its own component. Can't have this kind of styling here. %>
48
- <div class="flex items-center">
49
- <%= form.check_box :remember_me, class: "h-4 w-4 text-blue focus:ring-blue-800 border-slate-300 rounded dark:bg-slate-800 dark:border-slate-900" %>
50
- <%= form.label :remember_me, class: "ml-2 block" %>
51
- </div>
47
+ <%= render 'shared/fields/option', method: :remember_me, form: form, single_check_box: true %>
52
48
  <% end %>
53
49
  <% end %>
54
50
  <% end %>
@@ -60,19 +60,19 @@
60
60
 
61
61
  <%= render 'account/shared/menu/section', title: 'Introduction' do %>
62
62
  <%= render 'account/shared/menu/item', url: '/docs', label: 'Table of Contents' do |p| %>
63
- <% p.content_for :icon do %>
63
+ <% p.icon do %>
64
64
  <i class="fal fa-home-lg-alt ti ti-list"></i>
65
65
  <% end %>
66
66
  <% end %>
67
67
 
68
68
  <%= render 'account/shared/menu/item', url: '/docs/getting-started', label: 'Getting Started' do |p| %>
69
- <% p.content_for :icon do %>
69
+ <% p.icon do %>
70
70
  <i class="fal fa-terminal ti ti-flag"></i>
71
71
  <% end %>
72
72
  <% end %>
73
73
 
74
74
  <%= render 'account/shared/menu/item', url: '/docs/upgrades', label: 'Upgrades' do |p| %>
75
- <% p.content_for :icon do %>
75
+ <% p.icon do %>
76
76
  <i class="fal fa-sparkles ti ti-arrow-up"></i>
77
77
  <% end %>
78
78
  <% end %>
@@ -80,37 +80,37 @@
80
80
 
81
81
  <%= render 'account/shared/menu/section', title: 'General Topics' do %>
82
82
  <%= render 'account/shared/menu/item', url: '/docs/modeling', label: 'Domain Modeling' do |p| %>
83
- <% p.content_for :icon do %>
83
+ <% p.icon do %>
84
84
  <i class="fal fa-bolt ti ti-ruler-pencil"></i>
85
85
  <% end %>
86
86
  <% end %>
87
87
 
88
88
  <%= render 'account/shared/menu/item', url: '/docs/indirection', label: 'Indirection' do |p| %>
89
- <% p.content_for :icon do %>
89
+ <% p.icon do %>
90
90
  <i class="fal fa-bolt ti ti-direction"></i>
91
91
  <% end %>
92
92
  <% end %>
93
93
 
94
94
  <%= render 'account/shared/menu/item', url: '/docs/overriding', label: 'Overriding' do |p| %>
95
- <% p.content_for :icon do %>
95
+ <% p.icon do %>
96
96
  <i class="fal fa-bolt ti ti-spray"></i>
97
97
  <% end %>
98
98
  <% end %>
99
99
 
100
100
  <%= render 'account/shared/menu/item', url: '/docs/tunneling', label: 'Tunneling' do |p| %>
101
- <% p.content_for :icon do %>
101
+ <% p.icon do %>
102
102
  <i class="fal fa-bolt ti ti-bolt"></i>
103
103
  <% end %>
104
104
  <% end %>
105
105
 
106
106
  <%= render 'account/shared/menu/item', url: '/docs/javascript', label: 'JavaScript' do |p| %>
107
- <% p.content_for :icon do %>
107
+ <% p.icon do %>
108
108
  <i class="fa-brands fa-js ti ti-pulse"></i>
109
109
  <% end %>
110
110
  <% end %>
111
111
 
112
112
  <%= render 'account/shared/menu/item', url: '/docs/i18n', label: 'Internationalzation' do |p| %>
113
- <% p.content_for :icon do %>
113
+ <% p.icon do %>
114
114
  <i class="fa-brands fa-js ti ti-world"></i>
115
115
  <% end %>
116
116
  <% end %>
@@ -118,37 +118,37 @@
118
118
 
119
119
  <%= render 'account/shared/menu/section', title: 'Developer Tools' do %>
120
120
  <%= render 'account/shared/menu/item', url: '/docs/super-scaffolding', label: 'Super Scaffolding' do |p| %>
121
- <% p.content_for :icon do %>
121
+ <% p.icon do %>
122
122
  <i class="fal fa-magic ti ti-wand"></i>
123
123
  <% end %>
124
124
  <% end %>
125
125
 
126
126
  <%= render 'account/shared/menu/item', url: '/docs/action-models', label: 'Action Models' do |p| %>
127
- <% p.content_for :icon do %>
127
+ <% p.icon do %>
128
128
  <i class="fal fa-bars-progress ti ti-target"></i>
129
129
  <% end %>
130
130
  <% end %>
131
131
 
132
132
  <%= render 'account/shared/menu/item', url: '/docs/seeds', label: 'Database Seeds' do |p| %>
133
- <% p.content_for :icon do %>
133
+ <% p.icon do %>
134
134
  <i class="fal fa-seedling ti ti-server"></i>
135
135
  <% end %>
136
136
  <% end %>
137
137
 
138
138
  <%= render 'account/shared/menu/item', url: '/docs/testing', label: 'Test Suite' do |p| %>
139
- <% p.content_for :icon do %>
139
+ <% p.icon do %>
140
140
  <i class="fal fa-check ti ti-check"></i>
141
141
  <% end %>
142
142
  <% end %>
143
143
 
144
144
  <%= render 'account/shared/menu/item', url: 'https://github.com/bullet-train-co/magic_test', label: 'Magic Test' do |p| %>
145
- <% p.content_for :icon do %>
145
+ <% p.icon do %>
146
146
  <i class="fal fa-check ti ti-video-camera"></i>
147
147
  <% end %>
148
148
  <% end %>
149
149
 
150
150
  <%= render 'account/shared/menu/item', url: '/docs/application-options', label: 'Application Options' do |p| %>
151
- <% p.content_for :icon do %>
151
+ <% p.icon do %>
152
152
  <i class="fal fa-gear ti ti-settings"></i>
153
153
  <% end %>
154
154
  <% end %>
@@ -156,31 +156,31 @@
156
156
 
157
157
  <%= render 'account/shared/menu/section', title: 'Accounts & Teams' do %>
158
158
  <%= render 'account/shared/menu/item', url: '/docs/authentication', label: 'Authentication' do |p| %>
159
- <% p.content_for :icon do %>
159
+ <% p.icon do %>
160
160
  <i class="fal fa-fingerprint ti ti-id-badge"></i>
161
161
  <% end %>
162
162
  <% end %>
163
163
 
164
164
  <%= render 'account/shared/menu/item', url: '/docs/teams', label: 'Teams' do |p| %>
165
- <% p.content_for :icon do %>
165
+ <% p.icon do %>
166
166
  <i class="fal fa-users ti ti-user"></i>
167
167
  <% end %>
168
168
  <% end %>
169
169
 
170
170
  <%= render 'account/shared/menu/item', url: '/docs/permissions', label: 'Roles & Permissions' do |p| %>
171
- <% p.content_for :icon do %>
171
+ <% p.icon do %>
172
172
  <i class="fal fa-lock-alt ti ti-lock"></i>
173
173
  <% end %>
174
174
  <% end %>
175
175
 
176
176
  <%= render 'account/shared/menu/item', url: '/docs/onboarding', label: 'Onboarding' do |p| %>
177
- <% p.content_for :icon do %>
177
+ <% p.icon do %>
178
178
  <i class="fal fa-snowboarding ti ti-direction"></i>
179
179
  <% end %>
180
180
  <% end %>
181
181
 
182
182
  <%= render 'account/shared/menu/item', url: '/docs/namespacing', label: 'Namespacing' do |p| %>
183
- <% p.content_for :icon do %>
183
+ <% p.icon do %>
184
184
  <i class="fal fa-object-group ti ti-widgetized"></i>
185
185
  <% end %>
186
186
  <% end %>
@@ -188,19 +188,19 @@
188
188
 
189
189
  <%= render 'account/shared/menu/section', title: 'User Interface' do %>
190
190
  <%= render 'account/shared/menu/item', url: '/docs/field-partials', label: 'Field Partials' do |p| %>
191
- <% p.content_for :icon do %>
191
+ <% p.icon do %>
192
192
  <i class="fal fa-i-cursor ti ti-text"></i>
193
193
  <% end %>
194
194
  <% end %>
195
195
 
196
196
  <%= render 'account/shared/menu/item', url: '/docs/themes', label: 'Themes' do |p| %>
197
- <% p.content_for :icon do %>
197
+ <% p.icon do %>
198
198
  <i class="fal fa-swatchbook ti ti-palette"></i>
199
199
  <% end %>
200
200
  <% end %>
201
201
 
202
202
  <%= render 'account/shared/menu/item', url: 'https://github.com/bullet-train-co/nice_partials', label: 'Nice Partials' do |p| %>
203
- <% p.content_for :icon do %>
203
+ <% p.icon do %>
204
204
  <i class="fal fa-swatchbook ti ti-widget"></i>
205
205
  <% end %>
206
206
  <% end %>
@@ -208,7 +208,7 @@
208
208
 
209
209
  <%= render 'account/shared/menu/section', title: 'Billing' do %>
210
210
  <%= render 'account/shared/menu/item', url: '/docs/billing/stripe', label: 'Stripe' do |p| %>
211
- <% p.content_for :icon do %>
211
+ <% p.icon do %>
212
212
  <i class="fab fa-stripe-s ti ti-money"></i>
213
213
  <% end %>
214
214
  <% end %>
@@ -216,31 +216,31 @@
216
216
 
217
217
  <%= render 'account/shared/menu/section', title: 'Integration' do %>
218
218
  <%= render 'account/shared/menu/item', url: '/docs/api', label: 'REST API' do |p| %>
219
- <% p.content_for :icon do %>
219
+ <% p.icon do %>
220
220
  <i class="fal fa-brackets-curly ti ti-settings"></i>
221
221
  <% end %>
222
222
  <% end %>
223
223
 
224
224
  <%= render 'account/shared/menu/item', url: '/docs/zapier', label: 'Zapier' do |p| %>
225
- <% p.content_for :icon do %>
225
+ <% p.icon do %>
226
226
  <i class="fal fa-bolt ti ti-bolt"></i>
227
227
  <% end %>
228
228
  <% end %>
229
229
 
230
230
  <%= render 'account/shared/menu/item', url: '/docs/oauth', label: 'OAuth Providers' do |p| %>
231
- <% p.content_for :icon do %>
231
+ <% p.icon do %>
232
232
  <i class="fal fa-at ti ti-reload"></i>
233
233
  <% end %>
234
234
  <% end %>
235
235
 
236
236
  <%= render 'account/shared/menu/item', url: '/docs/webhooks/outgoing', label: 'Outgoing Webhooks' do |p| %>
237
- <% p.content_for :icon do %>
237
+ <% p.icon do %>
238
238
  <i class="fal fa-outlet ti ti-pulse"></i>
239
239
  <% end %>
240
240
  <% end %>
241
241
 
242
242
  <%= render 'account/shared/menu/item', url: '/docs/webhooks/incoming', label: 'Incoming Webhooks' do |p| %>
243
- <% p.content_for :icon do %>
243
+ <% p.icon do %>
244
244
  <i class="fal fa-plug ti ti-plug"></i>
245
245
  <% end %>
246
246
  <% end %>
@@ -248,7 +248,7 @@
248
248
 
249
249
  <%= render 'account/shared/menu/section', title: 'Internationalization' do %>
250
250
  <%= render 'account/shared/menu/item', url: '/docs/i18n', label: 'Translations' do |p| %>
251
- <% p.content_for :icon do %>
251
+ <% p.icon do %>
252
252
  <i class="fal fa-language ti ti-world"></i>
253
253
  <% end %>
254
254
  <% end %>
@@ -256,7 +256,7 @@
256
256
 
257
257
  <%= render 'account/shared/menu/section', title: 'Add-Ons' do %>
258
258
  <%= render 'account/shared/menu/item', url: '/docs/font-awesome-pro', label: 'Font Awesome Pro' do |p| %>
259
- <% p.content_for :icon do %>
259
+ <% p.icon do %>
260
260
  <i class="fal fa-flag ti ti-flag"></i>
261
261
  <% end %>
262
262
  <% end %>
@@ -264,13 +264,13 @@
264
264
 
265
265
  <%= render 'account/shared/menu/section', title: 'Deployment' do %>
266
266
  <%= render 'account/shared/menu/item', url: '/docs/heroku', label: 'Heroku' do |p| %>
267
- <% p.content_for :icon do %>
267
+ <% p.icon do %>
268
268
  <i class="fal fa-cloud ti ti-cloud-up"></i>
269
269
  <% end %>
270
270
  <% end %>
271
271
 
272
272
  <%= render 'account/shared/menu/item', url: '/docs/desktop', label: 'Desktop Applications' do |p| %>
273
- <% p.content_for :icon do %>
273
+ <% p.icon do %>
274
274
  <i class="fal fa-window-restore ti ti-desktop"></i>
275
275
  <% end %>
276
276
  <% end %>
@@ -15,6 +15,7 @@ The helper methods below can also be directly invoked in your application if you
15
15
  | FONTAWESOME_NPM_AUTH_TOKEN | String | `"your_font_awesome_token"` | `font_awesome?` |
16
16
  | SILENCE_LOGS | Boolean | `"true"` | `silence_logs?` |
17
17
  | TESTING_PROVISION_KEY | String | `"asdf123"` | N/A |
18
+ | OPENAI_ACCESS_TOKEN | String |`your_openai_token`| `openai_enabled?` |
18
19
 
19
20
  | Option | Description |
20
21
  | --- | --- |
@@ -27,3 +28,4 @@ The helper methods below can also be directly invoked in your application if you
27
28
  | FONTAWESOME_NPM_AUTH_TOKEN | Enables use of Font Awesome. |
28
29
  | SILENCE_LOGS | Silences Super Scaffolding logs. |
29
30
  | TESTING_PROVISION_KEY | Creates a test `Platform::Application` by accessing `/testing/provision?key=your_provision_key` |
31
+ | OPENAI_ACCESS_TOKEN | Enables use [OpenAI](https://openai.com/) with the [ruby-openai](https://github.com/alexrudall/ruby-openai) gem. |
@@ -114,7 +114,7 @@ Certain form field partials like `buttons` and `super_select` can also have thei
114
114
  | `boolean` | `boolean` | | `assign_boolean` | | |
115
115
  | [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | |
116
116
  | `cloudinary_image` | `string` | | | | |
117
- | `color_picker` | | | | [pickr](https://simonwep.github.io/pickr/) | |
117
+ | `color_picker` | `string` | | | [pickr](https://simonwep.github.io/pickr/) | |
118
118
  | `date_and_time_field` | `datetime` | | `assign_date_and_time` | [Date Range Picker](https://www.daterangepicker.com) | |
119
119
  | `date_field` | `date` | | `assign_date` | [Date Range Picker](https://www.daterangepicker.com) | |
120
120
  | `email_field` | `string` | | | | |
@@ -12,7 +12,7 @@ The `--sortable` option:
12
12
 
13
13
  1. Wraps the table's body in a `sortable` Stimulus controller, providing drag-and-drop re-ordering;
14
14
  2. Adds a `reorder` action to your resource via `include SortableActions`, triggered automatically on re-order;
15
- 3. Adds a migration to add the `sort_order` column to your model to store the ordering;
15
+ 3. Adds a `sort_order` attribute to your model to store the ordering;
16
16
  4. Adds a `default_scope` which orders by `sort_order` and auto increments `sort_order` on create via `include Sortable` on the model.
17
17
 
18
18
  ## Disabling Saving on Re-order
@@ -134,4 +134,4 @@ And on the `sortable` element, catch the `sortable:drop`, `sortable:drag` (for c
134
134
  data-confirm-reorder-target="sortable"
135
135
  ...
136
136
  >
137
- ```
137
+ ```
@@ -72,7 +72,10 @@ module BulletTrain
72
72
  if open
73
73
  path = source_file[:package_name] ? source_file[:absolute_path] : (source_file[:project_path]).to_s
74
74
  puts "Opening `#{path}`.\n".green
75
- exec "open #{path}"
75
+
76
+ # TODO: Use TerminalCommands to open this file
77
+ open_command = `which open`.present? ? "open" : "xdg-open"
78
+ exec "#{open_command} #{path}"
76
79
  end
77
80
  else
78
81
  puts "Couldn't resolve `#{@needle}`.".red
@@ -101,7 +104,8 @@ module BulletTrain
101
104
 
102
105
  if result[:absolute_path]
103
106
  if result[:absolute_path].include?("/bullet_train")
104
- base_path = "bullet_train" + result[:absolute_path].partition("/bullet_train").last
107
+ regex = /#{"bullet_train-core" if result[:absolute_path].include?("bullet_train-core")}\/bullet_train[.\-_a-z|0-9]*.*/
108
+ base_path = result[:absolute_path].scan(regex).pop
105
109
 
106
110
  # Try to calculate which package the file is from, and what it's path is within that project.
107
111
  ["app", "config", "lib"].each do |directory|
@@ -146,14 +150,13 @@ module BulletTrain
146
150
  # all we need to do is change it to "shared/attributes/code"
147
151
  partial_parts.last.gsub!(/(_)|(\.html\.erb)/, "")
148
152
  @needle = partial_parts.join("/")
149
- elsif @needle.match?(/bullet_train-/)
153
+ elsif @needle.match?(/bullet_train/)
150
154
  # If it's a full path, we need to make sure we're getting it from the right package.
151
- _, partial_view_package, partial_path_without_package = @needle.partition(/bullet_train-[a-z|\-_0-9.]*/)
155
+ _, partial_view_package, partial_path_without_package = @needle.partition(/bullet_train-core\/bullet_train[a-z|\-_0-9.]*/)
152
156
 
153
- # Pop off the version so we can call `bundle show` correctly.
154
- # Also change `bullet_train-base` to `bullet_train`.
157
+ # Pop off `bullet_train-core` and the gem's version so we can call `bundle show` correctly.
158
+ partial_view_package.gsub!(/bullet_train-core\//, "")
155
159
  partial_view_package.gsub!(/[-|.0-9]*$/, "") if partial_view_package.match?(/[-|.0-9]*$/)
156
- partial_view_package.gsub!("-base", "") if /base/.match?(@needle)
157
160
 
158
161
  local_package_path = `bundle show #{partial_view_package}`.chomp
159
162
  return local_package_path + partial_path_without_package
@@ -1,3 +1,3 @@
1
1
  module BulletTrain
2
- VERSION = "1.2.20"
2
+ VERSION = "1.2.22"
3
3
  end
data/lib/bullet_train.rb CHANGED
@@ -33,6 +33,7 @@ require "commonmarker"
33
33
  require "extended_email_reply_parser"
34
34
  require "pagy"
35
35
  require "devise/pwned_password"
36
+ require "openai"
36
37
 
37
38
  module BulletTrain
38
39
  mattr_accessor :routing_concerns, default: []
@@ -152,3 +153,11 @@ end
152
153
  def silence_logs?
153
154
  ENV["SILENCE_LOGS"].present?
154
155
  end
156
+
157
+ def openai_enabled?
158
+ ENV["OPENAI_ACCESS_TOKEN"].present?
159
+ end
160
+
161
+ def openai_organization_exists?
162
+ ENV["OPENAI_ORGANIZATION_ID"]
163
+ end
@@ -112,15 +112,23 @@ namespace :bullet_train do
112
112
  puts ""
113
113
  puts "bin/hack: " + "Clone bullet_train-core and link up gems (will only link up gems if already cloned).".blue
114
114
  puts "bin/hack --link: " + "Link all of your Bullet Train gems to `local/bullet_train-core`.".blue
115
+ puts "bin/hack --link github: " + "Link all of your Bullet Train gems to the public repositories on GitHub".blue
115
116
  puts "bin/hack --link (version-number): " + "Link all of your Bullet Train gems to the version number passed.".blue
116
117
  puts "bin/hack --reset: " + "Resets all of your gems to their original definition.".blue
117
118
  puts "bin/hack --watch-js: " + "Watches for any changes in JavaScript files gems that have an npm package.".blue
118
119
  puts "bin/hack --clean-js: " + "Resets all of your npm packages from `local/bullet_train-core` to their original definition.".blue
119
120
  exit
120
121
  when "--link", "--reset"
121
- version = process[:values].pop
122
- set_core_gems(process[:flag], version, framework_packages)
123
- stream "bundle install"
122
+ link_flag_value = process[:values].pop
123
+ set_core_gems(process[:flag], link_flag_value, framework_packages)
124
+
125
+ # Bundler will throw an error if we try to `bundle install` right after adding the GitHub link to the Gemfile.
126
+ if link_flag_value == "github"
127
+ puts ""
128
+ puts "Now you can run `bundle install` to check out the public repositories on GitHub."
129
+ else
130
+ stream "bundle install"
131
+ end
124
132
  when "--watch-js", "--clean-js"
125
133
  package_name = process[:values].pop
126
134
  framework_package = framework_packages.select { |k, v| k.to_s == package_name }
@@ -218,9 +226,10 @@ namespace :bullet_train do
218
226
  end
219
227
 
220
228
  # Pass "--link" or "--reset" as a flag to set the gems.
221
- def set_core_gems(flag, version, framework_packages)
229
+ def set_core_gems(flag, link_flag_value, framework_packages)
222
230
  packages = framework_packages.keys
223
231
  gemfile_lines = File.readlines("./Gemfile")
232
+ version_regexp = /[\d|.]/
224
233
 
225
234
  packages.each do |package|
226
235
  original_path = "gem \"#{package}\""
@@ -241,7 +250,14 @@ namespace :bullet_train do
241
250
  puts "We can't do anything with this. Sorry! We'll proceed, but you have to link this package yourself.".red
242
251
  elsif `cat Gemfile | grep "gem \\\"#{package}\\\""`.chomp.present?
243
252
  puts "#{package} is directly present in the `Gemfile`, so we'll update that line.".green
244
- line = version.present? ? "#{line.chomp}, \"#{version}\"\n" : line.gsub(original_path, local_path)
253
+
254
+ line = if link_flag_value == "github"
255
+ "#{line.chomp}, git: 'http://github.com/bullet-train-co/bullet_train-core.git'\n"
256
+ elsif link_flag_value&.match?(version_regexp)
257
+ "#{line.chomp}, \"#{link_flag_value}\"\n"
258
+ else
259
+ line.gsub(original_path, local_path)
260
+ end
245
261
  end
246
262
  elsif flag == "--reset"
247
263
  if line.match?(/bullet_train/)
@@ -258,8 +274,10 @@ namespace :bullet_train do
258
274
  if flag == "--link"
259
275
  unless match_found
260
276
  puts "Could not find #{package}. Adding to the end of the Gemfile.".blue
261
- new_lines << if version
262
- "#{original_path.chomp}, \"#{version}\"\n"
277
+ new_lines << if link_flag_value == "github"
278
+ "#{original_path.chomp}, git: 'http://github.com/bullet-train-co/bullet_train-core.git'\n"
279
+ elsif link_flag_value&.match?(version_regexp)
280
+ "#{original_path.chomp}, \"#{link_flag_value}\"\n"
263
281
  else
264
282
  "#{local_path}\n"
265
283
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet_train
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.20
4
+ version: 1.2.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-11 00:00:00.000000000 Z
11
+ date: 2023-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -388,6 +388,20 @@ dependencies:
388
388
  - - ">="
389
389
  - !ruby/object:Gem::Version
390
390
  version: '0'
391
+ - !ruby/object:Gem::Dependency
392
+ name: ruby-openai
393
+ requirement: !ruby/object:Gem::Requirement
394
+ requirements:
395
+ - - ">="
396
+ - !ruby/object:Gem::Version
397
+ version: '0'
398
+ type: :runtime
399
+ prerelease: false
400
+ version_requirements: !ruby/object:Gem::Requirement
401
+ requirements:
402
+ - - ">="
403
+ - !ruby/object:Gem::Version
404
+ version: '0'
391
405
  - !ruby/object:Gem::Dependency
392
406
  name: unicode-emoji
393
407
  requirement: !ruby/object:Gem::Requirement
@@ -722,7 +736,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
722
736
  - !ruby/object:Gem::Version
723
737
  version: '0'
724
738
  requirements: []
725
- rubygems_version: 3.4.1
739
+ rubygems_version: 3.3.7
726
740
  signing_key:
727
741
  specification_version: 4
728
742
  summary: Bullet Train