bullet_train 1.1.9 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/account/invitations/controller_base.rb +3 -11
  3. data/app/controllers/concerns/account/users/controller_base.rb +4 -25
  4. data/app/controllers/concerns/documentation_support.rb +1 -1
  5. data/app/controllers/concerns/registrations/controller_base.rb +9 -6
  6. data/app/controllers/sessions_controller.rb +9 -0
  7. data/app/helpers/account/teams_helper.rb +1 -1
  8. data/app/helpers/concerns/helpers/base.rb +0 -9
  9. data/app/javascript/controllers/index.js +2 -0
  10. data/app/javascript/controllers/select_all_controller.js +82 -0
  11. data/app/models/concerns/memberships/base.rb +3 -7
  12. data/app/models/concerns/users/base.rb +3 -0
  13. data/app/views/account/memberships/_index.html.erb +4 -35
  14. data/app/views/account/memberships/_membership.html.erb +29 -0
  15. data/app/views/account/memberships/index.html.erb +6 -1
  16. data/app/views/account/memberships/show.html.erb +1 -1
  17. data/app/views/account/onboarding/user_details/edit.html.erb +6 -6
  18. data/app/views/account/teams/_index.html.erb +1 -25
  19. data/app/views/account/teams/_team.html.erb +23 -0
  20. data/app/views/account/teams/index.html.erb +3 -1
  21. data/app/views/account/teams/show.html.erb +1 -1
  22. data/app/views/devise/registrations/new.html.erb +2 -2
  23. data/app/views/devise/sessions/new.html.erb +1 -1
  24. data/app/views/layouts/docs.html.erb +12 -0
  25. data/config/locales/en/base.yml +1 -0
  26. data/config/locales/en/framework_packages.yml +13 -17
  27. data/docs/application-options.md +29 -0
  28. data/docs/authentication.md +9 -0
  29. data/docs/field-partials/file-field.md +25 -0
  30. data/docs/field-partials.md +3 -1
  31. data/docs/i18n.md +28 -0
  32. data/docs/index.md +2 -0
  33. data/docs/invitation_only.md +1 -1
  34. data/docs/themes.md +13 -40
  35. data/docs/trademark.md +25 -0
  36. data/docs/two-factor-authentication.md +16 -0
  37. data/lib/bullet_train/resolver.rb +47 -0
  38. data/lib/bullet_train/version.rb +1 -1
  39. data/lib/bullet_train.rb +6 -1
  40. data/lib/colorizer.rb +1 -1
  41. data/lib/tasks/bullet_train_tasks.rake +74 -12
  42. metadata +9 -4
  43. data/app/assets/javascripts/bullet-train.js +0 -2
  44. data/app/assets/javascripts/bullet-train.js.map +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b2f6e8a8bd9f4303bd21b03d411b0623a8a334858e767a2495648bc826c5e9f
4
- data.tar.gz: abaf4b1241d0d8e501baf65b9fca1aee0d12030fc54c47e83e7d017f20dd0b40
3
+ metadata.gz: 4bb9dc7bc4b2ac1de4645e63ad3cf5da7bf2f4020365bf85efca8de4a4440a45
4
+ data.tar.gz: a328f4be111b4439a89ed0895bd92d16848fe81d9237e43c1f5def3759bed27a
5
5
  SHA512:
6
- metadata.gz: e65877ac21f2a4109b8a0461af3e68f9773d0c31aa85bb1a2b8d9b95a444965057d36f539bdb2921bd2bba9da77bd028614e468b9188135fd8aa7357c5908a9c
7
- data.tar.gz: a766131072e8b221f08d6c21eea4106688cb6b0ea5297730b2ecbb9c0c28f8fcfb5af3424739ffd734f31e1b0c9682b911ba9d0f26dbcf442b0b51857590acbb
6
+ metadata.gz: 4f5892c3867e7ddb2530abe9516e004939c3dc8d35d1347d40e224a6e3d10d912fbb60d8cdc5ed62dcba895a459935ca1e7f3dd33b1b53f6dc31754de867895a
7
+ data.tar.gz: d2c9875372791ca7cf424da1141db44f1f31c2cb3b60cb6001ab80bf30a87bc63b7e52dd8c2808a9c8fcc412c9ee9419b8e137eb60f75439c3b5b30d0dd53811
@@ -49,17 +49,9 @@ module Account::Invitations::ControllerBase
49
49
 
50
50
  # unless the user is signed in.
51
51
  if !current_user.present?
52
- # keep track of the uuid of the invitation so we can reload it
53
- # after they sign up. at this point we don't even know if it's
54
- # valid, but that's fine.
55
- session[:invitation_uuid] = params[:id]
56
-
57
- # also, we'll queue devise up to return to the invitation url after a sign in.
58
- session["user_return_to"] = request.path
59
-
60
- # assume the user needs to create an account.
61
- # this is not the default for devise, but a sensible default here.
62
- redirect_to new_user_registration_path
52
+ # We need them to register.
53
+ # We have to send `invitation_uuid` via params, not session, because Safari doesn't set cookies on redirect.
54
+ redirect_to new_user_registration_path(invitation_uuid: @invitation&.uuid)
63
55
 
64
56
  # session[:invitation_uuid] should only be present if the user is registering for the first time.
65
57
  elsif (@invitation = Invitation.find_by(uuid: session[:invitation_uuid] || params[:id]))
@@ -10,6 +10,10 @@ module Account::Users::ControllerBase
10
10
  # for magic locales.
11
11
  @child_object = @user
12
12
  end
13
+
14
+ private
15
+
16
+ include strong_parameters_from_api
13
17
  end
14
18
 
15
19
  # GET /account/users/1/edit
@@ -53,29 +57,4 @@ module Account::Users::ControllerBase
53
57
  def process_params(strong_params)
54
58
  raise "It looks like you've removed `process_params` from your controller. This will break Super Scaffolding."
55
59
  end
56
-
57
- # Never trust parameters from the scary internet, only allow the white list through.
58
- # TODO Update this to use `include strong_parameters_from_api`.
59
- def user_params
60
- # TODO enforce permissions on updating the user's team name.
61
- strong_params = params.require(:user).permit(
62
- *([
63
- :email,
64
- :first_name,
65
- :last_name,
66
- :time_zone,
67
- :current_password,
68
- :password,
69
- :password_confirmation,
70
- :profile_photo_id,
71
- :locale,
72
- ] + permitted_fields + [
73
- {
74
- current_team_attributes: [:name]
75
- }.merge(permitted_arrays)
76
- ])
77
- )
78
-
79
- process_params(strong_params)
80
- end
81
60
  end
@@ -4,7 +4,7 @@ module DocumentationSupport
4
4
  def docs
5
5
  target = params[:page].presence || "index"
6
6
  all_paths = ([Rails.root.to_s] + `bundle show --paths`.lines.map(&:chomp))
7
- @path = all_paths.map { |path| path + "/docs/#{target}.md" }.detect { |path| File.exists?(path) }
7
+ @path = all_paths.map { |path| path + "/docs/#{target}.md" }.detect { |path| File.exist?(path) }
8
8
  render :docs, layout: "docs"
9
9
  end
10
10
  end
@@ -3,6 +3,12 @@ module Registrations::ControllerBase
3
3
 
4
4
  included do
5
5
  def new
6
+ # We have to set the session here because Safari wouldn't save it on a redirect to this URL.
7
+ if params[:invitation_uuid]
8
+ session[:invitation_uuid] = params[:invitation_uuid]
9
+ session["user_return_to"] = accept_account_invitation_path(params[:invitation_uuid])
10
+ end
11
+
6
12
  if invitation_only?
7
13
  unless session[:invitation_uuid] || session[:invitation_key]
8
14
  return redirect_to root_path
@@ -19,17 +25,14 @@ module Registrations::ControllerBase
19
25
 
20
26
  # if current_user is defined, that means they were successful registering.
21
27
  if current_user
22
- # if the user doesn't have a team at this point, create one.
23
- # If the user is accepting an invitation, then the user's current_team is populated
24
- # with the information attached to their invitation via `@invitation.accept_for` later on,
25
- # so we don't have to create a default team for them here.
26
- unless current_user.teams.any? || session[:invitation_uuid].present?
28
+ # Don't create a default team if they're being invited to another team.
29
+ # Don't create a default team if they have another one for any reason.
30
+ unless session[:invitation_uuid].present? || current_user.teams.any?
27
31
  current_user.create_default_team
28
32
  end
29
33
 
30
34
  # send the welcome email.
31
35
  current_user.send_welcome_email unless current_user.email_is_oauth_placeholder?
32
-
33
36
  end
34
37
  end
35
38
  end
@@ -1,6 +1,15 @@
1
1
  class SessionsController < Devise::SessionsController
2
2
  include Sessions::ControllerBase
3
3
 
4
+ # If user_return_to points to an oauth path we disable Turbo on the sign in form.
5
+ # This makes it work when we need to redirect to external sites and/or custom protocols.
6
+ # With Turbo enabled the browser will block those redirects with a CORS error.
7
+ # https://github.com/bullet-train-co/bullet_train/issues/384
8
+ def user_return_to_is_oauth
9
+ session["user_return_to"]&.match(/^\/oauth/)
10
+ end
11
+ helper_method :user_return_to_is_oauth
12
+
4
13
  def destroy
5
14
  if params.include?(:onboard_logout)
6
15
  signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
@@ -2,7 +2,7 @@ module Account::TeamsHelper
2
2
  def current_team
3
3
  # TODO We do not want this to be based on the `current_team_id`.
4
4
  # TODO We want this to be based on the current resource being loaded.
5
- current_user&.current_team
5
+ @team || current_user&.current_team
6
6
  end
7
7
 
8
8
  def other_teams
@@ -6,13 +6,4 @@ module Helpers::Base
6
6
  # This scope has an order if the SQL changes when we remove any order clause.
7
7
  scope.to_sql != scope.reorder("").to_sql
8
8
  end
9
-
10
- # TODO This should really be in the API package and included from there.
11
- if defined?(BulletTrain::Api)
12
- def render_pagination(json)
13
- if @pagy
14
- json.has_more @pagy.has_more
15
- end
16
- end
17
- end
18
9
  end
@@ -6,6 +6,7 @@ import ClipboardController from './clipboard_controller'
6
6
  import FormController from './form_controller'
7
7
  import MobileMenuController from './mobile_menu_controller'
8
8
  import TextToggleController from './text_toggle_controller'
9
+ import SelectAllController from './select_all_controller'
9
10
 
10
11
  export const controllerDefinitions = [
11
12
  [BulkActionFormController, 'bulk_action_form_controller.js'],
@@ -14,6 +15,7 @@ export const controllerDefinitions = [
14
15
  [FormController, 'form_controller.js'],
15
16
  [MobileMenuController, 'mobile_menu_controller.js'],
16
17
  [TextToggleController, 'text_toggle_controller.js'],
18
+ [SelectAllController, 'select_all_controller.js'],
17
19
  ].map(function(d) {
18
20
  const key = d[1]
19
21
  const controller = d[0]
@@ -0,0 +1,82 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = [ "checkbox", "toggleCheckbox", "toggleLabel", "wrapper" ]
5
+ static classes = [ "unavailable" ]
6
+
7
+ connect() {
8
+ this.enableSelectAll()
9
+ }
10
+
11
+ enableSelectAll() {
12
+ if (!this.hasWrapperTarget) { return }
13
+ if (!this.hasUnavailableClass) { return }
14
+
15
+ this.wrapperTarget.classList.remove(this.unavailableClass)
16
+ this.updateToggle()
17
+ }
18
+
19
+ selectAllOrNone(event) {
20
+ event.preventDefault()
21
+ event.stopPropagation()
22
+ if (this.allSelected) {
23
+ this.selectNone()
24
+ } else {
25
+ this.selectAll()
26
+ }
27
+ this.updateToggle()
28
+ this.dispatch('toggled')
29
+ }
30
+
31
+ selectAll() {
32
+ this.checkboxTargets.forEach(checkbox => {
33
+ checkbox.checked = true
34
+ })
35
+ }
36
+
37
+ selectNone() {
38
+ this.checkboxTargets.forEach(checkbox => {
39
+ checkbox.checked = false
40
+ })
41
+ }
42
+
43
+ updateToggle() {
44
+ let checkbox = this.toggleCheckboxTarget
45
+ let useAlternateLabel = false
46
+
47
+ if (this.allSelected) {
48
+ if (checkbox) {
49
+ checkbox.checked = true
50
+ checkbox.indeterminate = false
51
+ }
52
+ useAlternateLabel = true
53
+ } else if (this.selectedValues.length > 0) {
54
+ if (checkbox) {
55
+ checkbox.indeterminate = true
56
+ }
57
+ } else {
58
+ if (checkbox) {
59
+ checkbox.checked = false
60
+ checkbox.indeterminate = false
61
+ }
62
+ }
63
+
64
+ if (this.hasToggleLabelTarget) {
65
+ this.toggleLabelTarget.dispatchEvent(new CustomEvent(`${this.identifier}:toggle-select-all-label`, { detail: { useAlternate: useAlternateLabel }} ))
66
+ }
67
+ }
68
+
69
+ get selectedValues() {
70
+ let values = []
71
+ this.checkboxTargets.forEach(checkbox => {
72
+ if (checkbox.checked) {
73
+ values.push(checkbox.value)
74
+ }
75
+ })
76
+ return values
77
+ }
78
+
79
+ get allSelected() {
80
+ return this.selectedValues.length === this.checkboxTargets.length
81
+ }
82
+ }
@@ -27,7 +27,7 @@ module Memberships::Base
27
27
 
28
28
  scope :current_and_invited, -> { includes(:invitation).where("user_id IS NOT NULL OR invitations.id IS NOT NULL").references(:invitation) }
29
29
  scope :current, -> { where("user_id IS NOT NULL") }
30
- scope :tombstones, -> { includes(:invitation).where("user_id IS NULL AND invitations.id IS NULL").references(:invitation) }
30
+ scope :tombstones, -> { includes(:invitation).where("user_id IS NULL AND invitations.id IS NULL AND platform_agent IS FALSE").references(:invitation) }
31
31
 
32
32
  # TODO Probably we can provide a way for gem packages to define these kinds of extensions.
33
33
  if billing_enabled?
@@ -62,7 +62,7 @@ module Memberships::Base
62
62
  end
63
63
 
64
64
  def tombstone?
65
- user.nil? && invitation.nil? && !platform_agent?
65
+ user.nil? && invitation.nil? && !platform_agent
66
66
  end
67
67
 
68
68
  def last_admin?
@@ -130,7 +130,7 @@ module Memberships::Base
130
130
  end
131
131
 
132
132
  def first_name_last_initial
133
- [first_name, last_initial].map(&:present?).join(" ")
133
+ [first_name, last_initial].select(&:present?).join(" ")
134
134
  end
135
135
 
136
136
  # TODO utilize this.
@@ -138,8 +138,4 @@ module Memberships::Base
138
138
  def should_receive_notifications?
139
139
  invitation.present? || user.present?
140
140
  end
141
-
142
- def platform_agent?
143
- platform_agent_of_id.present?
144
- end
145
141
  end
@@ -109,10 +109,12 @@ module Users::Base
109
109
  end
110
110
  end
111
111
 
112
+ # TODO https://github.com/bullet-train-co/bullet_train-base/pull/121 should have removed this, but it caused errors.
112
113
  def administrating_team_ids
113
114
  parent_ids_for(Role.admin, :memberships, :team)
114
115
  end
115
116
 
117
+ # TODO https://github.com/bullet-train-co/bullet_train-base/pull/121 should have removed this, but it caused errors.
116
118
  def parent_ids_for(role, through, parent)
117
119
  parent_id_column = "#{parent}_id"
118
120
  key = "#{role.key}_#{through}_#{parent_id_column}s"
@@ -125,6 +127,7 @@ module Users::Base
125
127
  value
126
128
  end
127
129
 
130
+ # TODO https://github.com/bullet-train-co/bullet_train-base/pull/121 should have removed this, but it caused errors.
128
131
  def invalidate_ability_cache
129
132
  update_column(:ability_cache, {})
130
133
  end
@@ -6,12 +6,12 @@
6
6
  <%= render 'account/shared/box' do |p| %>
7
7
  <% p.content_for :title, t(".contexts.#{context.class.name.underscore}.header") %>
8
8
  <% p.content_for :description do %>
9
- <%= raw t(".contexts.#{context.class.name.underscore}.#{memberships.any? ? 'description' : 'description_empty'}") %>
10
- <%= render "shared/limits/index", model: memberships.model %>
9
+ <%= raw t(".contexts.#{context.class.name.underscore}.#{@memberships.any? ? 'description' : 'description_empty'}") %>
10
+ <%= render "shared/limits/index", model: @memberships.model %>
11
11
  <% end %>
12
12
 
13
13
  <% p.content_for :table do %>
14
- <% if memberships.any? %>
14
+ <% if @memberships.any? %>
15
15
  <table class="table">
16
16
  <thead>
17
17
  <tr>
@@ -22,38 +22,7 @@
22
22
  </tr>
23
23
  </thead>
24
24
  <tbody data-model="Membership" data-scope="current">
25
- <% memberships.each do |membership| %>
26
- <tr data-id="<%= membership.id %>">
27
-
28
- <td class="px-6 py-4 whitespace-nowrap">
29
- <%= link_to [:account, membership], class: 'block flex items-center group hover:no-underline no-underline' do %>
30
- <div class="flex-shrink-0 h-10 w-10">
31
- <%= image_tag membership_profile_photo_url(membership), title: membership.label_string, class: 'h-10 w-10 rounded-full' %>
32
- </div>
33
-
34
- <div class="ml-3">
35
- <span class="group-hover:underline"><%= membership.label_string %></span>
36
- <% if membership.unclaimed? %>
37
- <span class="ml-1.5 px-2 inline-flex text-xs text-green-dark bg-green-light border border-green-dark rounded-md">
38
- Invited
39
- </span>
40
- <% end %>
41
- </div>
42
- <% end %>
43
- </td>
44
-
45
- <td>
46
- <% if membership.roles_without_defaults.any? %>
47
- <%= membership.roles_without_defaults.map { |role| t("memberships.fields.role_ids.options.#{role.key}.label") }.to_sentence %>
48
- <% else %>
49
- <%= t("memberships.fields.role_ids.options.default.label") %>
50
- <% end %>
51
- </td>
52
- <td class="text-right">
53
- <%= link_to t('.buttons.show'), [:account, membership], class: 'button-secondary button-smaller' %>
54
- </td>
55
- </tr>
56
- <% end %>
25
+ <%= yield %>
57
26
  </tbody>
58
27
  </table>
59
28
  <% end %>
@@ -0,0 +1,29 @@
1
+ <tr data-id="<%= membership.id %>">
2
+ <td class="px-6 py-4 whitespace-nowrap">
3
+ <%= link_to [:account, membership], class: 'block flex items-center group hover:no-underline no-underline' do %>
4
+ <div class="flex-shrink-0 h-10 w-10">
5
+ <%= image_tag membership_profile_photo_url(membership), title: membership.label_string, class: 'h-10 w-10 rounded-full' %>
6
+ </div>
7
+
8
+ <div class="ml-3">
9
+ <span class="group-hover:underline"><%= membership.label_string %></span>
10
+ <% if membership.unclaimed? %>
11
+ <span class="ml-1.5 px-2 inline-flex text-xs text-green-dark bg-green-light border border-green-dark rounded-md">
12
+ Invited
13
+ </span>
14
+ <% end %>
15
+ </div>
16
+ <% end %>
17
+ </td>
18
+
19
+ <td>
20
+ <% if membership.roles_without_defaults.any? %>
21
+ <%= membership.roles_without_defaults.map { |role| t("memberships.fields.role_ids.options.#{role.key}.label") }.to_sentence %>
22
+ <% else %>
23
+ <%= t("memberships.fields.role_ids.options.default.label") %>
24
+ <% end %>
25
+ </td>
26
+ <td class="text-right">
27
+ <%= link_to t('.buttons.show'), [:account, membership], class: 'button-secondary button-smaller' %>
28
+ </td>
29
+ </tr>
@@ -1,7 +1,12 @@
1
1
  <%= render 'account/shared/page' do |p| %>
2
2
  <% p.content_for :title, t('.section') %>
3
3
  <% p.content_for :body do %>
4
- <%= render 'index', memberships: @memberships.current_and_invited.includes(:user) if @memberships.current_and_invited.any? %>
4
+ <% if @memberships.current_and_invited.any? %>
5
+ <%= render 'index' do %>
6
+ <%= render @memberships.current_and_invited.includes(:user) %>
7
+ <% end %>
8
+ <% end %>
9
+
5
10
  <%= render 'tombstones', memberships: @memberships.tombstones.includes(:user) if @memberships.tombstones.any? %>
6
11
  <% end %>
7
12
  <% end %>
@@ -46,7 +46,7 @@
46
46
  <% else %>
47
47
  <%= link_to t('.buttons.promote'), [:promote, :account, @membership], method: :post, data: { confirm: t('global.confirm_message') }, class: first_button_primary if can? :promote, @membership %>
48
48
  <% end %>
49
- <% if (can? :destroy, @membership) && (!@membership.platform_agent?) %>
49
+ <% if (can? :destroy, @membership) && (!@membership.platform_agent) %>
50
50
  <%= button_to t(".buttons.#{membership_destroy_locale_key(@membership)}"), [:account, @membership], method: :delete, data: { confirm: t(".buttons.confirmations.#{membership_destroy_locale_key(@membership)}", model_locales(@membership)) }, class: first_button_primary %>
51
51
  <% end %>
52
52
  <% end %>
@@ -16,15 +16,15 @@
16
16
  <%= render 'shared/fields/text_field', form: f, method: :last_name %>
17
17
  </div>
18
18
 
19
- <div class="sm:col-span-2">
20
- <% # only edit the team name if this user is an admin and they are the first user. %>
21
- <% # yes, that's redundant. %>
22
- <% if can?(:edit, f.object.current_team) && f.object.current_team.users.count == 1 %>
19
+ <% # only edit the team name if this user is an admin and they are the first user. %>
20
+ <% # yes, that's redundant. %>
21
+ <% if can?(:edit, f.object.current_team) && f.object.current_team.users.count == 1 %>
22
+ <div class="sm:col-span-2">
23
23
  <%= f.fields_for :current_team do |tf| %>
24
24
  <%= render 'shared/fields/text_field', form: tf, method: :name %>
25
25
  <% end %>
26
- <% end %>
27
- </div>
26
+ </div>
27
+ <% end %>
28
28
 
29
29
  <div class="sm:col-span-2">
30
30
  <%= render 'shared/fields/super_select', form: f, method: :time_zone,
@@ -1,29 +1,5 @@
1
1
  <ul class="space-y">
2
- <% @teams.each do |team| %>
3
- <li class="bg-white shadow overflow-hidden sm:rounded-md dark:bg-sealBlue-400">
4
- <%= link_to [:account, team], class: "group block hover:bg-gray-50 dark:hover:bg-sealBlue-400 dark:text-sealBlue-800" do %>
5
- <div class="px-4 py-4 flex items-center sm:pl-8 sm:pr-6">
6
- <div class="min-w-0 flex-1 sm:flex sm:items-center sm:justify-between">
7
- <div>
8
- <div class="flex text-xl font-semibold text-blue uppercase group-hover:text-blue-dark tracking-widest dark:text-white">
9
- <%= team.name %>
10
- </div>
11
- </div>
12
- <div class="mt-4 flex-shrink-0 sm:mt-0">
13
- <div class="flex overflow-hidden">
14
- <%= render 'account/shared/memberships/photos', memberships: team.memberships.current_and_invited.first(10) %>
15
- </div>
16
- </div>
17
- </div>
18
- <div class="ml-5 flex-shrink-0">
19
- <svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
20
- <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
21
- </svg>
22
- </div>
23
- </div>
24
- <% end %>
25
- </li>
26
- <% end %>
2
+ <%= yield %>
27
3
  </ul>
28
4
 
29
5
  <% if show_sign_up_options? && can?(:create, Team.new) %>
@@ -0,0 +1,23 @@
1
+ <li class="bg-white shadow overflow-hidden sm:rounded-md dark:bg-sealBlue-400">
2
+ <%= link_to [:account, team], class: "group block hover:bg-gray-50 dark:hover:bg-sealBlue-400 dark:text-sealBlue-800" do %>
3
+ <div class="px-4 py-4 flex items-center sm:pl-8 sm:pr-6">
4
+ <div class="min-w-0 flex-1 sm:flex sm:items-center sm:justify-between">
5
+ <div>
6
+ <div class="flex text-xl font-semibold text-blue uppercase group-hover:text-blue-dark tracking-widest dark:text-white">
7
+ <%= team.name %>
8
+ </div>
9
+ </div>
10
+ <div class="mt-4 flex-shrink-0 sm:mt-0">
11
+ <div class="flex overflow-hidden">
12
+ <%= render 'account/shared/memberships/photos', memberships: team.memberships.current_and_invited.first(10) %>
13
+ </div>
14
+ </div>
15
+ </div>
16
+ <div class="ml-5 flex-shrink-0">
17
+ <svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
18
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
19
+ </svg>
20
+ </div>
21
+ </div>
22
+ <% end %>
23
+ </li>
@@ -1,6 +1,8 @@
1
1
  <%= render 'account/shared/page' do |p| %>
2
2
  <% p.content_for :title, t('.section') %>
3
3
  <% p.content_for :body do %>
4
- <%= render 'index', creative_concepts: @creative_concepts %>
4
+ <%= render 'index', creative_concepts: @creative_concepts do %>
5
+ <%= render @teams %>
6
+ <% end %>
5
7
  <% end %>
6
8
  <% end %>
@@ -13,7 +13,7 @@
13
13
  <% unless scaffolding_things_disabled? %>
14
14
  <%= render 'account/shared/commentary/box' do |p| %>
15
15
  <% p.content_for :content do %>
16
- <%= render 'account/scaffolding/absolutely_abstract/creative_concepts/index', creative_concepts: @team.scaffolding_absolutely_abstract_creative_concepts.accessible_by(current_ability), hide_back: true unless scaffolding_things_disabled? %>
16
+ <%= render 'account/scaffolding/absolutely_abstract/creative_concepts/index', creative_concepts: @team.scaffolding_absolutely_abstract_creative_concepts, hide_back: true unless scaffolding_things_disabled? %>
17
17
  <% end %>
18
18
 
19
19
  <% p.content_for :commentary do %>
@@ -22,9 +22,9 @@
22
22
  </div>
23
23
 
24
24
  <%= f.submit t('global.buttons.sign_up'), class: 'button full' %>
25
-
26
- <%= render 'devise/shared/oauth', verb: 'Sign Up' %>
27
25
  <% end %>
26
+
27
+ <%= render 'devise/shared/oauth', verb: 'Sign Up' %>
28
28
  <% end %>
29
29
  <% end %>
30
30
  <% end %>
@@ -2,7 +2,7 @@
2
2
  <% p.content_for :title, t('devise.headers.sign_in') %>
3
3
  <% p.content_for :body do %>
4
4
  <% within_fields_namespace(:self) do %>
5
- <%= 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 do |form| %>
5
+ <%= 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: !user_return_to_is_oauth} do |form| %>
6
6
  <% with_field_settings form: form do %>
7
7
  <%= render 'account/shared/notices', form: form %>
8
8
  <%= render 'account/shared/forms/errors', form: form %>
@@ -108,6 +108,12 @@
108
108
  <i class="fa-brands fa-js ti ti-pulse"></i>
109
109
  <% end %>
110
110
  <% end %>
111
+
112
+ <%= render 'account/shared/menu/item', url: '/docs/i18n', label: 'Internationalzation' do |p| %>
113
+ <% p.content_for :icon do %>
114
+ <i class="fa-brands fa-js ti ti-world"></i>
115
+ <% end %>
116
+ <% end %>
111
117
  <% end %>
112
118
 
113
119
  <%= render 'account/shared/menu/section', title: 'Developer Tools' do %>
@@ -140,6 +146,12 @@
140
146
  <i class="fal fa-check ti ti-video-camera"></i>
141
147
  <% end %>
142
148
  <% end %>
149
+
150
+ <%= render 'account/shared/menu/item', url: 'docs/application-options.md', label: 'Application Options' do |p| %>
151
+ <% p.content_for :icon do %>
152
+ <i class="fal fa-gear ti ti-settings"></i>
153
+ <% end %>
154
+ <% end %>
143
155
  <% end %>
144
156
 
145
157
  <%= render 'account/shared/menu/section', title: 'Accounts & Teams' do %>
@@ -77,6 +77,7 @@ en:
77
77
  one: Last Day
78
78
  other: Last %{count} Days
79
79
  formats:
80
+ timestamp_unavailable: Never
80
81
  date: '%m/%d/%Y'
81
82
  date_and_time: '%m/%d/%Y %l:%M %p'
82
83
 
@@ -6,38 +6,34 @@ en:
6
6
  bullet_train-api:
7
7
  git: "bullet-train-co/bullet_train-api"
8
8
  bullet_train-fields:
9
- git: "bullet-train-co/bullet_train-fields"
9
+ git: "bullet-train-co/bullet_train-core"
10
10
  npm: "@bullet-train/fields"
11
11
  bullet_train-has_uuid:
12
- git: "bullet-train-co/bullet_train-has_uuid"
12
+ git: "bullet-train-co/bullet_train-core"
13
13
  bullet_train-incoming_webhooks:
14
- git: "bullet-train-co/bullet_train-incoming_webhooks"
14
+ git: "bullet-train-co/bullet_train-core"
15
15
  bullet_train-integrations:
16
- git: "bullet-train-co/bullet_train-integrations"
16
+ git: "bullet-train-co/bullet_train-core"
17
17
  bullet_train-integrations-stripe:
18
- git: "bullet-train-co/bullet_train-base-integrations-stripe"
18
+ git: "bullet-train-co/bullet_train-core"
19
19
  bullet_train-obfuscates_id:
20
- git: "bullet-train-co/bullet_train-obfuscates_id"
20
+ git: "bullet-train-co/bullet_train-core"
21
21
  bullet_train-outgoing_webhooks:
22
22
  git: "bullet-train-co/bullet_train-outgoing_webhooks"
23
- bullet_train-outgoing_webhooks-core:
24
- git: "bullet-train-co/bullet_train-outgoing_webhooks-core"
25
23
  bullet_train-scope_questions:
26
- git: "bullet-train-co/bullet_train-scope_questions"
24
+ git: "bullet-train-co/bullet_train-core"
27
25
  bullet_train-scope_validator:
28
- git: "bullet-train-co/bullet_train-scope_validator"
26
+ git: "bullet-train-co/bullet_train-core"
29
27
  bullet_train-sortable:
30
- git: "bullet-train-co/bullet_train-sortable"
28
+ git: "bullet-train-co/bullet_train-core"
31
29
  npm: "@bullet-train/bullet-train-sortable"
32
30
  bullet_train-super_scaffolding:
33
31
  git: "bullet-train-co/bullet_train-super_scaffolding"
34
32
  bullet_train-super_load_and_authorize_resource:
35
- git: "bullet-train-co/bullet_train-super_load_and_authorize_resource"
33
+ git: "bullet-train-co/bullet_train-core"
36
34
  bullet_train-themes:
37
- git: "bullet-train-co/bullet_train-themes"
38
- bullet_train-themes-base:
39
- git: "bullet-train-co/bullet_train-themes-base"
35
+ git: "bullet-train-co/bullet_train-core"
40
36
  bullet_train-themes-light:
41
- git: "bullet-train-co/bullet_train-themes-light"
37
+ git: "bullet-train-co/bullet_train-core"
42
38
  bullet_train-themes-tailwind_css:
43
- git: "bullet-train-co/bullet_train-themes-tailwind_css"
39
+ git: "bullet-train-co/bullet_train-core"