pg_rails 7.3.0 → 7.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/pg_associable/app/helpers/pg_associable/form_builder_methods.rb +8 -0
  3. data/pg_associable/app/helpers/pg_associable/helpers.rb +2 -2
  4. data/pg_associable/app/javascript/modal_controller.js +66 -4
  5. data/pg_associable/spec/system/associable_spec.rb +28 -5
  6. data/pg_engine/app/assets/stylesheets/pg_rails_b5.scss +5 -0
  7. data/pg_engine/app/components/date_selector_component.rb +2 -2
  8. data/pg_engine/app/components/modal_content_component.rb +20 -19
  9. data/pg_engine/app/components/search_bar_component.html.slim +1 -1
  10. data/pg_engine/app/controllers/admin/accounts_controller.rb +1 -1
  11. data/pg_engine/app/controllers/admin/email_logs_controller.rb +1 -1
  12. data/pg_engine/app/controllers/admin/emails_controller.rb +1 -1
  13. data/pg_engine/app/controllers/admin/user_accounts_controller.rb +1 -1
  14. data/pg_engine/app/controllers/admin/users_controller.rb +1 -1
  15. data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +209 -86
  16. data/pg_engine/app/controllers/pg_engine/base_controller.rb +5 -0
  17. data/pg_engine/app/controllers/public/mensaje_contactos_controller.rb +1 -1
  18. data/pg_engine/app/decorators/pg_engine/base_record_decorator.rb +24 -19
  19. data/pg_engine/app/helpers/pg_engine/form_helper.rb +0 -5
  20. data/pg_engine/app/helpers/pg_engine/frame_helper.rb +52 -0
  21. data/pg_engine/app/lib/pg_engine/bootstrap5_breadcrumbs_builder.rb +22 -0
  22. data/pg_engine/app/lib/pg_engine/filtros_builder.rb +3 -2
  23. data/pg_engine/app/models/current.rb +1 -1
  24. data/pg_engine/app/models/pg_engine/base_record.rb +2 -0
  25. data/pg_engine/app/views/pg_engine/base/edit.html.slim +1 -2
  26. data/pg_engine/app/views/pg_engine/base/index.html.slim +2 -3
  27. data/pg_engine/config/initializers/ransack_memory.rb +13 -2
  28. data/pg_engine/config/locales/es.yml +1 -1
  29. data/pg_engine/spec/controllers/concerns/pg_engine/resource_helper_spec.rb +0 -2
  30. data/pg_engine/spec/lib/pg_engine/form_helper_spec.rb +0 -2
  31. data/pg_engine/spec/system/breadcrumbs_spec.rb +61 -0
  32. data/pg_engine/spec/system/destroy_spec.rb +1 -1
  33. data/pg_engine/spec/system/login_spec.rb +1 -1
  34. data/pg_engine/spec/system/modal_windows_spec.rb +4 -4
  35. data/pg_layout/app/javascript/application.js +14 -0
  36. data/pg_layout/app/javascript/config/turbo_rails/index.js +4 -1
  37. data/pg_layout/app/javascript/controllers/embedded_frame_controller.js +10 -0
  38. data/pg_layout/app/javascript/controllers/index.js +2 -0
  39. data/pg_layout/app/javascript/controllers/tooltip_controller.js +8 -0
  40. data/pg_layout/app/javascript/elements/pg_event.js +2 -1
  41. data/pg_layout/app/views/layouts/pg_layout/base.html.slim +45 -17
  42. data/pg_layout/app/views/layouts/pg_layout/containerized.html.slim +1 -1
  43. data/pg_rails/lib/version.rb +1 -1
  44. data/pg_rails/scss/bootstrap_overrides.scss +2 -1
  45. data/pg_rails/scss/pg_rails.scss +8 -1
  46. data/pg_scaffold/lib/generators/pg_scaffold/templates/controller.rb +2 -4
  47. metadata +6 -6
  48. data/pg_engine/app/components/form_modal_component.html.slim +0 -15
  49. data/pg_engine/app/components/form_modal_component.rb +0 -6
  50. data/pg_engine/app/components/show_modal_component.html.slim +0 -10
  51. data/pg_engine/app/components/show_modal_component.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 987f2b59fff584bde7004887e631c776fd0da367988e6ca6117726ff6b6de937
4
- data.tar.gz: 41676e4fbcadad6e6a7a2b999368137c4d200fe83da5d7a1a300ed8d0a24a99f
3
+ metadata.gz: ad67165e1aad7f3b3e31dd236706d4b923eb2139740a095018257899b43928a7
4
+ data.tar.gz: f3d907a47d97cb7abbfb0e148bb2c2e9466a5255284f14f06c0363966e35e46b
5
5
  SHA512:
6
- metadata.gz: 2cda455c10578a6c9b990e0f7c00317166c80d499ff82267a925912935f510b79195d1ad13caf9669af1f314da0dfeb23a7aa9782f3df56996b4a128af3b5535
7
- data.tar.gz: f394f37f00f3f7dad3abcdfaab5697e1cf2079733a9e385df66101f8e5d1fe55e61f48d385ba9e6d855c9990b509c4a98a63c4efc1e1d9cb2c8535702c1c34cd
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)
@@ -3,8 +3,8 @@ module PgAssociable
3
3
  MAX_RESULTS = 8
4
4
 
5
5
  def pg_respond_abrir_modal
6
- content = FormModalComponent.new(@clase_modelo.new.decorate)
7
- .render_in(view_context)
6
+ src = @clase_modelo.new.decorate.new_object_url
7
+ content = ModalContentComponent.new(src:).render_in(view_context)
8
8
  modal = AsociableModalComponent.new(modal_id: params[:id]).with_content(content)
9
9
  render turbo_stream: turbo_stream.append_all('body', modal)
10
10
  end
@@ -5,6 +5,7 @@ export default class extends Controller {
5
5
  static outlets = ['asociable']
6
6
 
7
7
  modalPuntero = null
8
+ history = []
8
9
 
9
10
  connect (e) {
10
11
  this.modalPuntero = new bootstrap.Modal(this.element)
@@ -15,22 +16,30 @@ export default class extends Controller {
15
16
  }
16
17
  this.modalPuntero.show()
17
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
+
18
25
  this.element.addEventListener('pg:record-created', (ev) => {
19
26
  const el = ev.data
20
27
  if (this.asociableOutlets.length > 0) {
21
28
  const newObject = JSON.parse(el.dataset.response)
22
29
  this.asociableOutlet.completarCampo(newObject)
23
30
  ev.stopPropagation()
31
+ this.remove()
32
+ } else {
33
+ this.back(ev)
24
34
  }
25
- this.modalPuntero.hide()
26
35
  })
27
36
 
28
37
  this.element.addEventListener('pg:record-updated', (ev) => {
29
- this.modalPuntero.hide()
38
+ this.back(ev)
30
39
  })
31
40
 
32
41
  this.element.addEventListener('pg:record-destroyed', (ev) => {
33
- this.modalPuntero.hide()
42
+ this.remove()
34
43
  })
35
44
 
36
45
  document.addEventListener('turbo:before-cache', () => {
@@ -38,12 +47,65 @@ export default class extends Controller {
38
47
  }, { once: true })
39
48
  }
40
49
 
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()
91
+ }
92
+
41
93
  openModal () {
42
94
  this.modalPuntero.show()
43
95
  }
44
96
 
97
+ remove () {
98
+ this.element.remove()
99
+ }
100
+
45
101
  disconnect (e) {
46
- 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
+ })
47
109
  document.dispatchEvent(new Event('hidden.bs.modal'))
48
110
  this.modalPuntero.dispose()
49
111
  }
@@ -3,16 +3,17 @@ 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'
@@ -21,4 +22,26 @@ describe 'Associable' do
21
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;
@@ -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
  ]
@@ -1,28 +1,29 @@
1
1
  class ModalContentComponent < ViewComponent::Base
2
- renders_one :actions
3
- renders_one :body
4
- renders_one :header
2
+ def initialize(src: nil)
3
+ @src = src
4
+ with_content(loading_html) if @src.present?
5
5
 
6
- def before_render
7
- controller.instance_variable_set(:@using_modal, true)
6
+ super
8
7
  end
9
8
 
10
- erb_template <<~ERB
11
- <%= helpers.turbo_frame_tag :modal_generic do %>
12
- <div class="modal-header">
13
- <%= header %>
14
- <a class="btn-close" type="button" data-bs-dismiss="modal" aria-label="Close"></a>
9
+ def loading_html
10
+ <<~HTML.html_safe
11
+ <div class="text-center text-body-secondary fs-3" style="min-height: 15em">
12
+ Cargando...
15
13
  </div>
16
- <div class="modal-body">
17
- <div class="d-flex justify-content-around sticky-top">
18
- <div class="flash position-relative w-100 d-flex justify-content-center">
19
- </div>
20
- </div>
21
- <div class="float-end">
22
- <%= actions %>
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">
23
21
  </div>
24
- <%= body %>
25
22
  </div>
26
- <% end %>
23
+ <%= helpers.turbo_frame_tag :modal_content,
24
+ **{ src: @src, refresh: :morph }.compact do %>
25
+ <%= content %>
26
+ <% end %>
27
+ </div>
27
28
  ERB
28
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
 
@@ -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