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