pg_rails 7.6.2 → 7.6.4

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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/pg_associable/app/helpers/pg_associable/form_builder_methods.rb +3 -0
  3. data/pg_engine/app/assets/stylesheets/pg_rails_b5.scss +29 -3
  4. data/pg_engine/app/components/bad_user_input_component.rb +1 -0
  5. data/pg_engine/app/components/inline_edit/inline_component.rb +27 -0
  6. data/pg_engine/app/components/inline_edit/inline_edit_component.html.slim +14 -0
  7. data/pg_engine/app/components/inline_edit/inline_edit_component.rb +13 -0
  8. data/pg_engine/app/components/inline_edit/inline_show_component.html.slim +8 -0
  9. data/pg_engine/app/components/inline_edit/inline_show_component.rb +2 -0
  10. data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +8 -4
  11. data/pg_engine/app/controllers/pg_engine/base_controller.rb +7 -16
  12. data/pg_engine/app/controllers/users/inline_edit_controller.rb +21 -0
  13. data/pg_engine/app/decorators/pg_engine/base_record_decorator.rb +2 -2
  14. data/pg_engine/app/helpers/pg_engine/index_helper.rb +1 -1
  15. data/pg_engine/app/lib/pg_form_builder.rb +18 -0
  16. data/pg_engine/app/models/pg_engine/base_record.rb +5 -1
  17. data/pg_engine/app/views/pg_engine/base/index.html.slim +2 -1
  18. data/pg_engine/config/initializers/zeitwerk.rb +2 -0
  19. data/pg_engine/config/routes.rb +4 -0
  20. data/pg_engine/config/simple_form/simple_form_bootstrap.rb +32 -2
  21. data/pg_engine/spec/controllers/pg_engine/base_controller_spec.rb +1 -16
  22. data/pg_engine/spec/requests/users/accounts_spec.rb +1 -2
  23. data/pg_engine/spec/requests/users/inline_edit_spec.rb +101 -0
  24. data/pg_layout/app/javascript/config/index.js +20 -20
  25. data/pg_layout/app/javascript/config/turbo_rails/index.js +4 -2
  26. data/pg_rails/lib/version.rb +1 -1
  27. data/pg_rails/scss/pg_rails.scss +4 -4
  28. data/pg_scaffold/lib/generators/pg_active_record/model/templates/model.rb +3 -0
  29. data/pg_scaffold/lib/generators/pg_slim/templates/_form.html.slim +1 -1
  30. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49f9abe4c2e4521dd99abe5a9220e3bece6ceb0e182c1a7d1fe252d836977bbf
4
- data.tar.gz: 105da76663a6b29c338c45cb0e46d2663b99c7463a91beb734771f34dd668319
3
+ metadata.gz: 558b69c5a93797c069002f3477d6ccc34b63b98fa4f1a37ddedcc4ab6010ef3b
4
+ data.tar.gz: a3cc4d53326372aaa5e7155b2d50cfdee3fc3d0814a81eee53ec3701814c3e23
5
5
  SHA512:
6
- metadata.gz: 344c3c89251c75d50c9ace0a1dac02d69ecb1d04e1392d330225c4496e7bfc5c24718cfb98c0c6843c24e5402d22b399d203cdbd6c3826c6f2cb9b8271b7da9e
7
- data.tar.gz: bb74de3073bb722ee4444a726306db6759c21e3ddc61e3f2a36e988b4ff688d72e31611d6168c2e936366d79c503924056da03ebd8f23dc7e07750cfb0ec2231
6
+ metadata.gz: 259c3f0cc7c935f4a5b9569a2cd33cb1cc60e71a1c5cc85118fb3190415ebad4d78065c641bbe0bdaf479639df1be0ef93ded0ad589313f7dd23011ecfa618d8
7
+ data.tar.gz: b0e0ad29958f836916d4469d43bd5f3c8797eb9e00a981694034c025158083f28a0ea32bce7057a957bd2d2898d75daf7905fc9e0facd2ec78677f0de06c3389
@@ -41,6 +41,7 @@ module PgAssociable
41
41
  user = Current.user
42
42
  puede_crear = !template.using_modal? && Pundit::PolicyFinder.new(klass).policy.new(user, klass).new?
43
43
  collection = Pundit::PolicyFinder.new(klass).scope.new(user, klass).resolve
44
+ collection = collection.kept if collection.respond_to?(:kept)
44
45
  [collection, puede_crear]
45
46
  end
46
47
 
@@ -50,9 +51,11 @@ module PgAssociable
50
51
  options.deep_merge!({ wrapper_html: { 'data-preload': collection.decorate.to_json } })
51
52
  end
52
53
  # TODO: usar una clase más precisa para el modal?
54
+ # quizás sea este el motivo por el cual no funciona el multimodal
53
55
  options.deep_merge!({ wrapper_html: { data: { controller: 'asociable',
54
56
  'asociable-modal-outlet': '.modal' } } })
55
57
  options[:as] = 'pg_associable'
58
+
56
59
  association atributo, options
57
60
  end
58
61
 
@@ -73,9 +73,10 @@ input[type=datetime-local], input[type=datetime] {
73
73
  display: flex;
74
74
  justify-content: flex-end;
75
75
  gap: 4px;
76
- }
77
- .listado .btn-sm {
78
- padding: 0em 0.3em;
76
+
77
+ .btn-sm {
78
+ padding: 0em 0.3em;
79
+ }
79
80
  }
80
81
 
81
82
  .list-group-item {
@@ -199,3 +200,28 @@ input[type=datetime-local], input[type=datetime] {
199
200
  }
200
201
  --fc-neutral-bg-color: none;
201
202
  }
203
+
204
+ // Inline edit
205
+
206
+ .inline-edit {
207
+ // text-decoration: underline;
208
+ // text-decoration-style: dotted;
209
+ // text-decoration-color: #262626;
210
+ border-bottom: 1px dotted #333;
211
+ padding-bottom: 1px;
212
+
213
+ a:hover {
214
+ i {
215
+ color: black;
216
+ }
217
+ }
218
+
219
+ input[type=text] {
220
+ min-width: 22em;
221
+ }
222
+
223
+ // To display correctly in tables with fixed witdh columns
224
+ .form-select {
225
+ width: initial;
226
+ }
227
+ }
@@ -1,3 +1,4 @@
1
+ # TODO: rename to WarningComponent or sth
1
2
  class BadUserInputComponent < BaseComponent
2
3
  def initialize(error_msg:)
3
4
  @error_msg = error_msg
@@ -0,0 +1,27 @@
1
+ class InlineComponent < ViewComponent::Base
2
+ def initialize(model, attribute)
3
+ @model = model
4
+ @attribute = attribute
5
+ @unsuffixed_attribute = unsuffixed(attribute)
6
+ @frame_id = dom_id(model, "#{attribute}_inline_edit")
7
+
8
+ super
9
+ end
10
+
11
+ def before_render
12
+ return unless controller.in_modal?
13
+
14
+ controller.instance_variable_set(:@using_modal, true)
15
+ end
16
+
17
+ SUFIJOS = %i[f text].freeze
18
+ def unsuffixed(attribute)
19
+ ret = attribute.to_s.dup
20
+
21
+ SUFIJOS.each do |sufijo|
22
+ ret.gsub!(/_#{sufijo}$/, '')
23
+ end
24
+
25
+ ret
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ = helpers.turbo_frame_tag(@frame_id, class: 'inline-edit')
2
+ = helpers.pg_form_for(@model, render_errors: false, wrapper_mappings: @wrapper_mappings,
3
+ html: { class: 'd-flex align-items-start gap-1' }) do |f|
4
+ = hidden_field_tag :inline_attribute, @attribute
5
+
6
+ = f.field @unsuffixed_attribute, label: false, html5: true
7
+
8
+ = button_tag class: 'btn btn-sm btn-primary',
9
+ data: { controller: 'tooltip', 'bs-title': 'Guardar' } do
10
+ i.bi.bi-check-lg
11
+ = link_to users_inline_show_path(model: @model.to_gid, attribute: @attribute),
12
+ class: 'btn btn-sm btn-secondary',
13
+ data: { controller: 'tooltip', 'bs-title': 'Cancelar' } do
14
+ i.bi.bi-x-lg
@@ -0,0 +1,13 @@
1
+ class InlineEditComponent < InlineComponent
2
+ def initialize(*)
3
+ @wrapper_mappings = {
4
+ string: :inline_form_grow,
5
+ pg_associable: :inline_form_control,
6
+ date: :inline_form_control,
7
+ datetime: :inline_form_control,
8
+ select: :inline_form_select
9
+ }
10
+
11
+ super
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ - if @model.class.inline_editable?(@unsuffixed_attribute) && helpers.policy(@model).edit?
2
+ = helpers.turbo_frame_tag(@frame_id, class: 'inline-edit')
3
+ = link_to users_inline_edit_path(model: @model.to_gid, attribute: @attribute),
4
+ class: 'text-body-tertiary', style: 'font-size: 0.8em' do
5
+ i.bi.bi-pencil
6
+ span.ms-1 = @model.decorate.send(@attribute)
7
+ - else
8
+ = @model.decorate.send(@attribute)
@@ -0,0 +1,2 @@
1
+ class InlineShowComponent < InlineComponent
2
+ end
@@ -257,7 +257,9 @@ module PgEngine
257
257
  if (@saved = object.save)
258
258
  respond_to do |format|
259
259
  format.html do
260
- if in_modal?
260
+ if params[:inline_attribute].present?
261
+ render InlineShowComponent.new(object, params[:inline_attribute]), layout: false
262
+ elsif in_modal?
261
263
  body = <<~HTML.html_safe
262
264
  <pg-event data-event-name="pg:record-updated" data-turbo-temporary
263
265
  data-response='#{object.decorate.to_json}'></pg-event>
@@ -272,6 +274,9 @@ module PgEngine
272
274
  render json: object.decorate.as_json
273
275
  end
274
276
  end
277
+ elsif params[:inline_attribute].present?
278
+ render InlineEditComponent.new(object, params[:inline_attribute]),
279
+ layout: false, status: :unprocessable_entity
275
280
  else
276
281
  add_breadcrumb instancia_modelo.decorate.to_s_short, instancia_modelo.decorate.target_object
277
282
  add_breadcrumb 'Modificando'
@@ -409,17 +414,16 @@ module PgEngine
409
414
  def set_instancia_modelo
410
415
  if action_name.in? %w[new create]
411
416
  self.instancia_modelo = clase_modelo.new(modelo_params)
417
+ authorize(instancia_modelo)
412
418
  if nested_id.present?
413
419
  instancia_modelo.send("#{nested_key}=", nested_id)
414
420
  end
415
421
  else
416
422
  self.instancia_modelo = buscar_instancia
417
-
423
+ authorize(instancia_modelo)
418
424
  instancia_modelo.assign_attributes(modelo_params) if action_name.in? %w[update]
419
425
  end
420
426
 
421
- authorize(instancia_modelo)
422
-
423
427
  # TODO: problema en create y update cuando falla la validacion
424
428
  # Reproducir el error antes de arreglarlo
425
429
  self.instancia_modelo = instancia_modelo.decorate if action_name.in? %w[show edit new]
@@ -216,22 +216,13 @@ module PgEngine
216
216
  end
217
217
 
218
218
  def not_authorized(_arg_required_for_active_admin)
219
- respond_to do |format|
220
- format.json do
221
- render json: { error: 'Acceso no autorizado' },
222
- status: :unprocessable_entity
223
- end
224
- # TODO: responder a turbo_stream
225
- format.html do
226
- if request.path == root_path
227
- # TODO!: renderear un 500.html y pg_err
228
- sign_out(Current.user) if Current.user.present?
229
- render plain: 'Acceso no autorizado', status: :unprocessable_entity
230
- else
231
- go_back('Acceso no autorizado')
232
- end
233
- end
234
- end
219
+ pg_warn <<~STRING
220
+ Acceso no autorizado.
221
+ User: #{Current.user.inspect}
222
+ Request: #{request.inspect}
223
+ STRING
224
+
225
+ render_my_component(BadUserInputComponent.new(error_msg: 'Acceso no autorizado'), :unauthorized)
235
226
  end
236
227
 
237
228
  def go_back(message = nil, type: :alert)
@@ -0,0 +1,21 @@
1
+ module Users
2
+ class InlineEditController < PgEngine.config.users_controller
3
+ before_action do
4
+ if current_turbo_frame.blank?
5
+ render_my_component(BadRequestComponent.new, :bad_request)
6
+ end
7
+ end
8
+
9
+ def edit
10
+ model = GlobalID::Locator.locate params[:model]
11
+ attribute = params[:attribute]
12
+ render InlineEditComponent.new(model, attribute), layout: false
13
+ end
14
+
15
+ def show
16
+ model = GlobalID::Locator.locate params[:model]
17
+ attribute = params[:attribute]
18
+ render InlineShowComponent.new(model, attribute), layout: false
19
+ end
20
+ end
21
+ end
@@ -118,8 +118,8 @@ module PgEngine
118
118
  end
119
119
  end
120
120
 
121
- def edit_object_url
122
- helpers.url_for([:edit, target_object].flatten)
121
+ def edit_object_url(**args)
122
+ helpers.url_for([:edit, target_object, **args].flatten)
123
123
  end
124
124
 
125
125
  def new_object_url
@@ -4,7 +4,7 @@ module PgEngine
4
4
  module IndexHelper
5
5
  def column_for(object, attribute)
6
6
  content_tag :td, **column_options_for(object, attribute) do
7
- object.send(attribute).to_s
7
+ render InlineShowComponent.new(object.object, attribute)
8
8
  end
9
9
  end
10
10
 
@@ -26,6 +26,24 @@ class PgFormBuilder < SimpleForm::FormBuilder
26
26
  super
27
27
  end
28
28
 
29
+ def field(attribute_name, options = {}, &)
30
+ model = convert_to_model(object)
31
+
32
+ if find_on_all_associations(model.class, attribute_name).present?
33
+ pg_associable(attribute_name, options)
34
+ else
35
+ input(attribute_name, options, &)
36
+ end
37
+ end
38
+
39
+ def find_on_all_associations(klass, campo)
40
+ return unless klass.respond_to? :reflect_on_all_associations
41
+
42
+ klass.reflect_on_all_associations.find do |a|
43
+ a.name == campo.to_sym
44
+ end
45
+ end
46
+
29
47
  def mensajes_de_error
30
48
  # TODO: quitar en before-cache?
31
49
  title = error_notification(message: mensaje, class: 'text-danger mb-2 error-title') if mensaje
@@ -16,7 +16,11 @@ module PgEngine
16
16
  class << self
17
17
  # This is a per class variable, all subclasses of BaseRecord inherit it
18
18
  # BUT **the values are independent between all of them**
19
- attr_accessor :default_modal
19
+ attr_accessor :default_modal, :inline_editable_fields
20
+
21
+ def inline_editable?(attribute)
22
+ inline_editable_fields.present? && inline_editable_fields.include?(attribute.to_sym)
23
+ end
20
24
  end
21
25
 
22
26
  # ransacker :search do |parent|
@@ -25,7 +25,8 @@ div
25
25
  th.text-nowrap style="font-size: 0.8em" = encabezado att, ordenable: true
26
26
  th.text-end
27
27
  - unless @export_link == false
28
- = @clase_modelo.new.decorate.export_link(request.url)
28
+ .actions-wrapper
29
+ = @clase_modelo.new.decorate.export_link(request.url)
29
30
  tbody
30
31
  - @collection.each do |object|
31
32
  - object = object.decorate
@@ -6,3 +6,5 @@ Rails.autoloaders.main.ignore(
6
6
  "#{PgEngine::Engine.root}/app/overrides",
7
7
  "#{PgEngine::Engine.root}/app/views"
8
8
  )
9
+
10
+ Rails.autoloaders.main.collapse("#{PgEngine::Engine.root}/app/components/inline_edit")
@@ -21,6 +21,10 @@ Rails.application.routes.draw do
21
21
  registrations: 'users/registrations'
22
22
  }, failure_app: PgEngine::DeviseFailureApp
23
23
  namespace :users, path: 'u' do
24
+ scope controller: 'inline_edit', path: 'inline', as: :inline do
25
+ get 'edit'
26
+ get 'show'
27
+ end
24
28
  get 'dashboard', to: 'dashboard#dashboard'
25
29
  post 'notifications/mark_as_seen', to: 'notifications#mark_as_seen'
26
30
  post 'notifications/mark_as_unseen', to: 'notifications#mark_as_unseen'
@@ -270,7 +270,7 @@ SimpleForm.setup do |config|
270
270
  # inline forms
271
271
  #
272
272
  # inline default_wrapper
273
- config.wrappers :inline_form, class: 'col-12' do |b|
273
+ config.wrappers :inline_form_grow, class: 'flex-grow-1' do |b|
274
274
  b.use :html5
275
275
  b.use :placeholder
276
276
  b.optional :maxlength
@@ -280,7 +280,37 @@ SimpleForm.setup do |config|
280
280
  b.optional :readonly
281
281
  b.use :label, class: 'visually-hidden'
282
282
 
283
- b.use :input, class: 'form-control', error_class: 'is-invalid'
283
+ b.use :input, class: 'form-control form-control-sm', error_class: 'is-invalid'
284
+ b.use :error, wrap_with: { class: 'invalid-feedback' }
285
+ b.optional :hint, wrap_with: { class: 'form-text' }
286
+ end
287
+
288
+ config.wrappers :inline_form_control, class: '' do |b|
289
+ b.use :html5
290
+ b.use :placeholder
291
+ b.optional :maxlength
292
+ b.optional :minlength
293
+ b.optional :pattern
294
+ b.optional :min_max
295
+ b.optional :readonly
296
+ b.use :label, class: 'visually-hidden'
297
+
298
+ b.use :input, class: 'form-control form-control-sm', error_class: 'is-invalid'
299
+ b.use :error, wrap_with: { class: 'invalid-feedback' }
300
+ b.optional :hint, wrap_with: { class: 'form-text' }
301
+ end
302
+
303
+ config.wrappers :inline_form_select, class: '' do |b|
304
+ b.use :html5
305
+ b.use :placeholder
306
+ b.optional :maxlength
307
+ b.optional :minlength
308
+ b.optional :pattern
309
+ b.optional :min_max
310
+ b.optional :readonly
311
+ b.use :label, class: 'visually-hidden'
312
+
313
+ b.use :input, class: 'form-select form-select-sm', error_class: 'is-invalid'
284
314
  b.use :error, wrap_with: { class: 'invalid-feedback' }
285
315
  b.optional :hint, wrap_with: { class: 'form-text' }
286
316
  end
@@ -84,22 +84,7 @@ describe DummyBaseController do
84
84
 
85
85
  it do
86
86
  subject
87
- expect(response).to redirect_to root_path
88
- expect(flash[:alert]).to eq 'Acceso no autorizado'
89
- expect(controller).to be_user_signed_in
90
- end
91
-
92
- context 'cuando ocurre en el root_path' do
93
- before do
94
- allow_any_instance_of(ActionController::TestRequest).to receive(:path).and_return(root_path)
95
- end
96
-
97
- it do
98
- subject
99
- expect(response).to have_http_status(:unprocessable_entity)
100
- expect(response.body).to eq 'Acceso no autorizado'
101
- expect(controller).not_to be_user_signed_in
102
- end
87
+ expect(response).to have_http_status(:unauthorized)
103
88
  end
104
89
  end
105
90
 
@@ -16,7 +16,6 @@ describe 'Users::AccountsController' do
16
16
  it 'denies foreign account' do
17
17
  other_account = create :account
18
18
  get "/u/cuentas/#{other_account.to_param}"
19
- expect(response).to have_http_status(:redirect)
20
- expect(flash[:alert]).to eq 'Acceso no autorizado'
19
+ expect(response).to have_http_status(:unauthorized)
21
20
  end
22
21
  end
@@ -0,0 +1,101 @@
1
+ require 'rails_helper'
2
+
3
+ describe 'inline edit' do
4
+ before do
5
+ user = create :user
6
+ sign_in user
7
+ end
8
+
9
+ let(:cosa) { create :cosa }
10
+
11
+ describe '#show' do
12
+ subject do
13
+ get '/u/inline/show', params:, headers: { 'Turbo-Frame': turbo_frame_id }
14
+ end
15
+
16
+ let(:params) do
17
+ { model: cosa.to_gid.to_param, attribute: :nombre }
18
+ end
19
+
20
+ let(:turbo_frame_id) { 'turbo-frame' }
21
+
22
+ it do
23
+ subject
24
+ expect(response).to have_http_status(:ok)
25
+ expect(response.body).to include cosa.nombre
26
+ end
27
+
28
+ context 'when no turbo frame targetted' do
29
+ let(:turbo_frame_id) { nil }
30
+
31
+ it do
32
+ subject
33
+ expect(response).to have_http_status(:bad_request)
34
+ end
35
+ end
36
+ end
37
+
38
+ describe '#edit' do
39
+ subject do
40
+ get '/u/inline/edit', params:, headers: { 'Turbo-Frame': turbo_frame_id }
41
+ end
42
+
43
+ let(:params) do
44
+ { model: cosa.to_gid.to_param, attribute: :nombre }
45
+ end
46
+
47
+ let(:turbo_frame_id) { 'turbo-frame' }
48
+
49
+ it do
50
+ subject
51
+ expect(response).to have_http_status(:ok)
52
+ expect(response.body).to include cosa.nombre
53
+ end
54
+
55
+ context 'when no turbo frame targetted' do
56
+ let(:turbo_frame_id) { nil }
57
+
58
+ it do
59
+ subject
60
+ expect(response).to have_http_status(:bad_request)
61
+ end
62
+ end
63
+ end
64
+
65
+ describe '#update' do
66
+ subject do
67
+ patch "/u/cosas/#{cosa.to_param}", params:
68
+ end
69
+
70
+ let(:params) do
71
+ {
72
+ inline_attribute: 'nombre',
73
+ cosa: {
74
+ nombre:
75
+ }
76
+ }
77
+ end
78
+
79
+ let(:nombre) { 'otro' }
80
+
81
+ it do
82
+ subject
83
+ expect(response.body).to include 'turbo-frame'
84
+ expect(response).to have_http_status(:ok)
85
+ end
86
+
87
+ it do
88
+ expect { subject }.to change { cosa.reload.nombre }.to 'otro'
89
+ end
90
+
91
+ context 'when validation fails' do
92
+ let(:nombre) { nil }
93
+
94
+ it do
95
+ subject
96
+ expect(response.body).to include 'turbo-frame'
97
+ expect(response).to have_http_status(:unprocessable_entity)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -7,23 +7,23 @@ import './tooltips'
7
7
  import 'trix'
8
8
  import '@rails/actiontext'
9
9
 
10
- function bindListingClick () {
11
- document.body.onclick = (ev) => {
12
- if (ev.target.closest('a')) return
13
- if (ev.target.closest('.listado')) {
14
- const row = ev.target.closest('tr')
15
- if (row) {
16
- const show = row.querySelector('.bi-eye-fill')
17
- if (show) {
18
- const link = show.closest('a')
19
- if (link) {
20
- link.click()
21
- }
22
- }
23
- }
24
- }
25
- }
26
- }
27
- bindListingClick()
28
- document.addEventListener('turbo:load', bindListingClick)
29
- document.addEventListener('turbo:render', bindListingClick)
10
+ // function bindListingClick () {
11
+ // document.body.onclick = (ev) => {
12
+ // if (ev.target.closest('a')) return
13
+ // if (ev.target.closest('.listado')) {
14
+ // const row = ev.target.closest('tr')
15
+ // if (row) {
16
+ // const show = row.querySelector('.bi-eye-fill')
17
+ // if (show) {
18
+ // const link = show.closest('a')
19
+ // if (link) {
20
+ // link.click()
21
+ // }
22
+ // }
23
+ // }
24
+ // }
25
+ // }
26
+ // }
27
+ // bindListingClick()
28
+ // document.addEventListener('turbo:load', bindListingClick)
29
+ // document.addEventListener('turbo:render', bindListingClick)
@@ -23,8 +23,10 @@ document.addEventListener('turbo:before-cache', () => {
23
23
  })
24
24
  })
25
25
 
26
- document.addEventListener('turbo:frame-missing', (ev) => {
27
- Rollbar.error('Turbo Frame missing')
26
+ document.addEventListener('turbo:frame-missing', async (ev) => {
27
+ const text = await ev.detail.response.text()
28
+ Rollbar.error('turbo:frame-missing', text, ev.detail)
29
+ console.error('turbo:frame-missing', text, ev.detail)
28
30
  ev.preventDefault()
29
31
  const html = `
30
32
  <div>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRails
4
- VERSION = '7.6.2'
4
+ VERSION = '7.6.4'
5
5
  end
@@ -89,7 +89,7 @@ $light-border-emphasis: shade-color($light, 60%);
89
89
  border: 1px solid $light-border-emphasis;
90
90
  }
91
91
 
92
- .listado tr:has(td:hover):has(.bi-eye-fill) td {
93
- background-color: #f2f2f2;
94
- cursor: pointer;
95
- }
92
+ // .listado tr:has(td:hover):has(.bi-eye-fill) td {
93
+ // background-color: #f2f2f2;
94
+ // cursor: pointer;
95
+ // }
@@ -15,6 +15,9 @@ class <%= class_name %> < <%= parent_class_name.classify %>
15
15
  <%- if options[:discard] -%>
16
16
  include Discard::Model
17
17
  <%- end -%>
18
+
19
+ self.default_modal = true
20
+ self.inline_editable_fields = %i[<%= attributes.map(&:name).join(' ') %>]
18
21
  <%- if attributes.any?(&:reference?) -%>
19
22
 
20
23
  <%- attributes.select(&:reference?).each do |attribute| -%>
@@ -3,7 +3,7 @@
3
3
  div style="max-width: 22em" data-controller="pg_form"
4
4
  = pg_form_for(@<%= singular_name %> || object) do |f|
5
5
  <%- attributes.each do |attribute| -%>
6
- = f.<%= attribute.reference? ? :pg_associable : :input %> :<%= attribute.name %>
6
+ = f.field :<%= attribute.name %>
7
7
  <%- end -%>
8
8
  .mt-2
9
9
  = f.button :submit
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.6.2
4
+ version: 7.6.4
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-09-30 00:00:00.000000000 Z
11
+ date: 2024-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -674,6 +674,11 @@ files:
674
674
  - pg_engine/app/components/date_selector_component.html.slim
675
675
  - pg_engine/app/components/date_selector_component.rb
676
676
  - pg_engine/app/components/flash_container_component.rb
677
+ - pg_engine/app/components/inline_edit/inline_component.rb
678
+ - pg_engine/app/components/inline_edit/inline_edit_component.html.slim
679
+ - pg_engine/app/components/inline_edit/inline_edit_component.rb
680
+ - pg_engine/app/components/inline_edit/inline_show_component.html.slim
681
+ - pg_engine/app/components/inline_edit/inline_show_component.rb
677
682
  - pg_engine/app/components/internal_error_component.rb
678
683
  - pg_engine/app/components/modal_component.html.slim
679
684
  - pg_engine/app/components/modal_component.rb
@@ -707,6 +712,7 @@ files:
707
712
  - pg_engine/app/controllers/users/confirmations_controller.rb
708
713
  - pg_engine/app/controllers/users/dashboard_controller.rb
709
714
  - pg_engine/app/controllers/users/date_jumper_controller.rb
715
+ - pg_engine/app/controllers/users/inline_edit_controller.rb
710
716
  - pg_engine/app/controllers/users/notifications_controller.rb
711
717
  - pg_engine/app/controllers/users/registrations_controller.rb
712
718
  - pg_engine/app/decorators/account_decorator.rb
@@ -902,6 +908,7 @@ files:
902
908
  - pg_engine/spec/requests/users/base_controller_spec.rb
903
909
  - pg_engine/spec/requests/users/dashboard_spec.rb
904
910
  - pg_engine/spec/requests/users/date_jumper_spec.rb
911
+ - pg_engine/spec/requests/users/inline_edit_spec.rb
905
912
  - pg_engine/spec/requests/users/registrations_spec.rb
906
913
  - pg_engine/spec/requests/users/switcher_spec.rb
907
914
  - pg_engine/spec/system/alerts_spec.rb