pg_rails 7.3.0 → 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 (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
@@ -1,15 +1,108 @@
1
1
  module PgEngine
2
2
  module Resource
3
+ # rubocop:disable Metrics/PerceivedComplexity
3
4
  def self.included(clazz)
4
- # clazz.before_action :authenticate_user!
5
+ class << clazz
6
+ # This is a per class variable, all subclasses of clazz inherit it
7
+ # BUT **the values are independent between all of them**
8
+ attr_accessor :nested_class, :nested_key, :clase_modelo
9
+
10
+ # TODO: separar los endpoints de la lógica de filtros para evitar esta variable
11
+ # en Agenda
12
+ attr_accessor :skip_default_breadcrumb
13
+ end
14
+ clazz.delegate :nested_key, :nested_class, :clase_modelo, to: clazz
15
+
16
+ clazz.helper_method :nested_class, :nested_key, :clase_modelo
17
+ clazz.helper_method :nested_record, :nested_id
18
+
5
19
  clazz.helper_method :atributos_para_listar
6
20
  clazz.helper_method :atributos_para_mostrar
7
21
  clazz.helper_method :current_page_size
8
22
  clazz.helper_method :show_filters?
9
23
  clazz.helper_method :available_page_sizes
10
24
 
25
+ clazz.before_action do
26
+ # TODO: quitar esto, que se use el attr_accessor
27
+ # o sea, quitar todas las referencias a @clase_modelo
28
+ @clase_modelo = clase_modelo
29
+ end
30
+
31
+ clazz.before_action unless: -> { clazz.skip_default_breadcrumb } do
32
+ if nested_record.present?
33
+ # Link al nested, siempre que sea no sea un embedded frame
34
+ # ya que en tal caso se supone que el nested está visible
35
+ # en el main frame. Además, si es un modal abierto desde
36
+ # el nested record, no muestro el link al mismo.
37
+ unless frame_embedded?
38
+ if modal_targeted? && referred_by?(nested_record)
39
+ add_breadcrumb nested_record.decorate.to_s_short
40
+ else
41
+ add_breadcrumb nested_record.decorate.to_s_short,
42
+ nested_record.decorate.target_object
43
+ end
44
+ end
45
+
46
+ # Texto de index pero sin link, porque se supone que es un
47
+ # embedded index o viene de tal
48
+ add_breadcrumb clase_modelo.nombre_plural
49
+
50
+ elsif !modal_targeted?
51
+ # Link al index, siempre que no sea un modal, porque en tal
52
+ # caso se supone que el index está visible en el main frame
53
+ if clase_modelo.present?
54
+ add_breadcrumb clase_modelo.nombre_plural,
55
+ url_for([pg_namespace, nested_record, clase_modelo])
56
+ else
57
+ # :nocov:
58
+ pg_warn 'clase_modelo is nil'
59
+ # :nocov:
60
+ end
61
+ end
62
+ end
63
+
11
64
  clazz.layout :set_layout
12
65
  end
66
+ # rubocop:enable Metrics/PerceivedComplexity
67
+
68
+ def referred_by?(object)
69
+ url_for(object.decorate.target_object) == request.referer
70
+ end
71
+
72
+ def nested_id
73
+ return unless nested_key.present? && nested_class.present?
74
+
75
+ id = params[nested_key]
76
+
77
+ # if using hashid-rails
78
+ if nested_class.respond_to? :decode_id
79
+ id = nested_class.decode_id(id)
80
+ end
81
+
82
+ id
83
+ end
84
+
85
+ def nested_record
86
+ return if nested_id.blank?
87
+
88
+ nested_class.find(nested_id)
89
+ end
90
+
91
+ def accepts_turbo_stream?
92
+ request.headers['Accept'].present? &&
93
+ request.headers['Accept'].include?('text/vnd.turbo-stream.html')
94
+ end
95
+
96
+ def respond_with_modal?
97
+ can_open_modal? || modal_targeted?
98
+ end
99
+
100
+ def can_open_modal?
101
+ request.get? &&
102
+ clase_modelo.default_modal &&
103
+ accepts_turbo_stream? &&
104
+ !in_modal?
105
+ end
13
106
 
14
107
  def set_layout
15
108
  if action_name == 'index'
@@ -38,13 +131,9 @@ module PgEngine
38
131
  pg_respond_show
39
132
  end
40
133
 
41
- def respond_with_modal(klass_or_string)
42
- if klass_or_string.is_a?(Class)
43
- content = klass_or_string.new(instancia_modelo).render_in(view_context)
44
- elsif klass_or_string.is_a?(String)
45
- content = ModalContentComponent.new.with_body_content(klass_or_string)
46
- .render_in(view_context)
47
- end
134
+ # FIXME: refactor
135
+ def respond_with_modal(component)
136
+ content = component.render_in(view_context)
48
137
 
49
138
  if can_open_modal?
50
139
  modal = ModalComponent.new.with_content(content)
@@ -55,19 +144,28 @@ module PgEngine
55
144
  end
56
145
 
57
146
  def new
58
- if respond_with_modal?
59
- respond_with_modal(FormModalComponent)
147
+ if can_open_modal?
148
+ path = [request.path, request.query_string].compact.join('?')
149
+ component = ModalContentComponent.new(src: path)
150
+ respond_with_modal(component)
60
151
  else
61
152
  add_breadcrumb instancia_modelo.submit_default_value
62
153
  end
63
154
  end
64
155
 
65
156
  def edit
66
- if respond_with_modal?
67
- respond_with_modal(FormModalComponent)
157
+ if can_open_modal?
158
+ path = [request.path, request.query_string].compact.join('?')
159
+ component = ModalContentComponent.new(src: path)
160
+ respond_with_modal(component)
68
161
  else
69
- add_breadcrumb instancia_modelo.to_s_short, instancia_modelo.target_object
70
- add_breadcrumb 'Editando'
162
+ if modal_targeted? && referred_by?(instancia_modelo)
163
+ add_breadcrumb instancia_modelo.to_s_short
164
+ else
165
+ add_breadcrumb instancia_modelo.to_s_short,
166
+ instancia_modelo.target_object
167
+ end
168
+ add_breadcrumb 'Modificando'
71
169
  end
72
170
  end
73
171
 
@@ -87,36 +185,59 @@ module PgEngine
87
185
  protected
88
186
 
89
187
  def default_sort
90
- nil
188
+ 'id desc'
91
189
  end
92
190
 
93
191
  def available_page_sizes
94
- [10, 20, 30, 50, 100].push(current_page_size).uniq.sort
192
+ [5, 10, 20, 30, 50, 100].push(current_page_size).uniq.sort
193
+ end
194
+
195
+ def show_filters_by_default?
196
+ true
197
+ end
198
+
199
+ def filters_applied?
200
+ params[RansackMemory::Core.config[:param].presence || :q].present?
201
+ end
202
+
203
+ def session_key_identifier
204
+ ::RansackMemory::Core.config[:session_key_format]
205
+ .gsub('%controller_name%', controller_path.parameterize.underscore)
206
+ .gsub('%action_name%', action_name)
207
+ .gsub('%request_format%', request.format.symbol.to_s)
208
+ .gsub('%turbo_frame%', request.headers['Turbo-Frame'] || 'top')
209
+ # FIXME: rename to main?
95
210
  end
96
211
 
97
212
  def show_filters?
98
- cur_route = pg_current_route
99
- idtf = cur_route[:controller] + '#' + cur_route[:action] + '#open-filters'
213
+ return true if filters_applied?
214
+
215
+ idtf = "show-filters_#{session_key_identifier}"
100
216
 
101
217
  if params[:ocultar_filtros]
102
- session[idtf] = nil
218
+ session[idtf] = false
103
219
  elsif params[:mostrar_filtros]
104
220
  session[idtf] = true
105
221
  end
106
222
 
107
- session[idtf]
223
+ if session[idtf].nil?
224
+ show_filters_by_default?
225
+ else
226
+ session[idtf]
227
+ end
108
228
  end
109
229
 
110
230
  def current_page_size
111
- if params[:page_size].present?
112
- session[page_size_session_key] = params[:page_size].to_i
231
+ aux = params[:page_size].presence&.to_i
232
+ if aux.present? && aux.positive?
233
+ session[page_size_session_key] = aux
113
234
  end
114
235
 
115
236
  session[page_size_session_key].presence || default_page_size
116
237
  end
117
238
 
118
239
  def page_size_session_key
119
- "#{controller_name}/#{action_name}/page_size"
240
+ "page_size_#{session_key_identifier}"
120
241
  end
121
242
 
122
243
  def default_page_size
@@ -126,22 +247,26 @@ module PgEngine
126
247
  def pg_respond_update
127
248
  object = instancia_modelo
128
249
  if (@saved = object.save)
129
- if in_modal?
130
- body = <<~HTML.html_safe
131
- <pg-event data-event-name="pg:record-created" data-turbo-temporary
132
- data-response='#{object.decorate.to_json}'></pg-event>
133
- HTML
134
- render html: ModalContentComponent.new.with_body_content(body)
135
- .render_in(view_context)
136
- else
137
- redirect_to object.decorate.target_object
250
+ respond_to do |format|
251
+ format.html do
252
+ if in_modal?
253
+ body = <<~HTML.html_safe
254
+ <pg-event data-event-name="pg:record-updated" data-turbo-temporary
255
+ data-response='#{object.decorate.to_json}'></pg-event>
256
+ HTML
257
+ render html: ModalContentComponent.new.with_content(body)
258
+ .render_in(view_context)
259
+ else
260
+ redirect_to object.decorate.target_object
261
+ end
262
+ end
263
+ format.json do
264
+ render json: object.decorate.as_json
265
+ end
138
266
  end
139
- elsif in_modal?
140
- render html: FormModalComponent.new(instancia_modelo.decorate)
141
- .render_in(view_context)
142
267
  else
143
268
  add_breadcrumb instancia_modelo.decorate.to_s_short, instancia_modelo.decorate.target_object
144
- add_breadcrumb 'Editando'
269
+ add_breadcrumb 'Modificando'
145
270
  # TODO: esto solucionaría el problema?
146
271
  # self.instancia_modelo = instancia_modelo.decorate
147
272
  #
@@ -157,15 +282,10 @@ module PgEngine
157
282
  <pg-event data-event-name="pg:record-created" data-turbo-temporary
158
283
  data-response='#{object.decorate.to_json}'></pg-event>
159
284
  HTML
160
- render html: ModalContentComponent.new.with_body_content(body)
161
- .render_in(view_context)
162
-
285
+ render turbo_stream: turbo_stream.append(current_turbo_frame, body)
163
286
  else
164
287
  redirect_to object.decorate.target_object
165
288
  end
166
- elsif in_modal?
167
- render html: FormModalComponent.new(instancia_modelo.decorate)
168
- .render_in(view_context)
169
289
  else
170
290
  add_breadcrumb instancia_modelo.decorate.submit_default_value
171
291
  # TODO: esto solucionaría el problema?
@@ -181,35 +301,17 @@ module PgEngine
181
301
  format.html { render_listing }
182
302
  format.xlsx do
183
303
  render xlsx: 'download',
184
- filename: "#{@clase_modelo.nombre_plural.gsub(' ', '-').downcase}" \
304
+ filename: "#{clase_modelo.nombre_plural.gsub(' ', '-').downcase}" \
185
305
  "-#{Time.zone.now.strftime('%Y-%m-%d-%H.%M.%S')}.xlsx"
186
306
  end
187
307
  end
188
308
  end
189
309
 
190
- def accepts_turbo_stream?
191
- request.headers['Accept'].present? &&
192
- request.headers['Accept'].include?('text/vnd.turbo-stream.html')
193
- end
194
-
195
- def in_modal?
196
- request.headers['turbo-frame'] == 'modal_generic'
197
- end
198
-
199
- def respond_with_modal?
200
- can_open_modal? || in_modal?
201
- end
202
-
203
- def can_open_modal?
204
- request.get? &&
205
- params[:start_modal] == 'true' &&
206
- accepts_turbo_stream? &&
207
- !in_modal?
208
- end
209
-
210
310
  def pg_respond_show
211
- if respond_with_modal?
212
- respond_with_modal(ShowModalComponent)
311
+ if can_open_modal?
312
+ path = [request.path, request.query_string].compact.join('?')
313
+ component = ModalContentComponent.new(src: path)
314
+ respond_with_modal(component)
213
315
  else
214
316
  add_breadcrumb instancia_modelo.to_s_short, instancia_modelo.target_object
215
317
  end
@@ -219,14 +321,16 @@ module PgEngine
219
321
  "#{model.model_name.human} #{model.gender == 'f' ? 'borrada' : 'borrado'}"
220
322
  end
221
323
 
324
+ # rubocop:disable Metrics/PerceivedComplexity
222
325
  def pg_respond_destroy(model, redirect_url = nil)
223
326
  if destroy_model(model)
224
- if respond_with_modal?
327
+ # FIXME: rename to main
328
+ if turbo_frame? && current_turbo_frame != 'top'
225
329
  body = <<~HTML.html_safe
226
330
  <pg-event data-event-name="pg:record-destroyed" data-turbo-temporary>
227
331
  </pg-event>
228
332
  HTML
229
- respond_with_modal(body)
333
+ render turbo_stream: turbo_stream.append(current_turbo_frame, body)
230
334
  elsif redirect_url.present?
231
335
  redirect_to redirect_url, notice: destroyed_message(model), status: :see_other
232
336
  elsif accepts_turbo_stream?
@@ -251,6 +355,7 @@ module PgEngine
251
355
  redirect_back(fallback_location: root_path, status: 303)
252
356
  end
253
357
  end
358
+ # rubocop:enable Metrics/PerceivedComplexity
254
359
 
255
360
  def destroy_model(model)
256
361
  @error_message = 'No se pudo eliminar el registro'
@@ -272,17 +377,22 @@ module PgEngine
272
377
  end
273
378
 
274
379
  def render_listing
275
- @collection = @collection.page(params[:page]).per(current_page_size)
380
+ total = @collection.count
381
+ current_page = params[:page].presence&.to_i || 1
382
+ if current_page_size * (current_page - 1) > total
383
+ current_page = (total.to_f / current_page_size).ceil
384
+ end
385
+ @collection = @collection.page(current_page).per(current_page_size)
276
386
  @records_filtered = default_scope_for_current_model.any? if @collection.empty?
277
387
  end
278
388
 
279
389
  def buscar_instancia
280
- if Object.const_defined?('FriendlyId') && @clase_modelo.is_a?(FriendlyId)
281
- @clase_modelo.friendly.find(params[:id])
282
- elsif @clase_modelo.respond_to? :find_by_hashid!
283
- @clase_modelo.find_by_hashid!(params[:id])
390
+ if Object.const_defined?('FriendlyId') && clase_modelo.is_a?(FriendlyId)
391
+ clase_modelo.friendly.find(params[:id])
392
+ elsif clase_modelo.respond_to? :find_by_hashid!
393
+ clase_modelo.find_by_hashid!(params[:id])
284
394
  else
285
- @clase_modelo.find(params[:id])
395
+ clase_modelo.find(params[:id])
286
396
  end
287
397
  rescue ActiveRecord::RecordNotFound
288
398
  raise PgEngine::PageNotFoundError
@@ -290,7 +400,10 @@ module PgEngine
290
400
 
291
401
  def set_instancia_modelo
292
402
  if action_name.in? %w[new create]
293
- self.instancia_modelo = @clase_modelo.new(modelo_params)
403
+ self.instancia_modelo = clase_modelo.new(modelo_params)
404
+ if nested_id.present?
405
+ instancia_modelo.send("#{nested_key}=", nested_id)
406
+ end
294
407
  else
295
408
  self.instancia_modelo = buscar_instancia
296
409
 
@@ -323,12 +436,7 @@ module PgEngine
323
436
  end
324
437
 
325
438
  def nombre_modelo
326
- @clase_modelo.name.underscore
327
- end
328
-
329
- def clase_modelo
330
- # agarro la variable o intento con el nombre del controller
331
- @clase_modelo ||= self.class.name.singularize.gsub('Controller', '').constantize
439
+ clase_modelo.name.underscore
332
440
  end
333
441
 
334
442
  def filtros_y_policy(campos, dflt_sort = nil)
@@ -337,20 +445,35 @@ module PgEngine
337
445
  )
338
446
  scope = policy_scope(clase_modelo)
339
447
 
340
- scope = @filtros.filtrar(scope)
448
+ if nested_id.present?
449
+ scope = scope.where(nested_key => nested_id)
450
+ scope = scope.undiscarded if scope.respond_to?(:undiscarded)
451
+ elsif scope.respond_to?(:kept)
452
+ scope = scope.kept
453
+ end
454
+ # Soft deleted
341
455
 
342
456
  shared_context = Ransack::Adapters::ActiveRecord::Context.new(scope)
343
- @q = @clase_modelo.ransack(params[:q], context: shared_context)
344
-
457
+ @q = clase_modelo.ransack(params[:q], context: shared_context)
345
458
  @q.sorts = dflt_sort if @q.sorts.empty? && dflt_sort.present?
346
459
 
347
460
  shared_context.evaluate(@q)
348
461
  end
349
462
 
350
463
  def default_scope_for_current_model
351
- PgEngine::FiltrosBuilder.new(
352
- self, clase_modelo, []
353
- ).filtrar(policy_scope(clase_modelo))
464
+ scope = policy_scope(clase_modelo)
465
+
466
+ if nested_id.present?
467
+ scope = scope.where(nested_key => nested_id)
468
+
469
+ # Skip nested discarded check
470
+ scope = scope.undiscarded if scope.respond_to?(:undiscarded)
471
+ elsif scope.respond_to?(:kept)
472
+ scope = scope.kept
473
+ end
474
+ # Soft deleted, including nested discarded check
475
+
476
+ scope
354
477
  end
355
478
  end
356
479
  end
@@ -3,6 +3,10 @@
3
3
  module PgEngine
4
4
  # rubocop:disable Rails/ApplicationController
5
5
  class BaseController < ActionController::Base
6
+ before_action do
7
+ Current.controller = self
8
+ end
9
+
6
10
  # rubocop:enable Rails/ApplicationController
7
11
  include Pundit::Authorization
8
12
  include PrintHelper
@@ -10,6 +14,7 @@ module PgEngine
10
14
  include FlashHelper
11
15
  include RouteHelper
12
16
  include PgAssociable::Helpers
17
+ include FrameHelper
13
18
 
14
19
  class Redirect < PgEngine::Error
15
20
  attr_accessor :url
@@ -6,7 +6,7 @@ module Public
6
6
  class MensajeContactosController < PublicController
7
7
  include PgEngine::Resource
8
8
 
9
- before_action { @clase_modelo = MensajeContacto }
9
+ self.clase_modelo = MensajeContacto
10
10
 
11
11
  before_action(only: :index) { authorize MensajeContacto }
12
12
 
@@ -49,7 +49,7 @@ module PgEngine
49
49
  end
50
50
  end
51
51
 
52
- def destroy_link(confirm_text: '¿Estás seguro?', klass: 'btn-light', redirect_to: nil)
52
+ def destroy_link(confirm_text: '¿Confirmás que querés borrar el registro?', klass: 'btn-light', redirect_to: nil)
53
53
  return unless Pundit.policy!(Current.user, object).destroy?
54
54
 
55
55
  helpers.content_tag :span, rel: :tooltip, title: 'Eliminar' do
@@ -64,28 +64,24 @@ module PgEngine
64
64
  def edit_link(text: ' Modificar', klass: 'btn-warning')
65
65
  return unless Pundit.policy!(Current.user, object).edit?
66
66
 
67
- start_modal = !helpers.using_modal? && object.class.default_modal
68
-
69
67
  helpers.content_tag :span, rel: :tooltip, title: 'Modificar' do
70
- helpers.link_to edit_object_url + url_suffix(start_modal:), class: "btn btn-sm #{klass}",
71
- 'data-turbo-stream': start_modal do
68
+ helpers.link_to edit_object_url,
69
+ class: "btn btn-sm #{klass}",
70
+ 'data-turbo-frame': 'modal_content',
71
+ 'data-turbo-stream': true do
72
72
  helpers.content_tag(:span, nil, class: clase_icono('pencil')) + text
73
73
  end
74
74
  end
75
75
  end
76
76
 
77
- def url_suffix(start_modal: nil)
78
- start_modal ? '?start_modal=true' : ''
79
- end
80
-
81
77
  def show_link(text: '', klass: 'btn-light')
82
78
  return unless Pundit.policy!(Current.user, object).show?
83
79
 
84
- start_modal = !helpers.using_modal? && object.class.default_modal
85
-
86
80
  helpers.content_tag :span, rel: :tooltip, title: 'Ver' do
87
- helpers.link_to object_url + url_suffix(start_modal:), class: "btn btn-sm #{klass}",
88
- 'data-turbo-stream': start_modal do
81
+ helpers.link_to object_url,
82
+ class: "btn btn-sm #{klass}",
83
+ 'data-turbo-frame': 'modal_content',
84
+ 'data-turbo-stream': true do
89
85
  helpers.content_tag(:span, nil, class: clase_icono('eye-fill')) + text
90
86
  end
91
87
  end
@@ -105,11 +101,11 @@ module PgEngine
105
101
  def new_link(klass: 'btn-warning')
106
102
  return unless Pundit.policy!(Current.user, object).new?
107
103
 
108
- start_modal = !helpers.using_modal? && object.class.default_modal
109
-
110
104
  helpers.content_tag :span, rel: :tooltip, title: submit_default_value do
111
- helpers.link_to(new_object_url + url_suffix(start_modal:), class: "btn btn-sm #{klass}",
112
- 'data-turbo-stream': start_modal) do
105
+ helpers.link_to(new_object_url,
106
+ class: "btn btn-sm #{klass}",
107
+ 'data-turbo-frame': 'modal_content',
108
+ 'data-turbo-stream': true) do
113
109
  helpers.content_tag(:span, nil,
114
110
  class: clase_icono('plus').to_s) + "<span class='d-none d-sm-inline'> #{submit_default_value}</span>".html_safe
115
111
  end
@@ -128,13 +124,22 @@ module PgEngine
128
124
  helpers.url_for(target_object)
129
125
  end
130
126
 
127
+ def nested_record
128
+ # TODO: esto es raro
129
+ return if !Current.controller.respond_to?(:nested_record) ||
130
+ Current.controller.nested_record.nil? ||
131
+ Current.controller.nested_record.instance_of?(object.class)
132
+
133
+ Current.controller.nested_record
134
+ end
135
+
131
136
  def target_object
132
- pg_namespace.present? ? [pg_namespace, object] : object
137
+ [pg_namespace, nested_record, object].compact
133
138
  end
134
139
 
135
140
  def target_new
136
141
  mod_name_sing = object.class.model_name.singular.to_sym
137
- pg_namespace.present? ? [:new, pg_namespace, mod_name_sing] : [:new, mod_name_sing]
142
+ [:new, pg_namespace, nested_record, mod_name_sing]
138
143
  end
139
144
 
140
145
  def target_index
@@ -2,10 +2,6 @@
2
2
 
3
3
  module PgEngine
4
4
  module FormHelper
5
- def using_modal?
6
- @using_modal || controller.instance_variable_get(:@using_modal)
7
- end
8
-
9
5
  # rubocop:disable Metrics/CyclomaticComplexity
10
6
  def pg_form_for(object, *args, &block_passed)
11
7
  resource = object
@@ -39,7 +35,6 @@ module PgEngine
39
35
  block_with_additives = lambda do |f|
40
36
  ret = ''.html_safe
41
37
  ret += f.mensajes_de_error if options[:render_errors]
42
- # ret += hidden_field_tag(:using_modal, true) if using_modal?
43
38
  ret += capture(f, &block_passed)
44
39
  ret
45
40
  end
@@ -0,0 +1,52 @@
1
+ module PgEngine
2
+ module FrameHelper
3
+ # Will the current view rendered in a modal?
4
+ def using_modal?
5
+ controller.instance_variable_get(:@using_modal) ||
6
+ modal_targeted?
7
+ end
8
+
9
+ def using_modal2?
10
+ @using_modal || modal_targeted?
11
+ end
12
+
13
+ def in_modal?
14
+ request.headers['Modal-Opened'] == 'true'
15
+ end
16
+
17
+ def current_turbo_frame
18
+ request.headers['Turbo-Frame']
19
+ end
20
+
21
+ def turbo_frame?
22
+ current_turbo_frame.present?
23
+ end
24
+
25
+ def modal_targeted?
26
+ current_turbo_frame == 'modal_content'
27
+ end
28
+
29
+ def frame_embedded?
30
+ turbo_frame? && current_turbo_frame.include?('embedded')
31
+ end
32
+
33
+ def embed_index(object, key)
34
+ content_tag(:div, 'data-controller': 'embedded-frame') do
35
+ turbo_frame_tag "embedded--#{key}",
36
+ refresh: :morph, src: url_for([pg_namespace, object, key]) do
37
+ content_tag(:p, class: 'p text-body-secondary text-center') { 'Cargando...' }
38
+ end
39
+ end
40
+ end
41
+
42
+ def nav_bg
43
+ if frame_embedded?
44
+ 'bg-warning bg-opacity-25'
45
+ elsif using_modal?
46
+ 'bg-warning bg-opacity-50'
47
+ else
48
+ 'bg-primary-subtle'
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ module PgEngine
2
+ class Bootstrap5BreadcrumbsBuilder < BreadcrumbsOnRails::Breadcrumbs::Builder
3
+ def render
4
+ @elements.collect do |element|
5
+ render_element(element)
6
+ end.join(@options[:separator] || '')
7
+ end
8
+
9
+ def render_element(element)
10
+ content = if element.path.nil?
11
+ compute_name(element)
12
+ else
13
+ # TODO: add aria-current="page"
14
+ @context.link_to_unless_current(
15
+ compute_name(element), compute_path(element), element.options
16
+ )
17
+ end
18
+
19
+ @context.content_tag('li', content, class: 'breadcrumb-item')
20
+ end
21
+ end
22
+ end
@@ -64,11 +64,12 @@ module PgEngine
64
64
  @filtros[campo][:scope_asociacion] = block
65
65
  end
66
66
 
67
+ # FIXME: deprecar
67
68
  def filtrar(query, parametros = nil)
68
- parametros = parametros_controller if parametros.nil?
69
+ parametros_controller if parametros.nil?
69
70
 
70
71
  # Filtro soft deleted
71
- query = query.kept if query.respond_to?(:kept) && parametros[:archived] != 'true'
72
+ query = query.kept if query.respond_to?(:kept)
72
73
 
73
74
  query
74
75
  end
@@ -1,5 +1,5 @@
1
1
  class Current < ActiveSupport::CurrentAttributes
2
- attribute :account, :user, :namespace
2
+ attribute :account, :user, :namespace, :controller
3
3
  # attribute :request_id, :user_agent, :ip_address
4
4
 
5
5
  # resets { Time.zone = nil }