pg_rails 7.2.3 → 7.3.1

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/pg_associable/app/helpers/pg_associable/form_builder_methods.rb +9 -2
  3. data/pg_associable/app/helpers/pg_associable/helpers.rb +4 -5
  4. data/pg_associable/app/javascript/modal_controller.js +80 -6
  5. data/pg_associable/spec/system/associable_spec.rb +30 -7
  6. data/pg_engine/app/assets/stylesheets/pg_rails_b5.scss +5 -0
  7. data/pg_engine/app/components/actions_component.rb +14 -0
  8. data/pg_engine/app/components/asociable_modal_component.html.slim +6 -0
  9. data/pg_engine/app/components/asociable_modal_component.rb +7 -0
  10. data/pg_engine/app/components/date_selector_component.rb +2 -2
  11. data/pg_engine/app/components/modal_component.html.slim +5 -0
  12. data/pg_engine/app/components/modal_component.rb +11 -0
  13. data/pg_engine/app/components/modal_content_component.rb +29 -0
  14. data/pg_engine/app/components/search_bar_component.html.slim +1 -1
  15. data/pg_engine/app/controllers/admin/accounts_controller.rb +1 -1
  16. data/pg_engine/app/controllers/admin/email_logs_controller.rb +1 -1
  17. data/pg_engine/app/controllers/admin/emails_controller.rb +4 -21
  18. data/pg_engine/app/controllers/admin/user_accounts_controller.rb +1 -1
  19. data/pg_engine/app/controllers/admin/users_controller.rb +1 -1
  20. data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +288 -133
  21. data/pg_engine/app/controllers/pg_engine/base_controller.rb +5 -0
  22. data/pg_engine/app/controllers/public/mensaje_contactos_controller.rb +1 -1
  23. data/pg_engine/app/decorators/pg_engine/base_record_decorator.rb +36 -10
  24. data/pg_engine/app/helpers/pg_engine/flash_helper.rb +6 -2
  25. data/pg_engine/app/helpers/pg_engine/form_helper.rb +15 -2
  26. data/pg_engine/app/helpers/pg_engine/frame_helper.rb +52 -0
  27. data/pg_engine/app/lib/pg_engine/bootstrap5_breadcrumbs_builder.rb +22 -0
  28. data/pg_engine/app/lib/pg_engine/filtros_builder.rb +3 -2
  29. data/pg_engine/app/models/current.rb +1 -1
  30. data/pg_engine/app/models/email.rb +2 -0
  31. data/pg_engine/app/models/pg_engine/base_record.rb +13 -0
  32. data/pg_engine/app/views/admin/accounts/_form.html.slim +1 -4
  33. data/pg_engine/app/views/admin/email_logs/_form.html.slim +2 -5
  34. data/pg_engine/app/views/admin/emails/_form.html.slim +13 -13
  35. data/pg_engine/app/views/admin/emails/_send.html.slim +0 -1
  36. data/pg_engine/app/views/admin/emails/show.html.slim +19 -20
  37. data/pg_engine/app/views/admin/eventos/new.html.slim +0 -2
  38. data/pg_engine/app/views/admin/user_accounts/_form.html.slim +1 -4
  39. data/pg_engine/app/views/admin/users/_form.html.slim +1 -4
  40. data/pg_engine/app/views/pg_engine/base/edit.html.slim +1 -2
  41. data/pg_engine/app/views/pg_engine/base/index.html.slim +6 -3
  42. data/pg_engine/app/views/pg_engine/base/new.html.slim +1 -2
  43. data/pg_engine/app/views/public/mensaje_contactos/new.html.slim +2 -5
  44. data/pg_engine/config/initializers/kaminari.rb +3 -0
  45. data/pg_engine/config/initializers/ransack_memory.rb +13 -2
  46. data/pg_engine/config/locales/es.yml +1 -1
  47. data/pg_engine/lib/pg_engine/utils/pg_logger.rb +10 -10
  48. data/pg_engine/spec/controllers/admin/accounts_controller_spec.rb +2 -2
  49. data/pg_engine/spec/controllers/admin/email_logs_controller_spec.rb +2 -2
  50. data/pg_engine/spec/controllers/admin/emails_controller_spec.rb +2 -2
  51. data/pg_engine/spec/controllers/admin/user_accounts_controller_spec.rb +2 -2
  52. data/pg_engine/spec/controllers/admin/users_controller_spec.rb +2 -2
  53. data/pg_engine/spec/controllers/concerns/pg_engine/resource_helper_spec.rb +0 -2
  54. data/pg_engine/spec/lib/pg_engine/form_helper_spec.rb +51 -0
  55. data/pg_engine/spec/system/breadcrumbs_spec.rb +61 -0
  56. data/pg_engine/spec/system/destroy_spec.rb +1 -1
  57. data/pg_engine/spec/system/login_spec.rb +1 -1
  58. data/pg_engine/spec/system/modal_windows_spec.rb +89 -0
  59. data/pg_engine/spec/system/send_mail_spec.rb +1 -1
  60. data/pg_layout/app/javascript/application.js +38 -0
  61. data/pg_layout/app/javascript/config/turbo_rails/index.js +4 -1
  62. data/pg_layout/app/javascript/controllers/embedded_frame_controller.js +10 -0
  63. data/pg_layout/app/javascript/controllers/index.js +2 -0
  64. data/pg_layout/app/javascript/controllers/popover_toggler_controller.js +3 -2
  65. data/pg_layout/app/javascript/controllers/tooltip_controller.js +8 -0
  66. data/pg_layout/app/javascript/elements/index.js +1 -0
  67. data/pg_layout/app/javascript/elements/pg_event.js +13 -0
  68. data/pg_layout/app/views/devise/confirmations/new.html.erb +0 -1
  69. data/pg_layout/app/views/devise/passwords/edit.html.erb +0 -2
  70. data/pg_layout/app/views/devise/passwords/new.html.erb +0 -2
  71. data/pg_layout/app/views/devise/registrations/edit.html.erb +0 -2
  72. data/pg_layout/app/views/devise/registrations/new.html.erb +0 -2
  73. data/pg_layout/app/views/devise/unlocks/new.html.erb +0 -1
  74. data/pg_layout/app/views/layouts/pg_layout/base.html.slim +45 -17
  75. data/pg_layout/app/views/layouts/pg_layout/containerized.html.slim +1 -1
  76. data/pg_rails/lib/version.rb +1 -1
  77. data/pg_rails/scss/bootstrap_overrides.scss +2 -1
  78. data/pg_rails/scss/pg_rails.scss +8 -1
  79. data/pg_scaffold/lib/generators/pg_rspec/scaffold/templates/controller_spec.rb +2 -2
  80. data/pg_scaffold/lib/generators/pg_scaffold/templates/controller.rb +2 -4
  81. data/pg_scaffold/lib/generators/pg_slim/templates/_form.html.slim +2 -5
  82. data/pg_scaffold/lib/generators/pg_slim/templates/show.html.slim +1 -1
  83. metadata +17 -4
  84. data/pg_associable/app/views/pg_engine/base/_pg_associable_modal.html.slim +0 -14
  85. data/pg_layout/app/views/pg_layout/_modal_show.html.slim +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2505003e224d063bd2c51742b431b315cef9e83b08c867adb0687f9184ad559
4
- data.tar.gz: 0d3e3c74ef4c00f0e369302a592fccc0749ddb53c7143abd0be4dc1cf7da6418
3
+ metadata.gz: ad67165e1aad7f3b3e31dd236706d4b923eb2139740a095018257899b43928a7
4
+ data.tar.gz: f3d907a47d97cb7abbfb0e148bb2c2e9466a5255284f14f06c0363966e35e46b
5
5
  SHA512:
6
- metadata.gz: 64ee127677a3f745bd0d29b8fac8150b03470d4cd03d6d6b37078168a3bfd43ac3332f085942bb9d0ea94b164fdd863f65df76c116f8e1ff708ebe012ac31348
7
- data.tar.gz: 6cb3a28799ddd2a7c2fb621a1875b246b825355cd0e7b3a66925030138f46b0d81e1d5c0fa22ce29c4c5c747984145076af5a89085891112230ed34ebcd61732
6
+ metadata.gz: 3d8482db6b3b8455c819d4db06db374e40785cec70a9737bfca652c2368bddad17ca7a2d3656e1632b48b0ebeb03c5142e83855d3d70cfd9d043de3e7d34609d
7
+ data.tar.gz: e6e2457ac2a84097209da469aa76dd2538e72c9da05ed383884c19fceddc071b5dc515a82c444c4f3487d7912ca79790bd6eb06f0eed0ae0c4caf48e8797884f
@@ -16,6 +16,14 @@ module PgAssociable
16
16
  end
17
17
 
18
18
  def pg_associable(atributo, options = {})
19
+ # Si es new y tiene el nested asignado, no permito que se modifique
20
+ # porque de todos modos se pisaría en el create
21
+ if !object.persisted? &&
22
+ template.nested_record.present? &&
23
+ object.send(template.nested_key) == (template.nested_record.id)
24
+ options[:disabled] = true
25
+ end
26
+
19
27
  return input(atributo, options) if options[:disabled]
20
28
 
21
29
  collection, puede_crear = collection_pc(atributo, options)
@@ -31,8 +39,7 @@ module PgAssociable
31
39
  def collection_pc(atributo, _options)
32
40
  klass = clase_asociacion(atributo)
33
41
  user = Current.user
34
- in_modal = options[:asociable].present?
35
- puede_crear = !in_modal && Pundit::PolicyFinder.new(klass).policy.new(user, klass).new?
42
+ puede_crear = !template.using_modal? && Pundit::PolicyFinder.new(klass).policy.new(user, klass).new?
36
43
  collection = Pundit::PolicyFinder.new(klass).scope.new(user, klass).resolve
37
44
  [collection, puede_crear]
38
45
  end
@@ -3,11 +3,10 @@ module PgAssociable
3
3
  MAX_RESULTS = 8
4
4
 
5
5
  def pg_respond_abrir_modal
6
- respond_to do |format|
7
- format.turbo_stream do
8
- render turbo_stream: turbo_stream.append_all('body', partial: 'pg_associable_modal')
9
- end
10
- end
6
+ src = @clase_modelo.new.decorate.new_object_url
7
+ content = ModalContentComponent.new(src:).render_in(view_context)
8
+ modal = AsociableModalComponent.new(modal_id: params[:id]).with_content(content)
9
+ render turbo_stream: turbo_stream.append_all('body', modal)
11
10
  end
12
11
 
13
12
  def pg_respond_buscar
@@ -3,9 +3,9 @@ import * as bootstrap from 'bootstrap'
3
3
 
4
4
  export default class extends Controller {
5
5
  static outlets = ['asociable']
6
- static targets = ['response']
7
6
 
8
7
  modalPuntero = null
8
+ history = []
9
9
 
10
10
  connect (e) {
11
11
  this.modalPuntero = new bootstrap.Modal(this.element)
@@ -15,23 +15,97 @@ export default class extends Controller {
15
15
  })
16
16
  }
17
17
  this.modalPuntero.show()
18
+
19
+ this.element.addEventListener('turbo:frame-render', (ev) => {
20
+ if (ev.detail.fetchResponse.response.ok && ev.target.id === 'modal_content') {
21
+ this.history.push(ev.target.src)
22
+ }
23
+ })
24
+
25
+ this.element.addEventListener('pg:record-created', (ev) => {
26
+ const el = ev.data
27
+ if (this.asociableOutlets.length > 0) {
28
+ const newObject = JSON.parse(el.dataset.response)
29
+ this.asociableOutlet.completarCampo(newObject)
30
+ ev.stopPropagation()
31
+ this.remove()
32
+ } else {
33
+ this.back(ev)
34
+ }
35
+ })
36
+
37
+ this.element.addEventListener('pg:record-updated', (ev) => {
38
+ this.back(ev)
39
+ })
40
+
41
+ this.element.addEventListener('pg:record-destroyed', (ev) => {
42
+ this.remove()
43
+ })
44
+
18
45
  document.addEventListener('turbo:before-cache', () => {
19
46
  this.element.remove()
20
47
  }, { once: true })
21
48
  }
22
49
 
23
- responseTargetConnected (e) {
24
- const newObject = JSON.parse(e.dataset.response)
25
- this.asociableOutlet.completarCampo(newObject)
26
- this.element.remove()
50
+ maximize (ev) {
51
+ const dialog = this.element.querySelector('.modal-dialog')
52
+ dialog.classList.toggle('modal-fullscreen')
53
+ const button = ev.currentTarget
54
+ const icon = button.querySelector('i')
55
+ icon.classList.toggle('bi-fullscreen')
56
+ icon.classList.toggle('bi-fullscreen-exit')
57
+
58
+ const tooltip = this.application.getControllerForElementAndIdentifier(button, 'tooltip')
59
+ if (tooltip) {
60
+ tooltip.hide()
61
+ if (icon.classList.contains('bi-fullscreen')) {
62
+ tooltip.setContent('Maximizar')
63
+ } else {
64
+ tooltip.setContent('Restaurar')
65
+ }
66
+ }
67
+ }
68
+
69
+ reloadTop () {
70
+ // FIXME: rename to main?
71
+ const topFrame = document.querySelector('#top')
72
+ if (topFrame.attributes.src) {
73
+ topFrame.reload()
74
+ } else {
75
+ topFrame.setAttribute('src', window.location)
76
+ }
77
+ }
78
+
79
+ back (ev) {
80
+ this.history.pop()
81
+ if (this.history.length > 0) {
82
+ const url = this.history[this.history.length - 1]
83
+ const frame = this.element.querySelector('#modal_content')
84
+ frame.src = url
85
+ frame.innerHTML = '<div style="min-height: 30em">Cargando...</div>'
86
+ } else {
87
+ this.modalPuntero.hide()
88
+ }
89
+ ev.stopPropagation()
90
+ this.reloadTop()
27
91
  }
28
92
 
29
93
  openModal () {
30
94
  this.modalPuntero.show()
31
95
  }
32
96
 
97
+ remove () {
98
+ this.element.remove()
99
+ }
100
+
33
101
  disconnect (e) {
34
- this.modalPuntero.hide()
102
+ // Antes, en lugar de quitar el modal-backdrop:
103
+ // this.modalPuntero.hide()
104
+ // pero tiraba a veces error:
105
+ // TypeError: can't convert null to object, _isWithActiveTrigger
106
+ document.querySelectorAll('.modal-backdrop').forEach((el) => {
107
+ el.remove()
108
+ })
35
109
  document.dispatchEvent(new Event('hidden.bs.modal'))
36
110
  this.modalPuntero.dispose()
37
111
  }
@@ -3,22 +3,45 @@ require 'rails_helper'
3
3
  describe 'Associable' do
4
4
  let(:user) { create :user, :developer }
5
5
 
6
+ let(:path) { '/admin/cosas/new' }
7
+
6
8
  before do
7
9
  login_as user
8
- driven_by :selenium
9
- visit '/admin/cosas/new'
10
- fill_in 'cosa_nombre', with: 'La cosa'
11
- select 'Los', from: 'cosa_tipo'
12
- find('.cosa_categoria_de_cosa input[type=text]').click
10
+ visit path
13
11
  end
14
12
 
15
13
  it do
14
+ fill_in 'cosa_nombre', with: 'La cosa'
15
+ select 'Los', from: 'cosa_tipo'
16
+ find('.cosa_categoria_de_cosa input[type=text]').click
16
17
  expect(page).to have_text :all, 'Nuevo'
17
18
  find('.cosa_categoria_de_cosa .list-group-item').click
18
19
  fill_in 'categoria_de_cosa_nombre', with: 'la categoría'
19
20
  select 'Completar', from: 'categoria_de_cosa_tipo'
20
- click_on 'Crear Categoría de cosa'
21
- click_on 'Crear Coso'
21
+ click_on 'Agregar Categoría de cosa'
22
+ click_on 'Cargar Coso'
22
23
  expect(page).to have_text 'Creado por'
23
24
  end
25
+
26
+ context 'cuando crea desde el nested' do
27
+ let!(:categ) { create :categoria_de_cosa }
28
+ let(:path) { "/admin/categoria_de_cosas/#{categ.hashid}/cosas/new" }
29
+
30
+ it do
31
+ input = find_by_id('cosa_categoria_de_cosa')
32
+ expect(input).to be_disabled
33
+ end
34
+ end
35
+
36
+ context 'cuando edita desde el nested' do
37
+ let!(:categ) { create :categoria_de_cosa }
38
+ let!(:cosa) { create :cosa, categoria_de_cosa: categ }
39
+ let(:path) { "/admin/categoria_de_cosas/#{categ.hashid}/cosas/#{cosa.id}/edit" }
40
+
41
+ it do
42
+ ele = find_by_id('cosa_categoria_de_cosa_id', visible: :all)
43
+ input = ele.sibling('input[type=text]')
44
+ expect(input).not_to be_disabled
45
+ end
46
+ end
24
47
  end
@@ -9,6 +9,11 @@
9
9
  --bs-form-invalid-border-color: #b50000;
10
10
  }
11
11
 
12
+ // Navs
13
+ nav[aria-label=breadcrumb] a {
14
+ font-weight: bold;
15
+ }
16
+
12
17
  // Toasts
13
18
  .toast.show {
14
19
  display: inline-block;
@@ -0,0 +1,14 @@
1
+ class ActionsComponent < ViewComponent::Base
2
+ def initialize(record)
3
+ @record = record.decorate
4
+
5
+ super
6
+ end
7
+
8
+ erb_template <<~ERB
9
+ <div>
10
+ <%= @record.edit_link %>
11
+ <%= @record.destroy_link_redirect %>
12
+ </div>
13
+ ERB
14
+ end
@@ -0,0 +1,6 @@
1
+ .modal[class="#{@klass} modal-#{@modal_id}" tabindex="-1" data-controller="modal"
2
+ data-modal-asociable-outlet=".asociable-#{@modal_id}"
3
+ data-turbo-temporary="true"]
4
+ .modal-dialog
5
+ .modal-content
6
+ = content
@@ -0,0 +1,7 @@
1
+ class AsociableModalComponent < ModalComponent
2
+ def initialize(modal_id: nil, **)
3
+ @modal_id = modal_id
4
+
5
+ super(**)
6
+ end
7
+ end
@@ -3,9 +3,9 @@ class DateSelectorComponent < ViewComponent::Base
3
3
  @field_id = field_id
4
4
 
5
5
  @types = [
6
- ['Días corridos (L a D)', 'calendar_days'],
7
- ['Días hábiles (L a V)', 'business_days'],
8
6
  ['Días hábiles no feriados', 'business_days_excluding_holidays'],
7
+ ['Días hábiles (L a V)', 'business_days'],
8
+ ['Días corridos (L a D)', 'calendar_days'],
9
9
  ['Semanas', 'weeks'],
10
10
  ['Meses', 'months']
11
11
  ]
@@ -0,0 +1,5 @@
1
+ .modal[class="#{@klass}" tabindex="-1" data-controller="modal"
2
+ data-remove-on-hide="true" data-turbo-temporary="true"]
3
+ .modal-dialog
4
+ .modal-content
5
+ = content
@@ -0,0 +1,11 @@
1
+ class ModalComponent < ViewComponent::Base
2
+ def initialize(klass: 'modal-xl')
3
+ @klass = klass
4
+
5
+ super
6
+ end
7
+
8
+ def before_render
9
+ controller.instance_variable_set(:@using_modal, true)
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ class ModalContentComponent < ViewComponent::Base
2
+ def initialize(src: nil)
3
+ @src = src
4
+ with_content(loading_html) if @src.present?
5
+
6
+ super
7
+ end
8
+
9
+ def loading_html
10
+ <<~HTML.html_safe
11
+ <div class="text-center text-body-secondary fs-3" style="min-height: 15em">
12
+ Cargando...
13
+ </div>
14
+ HTML
15
+ end
16
+
17
+ erb_template <<~ERB
18
+ <div class="modal-body">
19
+ <div class="d-flex justify-content-around sticky-top">
20
+ <div class="flash position-relative w-100 d-flex justify-content-center">
21
+ </div>
22
+ </div>
23
+ <%= helpers.turbo_frame_tag :modal_content,
24
+ **{ src: @src, refresh: :morph }.compact do %>
25
+ <%= content %>
26
+ <% end %>
27
+ </div>
28
+ ERB
29
+ end
@@ -3,7 +3,7 @@
3
3
  .d-flex.align-items-center.px-3.py-2
4
4
  .px-2.d-none.d-sm-inline-block
5
5
  span.bi.bi-funnel-fill
6
- = helpers.search_form_for @q, url: url_for, html: { 'data-turbo-action': :advance } do |f|
6
+ = helpers.search_form_for @q, url: url_for do |f|
7
7
  .row.g-1
8
8
  .col
9
9
  .row.g-1
@@ -6,7 +6,7 @@ module Admin
6
6
  class AccountsController < AdminController
7
7
  include PgEngine::Resource
8
8
 
9
- before_action { @clase_modelo = Account }
9
+ self.clase_modelo = Account
10
10
 
11
11
  before_action(only: :index) { authorize Account }
12
12
 
@@ -6,7 +6,7 @@ module Admin
6
6
  class EmailLogsController < AdminController
7
7
  include PgEngine::Resource
8
8
 
9
- before_action { @clase_modelo = EmailLog }
9
+ self.clase_modelo = EmailLog
10
10
 
11
11
  before_action(only: :index) { authorize EmailLog }
12
12
 
@@ -6,7 +6,7 @@ module Admin
6
6
  class EmailsController < AdminController
7
7
  include PgEngine::Resource
8
8
 
9
- before_action { @clase_modelo = Email }
9
+ self.clase_modelo = Email
10
10
 
11
11
  before_action(only: :index) { authorize Email }
12
12
 
@@ -14,26 +14,9 @@ module Admin
14
14
 
15
15
  add_breadcrumb Email.nombre_plural, :admin_emails_path
16
16
 
17
- def new
18
- render template: 'admin/emails/_send', locals: { email: @email },
19
- layout: 'pg_layout/containerized'
20
- end
21
-
22
- def create
23
- saved = false
24
- ActiveRecord::Base.transaction do
25
- # TODO: acá la transaction jode porque el ActiveJob no puede deserializar el Email
26
- # Con rails 7.2 esto se debería arreglar
27
- if (saved = @email.save)
28
- PgEngine::AdminMailer.with(email_object: @email).admin_mail.deliver_later
29
- end
30
- end
31
- if saved
32
- redirect_to @email.decorate.target_object
33
- else
34
- render template: 'admin/emails/_send',
35
- layout: 'pg_layout/containerized', status: :unprocessable_entity,
36
- locals: { email: @email }
17
+ after_action only: :create do
18
+ if @saved
19
+ PgEngine::AdminMailer.with(email_object: @email).admin_mail.deliver_later
37
20
  end
38
21
  end
39
22
 
@@ -6,7 +6,7 @@ module Admin
6
6
  class UserAccountsController < AdminController
7
7
  include PgEngine::Resource
8
8
 
9
- before_action { @clase_modelo = UserAccount }
9
+ self.clase_modelo = UserAccount
10
10
 
11
11
  before_action(only: :index) { authorize UserAccount }
12
12
 
@@ -6,7 +6,7 @@ module Admin
6
6
  class UsersController < AdminController
7
7
  include PgEngine::Resource
8
8
 
9
- before_action { @clase_modelo = User }
9
+ self.clase_modelo = User
10
10
 
11
11
  before_action(only: :index) { authorize User }
12
12