pg_rails 7.0.8.pre.alpha.85 → 7.0.8.pre.alpha.86
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 +4 -4
- data/pg_engine/app/controllers/admin/emails_controller.rb +1 -1
- data/pg_engine/app/controllers/admin/users_controller.rb +1 -0
- data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +2 -0
- data/pg_engine/app/controllers/public/webhooks_controller.rb +7 -6
- data/pg_engine/app/decorators/email_decorator.rb +31 -1
- data/pg_engine/app/models/email.rb +4 -1
- data/pg_engine/app/policies/pg_engine/base_policy.rb +0 -1
- data/pg_engine/app/views/admin/emails/_form.html.slim +8 -7
- data/pg_engine/config/locales/es.yml +9 -2
- data/pg_engine/lib/pg_engine.rb +6 -0
- data/pg_engine/spec/decorators/email_decorator_spec.rb +18 -0
- data/pg_engine/spec/factories/emails.rb +1 -0
- data/pg_engine/spec/lib/pg_engine/mailgun/log_sync_spec.rb +1 -1
- data/pg_engine/spec/models/email_spec.rb +1 -1
- data/pg_engine/spec/{features → system}/destroy_spec.rb +13 -13
- data/pg_engine/spec/{features → system}/login_spec.rb +14 -14
- data/pg_engine/spec/{features → system}/signup_spec.rb +13 -13
- data/pg_layout/app/javascript/application.js +0 -91
- data/pg_layout/app/javascript/channels/consumer.js +36 -1
- data/pg_layout/app/javascript/config/bootstrap.js +42 -0
- data/pg_layout/app/javascript/config/cable_ready.js +0 -26
- data/pg_layout/app/javascript/config/index.js +3 -0
- data/pg_layout/app/javascript/config/rollbar.js +28 -0
- data/pg_layout/app/javascript/config/turbo_rails/index.js +27 -0
- data/pg_layout/app/javascript/config/turbo_rails/set_consumer.js +4 -0
- data/pg_layout/app/javascript/controllers/application.js +6 -4
- data/pg_layout/app/javascript/controllers/index.js +2 -0
- data/pg_layout/app/lib/navbar.rb +1 -0
- data/pg_layout/app/views/layouts/pg_layout/base.html.slim +3 -2
- data/pg_rails/js/index.js +1 -1
- data/pg_rails/lib/pg_rails/rspec_logger_matchers.rb +2 -1
- data/pg_rails/lib/version.rb +1 -1
- data/pg_scaffold/spec/generators_spec.rb +2 -1
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 777adfba6510fb280d827dab94dc0a924f851608924a38e16eeedc43c3bba896
|
4
|
+
data.tar.gz: 9d099949a82596a82e8c2d62e71aaef3bda568cfc3a58793daaa2ab4d53f1d1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 142b66b567ed6f4aa81666b04f7157bb327af673420d4a3a333c723ffb2aa85895e6c80acbfa826a4f81b1db363f025a46d2d850b9dc6b399b4fad281caffa42
|
7
|
+
data.tar.gz: 8317ed39418fe41a693810801ed8fdd5936d3b3dd4670f6247e92575c3a566962e61565c388cced8f5f8512a5910be7b06ca7d9d4b58ffe155168eca61f28749
|
@@ -17,7 +17,7 @@ module Admin
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def atributos_permitidos
|
20
|
-
%i[from_address from_name reply_to to subject body_input associated_id associated_type]
|
20
|
+
%i[status from_address from_name reply_to to subject body_input associated_id associated_type]
|
21
21
|
end
|
22
22
|
|
23
23
|
def atributos_para_buscar
|
@@ -229,6 +229,8 @@ module PgEngine
|
|
229
229
|
instancia_modelo.assign_attributes(modelo_params) if action_name.in? %w[update]
|
230
230
|
end
|
231
231
|
|
232
|
+
# FIXME: estaría bueno delegar directamente a pundit, pero habría que
|
233
|
+
# arreglar tema policies
|
232
234
|
Current.user&.developer? || authorize(instancia_modelo)
|
233
235
|
|
234
236
|
# TODO: problema en create y update cuando falla la validacion
|
@@ -4,8 +4,8 @@ module Public
|
|
4
4
|
|
5
5
|
before_action :verify_signature, only: :mailgun
|
6
6
|
|
7
|
-
rescue_from StandardError do
|
8
|
-
pg_err 'webhook internal server error', request.body.read
|
7
|
+
rescue_from StandardError do |err|
|
8
|
+
pg_err err, 'webhook internal server error', request.body.read
|
9
9
|
head :internal_server_error
|
10
10
|
end
|
11
11
|
|
@@ -21,7 +21,7 @@ module Public
|
|
21
21
|
# Si no se guardó el log es porque ya existía un log con ese ID
|
22
22
|
# Mando :not_acceptable (406) para que Mailgun no vuelva a intentar
|
23
23
|
# https://documentation.mailgun.com/docs/mailgun/user-manual/tracking-messages
|
24
|
-
pg_warn 'ya existía un log con ese id, raaaaro',
|
24
|
+
pg_warn 'ya existía un log con ese id, raaaaro', request.body.read
|
25
25
|
head :not_acceptable
|
26
26
|
end
|
27
27
|
end
|
@@ -34,7 +34,7 @@ module Public
|
|
34
34
|
|
35
35
|
def not_used_token(token)
|
36
36
|
if used_tokens.elements.include?(token)
|
37
|
-
pg_warn 'Mailgun Webhook: refusing used token'
|
37
|
+
pg_warn 'Mailgun Webhook: refusing used token', request.body.read
|
38
38
|
head :ok
|
39
39
|
|
40
40
|
false
|
@@ -46,7 +46,7 @@ module Public
|
|
46
46
|
|
47
47
|
def timestamp_not_too_far(timestamp)
|
48
48
|
if (Time.zone.at(timestamp.to_i) - Time.zone.now).abs > 1.hour
|
49
|
-
pg_warn 'Mailgun Webhook: refusing due to timestamp too far'
|
49
|
+
pg_warn 'Mailgun Webhook: refusing due to timestamp too far', request.body.read
|
50
50
|
head :ok
|
51
51
|
|
52
52
|
false
|
@@ -65,12 +65,13 @@ module Public
|
|
65
65
|
return unless timestamp_not_too_far(timestamp)
|
66
66
|
return unless hexdigest != signature
|
67
67
|
|
68
|
-
pg_warn 'Mailgun Webhook: refusing invalid signature'
|
68
|
+
pg_warn 'Mailgun Webhook: refusing invalid signature', request.body.read
|
69
69
|
head :ok
|
70
70
|
end
|
71
71
|
|
72
72
|
def encode(data)
|
73
73
|
webhook_secret_key = Rails.application.credentials.dig(:mailgun, :webhook_secret_key)
|
74
|
+
# TODO: raise if nil
|
74
75
|
OpenSSL::HMAC.hexdigest('sha256', webhook_secret_key, data)
|
75
76
|
end
|
76
77
|
end
|
@@ -14,9 +14,39 @@ class EmailDecorator < PgEngine::BaseRecordDecorator
|
|
14
14
|
# end
|
15
15
|
# end
|
16
16
|
|
17
|
+
def status_f
|
18
|
+
klass = "badge align-content-center #{status_badge_class}"
|
19
|
+
content_tag :span, id: dom_id(object, :status), class: klass do
|
20
|
+
status_text
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def status_text
|
25
|
+
{
|
26
|
+
'pending' => 'Enviando',
|
27
|
+
'failed' => 'Falló',
|
28
|
+
'sent' => 'Enviando',
|
29
|
+
'accepted' => 'Enviando',
|
30
|
+
'delivered' => 'Entregado',
|
31
|
+
'rejected' => 'Falló'
|
32
|
+
}[object.status]
|
33
|
+
end
|
34
|
+
|
35
|
+
def status_badge_class
|
36
|
+
{
|
37
|
+
'pending' => 'text-bg-warning',
|
38
|
+
'failed' => 'text-bg-danger',
|
39
|
+
'sent' => 'text-bg-warning',
|
40
|
+
'accepted' => 'text-bg-warning',
|
41
|
+
'delivered' => 'text-bg-success',
|
42
|
+
'rejected' => 'text-bg-danger'
|
43
|
+
}[object.status]
|
44
|
+
end
|
45
|
+
|
17
46
|
def encoded_eml_link
|
18
47
|
return if object.encoded_eml.blank?
|
19
48
|
|
20
|
-
link_to 'Download', helpers.rails_blob_path(object.encoded_eml),
|
49
|
+
link_to 'Download', helpers.rails_blob_path(object.encoded_eml),
|
50
|
+
target: :_blank, rel: :noopener
|
21
51
|
end
|
22
52
|
end
|
@@ -36,6 +36,10 @@ class Email < ApplicationRecord
|
|
36
36
|
include Hashid::Rails
|
37
37
|
audited
|
38
38
|
|
39
|
+
after_commit do
|
40
|
+
associated.email_updated(self) if associated.respond_to? :email_updated
|
41
|
+
end
|
42
|
+
|
39
43
|
attr_accessor :require_body_input
|
40
44
|
|
41
45
|
has_one_attached :encoded_eml
|
@@ -63,7 +67,6 @@ class Email < ApplicationRecord
|
|
63
67
|
validates :from_name, length: { within: 0..80 }
|
64
68
|
validates :to, length: { within: 3..200 }
|
65
69
|
|
66
|
-
validates :body_input, length: { minimum: 10 }, if: -> { require_body_input }
|
67
70
|
validates :body_input, presence: true, if: -> { require_body_input }
|
68
71
|
|
69
72
|
validates :from_name, :subject, :to,
|
@@ -4,13 +4,14 @@ div style="max-width: 22em" data-controller="pg_form"
|
|
4
4
|
= pg_form_for(@email || object, asociable:) do |f|
|
5
5
|
= f.mensajes_de_error
|
6
6
|
|
7
|
-
= hidden_field_tag :asociable, true if asociable
|
8
|
-
= f.input :from_address
|
9
|
-
= f.input :from_name
|
10
|
-
= f.input :reply_to
|
11
|
-
= f.input :to
|
12
|
-
= f.input :subject
|
13
|
-
= f.input :body_input, as: :text
|
7
|
+
/ = hidden_field_tag :asociable, true if asociable
|
8
|
+
/ = f.input :from_address
|
9
|
+
/ = f.input :from_name
|
10
|
+
/ = f.input :reply_to
|
11
|
+
/ = f.input :to
|
12
|
+
/ = f.input :subject
|
13
|
+
/ = f.input :body_input, as: :text
|
14
|
+
= f.input :status
|
14
15
|
|
15
16
|
.mt-2
|
16
17
|
= f.button :submit
|
@@ -11,8 +11,15 @@ es:
|
|
11
11
|
confirmed_at: Fecha de confirmación
|
12
12
|
actualizado_por: Actualizado por
|
13
13
|
creado_por: Creado por
|
14
|
-
|
15
|
-
|
14
|
+
enumerize:
|
15
|
+
email:
|
16
|
+
status:
|
17
|
+
pending: Enviando
|
18
|
+
failed: Falló
|
19
|
+
sent: Enviando
|
20
|
+
accepted: Aceptado
|
21
|
+
delivered: Entregado
|
22
|
+
rejected: Rechazado
|
16
23
|
simple_form:
|
17
24
|
"yes": 'Sí'
|
18
25
|
"no": 'No'
|
data/pg_engine/lib/pg_engine.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe EmailDecorator do
|
4
|
+
let(:email) { create :email, status: }
|
5
|
+
let(:decorator) { email.decorate }
|
6
|
+
|
7
|
+
describe '#status_f' do
|
8
|
+
subject { decorator.status_f }
|
9
|
+
|
10
|
+
context 'cuando está entregado' do
|
11
|
+
let(:status) { :delivered }
|
12
|
+
|
13
|
+
it 'tiene badge success' do
|
14
|
+
expect(subject).to include('text-bg-success').and(include('Entregado'))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -13,6 +13,7 @@ FactoryBot.define do
|
|
13
13
|
to { Faker::Internet.email }
|
14
14
|
subject { Faker::Lorem.sentence }
|
15
15
|
body_input { Faker::Lorem.sentence }
|
16
|
+
status { Email.status.values.sample }
|
16
17
|
# tags { Faker::Lorem.sentence }
|
17
18
|
# associated
|
18
19
|
# message_id { Faker::Lorem.sentence }
|
@@ -75,7 +75,7 @@ describe PgEngine::Mailgun::LogSync, vcr: { cassette_name: 'mailgun/log_sync_dow
|
|
75
75
|
end
|
76
76
|
|
77
77
|
context 'cuando se asocia a un email' do
|
78
|
-
let!(:email) { create :email, message_id: 'msgid@fakeapp2024.mail' }
|
78
|
+
let!(:email) { create :email, status: :pending, message_id: 'msgid@fakeapp2024.mail' }
|
79
79
|
|
80
80
|
it do
|
81
81
|
expect(subject.email).to eq email
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
4
|
|
5
|
-
describe 'Sign in'
|
5
|
+
describe 'Sign in' do
|
6
6
|
include ActionView::RecordIdentifier
|
7
7
|
|
8
8
|
shared_examples 'destroy from index' do
|
@@ -50,21 +50,21 @@ describe 'Sign in', :js do
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
]
|
60
|
-
# drivers = %i[selenium_chrome_headless_notebook]
|
61
|
-
# drivers = %i[selenium_chrome_debugger]
|
62
|
-
# drivers = %i[selenium]
|
63
|
-
# drivers = %i[selenium_chrome]
|
53
|
+
# drivers = %i[
|
54
|
+
# selenium_headless
|
55
|
+
# selenium_chrome_headless
|
56
|
+
# selenium_chrome_headless_notebook
|
57
|
+
# selenium_chrome_headless_iphone
|
58
|
+
# ]
|
59
|
+
drivers = %i[selenium_chrome_headless_iphone]
|
64
60
|
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
65
61
|
|
66
62
|
drivers.each do |driver|
|
67
|
-
context("with driver '#{driver}'"
|
63
|
+
context("with driver '#{driver}'") do
|
64
|
+
before do
|
65
|
+
driven_by driver
|
66
|
+
end
|
67
|
+
|
68
68
|
it_behaves_like 'destroy from index'
|
69
69
|
it_behaves_like 'destroy from show'
|
70
70
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
4
|
|
5
|
-
describe 'Sign in'
|
5
|
+
describe 'Sign in' do
|
6
6
|
shared_examples 'sign_in' do
|
7
7
|
subject do
|
8
8
|
visit '/users/sign_in'
|
@@ -20,22 +20,22 @@ describe 'Sign in', :js do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
]
|
30
|
-
# drivers = %i[selenium_chrome_headless_notebook]
|
31
|
-
# drivers = %i[selenium_chrome_debugger]
|
32
|
-
# drivers = %i[selenium]
|
33
|
-
# drivers = %i[selenium_chrome]
|
23
|
+
# drivers = %i[
|
24
|
+
# selenium_headless
|
25
|
+
# selenium_chrome_headless
|
26
|
+
# selenium_chrome_headless_notebook
|
27
|
+
# selenium_chrome_headless_iphone
|
28
|
+
# ]
|
29
|
+
drivers = %i[selenium_chrome_headless_iphone]
|
34
30
|
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
35
31
|
|
36
32
|
drivers.each do |driver|
|
37
|
-
context("with driver '#{driver}'"
|
38
|
-
|
33
|
+
context("with driver '#{driver}'") do
|
34
|
+
before do
|
35
|
+
driven_by driver
|
36
|
+
end
|
37
|
+
|
38
|
+
it_behaves_like 'sign_in'
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
4
|
|
5
|
-
describe 'Al Registrarse'
|
5
|
+
describe 'Al Registrarse' do
|
6
6
|
include ActiveJob::TestHelper
|
7
7
|
|
8
8
|
find_scroll = proc do |selector, options = {}|
|
@@ -56,21 +56,21 @@ describe 'Al Registrarse', :js do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
]
|
66
|
-
# drivers = %i[selenium_chrome_headless_notebook]
|
67
|
-
# drivers = %i[selenium_chrome_debugger]
|
68
|
-
# drivers = %i[selenium]
|
69
|
-
# drivers = %i[selenium_chrome]
|
59
|
+
# drivers = %i[
|
60
|
+
# selenium_headless
|
61
|
+
# selenium_chrome_headless
|
62
|
+
# selenium_chrome_headless_notebook
|
63
|
+
# selenium_chrome_headless_iphone
|
64
|
+
# ]
|
65
|
+
drivers = %i[selenium_chrome_headless_iphone]
|
70
66
|
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
71
67
|
|
72
68
|
drivers.each do |driver|
|
73
|
-
context("with driver '#{driver}'"
|
69
|
+
context("with driver '#{driver}'") do
|
70
|
+
before do
|
71
|
+
driven_by driver
|
72
|
+
end
|
73
|
+
|
74
74
|
it_behaves_like 'sign_up'
|
75
75
|
it_behaves_like 'edit user'
|
76
76
|
end
|
@@ -1,94 +1,3 @@
|
|
1
|
-
import Rollbar from 'rollbar'
|
2
|
-
|
3
1
|
import './config'
|
4
2
|
import './channels'
|
5
3
|
import './controllers'
|
6
|
-
|
7
|
-
// Bootstrap's toasts
|
8
|
-
import * as bootstrap from 'bootstrap'
|
9
|
-
|
10
|
-
let rollbarToken = document.head.querySelector('meta[name=rollbar-token]')
|
11
|
-
rollbarToken = rollbarToken && rollbarToken.content
|
12
|
-
|
13
|
-
let rollbarEnv = document.head.querySelector('meta[name=rollbar-env]')
|
14
|
-
rollbarEnv = rollbarEnv && rollbarEnv.content
|
15
|
-
rollbarEnv = rollbarEnv || 'unknown'
|
16
|
-
|
17
|
-
window.Rollbar = Rollbar
|
18
|
-
|
19
|
-
Rollbar.init()
|
20
|
-
|
21
|
-
Rollbar.global({
|
22
|
-
itemsPerMinute: 2,
|
23
|
-
maxItems: 5
|
24
|
-
})
|
25
|
-
Rollbar.configure({
|
26
|
-
enabled: !!rollbarToken,
|
27
|
-
accessToken: rollbarToken,
|
28
|
-
captureUncaught: true,
|
29
|
-
captureUnhandledRejections: true,
|
30
|
-
reportLevel: 'warning',
|
31
|
-
payload: {
|
32
|
-
environment: rollbarEnv
|
33
|
-
}
|
34
|
-
})
|
35
|
-
|
36
|
-
document.addEventListener('turbo:load', bindAndObserveToasts)
|
37
|
-
document.addEventListener('turbo:render', bindAndObserveToasts)
|
38
|
-
|
39
|
-
document.addEventListener('turbo:before-cache', () => {
|
40
|
-
document.querySelectorAll('#flash .alert').forEach((el) => {
|
41
|
-
el.remove()
|
42
|
-
})
|
43
|
-
document.querySelectorAll('.offcanvas-backdrop').forEach((el) => {
|
44
|
-
el.remove()
|
45
|
-
})
|
46
|
-
document.querySelectorAll('.offcanvas').forEach((el) => {
|
47
|
-
el.classList.remove('show')
|
48
|
-
})
|
49
|
-
})
|
50
|
-
|
51
|
-
function bindToastElements () {
|
52
|
-
const toastQuery = '.pg-toast:not(.hide):not(.show)'
|
53
|
-
|
54
|
-
const toastElList = document.querySelectorAll(toastQuery)
|
55
|
-
Array.from(toastElList).map(toastEl => {
|
56
|
-
toastEl.addEventListener('hidden.bs.toast', () => {
|
57
|
-
toastEl.remove()
|
58
|
-
})
|
59
|
-
return new bootstrap.Toast(toastEl).show()
|
60
|
-
})
|
61
|
-
}
|
62
|
-
|
63
|
-
function bindAndObserveToasts () {
|
64
|
-
bindToastElements()
|
65
|
-
|
66
|
-
// Select the node that will be observed for mutations
|
67
|
-
const targetNode = document.getElementById('flash')
|
68
|
-
|
69
|
-
// Options for the observer (which mutations to observe)
|
70
|
-
const config = { attributes: true, childList: true, subtree: true }
|
71
|
-
|
72
|
-
// Callback function to execute when mutations are observed
|
73
|
-
const callback = (mutationList, observer) => {
|
74
|
-
for (const mutation of mutationList) {
|
75
|
-
if (mutation.type === 'childList') {
|
76
|
-
bindToastElements()
|
77
|
-
}
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
|
-
// Create an observer instance linked to the callback function
|
82
|
-
const observer = new MutationObserver(callback)
|
83
|
-
|
84
|
-
// Start observing the target node for configured mutations
|
85
|
-
observer.observe(targetNode, config)
|
86
|
-
}
|
87
|
-
|
88
|
-
// document.addEventListener('turbo:before-stream-render', function () { console.log('turbo:before-stream-render') })
|
89
|
-
// document.addEventListener('turbo:render', function () { console.log('turbo:render') })
|
90
|
-
// document.addEventListener('turbo:before-render', function () { console.log('turbo:before-render') })
|
91
|
-
// document.addEventListener('turbo:before-frame-render', function () { console.log('turbo:before-frame-render') })
|
92
|
-
// document.addEventListener('turbo:frame-load', function () { console.log('turbo:frame-load') })
|
93
|
-
// document.addEventListener('turbo:before-fetch-request', function () { console.log('turbo:before-fetch-request') })
|
94
|
-
// document.addEventListener('turbo:fetch-request-error', function () { console.log('turbo:fetch-request-error') })
|
@@ -2,11 +2,46 @@
|
|
2
2
|
// You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
|
3
3
|
|
4
4
|
import { createConsumer } from '@anycable/web'
|
5
|
+
import Rollbar from 'rollbar'
|
5
6
|
|
6
7
|
let cableProtocol = document.head.querySelector('meta[name=actioncable-protocol]')
|
7
8
|
cableProtocol = cableProtocol && cableProtocol.content
|
8
9
|
cableProtocol = cableProtocol || 'actioncable-v1-ext-json'
|
9
10
|
|
10
|
-
|
11
|
+
const consumer = createConsumer({
|
11
12
|
protocol: cableProtocol
|
12
13
|
})
|
14
|
+
|
15
|
+
const anycable = consumer.cable
|
16
|
+
|
17
|
+
if (anycable) {
|
18
|
+
anycable.on('connect', ev => {
|
19
|
+
document.head.dataset.cableConnected = true
|
20
|
+
if (ev.reconnect) {
|
21
|
+
console.log('Welcome back!')
|
22
|
+
} else {
|
23
|
+
console.log('Welcome!')
|
24
|
+
}
|
25
|
+
})
|
26
|
+
|
27
|
+
anycable.on('disconnect', ev => {
|
28
|
+
document.head.dataset.cableConnected = false
|
29
|
+
// document.head.dataset.cableDisconnectedEvent = ev
|
30
|
+
if (ev.reason) {
|
31
|
+
if (ev.reason === 'transport_closed') {
|
32
|
+
// no hago nada (?
|
33
|
+
} else {
|
34
|
+
Rollbar.warning(`Disconnected because: ${ev.reason}`)
|
35
|
+
}
|
36
|
+
console.log(`Disconnected because: ${ev.reason}`)
|
37
|
+
} else {
|
38
|
+
Rollbar.warning('Disconnected for unknown reason')
|
39
|
+
console.log('Disconnected for unknown reason')
|
40
|
+
}
|
41
|
+
})
|
42
|
+
}
|
43
|
+
|
44
|
+
// Para desconectar
|
45
|
+
// anycable.disconnect()
|
46
|
+
|
47
|
+
export default consumer
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import * as bootstrap from 'bootstrap'
|
2
|
+
|
3
|
+
document.addEventListener('turbo:load', bindAndObserveToasts)
|
4
|
+
document.addEventListener('turbo:render', bindAndObserveToasts)
|
5
|
+
|
6
|
+
// TODO: testear con capybara
|
7
|
+
function bindToastElements () {
|
8
|
+
const toastQuery = '.pg-toast:not(.hide):not(.show)'
|
9
|
+
|
10
|
+
const toastElList = document.querySelectorAll(toastQuery)
|
11
|
+
Array.from(toastElList).map(toastEl => {
|
12
|
+
toastEl.addEventListener('hidden.bs.toast', () => {
|
13
|
+
toastEl.remove()
|
14
|
+
})
|
15
|
+
return new bootstrap.Toast(toastEl).show()
|
16
|
+
})
|
17
|
+
}
|
18
|
+
|
19
|
+
function bindAndObserveToasts () {
|
20
|
+
bindToastElements()
|
21
|
+
|
22
|
+
// Select the node that will be observed for mutations
|
23
|
+
const targetNode = document.getElementById('flash')
|
24
|
+
|
25
|
+
// Options for the observer (which mutations to observe)
|
26
|
+
const config = { attributes: true, childList: true, subtree: true }
|
27
|
+
|
28
|
+
// Callback function to execute when mutations are observed
|
29
|
+
const callback = (mutationList, observer) => {
|
30
|
+
for (const mutation of mutationList) {
|
31
|
+
if (mutation.type === 'childList') {
|
32
|
+
bindToastElements()
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
// Create an observer instance linked to the callback function
|
38
|
+
const observer = new MutationObserver(callback)
|
39
|
+
|
40
|
+
// Start observing the target node for configured mutations
|
41
|
+
observer.observe(targetNode, config)
|
42
|
+
}
|
@@ -1,30 +1,4 @@
|
|
1
1
|
import consumer from '../channels/consumer'
|
2
2
|
import CableReady from 'cable_ready'
|
3
|
-
import Rollbar from 'rollbar'
|
4
|
-
|
5
|
-
const anycable = consumer.cable
|
6
|
-
|
7
|
-
if (anycable) {
|
8
|
-
anycable.on('connect', ev => {
|
9
|
-
document.head.dataset.cableConnected = true
|
10
|
-
if (ev.reconnect) {
|
11
|
-
console.log('Welcome back!')
|
12
|
-
} else {
|
13
|
-
console.log('Welcome!')
|
14
|
-
}
|
15
|
-
})
|
16
|
-
|
17
|
-
anycable.on('disconnect', ev => {
|
18
|
-
document.head.dataset.cableConnected = false
|
19
|
-
// document.head.dataset.cableDisconnectedEvent = ev
|
20
|
-
if (ev.reason) {
|
21
|
-
Rollbar.warning(`Disconnected because: ${ev.reason}`)
|
22
|
-
console.log(`Disconnected because: ${ev.reason}`)
|
23
|
-
} else {
|
24
|
-
Rollbar.warning('Disconnected for unknown reason')
|
25
|
-
console.log('Disconnected for unknown reason')
|
26
|
-
}
|
27
|
-
})
|
28
|
-
}
|
29
3
|
|
30
4
|
CableReady.initialize({ consumer })
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import Rollbar from 'rollbar'
|
2
|
+
|
3
|
+
// TODO: testear con capybara, si se puede
|
4
|
+
let rollbarToken = document.head.querySelector('meta[name=rollbar-token]')
|
5
|
+
rollbarToken = rollbarToken && rollbarToken.content
|
6
|
+
|
7
|
+
let rollbarEnv = document.head.querySelector('meta[name=rollbar-env]')
|
8
|
+
rollbarEnv = rollbarEnv && rollbarEnv.content
|
9
|
+
rollbarEnv = rollbarEnv || 'unknown'
|
10
|
+
|
11
|
+
window.Rollbar = Rollbar
|
12
|
+
|
13
|
+
Rollbar.init()
|
14
|
+
|
15
|
+
Rollbar.global({
|
16
|
+
itemsPerMinute: 2,
|
17
|
+
maxItems: 5
|
18
|
+
})
|
19
|
+
Rollbar.configure({
|
20
|
+
enabled: !!rollbarToken,
|
21
|
+
accessToken: rollbarToken,
|
22
|
+
captureUncaught: true,
|
23
|
+
captureUnhandledRejections: true,
|
24
|
+
reportLevel: 'warning',
|
25
|
+
payload: {
|
26
|
+
environment: rollbarEnv
|
27
|
+
}
|
28
|
+
})
|
@@ -0,0 +1,27 @@
|
|
1
|
+
// Es necesario que el consumer se setee antes de cargar la librería
|
2
|
+
// para que lo tomen los TurboCableStreamSourceElement's
|
3
|
+
|
4
|
+
import './set_consumer'
|
5
|
+
|
6
|
+
import '@hotwired/turbo-rails'
|
7
|
+
|
8
|
+
// TODO: testear con capybara
|
9
|
+
document.addEventListener('turbo:before-cache', () => {
|
10
|
+
document.querySelectorAll('#flash .alert').forEach((el) => {
|
11
|
+
el.remove()
|
12
|
+
})
|
13
|
+
document.querySelectorAll('.offcanvas-backdrop').forEach((el) => {
|
14
|
+
el.remove()
|
15
|
+
})
|
16
|
+
document.querySelectorAll('.offcanvas').forEach((el) => {
|
17
|
+
el.classList.remove('show')
|
18
|
+
})
|
19
|
+
})
|
20
|
+
|
21
|
+
// document.addEventListener('turbo:before-stream-render', function () { console.log('turbo:before-stream-render') })
|
22
|
+
// document.addEventListener('turbo:render', function () { console.log('turbo:render') })
|
23
|
+
// document.addEventListener('turbo:before-render', function () { console.log('turbo:before-render') })
|
24
|
+
// document.addEventListener('turbo:before-frame-render', function () { console.log('turbo:before-frame-render') })
|
25
|
+
// document.addEventListener('turbo:frame-load', function () { console.log('turbo:frame-load') })
|
26
|
+
// document.addEventListener('turbo:before-fetch-request', function () { console.log('turbo:before-fetch-request') })
|
27
|
+
// document.addEventListener('turbo:fetch-request-error', function () { console.log('turbo:fetch-request-error') })
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
console.error('window.Stimulus must be set')
|
3
|
-
}
|
1
|
+
import { Application } from '@hotwired/stimulus'
|
4
2
|
|
5
|
-
const application =
|
3
|
+
const application = Application.start()
|
4
|
+
|
5
|
+
// Configure Stimulus development experience
|
6
|
+
application.debug = false
|
7
|
+
window.Stimulus = application
|
6
8
|
|
7
9
|
export { application }
|
@@ -15,3 +15,5 @@ application.register('fadein_onload', FadeinOnloadController)
|
|
15
15
|
application.register('clear-timeout', ClearTimeoutController)
|
16
16
|
application.register('switcher', SwitcherController)
|
17
17
|
application.register('filtros', FiltrosController)
|
18
|
+
|
19
|
+
// TODO: testear con capybara todo lo que se pueda
|
data/pg_layout/app/lib/navbar.rb
CHANGED
@@ -36,7 +36,8 @@ html
|
|
36
36
|
|
37
37
|
link rel="preconnect" href="https://fonts.googleapis.com"
|
38
38
|
link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="crossorigin"
|
39
|
-
link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;
|
39
|
+
link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400; \
|
40
|
+
0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet"
|
40
41
|
css:
|
41
42
|
body {
|
42
43
|
font-family: "Ubuntu", sans-serif;
|
@@ -59,7 +60,7 @@ html
|
|
59
60
|
nav aria-label="breadcrumb"
|
60
61
|
= render_breadcrumbs
|
61
62
|
/ = render_breadcrumbs builder: ::Bootstrap4BreadcrumbsBuilder
|
62
|
-
.btn-toolbar
|
63
|
+
.btn-toolbar.gap-1
|
63
64
|
= yield(:actions)
|
64
65
|
hr.my-0
|
65
66
|
- content = content_for?(:content) ? yield(:content) : yield
|
data/pg_rails/js/index.js
CHANGED
@@ -36,12 +36,13 @@ module PgEngine
|
|
36
36
|
def failure_message
|
37
37
|
msg = "expected to #{@level || log}"
|
38
38
|
msg << "with text: #{@text}" if @text.present?
|
39
|
-
return unless @new_messages.any?
|
39
|
+
return msg unless @new_messages.any?
|
40
40
|
|
41
41
|
msg << "\nLogged messages:"
|
42
42
|
@new_messages.each do |level, message|
|
43
43
|
msg << "\n #{level}: #{message[0..200]}"
|
44
44
|
end
|
45
|
+
msg
|
45
46
|
end
|
46
47
|
|
47
48
|
def supports_block_expectations?
|
data/pg_rails/lib/version.rb
CHANGED
@@ -4,7 +4,8 @@ require 'generators/pg_rspec/scaffold/scaffold_generator'
|
|
4
4
|
require 'generators/pg_decorator/pg_decorator_generator'
|
5
5
|
require 'generators/pg_active_record/model/model_generator'
|
6
6
|
|
7
|
-
|
7
|
+
TEST_ENV_NUMBER = ENV.fetch('TEST_ENV_NUMBER', '')
|
8
|
+
DESTINATION_PATH = File.expand_path("./../../tmp/generator_testing#{TEST_ENV_NUMBER}", __dir__)
|
8
9
|
|
9
10
|
describe 'Generators', type: :generator do
|
10
11
|
describe 'PgDecoratorGenerator' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.8.pre.alpha.
|
4
|
+
version: 7.0.8.pre.alpha.86
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martín Rosso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05-
|
11
|
+
date: 2024-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -1082,15 +1082,13 @@ files:
|
|
1082
1082
|
- pg_engine/spec/controllers/public/webhooks_controller_spec.rb
|
1083
1083
|
- pg_engine/spec/controllers/users/confirmations_controller_spec.rb
|
1084
1084
|
- pg_engine/spec/controllers/users/registrations_controller_spec.rb
|
1085
|
+
- pg_engine/spec/decorators/email_decorator_spec.rb
|
1085
1086
|
- pg_engine/spec/factories/accounts.rb
|
1086
1087
|
- pg_engine/spec/factories/email_logs.rb
|
1087
1088
|
- pg_engine/spec/factories/emails.rb
|
1088
1089
|
- pg_engine/spec/factories/mensaje_contactos.rb
|
1089
1090
|
- pg_engine/spec/factories/user_accounts.rb
|
1090
1091
|
- pg_engine/spec/factories/users.rb
|
1091
|
-
- pg_engine/spec/features/destroy_spec.rb
|
1092
|
-
- pg_engine/spec/features/login_spec.rb
|
1093
|
-
- pg_engine/spec/features/signup_spec.rb
|
1094
1092
|
- pg_engine/spec/fixtures/test.pdf
|
1095
1093
|
- pg_engine/spec/helpers/pg_engine/pg_rails_helper_spec.rb
|
1096
1094
|
- pg_engine/spec/helpers/pg_engine/print_helper_spec.rb
|
@@ -1107,13 +1105,20 @@ files:
|
|
1107
1105
|
- pg_engine/spec/models/user_account_spec.rb
|
1108
1106
|
- pg_engine/spec/models/user_spec.rb
|
1109
1107
|
- pg_engine/spec/pg_engine/pdf_preview_generator_spec.rb
|
1108
|
+
- pg_engine/spec/system/destroy_spec.rb
|
1109
|
+
- pg_engine/spec/system/login_spec.rb
|
1110
|
+
- pg_engine/spec/system/signup_spec.rb
|
1110
1111
|
- pg_layout/app/assets/stylesheets/animations.scss
|
1111
1112
|
- pg_layout/app/assets/stylesheets/sidebar.scss
|
1112
1113
|
- pg_layout/app/javascript/application.js
|
1113
1114
|
- pg_layout/app/javascript/channels/consumer.js
|
1114
1115
|
- pg_layout/app/javascript/channels/index.js
|
1116
|
+
- pg_layout/app/javascript/config/bootstrap.js
|
1115
1117
|
- pg_layout/app/javascript/config/cable_ready.js
|
1116
1118
|
- pg_layout/app/javascript/config/index.js
|
1119
|
+
- pg_layout/app/javascript/config/rollbar.js
|
1120
|
+
- pg_layout/app/javascript/config/turbo_rails/index.js
|
1121
|
+
- pg_layout/app/javascript/config/turbo_rails/set_consumer.js
|
1117
1122
|
- pg_layout/app/javascript/controllers/application.js
|
1118
1123
|
- pg_layout/app/javascript/controllers/clear_timeout_controller.js
|
1119
1124
|
- pg_layout/app/javascript/controllers/fadein_onload_controller.js
|