pg_rails 7.3.0 → 7.3.2

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 +27 -16
  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,28 @@ 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
67
+ modal = object.class.default_modal
68
68
 
69
69
  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
70
+ helpers.link_to edit_object_url,
71
+ class: "btn btn-sm #{klass}",
72
+ 'data-turbo-frame': modal ? 'modal_content' : '_top',
73
+ 'data-turbo-stream': modal do
72
74
  helpers.content_tag(:span, nil, class: clase_icono('pencil')) + text
73
75
  end
74
76
  end
75
77
  end
76
78
 
77
- def url_suffix(start_modal: nil)
78
- start_modal ? '?start_modal=true' : ''
79
- end
80
-
81
79
  def show_link(text: '', klass: 'btn-light')
82
80
  return unless Pundit.policy!(Current.user, object).show?
83
81
 
84
- start_modal = !helpers.using_modal? && object.class.default_modal
82
+ modal = object.class.default_modal
85
83
 
86
84
  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
85
+ helpers.link_to object_url,
86
+ class: "btn btn-sm #{klass}",
87
+ 'data-turbo-frame': modal ? 'modal_content' : '_top',
88
+ 'data-turbo-stream': modal do
89
89
  helpers.content_tag(:span, nil, class: clase_icono('eye-fill')) + text
90
90
  end
91
91
  end
@@ -105,11 +105,13 @@ module PgEngine
105
105
  def new_link(klass: 'btn-warning')
106
106
  return unless Pundit.policy!(Current.user, object).new?
107
107
 
108
- start_modal = !helpers.using_modal? && object.class.default_modal
108
+ modal = object.class.default_modal
109
109
 
110
110
  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
111
+ helpers.link_to(new_object_url,
112
+ class: "btn btn-sm #{klass}",
113
+ 'data-turbo-frame': modal ? 'modal_content' : '_top',
114
+ 'data-turbo-stream': modal) do
113
115
  helpers.content_tag(:span, nil,
114
116
  class: clase_icono('plus').to_s) + "<span class='d-none d-sm-inline'> #{submit_default_value}</span>".html_safe
115
117
  end
@@ -128,13 +130,22 @@ module PgEngine
128
130
  helpers.url_for(target_object)
129
131
  end
130
132
 
133
+ def nested_record
134
+ # TODO: esto es raro
135
+ return if !Current.controller.respond_to?(:nested_record) ||
136
+ Current.controller.nested_record.nil? ||
137
+ Current.controller.nested_record.instance_of?(object.class)
138
+
139
+ Current.controller.nested_record
140
+ end
141
+
131
142
  def target_object
132
- pg_namespace.present? ? [pg_namespace, object] : object
143
+ [pg_namespace, nested_record, object].compact
133
144
  end
134
145
 
135
146
  def target_new
136
147
  mod_name_sing = object.class.model_name.singular.to_sym
137
- pg_namespace.present? ? [:new, pg_namespace, mod_name_sing] : [:new, mod_name_sing]
148
+ [:new, pg_namespace, nested_record, mod_name_sing]
138
149
  end
139
150
 
140
151
  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 }