bullet_train 1.0.26 → 1.0.29

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: 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