bullet_train 1.4.3 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9521826a1552bab65baf10d7144bc10be7f61da32e17e799d498c3e7fdf32f82
4
- data.tar.gz: cf4c3769472e2a4a25a497b1bc40ac95436dd83d9d0b06f78c23bfb30cc9c332
3
+ metadata.gz: 5d073ab349f58c17453f4e4d3f493e97202a56a9c6d521bffe36109f4e78d63b
4
+ data.tar.gz: 870e67cb3d4b7562f3fb8faad380bc45d3b0866b9f51bedc808481db82ce61f3
5
5
  SHA512:
6
- metadata.gz: d6370f74971ba12c953ec66bd63edae2434457a0a84a07ec0dcab44685661026b1b57ba4b99377f2ef696c21bc63aaca6661008f4cc098aeed76fb55751aed68
7
- data.tar.gz: 2705720d73d70dcd59ec85bc322d16f786ff6da81e3399a18b58b775a5a52befe7d8336e636f6544041843e829fd641d04096ab07d0cb865c8493f311b0333de
6
+ metadata.gz: 02a859e9c7b3be4b50ede0d7f45bf4fb53614953a5056bfc94511facb63179b56d4b8b94227fdce6bd23bf3af78d4e5d5ccc0d92c89abf6662a6c868f8c7a15d
7
+ data.tar.gz: 648560376f7307b66aa2eb52788c82278f5c277e8d34d22f6808d3053216634c5e482fd6b995102af9313c3aed123062764ca89c171eaa5b562475e2c42ec314
@@ -0,0 +1,3 @@
1
+ class Account::Onboarding::InvitationListsController < Account::ApplicationController
2
+ include Account::Onboarding::InvitationLists::ControllerBase
3
+ end
@@ -0,0 +1,64 @@
1
+ module Account::Onboarding::InvitationLists::ControllerBase
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ layout "devise"
6
+
7
+ before_action do
8
+ # TODO: Is this okay?
9
+ @user = current_user
10
+ end
11
+ end
12
+
13
+ def new
14
+ @account_onboarding_invitation_list = Account::Onboarding::InvitationList.new
15
+ end
16
+
17
+ def create
18
+ @account_onboarding_invitation_list = Account::Onboarding::InvitationList.new(account_onboarding_invitation_list_params)
19
+
20
+ # Set default values for invitations and memberships.
21
+ # `save` below checks if the values are valid or not.
22
+ @account_onboarding_invitation_list.team = current_team
23
+ @account_onboarding_invitation_list.invitations.each_with_index do |invitation, idx|
24
+ invitation.team = current_team
25
+ invitation.from_membership = current_membership
26
+ invitation.membership.team = current_team
27
+ invitation.membership.user_email = invitation.email
28
+ end
29
+
30
+ respond_to do |format|
31
+ if @account_onboarding_invitation_list.save
32
+ format.html { redirect_to account_team_path(@user.teams.first), notice: "" }
33
+ format.json { render :show, status: :ok, location: [:account, @user] }
34
+ else
35
+ format.html { render :new, status: :unprocessable_entity }
36
+ format.json { render json: @account_onboarding_invitation_list.errors, status: :unprocessable_entity }
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # Never trust parameters from the scary internet, only allow the white list through.
44
+ def account_onboarding_invitation_list_params
45
+ params.require(:account_onboarding_invitation_list).permit(
46
+ invitations_attributes: [
47
+ :email,
48
+ membership_attributes: [
49
+ role_ids: []
50
+ ]
51
+ ]
52
+ )
53
+ end
54
+
55
+ def current_membership
56
+ current_user.memberships.find_by(team: current_team)
57
+ end
58
+
59
+ # Since there is only one membership (an admin) on the team when sending bulk invitations,
60
+ # we don't have to worry about filtering these roles according to if they're manageable or not.
61
+ def available_roles
62
+ current_membership.roles.map { |role| [role.attributes[:key]] + role.attributes[:manageable_roles] }.flatten.uniq.reject { |role| role.match?("default") }
63
+ end
64
+ end
@@ -24,8 +24,14 @@ module Account::Onboarding::UserDetails::ControllerBase
24
24
  # if you update your own user account, devise will normally kick you out, so we do this instead.
25
25
  bypass_sign_in current_user.reload
26
26
 
27
+ # Only redirect users to the bulk invitation page if they're the
28
+ # one who created the team (meaning there's only one membership on the team).
27
29
  if @user.details_provided?
28
- format.html { redirect_to account_team_path(@user.teams.first), notice: "" }
30
+ if bulk_invitations_enabled? && @user.teams.first.memberships.size == 1
31
+ format.html { redirect_to new_account_onboarding_invitation_list_path(@user) }
32
+ else
33
+ format.html { redirect_to account_team_path(@user.teams.first), notice: "" }
34
+ end
29
35
  else
30
36
  format.html {
31
37
  flash[:error] = I18n.t("global.notifications.all_fields_required")
@@ -0,0 +1,9 @@
1
+ module Account::Onboarding::InvitationListsHelper
2
+ # When sending bulk invitations, the current user is the only one with a membership on the team.
3
+ # This means that we can access all of the available roles with the following code.
4
+ def available_roles
5
+ current_user.memberships.first.roles.map do |role|
6
+ [role.attributes[:key]] + role.attributes[:manageable_roles]
7
+ end.flatten.uniq.reject { |role| role.match?("default") }
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ class Account::Onboarding::InvitationList < ApplicationRecord
2
+ include Account::Onboarding::InvitationLists::Base
3
+
4
+ def self.table_name_prefix
5
+ "account_onboarding_"
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Account::Onboarding::InvitationLists::Base
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ belongs_to :team
6
+ has_many :invitations
7
+ has_many :memberships, through: :invitations
8
+
9
+ accepts_nested_attributes_for :invitations, :memberships
10
+ end
11
+ end
@@ -4,6 +4,7 @@ module Invitations::Base
4
4
  included do
5
5
  belongs_to :team
6
6
  belongs_to :from_membership, class_name: "Membership"
7
+ belongs_to :invitation_list, class_name: "Account::Onboarding::InvitationList", optional: true
7
8
  has_one :membership, dependent: :nullify
8
9
 
9
10
  accepts_nested_attributes_for :membership
@@ -0,0 +1,11 @@
1
+ <%= form.fields_for :invitations, Invitation.new do |invitation_form| %>
2
+ <div class="col-span-1">
3
+ <%= render 'shared/fields/email_field', form: invitation_form, method: :email, options: {autofocus: true} %>
4
+ </div>
5
+
6
+ <%= invitation_form.fields_for :membership, Membership.new do |membership_form| %>
7
+ <div class="col-span-1">
8
+ <%= render 'shared/fields/super_select', form: membership_form, method: :role_ids, choices: available_roles, html_options: {multiple: true}, select2_options: {placeholder: t('.membership.roles.default')}, other_options: {label: t('.membership.roles.label')} %>
9
+ </div>
10
+ <% end %>
11
+ <% end %>
@@ -0,0 +1,31 @@
1
+ <% @title = t('.header') %>
2
+
3
+ <%= render 'account/shared/workflow/box' do |box| %>
4
+ <% box.title @title %>
5
+ <% box.body do %>
6
+ <% within_fields_namespace(:self) do %>
7
+ <%= form_with(model: @account_onboarding_invitation_list, class: 'form', local: true) do |f| %>
8
+ <% f.object.errors.each do |error| %>
9
+ <%= render 'account/shared/forms/errors', form: f, attributes: [error.attribute], resource: @account_onboarding_invitation_list %>
10
+ <% end %>
11
+ <%= render 'account/shared/notices', form: f %>
12
+
13
+ <div class="grid gap-y gap-x grid-cols-2">
14
+ <% 1.times do %>
15
+ <%= render 'invitation_form', form: f %>
16
+ <% end %>
17
+ </div>
18
+
19
+ <div class="buttons">
20
+ <%= f.submit t('.buttons.next'), class: first_button_primary %>
21
+ <%= link_to t('.buttons.skip'), main_app.account_teams_path, class: first_button_primary %>
22
+ <% if other_teams.any? %>
23
+ <%= link_to t('global.buttons.back'), main_app.account_teams_path, class: first_button_primary %>
24
+ <% else %>
25
+ <%= link_to t('menus.main.labels.logout'), main_app.destroy_user_session_path(@user, onboard_logout: true), class: first_button_primary, method: 'delete' %>
26
+ <% end %>
27
+ </div>
28
+ <% end %>
29
+ <% end %>
30
+ <% end %>
31
+ <% end %>
@@ -0,0 +1,16 @@
1
+ en:
2
+ onboarding: &onboarding
3
+ invitation_lists:
4
+ buttons: &buttons
5
+ next: Next
6
+ skip: Skip
7
+ new:
8
+ header: Invite your team members
9
+ buttons: *buttons
10
+ invitation_form:
11
+ membership:
12
+ roles:
13
+ label: Roles
14
+ default: Default
15
+ account:
16
+ onboarding: *onboarding
data/config/routes.rb CHANGED
@@ -26,6 +26,7 @@ Rails.application.routes.draw do
26
26
  namespace :onboarding do
27
27
  resources :user_details
28
28
  resources :user_email
29
+ resources :invitation_lists, only: [:new, :create]
29
30
  end
30
31
 
31
32
  # user specific resources.
@@ -1,4 +1,4 @@
1
- Note: before you attempt to manually wire up a `super_select` field, note that Super Scaffolding will automatically do that for your models. See [Super Scoffolding](/docs/super-scaffolding.md) docs, section 4, for an example. And make sure Super Scoffolding doesn't automatically do what you're trying to do.
1
+ Note: before you attempt to manually wire up a `super_select` field, note that Super Scaffolding will automatically do that for your models. See [Super Scaffolding](/docs/super-scaffolding.md) docs, section 4, for an example. And make sure Super Scaffolding doesn't automatically do what you're trying to do.
2
2
 
3
3
  # Examples for the `super_select` Field Partial
4
4
 
@@ -136,7 +136,7 @@ gem "bullet_train-themes-tailwind_css", BULLET_TRAIN_VERSION
136
136
  (We have to do this since we didn't start explicitly tracking versions until `1.4.0` and
137
137
  want to make sure that our gem versions match what the starter repo expects.)
138
138
 
139
- Then run `bundle update`
139
+ Then run `bundle install`
140
140
 
141
141
  Then go ahead and commit the changes.
142
142
 
@@ -247,7 +247,7 @@ BULLET_TRAIN_VERSION = "1.3.1"
247
247
  (We have to do this since we didn't start explicitly tracking versions until `1.4.0` and
248
248
  want to make sure that our gem versions match what the starter repo expects.)
249
249
 
250
- Then run `bundle update`
250
+ Then run `bundle install`
251
251
 
252
252
  Then go ahead and commit the changes.
253
253
 
@@ -272,7 +272,7 @@ If anything fails, investigate the failures and get things working again, and co
272
272
  git checkout main
273
273
  git merge updating-bullet-train-v1.3.1
274
274
  git push origin main
275
- git branch -d updating-bullet-train-v1.3.1`
275
+ git branch -d updating-bullet-train-v1.3.1
276
276
  ```
277
277
 
278
- Alternatively, if you're using GitHub, you can push the `updating-bullet-train-v1.3.1` branch up and create a PR from it and let your CI integration do it's thing and then merge in the PR and delete the branch there. (That's what we typically do.)
278
+ Alternatively, if you're using GitHub, you can push the `updating-bullet-train-v1.3.1` branch up and create a PR from it and let your CI integration do its thing and then merge in the PR and delete the branch there. (That's what we typically do.)
@@ -57,7 +57,7 @@ generate a new one that matches what you need:
57
57
 
58
58
  ```
59
59
  git checkout HEAD -- Gemfile.lock
60
- bundle update
60
+ bundle install
61
61
  ```
62
62
 
63
63
  If you choose to sort out `Gemfile.lock` by hand it's a good idea to run `bundle install` just to make
@@ -84,11 +84,11 @@ If anything fails, investigate the failures and get things working again, and co
84
84
 
85
85
  ```
86
86
  git checkout main
87
- git merge updating-bullet-train-v1.3.0
87
+ git merge updating-bullet-train-v1.4.0
88
88
  git push origin main
89
- git branch -d updating-bullet-train-v1.3.0
89
+ git branch -d updating-bullet-train-v1.4.0
90
90
  ```
91
91
 
92
- Alternatively, if you're using GitHub, you can push the `updating-bullet-train-v1.3.0` branch up and create a PR from it and let your CI integration do it's thing and then merge in the PR and delete the branch there. (That's what we typically do.)
92
+ Alternatively, if you're using GitHub, you can push the `updating-bullet-train-v1.4.0` branch up and create a PR from it and let your CI integration do it's thing and then merge in the PR and delete the branch there. (That's what we typically do.)
93
93
 
94
94
 
data/docs/upgrades.md CHANGED
@@ -30,6 +30,8 @@ recent version of the starter repository should cause a merge conflict in Git. T
30
30
  opportunity to compare our upstream changes with your local customizations and allow you to resolve them in a way that makes sense for
31
31
  your application.
32
32
 
33
+ ⚠️ If you have ejected files or a new custom theme, there is a possibility that those ejected files need to be updated although no merge conflicts arose from `git merge`. You will need to compare your ejected views with the original views in [bullet_train-core](https://github.com/bullet-train-co/bullet_train-core) to ensure everything is working properly. Please refer to the documentation on [indirection](indirection) to find out more about ejected views.
34
+
33
35
  ### 1. Decide which version you want to upgrade to
34
36
 
35
37
  For the purposes of these instructions we'll assume that you're on version `1.4.0` and are going to upgrade to version `1.4.1`.
@@ -66,7 +68,7 @@ git checkout -b updating-bullet-train-1.4.1
66
68
 
67
69
  ### 5. Merge in the newest stuff from Bullet Train and resolve any merge conflicts.
68
70
 
69
- Each version of the starter repo is tagged, so you can merge in the tag from the upstread repo.
71
+ Each version of the starter repo is tagged, so you can merge in the tag from the upstream repo.
70
72
 
71
73
  ```
72
74
  git merge v1.4.1
@@ -114,5 +116,5 @@ git branch -d updating-bullet-train-1.4.1
114
116
  ```
115
117
 
116
118
  Alternatively, if you're using GitHub, you can push the `updating-bullet-train-1.4.1` branch up and create a
117
- PR from it and let your CI integration do it's thing and then merge in the PR and delete the branch there.
119
+ PR from it and let your CI integration do its thing and then merge in the PR and delete the branch there.
118
120
  (That's what we typically do.)
@@ -1,7 +1,7 @@
1
1
  module BulletTrain
2
2
  class Configuration
3
3
  include Singleton
4
- attr_accessor :strong_passwords, :incoming_webhooks_parent_class_name
4
+ attr_accessor :strong_passwords, :enable_bulk_invitations, :incoming_webhooks_parent_class_name
5
5
 
6
6
  @@config = nil
7
7
 
@@ -10,6 +10,7 @@ module BulletTrain
10
10
 
11
11
  # Default values
12
12
  @strong_passwords = true
13
+ @enable_bulk_invitations = false
13
14
  @incoming_webhooks_parent_class_name = "ApplicationRecord"
14
15
  end
15
16
 
@@ -18,6 +19,10 @@ module BulletTrain
18
19
  @@config&.strong_passwords
19
20
  end
20
21
 
22
+ def enable_bulk_invitations
23
+ @@config&.enable_bulk_invitations
24
+ end
25
+
21
26
  def incoming_webhooks_parent_class_name
22
27
  @@config&.incoming_webhooks_parent_class_name
23
28
  end
@@ -11,12 +11,16 @@ module BulletTrain
11
11
  def run(eject: false, open: false, force: false, interactive: false)
12
12
  # Try to figure out what kind of thing they're trying to look up.
13
13
  source_file = calculate_source_file_details
14
+ source_file[:relative_path] = nil
14
15
 
15
16
  if source_file[:absolute_path]
16
17
  puts ""
17
18
  puts "Absolute path:".green
18
19
  puts " #{source_file[:absolute_path]}".green
19
20
  puts ""
21
+
22
+ source_file[:relative_path] = source_file[:absolute_path].split(/(?=#{source_file[:package_name]})/).pop
23
+
20
24
  if source_file[:package_name].present?
21
25
  puts "Package name:".green
22
26
  puts " #{source_file[:package_name]}".green
@@ -44,9 +48,9 @@ module BulletTrain
44
48
  File.open((source_file[:project_path]).to_s, "w+") do |file|
45
49
  case source_file[:project_path].split(".").last
46
50
  when "rb", "yml"
47
- file.puts "# Ejected from `#{source_file[:package_name]}`.\n\n"
51
+ file.puts "# Ejected from `#{source_file[:relative_path] || source_file[:package_name]}`.\n\n"
48
52
  when "erb"
49
- file.puts "<% # Ejected from `#{source_file[:package_name]}`. %>\n\n"
53
+ file.puts "<% # Ejected from `#{source_file[:relative_path] || source_file[:package_name]}`. %>\n\n"
50
54
  end
51
55
  end
52
56
  `cat #{source_file[:absolute_path]} >> #{source_file[:project_path]}`.strip
@@ -1,3 +1,3 @@
1
1
  module BulletTrain
2
- VERSION = "1.4.3"
2
+ VERSION = "1.4.4"
3
3
  end
data/lib/bullet_train.rb CHANGED
@@ -167,6 +167,10 @@ def openai_organization_exists?
167
167
  ENV["OPENAI_ORGANIZATION_ID"]
168
168
  end
169
169
 
170
+ def bulk_invitations_enabled?
171
+ BulletTrain::Configuration.enable_bulk_invitations
172
+ end
173
+
170
174
  def disable_developer_menu?
171
175
  ENV["DISABLE_DEVELOPER_MENU"].present?
172
176
  end
@@ -82,20 +82,30 @@ namespace :bullet_train do
82
82
  gem_names.each do |gem|
83
83
  puts "Searching for locales in #{gem}...".blue
84
84
  gem_path = `bundle show #{gem}`.chomp
85
+ gem_with_version = gem_path.split("/").last
85
86
  locales = Dir.glob("#{gem_path}/**/config/locales/**/*.yml").reject { |path| path.match?("dummy") }
86
87
  next if locales.empty?
87
88
 
88
89
  puts "Found locales. Ejecting to your application...".green
89
90
  locales.each do |locale|
90
- relative_path = locale.split("/config/locales").pop
91
- path_parts = relative_path.split("/")
92
- base_path = path_parts.join("/")
93
- FileUtils.mkdir_p("./config/locales#{base_path}") unless Dir.exist?("./config/locales#{base_path}")
94
-
95
- unless File.exist?("config/locales#{relative_path}")
96
- puts "Ejecting #{relative_path}..."
97
- File.new("config/locales#{relative_path}", "w")
98
- `cp #{locale} config/locales#{relative_path}`
91
+ relative_path = locale.split(/(?=#{gem_with_version}\/config\/locales)/).last
92
+ path_in_locale = locale.split("/config/locales").pop
93
+
94
+ base_path = relative_path.split("/")
95
+ base_path.pop
96
+ base_path = base_path.join("/")
97
+ starter_repo_locale_path = base_path.gsub(gem_with_version, ".")
98
+
99
+ FileUtils.mkdir_p(starter_repo_locale_path) unless Dir.exist?(starter_repo_locale_path)
100
+
101
+ unless File.exist?("config/locales#{path_in_locale}")
102
+ puts "Ejecting #{path_in_locale}..."
103
+ File.new("config/locales#{path_in_locale}", "w")
104
+ `cp #{locale} config/locales#{path_in_locale}`
105
+ file = Pathname.new("config/locales#{path_in_locale}")
106
+ lines = file.readlines
107
+ lines.unshift("# Ejected from #{relative_path}\n\n")
108
+ file.write(lines.join)
99
109
  end
100
110
  end
101
111
  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.4.3
4
+ version: 1.4.4
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-09-14 00:00:00.000000000 Z
11
+ date: 2023-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -513,6 +513,7 @@ files:
513
513
  - app/assets/config/bullet_train_manifest.js
514
514
  - app/controllers/account/invitations_controller.rb
515
515
  - app/controllers/account/memberships_controller.rb
516
+ - app/controllers/account/onboarding/invitation_lists_controller.rb
516
517
  - app/controllers/account/onboarding/user_details_controller.rb
517
518
  - app/controllers/account/onboarding/user_email_controller.rb
518
519
  - app/controllers/account/teams_controller.rb
@@ -521,6 +522,7 @@ files:
521
522
  - app/controllers/concerns/account/controllers/base.rb
522
523
  - app/controllers/concerns/account/invitations/controller_base.rb
523
524
  - app/controllers/concerns/account/memberships/controller_base.rb
525
+ - app/controllers/concerns/account/onboarding/invitation_lists/controller_base.rb
524
526
  - app/controllers/concerns/account/onboarding/user_details/controller_base.rb
525
527
  - app/controllers/concerns/account/onboarding/user_email/controller_base.rb
526
528
  - app/controllers/concerns/account/teams/controller_base.rb
@@ -541,6 +543,7 @@ files:
541
543
  - app/helpers/account/locale_helper.rb
542
544
  - app/helpers/account/markdown_helper.rb
543
545
  - app/helpers/account/memberships_helper.rb
546
+ - app/helpers/account/onboarding/invitation_lists_helper.rb
544
547
  - app/helpers/account/role_helper.rb
545
548
  - app/helpers/account/teams_helper.rb
546
549
  - app/helpers/account/users_helper.rb
@@ -567,12 +570,14 @@ files:
567
570
  - app/mailers/concerns/mailers/base.rb
568
571
  - app/mailers/devise_mailer.rb
569
572
  - app/mailers/user_mailer.rb
573
+ - app/models/account/onboarding/invitation_list.rb
570
574
  - app/models/address.rb
571
575
  - app/models/addresses/continent.rb
572
576
  - app/models/addresses/country.rb
573
577
  - app/models/addresses/region.rb
574
578
  - app/models/addresses/subcontinent.rb
575
579
  - app/models/billing/mock_limiter.rb
580
+ - app/models/concerns/account/onboarding/invitation_lists/base.rb
576
581
  - app/models/concerns/addresses/base.rb
577
582
  - app/models/concerns/addresses/continents/base.rb
578
583
  - app/models/concerns/addresses/countries/base.rb
@@ -606,6 +611,8 @@ files:
606
611
  - app/views/account/memberships/edit.html.erb
607
612
  - app/views/account/memberships/index.html.erb
608
613
  - app/views/account/memberships/show.html.erb
614
+ - app/views/account/onboarding/invitation_lists/_invitation_form.html.erb
615
+ - app/views/account/onboarding/invitation_lists/new.html.erb
609
616
  - app/views/account/onboarding/user_details/edit.html.erb
610
617
  - app/views/account/onboarding/user_email/edit.html.erb
611
618
  - app/views/account/teams/_breadcrumbs.html.erb
@@ -664,6 +671,7 @@ files:
664
671
  - config/locales/en/invitations.en.yml
665
672
  - config/locales/en/memberships.en.yml
666
673
  - config/locales/en/oauth.en.yml
674
+ - config/locales/en/onboarding/invitation_lists.en.yml
667
675
  - config/locales/en/onboarding/user_details.en.yml
668
676
  - config/locales/en/onboarding/user_email.en.yml
669
677
  - config/locales/en/roles.en.yml