bullet_train 1.0.26 → 1.0.29

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 736f0b129992c87c1813769d963aa769e8677b8aa34114e1271358ea6cb315f2
4
- data.tar.gz: ba9c8955e07d738664793dbfc25adcf66c31d57008e9e3a8e93f1a850c307019
3
+ metadata.gz: b21c5d19664f00d67f8d24604a6aadf16d34074b4471118893dc4245d52aa048
4
+ data.tar.gz: 68866b87e82a35d9005c0e75259f44f50a0b2607176e78d7de4f7d6f729a82be
5
5
  SHA512:
6
- metadata.gz: 19c0375970f7a2f3399f18cf5549c57a6d289bd7cf32f4f858b8aba06656ca37c6561ae9dcd2972691de1db0f41bcbfea0b3c419f2568682d4f4199a7703da8d
7
- data.tar.gz: 50a5943e0e7c03197d5eb7b4e7c7cfd74011706c1ee8363bd5e6e82c4947fa929ebe7a773eae856385fa78ce9b3c5ffa963cfd08e0ee7ae94ceb98e7288688d1
6
+ metadata.gz: 8744327543da313a00acb719c0b838fb380c5ba10946291ecb3c7d0ba83c927a3cb98ecff024a93480ad0ed044bc1e171c91c8def9c4c58679ce2be5db4e6b51
7
+ data.tar.gz: 74d3acfc5ab9258eb3a3eaaea9e313757a26469404d04bfc5b0c0f210c2f60d3a39abe81d8d563d23a55d019ed813f55a583683d7d2ee24b23379a870cec23c6
@@ -0,0 +1,36 @@
1
+ module CurrentAttributes::Base
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ attribute :user, :team, :membership, :ability
6
+
7
+ resets do
8
+ Time.zone = nil
9
+ end
10
+ end
11
+
12
+ def user=(user)
13
+ super
14
+
15
+ if user
16
+ Time.zone = user.time_zone
17
+ self.ability = Ability.new(user)
18
+ else
19
+ Time.zone = nil
20
+ self.ability = nil
21
+ end
22
+
23
+ update_membership
24
+ end
25
+
26
+ def team=(team)
27
+ super
28
+ update_membership
29
+ end
30
+
31
+ def update_membership
32
+ self.membership = if user && team
33
+ user.memberships.where(team: team)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,2 @@
1
+ <%= render @needle do |p| %>
2
+ <% end %>
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  <%= render 'account/shared/workflow/box' do |p| %>
4
2
  <% p.content_for :title, t('devise.headers.sign_in') %>
5
3
  <% p.content_for :body do %>
@@ -0,0 +1,305 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <%
6
+ # we're going to use the
7
+ body = Nokogiri::HTML(@body)
8
+ title = body.css('h1').first.text.presence || t('bullet_train.tagline')
9
+ first_paragraph = body.css('p').first
10
+ preceding_heading = first_paragraph&.xpath("preceding-sibling::h2")
11
+ description = [preceding_heading&.text, first_paragraph&.text].select(&:present?).join(" — ") || t('bullet_train.description')
12
+ image_url = "https://avatars.githubusercontent.com/u/5976880?s=280&amp;v=4"
13
+ site_name = "Bullet Train Developer Documentation"
14
+ %>
15
+
16
+ <% content_for :title do %>
17
+ <title><%= [site_name, title, t('bullet_train.tagline')].select(&:present?).uniq.first(2).reverse.join(' — ') %></title>
18
+ <% end %>
19
+
20
+ <%= render 'themes/light/layouts/head' %>
21
+ <meta content="<%= t('bullet_train.keywords') %>" name="keywords" />
22
+ <meta content="<%= description.truncate(200) %>" name="description" />
23
+ <meta name="twitter:image:src" content="<%= image_url %>" />
24
+ <meta name="twitter:site" content="@bullettrainco" />
25
+ <meta name="twitter:card" content="summary" />
26
+ <meta name="twitter:title" content="<%= title.truncate(70) %>" />
27
+ <meta name="twitter:description" content="<%= description.truncate(160) %>" />
28
+ <meta property="og:image" content="<%= image_url %>" />
29
+ <meta property="og:site_name" content="<%= site_name %>" />
30
+ <meta property="og:type" content="object" />
31
+ <meta property="og:title" content="<%= title.truncate(95) %>" />
32
+ <meta property="og:url" content="<%= request.base_url + request.path %>" />
33
+ <meta property="og:description" content="<%= description.truncate(200) %>" />
34
+ </head>
35
+ <body class="bg-light-blue-gradient text-gray-700 text-sm font-normal dark:bg-dark-blue-gradient dark:text-sealBlue-900">
36
+ <div class="md:p-5">
37
+ <div class="h-screen md:h-auto overflow-hidden md:rounded-lg flex shadow"
38
+ data-controller="mobile-menu"
39
+ data-mobile-menu-hidden-class="hidden"
40
+ data-mobile-menu-show-event-name-value="mobile-menu:show"
41
+ data-mobile-menu-hide-event-name-value="mobile-menu:hide"
42
+ >
43
+
44
+ <% menu = capture do %>
45
+ <div class="flex items-center flex-shrink-0 p-4 bg-blue-darker md:rounded-tl-lg">
46
+ <%= image_tag image_path("light/logo/logo.png"), class: 'h-5 w-auto mx-auto' %>
47
+
48
+ <div class="lg:hidden absolute right-0">
49
+ <button class="ml-1 flex items-center justify-center h-10 w-10 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
50
+ data-action="reveal#hide"
51
+ >
52
+ <span class="sr-only">Close Application Menu</span>
53
+ <svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
54
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
55
+ </svg>
56
+ </button>
57
+ </div>
58
+ </div>
59
+
60
+ <nav class="flex-1 space-y-1 overflow-y-auto">
61
+ <div class="px-5 py-4" id="menu">
62
+
63
+ <%= render 'account/shared/menu/section', title: 'Introduction' do %>
64
+ <%= render 'account/shared/menu/item', url: '/docs', label: 'Table of Contents' do |p| %>
65
+ <% p.content_for :icon do %>
66
+ <i class="fal fa-home-lg-alt ti ti-list"></i>
67
+ <% end %>
68
+ <% end %>
69
+
70
+ <%= render 'account/shared/menu/item', url: '/docs/getting-started', label: 'Getting Started' do |p| %>
71
+ <% p.content_for :icon do %>
72
+ <i class="fal fa-terminal ti ti-flag"></i>
73
+ <% end %>
74
+ <% end %>
75
+
76
+ <%= render 'account/shared/menu/item', url: '/docs/philosophy', label: 'Philosophy' do |p| %>
77
+ <% p.content_for :icon do %>
78
+ <i class="fal fa-lightbulb-on ti ti-light-bulb"></i>
79
+ <% end %>
80
+ <% end %>
81
+
82
+ <%= render 'account/shared/menu/item', url: '/docs/upgrades', label: 'Upgrades' do |p| %>
83
+ <% p.content_for :icon do %>
84
+ <i class="fal fa-sparkles ti ti-arrow-up"></i>
85
+ <% end %>
86
+ <% end %>
87
+
88
+ <%= render 'account/shared/menu/item', url: '/docs/tunneling', label: 'Tunneling' do |p| %>
89
+ <% p.content_for :icon do %>
90
+ <i class="fal fa-bolt ti ti-bolt"></i>
91
+ <% end %>
92
+ <% end %>
93
+ <% end %>
94
+
95
+ <%= render 'account/shared/menu/section', title: 'Developer Tools' do %>
96
+ <%= render 'account/shared/menu/item', url: '/docs/super-scaffolding', label: 'Super Scaffolding' do |p| %>
97
+ <% p.content_for :icon do %>
98
+ <i class="fal fa-magic ti ti-wand"></i>
99
+ <% end %>
100
+ <% end %>
101
+
102
+ <%= render 'account/shared/menu/item', url: '/docs/field-partials', label: 'Field Partials' do |p| %>
103
+ <% p.content_for :icon do %>
104
+ <i class="fal fa-i-cursor ti ti-text"></i>
105
+ <% end %>
106
+ <% end %>
107
+
108
+ <%= render 'account/shared/menu/item', url: '/docs/themes', label: 'Themes' do |p| %>
109
+ <% p.content_for :icon do %>
110
+ <i class="fal fa-swatchbook ti ti-palette"></i>
111
+ <% end %>
112
+ <% end %>
113
+
114
+ <%= render 'account/shared/menu/item', url: '/docs/seeds', label: 'Database Seeds' do |p| %>
115
+ <% p.content_for :icon do %>
116
+ <i class="fal fa-seedling ti ti-server"></i>
117
+ <% end %>
118
+ <% end %>
119
+
120
+ <%= render 'account/shared/menu/item', url: '/docs/testing', label: 'Test Suite' do |p| %>
121
+ <% p.content_for :icon do %>
122
+ <i class="fal fa-check ti ti-check"></i>
123
+ <% end %>
124
+ <% end %>
125
+ <% end %>
126
+
127
+ <%= render 'account/shared/menu/section', title: 'Accounts & Teams' do %>
128
+ <%= render 'account/shared/menu/item', url: '/docs/authentication', label: 'Authentication' do |p| %>
129
+ <% p.content_for :icon do %>
130
+ <i class="fal fa-fingerprint ti ti-id-badge"></i>
131
+ <% end %>
132
+ <% end %>
133
+
134
+ <%= render 'account/shared/menu/item', url: '/docs/teams', label: 'Teams' do |p| %>
135
+ <% p.content_for :icon do %>
136
+ <i class="fal fa-users ti ti-user"></i>
137
+ <% end %>
138
+ <% end %>
139
+
140
+ <%= render 'account/shared/menu/item', url: '/docs/permissions', label: 'Roles & Permissions' do |p| %>
141
+ <% p.content_for :icon do %>
142
+ <i class="fal fa-lock-alt ti ti-lock"></i>
143
+ <% end %>
144
+ <% end %>
145
+
146
+ <%= render 'account/shared/menu/item', url: '/docs/onboarding', label: 'Onboarding' do |p| %>
147
+ <% p.content_for :icon do %>
148
+ <i class="fal fa-snowboarding ti ti-direction"></i>
149
+ <% end %>
150
+ <% end %>
151
+
152
+ <%= render 'account/shared/menu/item', url: '/docs/namespacing', label: 'Namespacing' do |p| %>
153
+ <% p.content_for :icon do %>
154
+ <i class="fal fa-object-group ti ti-widgetized"></i>
155
+ <% end %>
156
+ <% end %>
157
+ <% end %>
158
+
159
+ <%= render 'account/shared/menu/section', title: 'Billing' do %>
160
+ <%= render 'account/shared/menu/item', url: '/docs/billing/stripe', label: 'Stripe' do |p| %>
161
+ <% p.content_for :icon do %>
162
+ <i class="fab fa-stripe-s ti ti-money"></i>
163
+ <% end %>
164
+ <% end %>
165
+ <% end %>
166
+
167
+ <%= render 'account/shared/menu/section', title: 'Integration' do %>
168
+ <%= render 'account/shared/menu/item', url: '/docs/oauth', label: 'OAuth Providers' do |p| %>
169
+ <% p.content_for :icon do %>
170
+ <i class="fal fa-at ti ti-reload"></i>
171
+ <% end %>
172
+ <% end %>
173
+
174
+ <%= render 'account/shared/menu/item', url: '/docs/api', label: 'REST API' do |p| %>
175
+ <% p.content_for :icon do %>
176
+ <i class="fal fa-brackets-curly ti ti-settings"></i>
177
+ <% end %>
178
+ <% end if false %>
179
+
180
+ <%= render 'account/shared/menu/item', url: '/docs/webhooks/outgoing', label: 'Outgoing Webhooks' do |p| %>
181
+ <% p.content_for :icon do %>
182
+ <i class="fal fa-outlet ti ti-pulse"></i>
183
+ <% end %>
184
+ <% end if false %>
185
+
186
+ <%= render 'account/shared/menu/item', url: '/docs/webhooks/incoming', label: 'Incoming Webhooks' do |p| %>
187
+ <% p.content_for :icon do %>
188
+ <i class="fal fa-plug ti ti-plug"></i>
189
+ <% end %>
190
+ <% end if false %>
191
+ <% end %>
192
+
193
+ <%= render 'account/shared/menu/section', title: 'Internationalization' do %>
194
+ <%= render 'account/shared/menu/item', url: '/docs/i18n', label: 'Translations' do |p| %>
195
+ <% p.content_for :icon do %>
196
+ <i class="fal fa-language ti ti-world"></i>
197
+ <% end %>
198
+ <% end %>
199
+ <% end if false %>
200
+
201
+ <%= render 'account/shared/menu/section', title: 'Add-Ons' do %>
202
+ <%= render 'account/shared/menu/item', url: '/docs/font-awesome-pro', label: 'Font Awesome Pro' do |p| %>
203
+ <% p.content_for :icon do %>
204
+ <i class="fal fa-flag ti ti-flag"></i>
205
+ <% end %>
206
+ <% end %>
207
+ <% end %>
208
+
209
+ <%= render 'account/shared/menu/section', title: 'Deployment' do %>
210
+ <%= render 'account/shared/menu/item', url: '/docs/heroku', label: 'Heroku' do |p| %>
211
+ <% p.content_for :icon do %>
212
+ <i class="fal fa-cloud ti ti-cloud-up"></i>
213
+ <% end %>
214
+ <% end %>
215
+
216
+ <%= render 'account/shared/menu/item', url: '/docs/desktop', label: 'Desktop Applications' do |p| %>
217
+ <% p.content_for :icon do %>
218
+ <i class="fal fa-window-restore ti ti-desktop"></i>
219
+ <% end %>
220
+ <% end %>
221
+ <% end %>
222
+ </div>
223
+ </nav>
224
+ <% end %>
225
+
226
+ <div class="lg:hidden hidden"
227
+ data-mobile-menu-target="wrapper"
228
+
229
+ data-controller="reveal"
230
+ data-reveal-away-value="true"
231
+ data-reveal-hide-keys-value="escape"
232
+
233
+ data-action="mobile-menu:show->reveal#show mobile-menu:hide->reveal#hide mobile-menu-toggle->reveal#toggle reveal:hidden->mobile-menu#hideWrapper"
234
+ >
235
+ <div class="fixed inset-0 flex z-40">
236
+ <button
237
+ data-action="reveal#hide"
238
+
239
+ hidden
240
+ data-reveal
241
+ data-transition
242
+ data-transition-enter="transition-opacity ease-linear duration-200"
243
+ data-transition-enter-start="opacity-0"
244
+ data-transition-enter-end="opacity-100"
245
+ data-transition-leave="transition-opacity ease-linear duration-200"
246
+ data-transition-leave-start="opacity-100"
247
+ data-transition-leave-end="opacity-0"
248
+
249
+ class="fixed inset-0" aria-hidden="true"
250
+ >
251
+ <div class="absolute inset-0 bg-light-blue-gradient opacity-75"></div>
252
+ </button>
253
+ <div
254
+ hidden
255
+ data-reveal
256
+ data-transition
257
+ data-transition-enter="transition ease-in-out duration-200 transform"
258
+ data-transition-enter-start="-translate-x-full"
259
+ data-transition-enter-end="translate-x-0"
260
+ data-transition-leave="transition ease-in-out duration-200 transform"
261
+ data-transition-leave-start="translate-x-0"
262
+ data-transition-leave-end="-translate-x-full"
263
+
264
+ class="relative flex-1 flex flex-col max-w-xs w-full shadow-xl bg-gradient-to-b from-vividBlue-700 to-vividBlue-800 dark:from-sealBlue-200 dark:to-sealBlue-200"
265
+ >
266
+ <%= menu %>
267
+ </div>
268
+ <div class="flex-shrink-0 w-14" aria-hidden="true"></div>
269
+ </div>
270
+ </div>
271
+
272
+ <div class="hidden lg:flex lg:flex-shrink-0 bg-gradient-to-b from-vividBlue-700 to-vividBlue-800 dark:from-sealBlue-200 dark:to-sealBlue-200">
273
+ <div class="w-64">
274
+ <%= menu %>
275
+ </div>
276
+ </div>
277
+
278
+ <div class="flex flex-col w-0 flex-1 overflow-hidden bg-gray-100 dark:bg-sealBlue-200 lg:border-l dark:border-gray-500">
279
+ <main class="flex-1 relative z-0 overflow-y-auto focus:outline-none" tabindex="0">
280
+
281
+ <button class="lg:hidden h-12 w-12 ml-1 flex-none inline-flex items-center justify-center rounded-md text-gray-500 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue"
282
+ data-action="mobile-menu#toggle"
283
+ >
284
+ <span class="sr-only">Open Application Menu</span>
285
+ <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
286
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
287
+ </svg>
288
+ </button>
289
+
290
+ <div class="py-2 px-1">
291
+ <div class="mx-auto sm:px-6 sm:py-4 px-2">
292
+ <div class="bg-white rounded-md shadow sm:py-14 sm:px-12 py-10 px-7">
293
+ <div class="prose" style="max-width: none;">
294
+ <%= yield %>
295
+ </div>
296
+ </div>
297
+
298
+ </div>
299
+ </div>
300
+ </main>
301
+ </div>
302
+ </div>
303
+ </div>
304
+ </body>
305
+ </html>
@@ -0,0 +1,65 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <title>Welcome to <%= t('application.name') %>!</title>
7
+ </head>
8
+ <body>
9
+ <% if content_for? :preheader %>
10
+ <span class="preheader"><% yield :preheader %></span>
11
+ <% end %>
12
+ <table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0">
13
+ <tr>
14
+ <td align="center">
15
+ <table class="email-content" width="100%" cellpadding="0" cellspacing="0">
16
+ <tr>
17
+ <td class="email-masthead">
18
+ <a href="<%= root_url %>" class="email-masthead_name">
19
+ <%= email_image_tag("light/logo/logo.png", width: image_width_for_height('light/logo/logo.png', 50), height: 50, style: "width: #{image_width_for_height('light/logo/logo.png', 50)}px; height: 50px;") %>
20
+ </a>
21
+ </td>
22
+ </tr>
23
+ <!-- Email Body -->
24
+ <tr>
25
+ <td class="email-body" width="100%" cellpadding="0" cellspacing="0">
26
+ <table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0">
27
+ <!-- Body content -->
28
+ <tr>
29
+ <td class="content-cell">
30
+
31
+ <%= yield %>
32
+
33
+ <% if false %>
34
+ <!-- Sub copy -->
35
+ <table class="body-sub">
36
+ <tr>
37
+ <td>
38
+ <p class="sub"><%= t('.trouble') %></p>
39
+ <p class="sub">{{action_url}}</p>
40
+ </td>
41
+ </tr>
42
+ </table>
43
+ <% end %>
44
+ </td>
45
+ </tr>
46
+ </table>
47
+ </td>
48
+ </tr>
49
+ <tr>
50
+ <td>
51
+ <table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0">
52
+ <tr>
53
+ <td class="content-cell" align="center">
54
+ <p class="sub align-center">&copy; <%= t('.all_rights_reserved', year: Date.today.year, product_name: t('application.name')) %></p>
55
+ </td>
56
+ </tr>
57
+ </table>
58
+ </td>
59
+ </tr>
60
+ </table>
61
+ </td>
62
+ </tr>
63
+ </table>
64
+ </body>
65
+ </html>
@@ -0,0 +1 @@
1
+ <%= @body = markdown(File.read(Rails.root.to_s + "/docs/#{@file}.md").gsub('.md)', ')')) %>
@@ -0,0 +1,29 @@
1
+ <% content_for :preheader do %>
2
+ <%= t('.preview', @values) %>
3
+ <% end %>
4
+
5
+ <h1><%= t('.heading', @values) %></h1>
6
+ <%= t('.body.html', @values) %>
7
+
8
+ <!-- Action -->
9
+ <table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0">
10
+ <tr>
11
+ <td align="center">
12
+ <!-- Border based button https://litmus.com/blog/a-guide-to-bulletproof-buttons-in-email-design -->
13
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
14
+ <tr>
15
+ <td align="center">
16
+ <table border="0" cellspacing="0" cellpadding="0">
17
+ <tr>
18
+ <td>
19
+ <a href="<%= @cta_url %>" class="button button--" target="_blank"><%= t('.cta.label', @values) %></a>
20
+ </td>
21
+ </tr>
22
+ </table>
23
+ </td>
24
+ </tr>
25
+ </table>
26
+ </td>
27
+ </tr>
28
+ </table>
29
+ <%= t('.signature.html', @values.merge({support_email: t('application.support_email')})) %>
@@ -0,0 +1,31 @@
1
+ <% content_for :preheader do %>
2
+ <%= t('.preview', @values) %>
3
+ <% end %>
4
+
5
+ <h1><%= t('.heading', @values) %></h1>
6
+ <%= t('.body.html', @values) %>
7
+
8
+ <h2><%= t('.cta.heading', @values) %></h2>
9
+ <p><%= t('.cta.body', @values) %></p>
10
+ <!-- Action -->
11
+ <table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0">
12
+ <tr>
13
+ <td align="center">
14
+ <!-- Border based button https://litmus.com/blog/a-guide-to-bulletproof-buttons-in-email-design -->
15
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
16
+ <tr>
17
+ <td align="center">
18
+ <table border="0" cellspacing="0" cellpadding="0">
19
+ <tr>
20
+ <td>
21
+ <a href="<%= @cta_url %>" class="button button--" target="_blank"><%= t('.cta.label', @values) %></a>
22
+ </td>
23
+ </tr>
24
+ </table>
25
+ </td>
26
+ </tr>
27
+ </table>
28
+ </td>
29
+ </tr>
30
+ </table>
31
+ <%= t('.signature.html', @values.merge({support_email: t('application.support_email')})) %>
@@ -0,0 +1,132 @@
1
+ # Files in the config/locales directory are used for internationalization
2
+ # and are automatically loaded by Rails. If you want to use locales other
3
+ # than English, add the necessary files in this directory.
4
+ #
5
+ # To use the locales, use `I18n.t`:
6
+ #
7
+ # I18n.t "hello"
8
+ #
9
+ # In views, this is aliased to just `t`:
10
+ #
11
+ # <%= t("hello") %>
12
+ #
13
+ # To use a different locale, set it with `I18n.locale`:
14
+ #
15
+ # I18n.locale = :es
16
+ #
17
+ # This would use the information in config/locales/es.yml.
18
+ #
19
+ # The following keys must be escaped otherwise they will not be retrieved by
20
+ # the default I18n backend:
21
+ #
22
+ # true, false, on, off, yes, no
23
+ #
24
+ # Instead, surround them with single quotes.
25
+ #
26
+ # en:
27
+ # "true": "foo"
28
+ #
29
+ # To learn more, please read the Rails Internationalization guide
30
+ # available at https://guides.rubyonrails.org/i18n.html.
31
+
32
+ en:
33
+ bullet_train:
34
+ name: Bullet Train
35
+ tagline: The Ruby on Rails SaaS Template
36
+ description: Bullet Train is a Ruby on Rails SaaS-in-a-Box that saves developers weeks of effort.
37
+ keywords: bullet train ruby on rails saas template starter kit
38
+ support_email: ask@bullettrain.co
39
+ global:
40
+ or: Or
41
+ more: More
42
+ is_admin: Admin?
43
+ person: Person
44
+ admin: Admin
45
+ confirm_message: Are you sure?
46
+ typing_search: Start typing search...
47
+ sidebar: Sidebar
48
+ creator: Bullet Train, Inc.
49
+ buttons:
50
+ other: Other
51
+ debug: Debug
52
+ details: Details
53
+ revoke: Revoke
54
+ cancel: Cancel
55
+ next: Next
56
+ back: Back
57
+ new: New
58
+ edit: Edit
59
+ settings: Settings
60
+ configure: Configure
61
+ remove: Remove
62
+ delete: Delete
63
+ update: Update
64
+ sign_up: Sign Up
65
+ sign_in: Sign In
66
+ notifications:
67
+ not_found: not found
68
+ all_fields_required: All of these fields are required.
69
+ dates:
70
+ today: Today
71
+ day:
72
+ one: 1 Day
73
+ other: '%{count} Days'
74
+ last_month: Last Month
75
+ last_week: Last Week
76
+ last_day:
77
+ one: Last Day
78
+ other: Last %{count} Days
79
+ formats:
80
+ date: '%m/%d/%Y'
81
+ date_and_time: '%m/%d/%Y %l:%M %p'
82
+
83
+ menus:
84
+ main:
85
+ labels:
86
+ account: Account
87
+ new: New
88
+ profile_details: Profile Details
89
+ logout: Logout
90
+ skip: Skip For Now
91
+ dashboard: Dashboard
92
+ team_members: Team Members
93
+ webhooks: Webhooks
94
+ invitations: Invitations
95
+ billing: Billing
96
+ upgrade: Upgrade
97
+ switch_teams: Switch Teams
98
+ add_new_team: Add New Team
99
+ edit_account_details: Account Details
100
+ resources: Resources
101
+ collaborate: Collaborate
102
+ integrations: Integrations
103
+ developers: Developers
104
+ your_account: Your Account
105
+
106
+ breadcrumbs:
107
+ your_dashboard: Your Dashboard
108
+ actions:
109
+ edit: 'Edit'
110
+ new: 'New'
111
+
112
+ fields:
113
+ date_field:
114
+ apply: Apply
115
+ cancel: Clear
116
+
117
+ layouts:
118
+
119
+ application:
120
+ raise: we should never be using the application layout.
121
+
122
+ mailer:
123
+ trouble: If you’re having trouble with the button above, copy and paste the URL below into your web browser.
124
+ all_rights_reserved: "%{year} %{product_name}. All rights reserved."
125
+
126
+ public:
127
+ launch_help: We're helping people launch high quality SaaS products!
128
+ developed_by: Developed By
129
+ made_with_love: Made With Love In
130
+ location: Los Angeles, California
131
+ follow_us: Follow Us
132
+ all_rights_reserved: "%{year} Bullet Train, Inc., All Rights Reserved"
@@ -0,0 +1,152 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ platform/application:
5
+ name: 'Name'
6
+ redirect_uri: 'Redirect URI'
7
+ errors:
8
+ models:
9
+ platform/application:
10
+ attributes:
11
+ redirect_uri:
12
+ fragment_present: 'cannot contain a fragment.'
13
+ invalid_uri: 'must be a valid URI.'
14
+ unspecified_scheme: 'must specify a scheme.'
15
+ relative_uri: 'must be an absolute URI.'
16
+ secured_uri: 'must be an HTTPS/SSL URI.'
17
+ forbidden_uri: 'is forbidden by the server.'
18
+ scopes:
19
+ not_match_configured: "can only contain the strings \"read\", \"write\", or \"delete\". You can also leave this field blank"
20
+
21
+ platform:
22
+ applications:
23
+ confirmations:
24
+ destroy: 'Are you sure?'
25
+ buttons:
26
+ edit: 'Edit'
27
+ destroy: 'Destroy'
28
+ submit: 'Submit'
29
+ cancel: 'Cancel'
30
+ authorize: 'Authorize'
31
+ form:
32
+ error: 'Whoops! Check your form for possible errors'
33
+ help:
34
+ confidential: 'Application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.'
35
+ redirect_uri: 'Use one line per URI'
36
+ blank_redirect_uri: "Leave it blank if you configured your provider to use Client Credentials, Resource Owner Password Credentials or any other grant type that doesn't require redirect URI."
37
+ scopes: 'Separate scopes with spaces. Leave blank to use the default scope.'
38
+ edit:
39
+ title: 'Edit application'
40
+ index:
41
+ title: 'Your applications'
42
+ new: 'New Application'
43
+ name: 'Name'
44
+ callback_url: 'Callback URL'
45
+ confidential: 'Confidential?'
46
+ actions: 'Actions'
47
+ confidentiality:
48
+ 'yes': 'Yes'
49
+ 'no': 'No'
50
+ new:
51
+ title: 'New Application'
52
+ show:
53
+ title: 'Application: %{name}'
54
+ application_id: 'UID'
55
+ secret: 'Secret'
56
+ secret_hashed: 'Secret hashed'
57
+ scopes: 'Scopes'
58
+ confidential: 'Confidential'
59
+ callback_urls: 'Callback urls'
60
+ actions: 'Actions'
61
+ not_defined: 'Not defined'
62
+
63
+ doorkeeper:
64
+ authorizations:
65
+ buttons:
66
+ authorize: 'Authorize'
67
+ deny: 'Deny'
68
+ error:
69
+ title: 'An error has occurred'
70
+ new:
71
+ title: 'Authorization required'
72
+ prompt: 'Authorize %{client_name} to use your account?'
73
+ able_to: 'This application will be able to'
74
+ show:
75
+ title: 'Authorization code'
76
+
77
+ authorized_applications:
78
+ confirmations:
79
+ revoke: 'Are you sure?'
80
+ buttons:
81
+ revoke: 'Revoke'
82
+ index:
83
+ title: 'Your authorized applications'
84
+ application: 'Application'
85
+ created_at: 'Created At'
86
+ date_format: '%Y-%m-%d %H:%M:%S'
87
+
88
+ pre_authorization:
89
+ status: 'Pre-authorization'
90
+
91
+ errors:
92
+ messages:
93
+ # Common error messages
94
+ invalid_request:
95
+ unknown: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
96
+ missing_param: 'Missing required parameter: %{value}.'
97
+ not_support_pkce: 'Invalid code_verifier parameter. Server does not support pkce.'
98
+ request_not_authorized: 'Request need to be authorized. Required parameter for authorizing request is missing or invalid.'
99
+ invalid_redirect_uri: "The requested redirect uri is malformed or doesn't match client redirect URI."
100
+ unauthorized_client: 'The client is not authorized to perform this request using this method.'
101
+ access_denied: 'The resource owner or authorization server denied the request.'
102
+ invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
103
+ invalid_code_challenge_method: 'The code challenge method must be plain or S256.'
104
+ server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
105
+ temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
106
+
107
+ # Configuration error messages
108
+ credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
109
+ resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfigured.'
110
+ admin_authenticator_not_configured: 'Access to admin panel is forbidden due to Doorkeeper.configure.admin_authenticator being unconfigured.'
111
+
112
+ # Access grant errors
113
+ unsupported_response_type: 'The authorization server does not support this response type.'
114
+
115
+ # Access token errors
116
+ invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.'
117
+ invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'
118
+ unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
119
+
120
+ invalid_token:
121
+ revoked: "The access token was revoked"
122
+ expired: "The access token expired"
123
+ unknown: "The access token is invalid"
124
+ revoke:
125
+ unauthorized: "You are not authorized to revoke this token"
126
+
127
+ flash:
128
+ applications:
129
+ create:
130
+ notice: 'Application created.'
131
+ destroy:
132
+ notice: 'Application deleted.'
133
+ update:
134
+ notice: 'Application updated.'
135
+ authorized_applications:
136
+ destroy:
137
+ notice: 'Application revoked.'
138
+
139
+ layouts:
140
+ admin:
141
+ title: 'Doorkeeper'
142
+ nav:
143
+ oauth2_provider: 'OAuth2 Provider'
144
+ applications: 'Applications'
145
+ home: 'Home'
146
+ application:
147
+ title: 'OAuth authorization required'
148
+
149
+ scopes:
150
+ delete: "Your OAuth application is missing the 'delete' scope to access this API method."
151
+ read: "Your OAuth application is missing the 'read' scope to access this API method."
152
+ write: "Your OAuth application is missing the 'write' scope to access this API method."
@@ -0,0 +1,15 @@
1
+ en:
2
+ stripe_connect: Stripe
3
+ # 🚅 super scaffolding will insert new oauth providers above this line.
4
+ omniauth:
5
+ team:
6
+ connected: "We've successfully added that %{provider} account to your team!"
7
+ denied: "Permission to connect to %{provider} was not granted. Not a problem! You can try again if you want to."
8
+ already_present: "That %{provider} account is already present for this team!"
9
+ not_allowed: "You're not allowed to add a %{provider} account to a team you don't have access to."
10
+ user:
11
+ connected: "We've successfully connected that %{provider} account to your user account."
12
+ reconnected: "That %{provider} account is already connected to your user account."
13
+ already_registered: "That %{provider} account is already connected to another user. Before you can connect that %{provider} account with your user account, you'll need to sign out and sign back in using that account and remove it from that user account profile."
14
+ email_already_registered: "Sorry, there is already a user registered with the email address %{email}, but this %{provider} account isn't configured for login with that account. Please sign in using your password and then add this account."
15
+ account_not_found: "Sorry, no existing account was found for that %{provider} account. In order to create a new account, please click the link in the invitation you received via email."
@@ -0,0 +1,6 @@
1
+ en:
2
+ roles:
3
+ label: &label Special Privileges
4
+ breadcrumbs:
5
+ label: *label
6
+ header: Special Privileges
@@ -0,0 +1,36 @@
1
+ en:
2
+ user_mailer:
3
+ signature: &SIGNATURE
4
+ html:
5
+ <p>If you have any questions, please don't hesitate to <a href="mailto:%{support_email}">send us an email</a>.</p>
6
+ <p>Thanks,<br>Bullet Train, Inc.</p>
7
+ invited:
8
+ subject: Invitation to join %{team_name} on Bullet Train!
9
+ preview: '%{inviter_name} has sent you this invitation.'
10
+ heading: You're invited!
11
+ body:
12
+ html:
13
+ <p>
14
+ %{inviter_name} has invited you to join %{team_name} on Bullet Train.
15
+ You can join %{team_name} by clicking the button below.
16
+ </p>
17
+ cta:
18
+ label: Join %{team_name}
19
+ signature:
20
+ <<: *SIGNATURE
21
+ welcome:
22
+ subject: Welcome to the Bullet Train demo!
23
+ preview: This is the default Bullet Train welcome email. Check out the layout!
24
+ heading: Welcome to Bullet Train!
25
+ body:
26
+ html:
27
+ <p>This is the default welcome email for Bullet Train!</p>
28
+ <p>If you have any questions about Bullet Train, just reply to this email!</p>
29
+ <p>It was important to us that Bullet Train applications have a good looking, branded email template by default.</p>
30
+ <p>Thankfully our friends at <a href="https://postmarkapp.com">Postmark</a> made the foundation of this email template <a href="https://github.com/wildbit/postmark-templates">freely available</a>. From there, we've customized it slightly to better match the default Bullet Train look-and-feel.</p>
31
+ cta:
32
+ heading: What's next?
33
+ body: You can use the following link to always return to your Bullet Train account dashboard.
34
+ label: View Your Account Dashboard
35
+ signature:
36
+ <<: *SIGNATURE
@@ -0,0 +1,148 @@
1
+ require 'io/wait'
2
+
3
+ module BulletTrain
4
+ class Resolver
5
+ def initialize(needle)
6
+ @needle = needle
7
+ end
8
+
9
+ def run(eject: false, open: false, force: false, interactive: false)
10
+ # Try to figure out what kind of thing they're trying to look up.
11
+ source_file = calculate_source_file_details
12
+
13
+ if source_file[:absolute_path]
14
+ if source_file[:package_name].present?
15
+ puts ""
16
+ puts "Absolute path:".green
17
+ puts " #{source_file[:absolute_path]}".green
18
+ puts ""
19
+ puts "Package name:".green
20
+ puts " #{source_file[:package_name]}".green
21
+ puts ""
22
+ else
23
+ puts ""
24
+ puts "Project path:".green
25
+ puts " #{source_file[:project_path]}".green
26
+ puts ""
27
+ puts "Note: If this file was previously ejected from a package, we can no longer see which package it came from. However, it should say at the top of the file where it was ejected from.".yellow
28
+ puts ""
29
+ end
30
+
31
+ if interactive && !eject
32
+ puts "\nWould you like to eject the file into the local project? (y/n)\n"
33
+ input = $stdin.gets
34
+ $stdin.getc while $stdin.ready?
35
+ if input.first.downcase == 'y'
36
+ eject = true
37
+ end
38
+ end
39
+
40
+ if eject
41
+ if source_file[:package_name]
42
+ if File.exist?(source_file[:project_path]) && !force
43
+ return puts "Can't eject! `#{source_file[:project_path]}` already exists!\n".red
44
+ else
45
+ `mkdir -p #{source_file[:project_path].split("/")[0...-1].join("/")}`
46
+ puts "Ejecting `#{source_file[:absolute_path]}` to `#{source_file[:project_path]}`".green
47
+ File.open("#{source_file[:project_path]}", "w+") do |file|
48
+ case source_file[:project_path].split(".").last
49
+ when "rb", "yml"
50
+ file.puts "# Ejected from `#{source_file[:package_name]}`.\n\n"
51
+ when "erb"
52
+ file.puts "<% # Ejected from `#{source_file[:package_name]}`. %>\n\n"
53
+ end
54
+ end
55
+ `cat #{source_file[:absolute_path]} >> #{source_file[:project_path]}`.strip
56
+ end
57
+
58
+ # Just in case they try to open the file, open it from the new location.
59
+ source_file[:absolute_path] = source_file[:project_path]
60
+ else
61
+ puts "This file is already in the local project directory. Skipping ejection.".yellow
62
+ puts ""
63
+ end
64
+ end
65
+
66
+ if interactive && !open
67
+ puts "\nWould you like to open `#{source_file[:absolute_path]}`? (y/n)\n"
68
+ input = $stdin.gets
69
+ $stdin.getc while $stdin.ready?
70
+ if input.first.downcase == 'y'
71
+ open = true
72
+ end
73
+ end
74
+
75
+ if open
76
+ path = source_file[:package_name] ? source_file[:absolute_path] : "#{source_file[:project_path]}"
77
+ puts "Opening `#{path}`.\n".green
78
+ exec "open #{path}"
79
+ end
80
+ else
81
+ puts "Couldn't resolve `#{@needle}`.".red
82
+ end
83
+ end
84
+
85
+ def calculate_source_file_details
86
+ result = {
87
+ absolute_path: nil,
88
+ project_path: nil,
89
+ package_name: nil,
90
+ }
91
+
92
+ result[:absolute_path] = class_path || partial_path || file_path
93
+
94
+ if result[:absolute_path]
95
+ base_path = "bullet_train" + result[:absolute_path].split("/bullet_train").last
96
+
97
+ # Try to calculate which package the file is from, and what it's path is within that project.
98
+ ["app", "config", "lib"].each do |directory|
99
+ regex = /\/#{directory}\//
100
+ if base_path.match?(regex)
101
+ project_path = "./#{directory}/#{base_path.rpartition(regex).last}"
102
+ package_name = base_path.rpartition(regex).first.split("/").last
103
+ # If the "package name" is actually just the local project directory.
104
+ if package_name == `pwd`.chomp.split("/").last
105
+ package_name = nil
106
+ end
107
+
108
+ result[:project_path] = project_path
109
+ result[:package_name] = package_name
110
+ end
111
+ end
112
+ end
113
+
114
+ result
115
+ end
116
+
117
+ def url?
118
+ @needle.match?(/https?:\/\//)
119
+ end
120
+
121
+ def class_path
122
+ begin
123
+ @needle.constantize
124
+ return Object.const_source_location(@needle).first
125
+ rescue NameError => _
126
+ return false
127
+ end
128
+ end
129
+
130
+ def partial_path
131
+ begin
132
+ xray_path = ApplicationController.render(template: "bullet_train/partial_resolver", layout: nil, assigns: {needle: @needle}).lines[1].chomp
133
+ if xray_path.match(/<!--XRAY START \d+ (.*)-->/)
134
+ return $1
135
+ else
136
+ raise "It looks like Xray-rails isn't properly enabled?"
137
+ end
138
+ rescue ActionView::Template::Error => _
139
+ return nil
140
+ end
141
+ end
142
+
143
+ def file_path
144
+ # We don't have to do anything here... the absolute path is what we're passed, and we just pass it back.
145
+ @needle
146
+ end
147
+ end
148
+ end
@@ -1,3 +1,3 @@
1
1
  module BulletTrain
2
- VERSION = "1.0.26"
2
+ VERSION = "1.0.29"
3
3
  end
data/lib/bullet_train.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "bullet_train/version"
2
2
  require "bullet_train/engine"
3
+ require "bullet_train/resolver"
3
4
 
4
5
  require "bullet_train/fields"
5
6
  require "bullet_train/roles"
@@ -1,3 +1,5 @@
1
+ require 'io/wait'
2
+
1
3
  namespace :bullet_train do
2
4
  desc "Symlink registered gems in `./tmp/gems` so their views, etc. can be inspected by Tailwind CSS."
3
5
  task :link_gems => :environment do
@@ -23,4 +25,33 @@ namespace :bullet_train do
23
25
  end
24
26
  end
25
27
  end
28
+
29
+ desc "Figure out where something is coming from."
30
+ task :resolve, [:all_options] => :environment do |t, arguments|
31
+ ARGV.pop while ARGV.any?
32
+
33
+ arguments[:all_options]&.split&.each do |argument|
34
+ ARGV.push(argument)
35
+ end
36
+
37
+ if ARGV.include?("--interactive")
38
+ puts "\nOK, paste what you've got for us and hit <Return>!\n".blue
39
+
40
+ input = $stdin.gets.strip
41
+ $stdin.getc while $stdin.ready?
42
+
43
+ # Extract absolute paths from XRAY comments.
44
+ if input.match(/<!--XRAY START \d+ (.*)-->/)
45
+ input = $1
46
+ end
47
+
48
+ ARGV.unshift input.strip
49
+ end
50
+
51
+ if ARGV.first.present?
52
+ BulletTrain::Resolver.new(ARGV.first).run(eject: ARGV.include?("--eject"), open: ARGV.include?("--open"), force: ARGV.include?("--force"), interactive: ARGV.include?("--interactive"))
53
+ else
54
+ $stderr.puts "\n🚅 Usage: `bin/resolve [path, partial, or URL] (--eject) (--open)`\n".blue
55
+ end
56
+ end
26
57
  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.0.26
4
+ version: 1.0.29
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-04 00:00:00.000000000 Z
11
+ date: 2022-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -399,6 +399,7 @@ files:
399
399
  - app/mailers/concerns/mailers/base.rb
400
400
  - app/mailers/devise_mailer.rb
401
401
  - app/mailers/user_mailer.rb
402
+ - app/models/concerns/current_attributes/base.rb
402
403
  - app/models/concerns/invitations/base.rb
403
404
  - app/models/concerns/memberships/base.rb
404
405
  - app/models/concerns/records/base.rb
@@ -449,6 +450,7 @@ files:
449
450
  - app/views/account/users/_form.html.erb
450
451
  - app/views/account/users/edit.html.erb
451
452
  - app/views/account/users/show.html.erb
453
+ - app/views/bullet_train/partial_resolver.html.erb
452
454
  - app/views/devise/confirmations/new.html.erb
453
455
  - app/views/devise/mailer/confirmation_instructions.html.erb
454
456
  - app/views/devise/mailer/password_change.html.erb
@@ -466,12 +468,22 @@ files:
466
468
  - app/views/devise/unlocks/new.html.erb
467
469
  - app/views/layouts/account.html.erb
468
470
  - app/views/layouts/devise.html.erb
471
+ - app/views/layouts/docs.html.erb
472
+ - app/views/layouts/mailer.html.erb
473
+ - app/views/public/home/docs.html.erb
474
+ - app/views/user_mailer/invited.html.erb
475
+ - app/views/user_mailer/welcome.html.erb
476
+ - config/locales/en/base.yml
469
477
  - config/locales/en/devise.en.yml
478
+ - config/locales/en/doorkeeper.en.yml
470
479
  - config/locales/en/invitations.en.yml
471
480
  - config/locales/en/memberships.en.yml
481
+ - config/locales/en/oauth.en.yml
472
482
  - config/locales/en/onboarding/user_details.en.yml
473
483
  - config/locales/en/onboarding/user_email.en.yml
484
+ - config/locales/en/roles.en.yml
474
485
  - config/locales/en/teams.en.yml
486
+ - config/locales/en/user_mailer.en.yml
475
487
  - config/locales/en/users.en.yml
476
488
  - config/routes.rb
477
489
  - db/migrate/20161115160419_devise_create_users.rb
@@ -511,6 +523,7 @@ files:
511
523
  - db/migrate/20211027002944_add_doorkeeper_application_to_users.rb
512
524
  - lib/bullet_train.rb
513
525
  - lib/bullet_train/engine.rb
526
+ - lib/bullet_train/resolver.rb
514
527
  - lib/bullet_train/version.rb
515
528
  - lib/colorizer.rb
516
529
  - lib/string/emoji.rb