pg_rails 7.0.8.pre.alpha.85 → 7.0.8.pre.alpha.86

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/pg_engine/app/controllers/admin/emails_controller.rb +1 -1
  3. data/pg_engine/app/controllers/admin/users_controller.rb +1 -0
  4. data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +2 -0
  5. data/pg_engine/app/controllers/public/webhooks_controller.rb +7 -6
  6. data/pg_engine/app/decorators/email_decorator.rb +31 -1
  7. data/pg_engine/app/models/email.rb +4 -1
  8. data/pg_engine/app/policies/pg_engine/base_policy.rb +0 -1
  9. data/pg_engine/app/views/admin/emails/_form.html.slim +8 -7
  10. data/pg_engine/config/locales/es.yml +9 -2
  11. data/pg_engine/lib/pg_engine.rb +6 -0
  12. data/pg_engine/spec/decorators/email_decorator_spec.rb +18 -0
  13. data/pg_engine/spec/factories/emails.rb +1 -0
  14. data/pg_engine/spec/lib/pg_engine/mailgun/log_sync_spec.rb +1 -1
  15. data/pg_engine/spec/models/email_spec.rb +1 -1
  16. data/pg_engine/spec/{features → system}/destroy_spec.rb +13 -13
  17. data/pg_engine/spec/{features → system}/login_spec.rb +14 -14
  18. data/pg_engine/spec/{features → system}/signup_spec.rb +13 -13
  19. data/pg_layout/app/javascript/application.js +0 -91
  20. data/pg_layout/app/javascript/channels/consumer.js +36 -1
  21. data/pg_layout/app/javascript/config/bootstrap.js +42 -0
  22. data/pg_layout/app/javascript/config/cable_ready.js +0 -26
  23. data/pg_layout/app/javascript/config/index.js +3 -0
  24. data/pg_layout/app/javascript/config/rollbar.js +28 -0
  25. data/pg_layout/app/javascript/config/turbo_rails/index.js +27 -0
  26. data/pg_layout/app/javascript/config/turbo_rails/set_consumer.js +4 -0
  27. data/pg_layout/app/javascript/controllers/application.js +6 -4
  28. data/pg_layout/app/javascript/controllers/index.js +2 -0
  29. data/pg_layout/app/lib/navbar.rb +1 -0
  30. data/pg_layout/app/views/layouts/pg_layout/base.html.slim +3 -2
  31. data/pg_rails/js/index.js +1 -1
  32. data/pg_rails/lib/pg_rails/rspec_logger_matchers.rb +2 -1
  33. data/pg_rails/lib/version.rb +1 -1
  34. data/pg_scaffold/spec/generators_spec.rb +2 -1
  35. metadata +10 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8e7f1383530ebb81fee806358820682f5296214306d3e7a31e552f977f84e08
4
- data.tar.gz: c824d6e755c9048e05f30cb628ab21d991b9a737f754e5be17fc915c273d9446
3
+ metadata.gz: 777adfba6510fb280d827dab94dc0a924f851608924a38e16eeedc43c3bba896
4
+ data.tar.gz: 9d099949a82596a82e8c2d62e71aaef3bda568cfc3a58793daaa2ab4d53f1d1b
5
5
  SHA512:
6
- metadata.gz: e96376b503168349f4383a6f12a9b617c0da2454b3a03e490e48bebe5bb4ee7732581fd8b9757e2ade08559c5a3d9b2b189f23b2d095740a318cd5964fa3dab2
7
- data.tar.gz: f2f9f557c97be28535b81cc28efcf6aca1e306ef3aa22e1b97941161f468bf2381038c4c952bdd9da56ea233fe04e36e1f206baf424711b6596c83457d711328
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
@@ -28,6 +28,7 @@ module Admin
28
28
  pg_respond_update
29
29
  end
30
30
 
31
+ # TODO: sacar este método a otro lado, que no sea AdminController
31
32
  skip_before_action :authenticate_user!, only: [:login_as]
32
33
 
33
34
  # :nocov:
@@ -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', params
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), target: :_blank, rel: :noopener
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,
@@ -14,7 +14,6 @@ module PgEngine
14
14
  end
15
15
 
16
16
  def show?
17
- # scope.where(id: record.id).exists?
18
17
  base_access_to_record?
19
18
  end
20
19
 
@@ -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
- ancestry:
15
- exclude_self: No puede ser hijx de si mismx
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'
@@ -90,4 +90,10 @@ module PgEngine
90
90
  yield(configuracion)
91
91
  end
92
92
  end
93
+
94
+ def self.redis_url
95
+ env_value = ENV.fetch('TEST_ENV_NUMBER', nil)
96
+ db = (env_value.nil? ? 1 : (env_value.presence || 1)).to_i - 1
97
+ "redis://127.0.0.1:6379/#{db}"
98
+ end
93
99
  end
@@ -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
@@ -5,7 +5,7 @@
5
5
  require 'rails_helper'
6
6
 
7
7
  RSpec.describe Email do
8
- let(:email) { create(:email) }
8
+ let(:email) { create(:email, status: :pending) }
9
9
 
10
10
  it 'se persiste' do
11
11
  expect(email).to be_persisted
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'rails_helper'
4
4
 
5
- describe 'Sign in', :js do
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
- # Capybara.drivers.keys
54
- drivers = %i[
55
- selenium_headless
56
- selenium_chrome_headless
57
- selenium_chrome_headless_notebook
58
- selenium_chrome_headless_iphone
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}'", driver:) do
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', :js do
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
- # Capybara.drivers.keys
24
- drivers = %i[
25
- selenium_headless
26
- selenium_chrome_headless
27
- selenium_chrome_headless_notebook
28
- selenium_chrome_headless_iphone
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}'", driver:) do
38
- include_examples 'sign_in'
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', :js do
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
- # Capybara.drivers.keys
60
- drivers = %i[
61
- selenium_headless
62
- selenium_chrome_headless
63
- selenium_chrome_headless_notebook
64
- selenium_chrome_headless_iphone
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}'", driver:) do
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
- export default createConsumer({
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 })
@@ -1 +1,4 @@
1
1
  import './cable_ready'
2
+ import './turbo_rails'
3
+ import './rollbar'
4
+ import './bootstrap'
@@ -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') })
@@ -0,0 +1,4 @@
1
+ import consumer from '../../channels/consumer'
2
+ import { setConsumer } from '@hotwired/turbo-rails/app/javascript/turbo/cable.js'
3
+
4
+ setConsumer(consumer)
@@ -1,7 +1,9 @@
1
- if (!window.Stimulus) {
2
- console.error('window.Stimulus must be set')
3
- }
1
+ import { Application } from '@hotwired/stimulus'
4
2
 
5
- const application = window.Stimulus
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
@@ -39,6 +39,7 @@ class Navbar
39
39
  show: item['policy'] ? eval(item['policy']) : true
40
40
  }
41
41
  rescue StandardError => e
42
+ # FIXME: que rompa los tests
42
43
  # TODO!: testear
43
44
  pg_err e, item
44
45
  return []
@@ -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;0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet"
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
@@ -1,2 +1,2 @@
1
- import './../../pg_associable'
2
1
  import './../../pg_layout/app/javascript/application'
2
+ import './../../pg_associable'
@@ -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?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRails
4
- VERSION = '7.0.8-alpha.85'
4
+ VERSION = '7.0.8-alpha.86'
5
5
  end
@@ -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
- DESTINATION_PATH = File.expand_path('./../../tmp/generator_testing', __dir__)
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.85
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-27 00:00:00.000000000 Z
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