pg_rails 7.6.1 → 7.6.3
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.
- checksums.yaml +4 -4
- data/pg_associable/app/helpers/pg_associable/form_builder_methods.rb +3 -0
- data/pg_engine/app/assets/stylesheets/pg_rails_b5.scss +22 -3
- data/pg_engine/app/components/bad_user_input_component.rb +1 -0
- data/pg_engine/app/components/inline_edit/inline_edit_component.html.slim +14 -0
- data/pg_engine/app/components/inline_edit/inline_edit_component.rb +23 -0
- data/pg_engine/app/components/inline_edit/inline_show_component.html.slim +8 -0
- data/pg_engine/app/components/inline_edit/inline_show_component.rb +15 -0
- data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +8 -4
- data/pg_engine/app/controllers/pg_engine/base_controller.rb +7 -16
- data/pg_engine/app/controllers/pg_engine/health_controller.rb +30 -0
- data/pg_engine/app/controllers/users/inline_edit_controller.rb +21 -0
- data/pg_engine/app/controllers/users/registrations_controller.rb +1 -1
- data/pg_engine/app/decorators/pg_engine/base_record_decorator.rb +2 -2
- data/pg_engine/app/helpers/pg_engine/index_helper.rb +1 -1
- data/pg_engine/app/lib/pg_form_builder.rb +18 -0
- data/pg_engine/app/models/pg_engine/base_record.rb +5 -1
- data/pg_engine/app/views/pg_engine/base/index.html.slim +2 -1
- data/pg_engine/config/initializers/zeitwerk.rb +2 -0
- data/pg_engine/config/locales/es.yml +5 -0
- data/pg_engine/config/routes.rb +4 -0
- data/pg_engine/config/simple_form/simple_form_bootstrap.rb +17 -2
- data/pg_engine/lib/pg_engine.rb +2 -0
- data/pg_engine/spec/controllers/pg_engine/base_controller_spec.rb +1 -16
- data/pg_engine/spec/requests/users/accounts_spec.rb +1 -2
- data/pg_engine/spec/requests/users/inline_edit_spec.rb +101 -0
- data/pg_engine/spec/requests/users/registrations_spec.rb +19 -0
- data/pg_layout/app/javascript/config/index.js +20 -20
- data/pg_layout/app/javascript/config/turbo_rails/index.js +4 -2
- data/pg_rails/lib/version.rb +1 -1
- data/pg_rails/scss/pg_rails.scss +4 -4
- data/pg_scaffold/lib/generators/pg_active_record/model/templates/model.rb +3 -0
- data/pg_scaffold/lib/generators/pg_slim/templates/_form.html.slim +1 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c827faeb7ffa9b904395708a6f9c6184a930ee22663bcec472b600046497baa
|
4
|
+
data.tar.gz: bb256bb482b6697302d7e3b2131f5cd9e3ddeaa17447f739b943091a6b90c431
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c06b67c6b8bdeb5462db606077e29b1d1a68bc58ee65a6df7c9e21a13615f723d68189a497b769faf401160875741caf946010f6b162659aa5d9c8dffec6f35d
|
7
|
+
data.tar.gz: 471922d32d56e46a8e7d20ecd0fe2793d22849a66d813c8fc103a51a8e1d44d4d8229f1b04457d0b3f16f9a9c6ab6ea052dac95dcd43605b9120ddaf8eeb8a88
|
@@ -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
|
-
.
|
78
|
-
|
76
|
+
|
77
|
+
.btn-sm {
|
78
|
+
padding: 0em 0.3em;
|
79
|
+
}
|
79
80
|
}
|
80
81
|
|
81
82
|
.list-group-item {
|
@@ -199,3 +200,21 @@ 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
|
+
|
211
|
+
a:hover {
|
212
|
+
i {
|
213
|
+
color: black;
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
input[type=text] {
|
218
|
+
min-width: 22em;
|
219
|
+
}
|
220
|
+
}
|
@@ -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 @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,23 @@
|
|
1
|
+
class InlineEditComponent < ViewComponent::Base
|
2
|
+
def initialize(model, attribute)
|
3
|
+
@model = model
|
4
|
+
@attribute = attribute
|
5
|
+
@frame_id = dom_id(model, "#{attribute}_inline_edit")
|
6
|
+
|
7
|
+
@wrapper_mappings = {
|
8
|
+
string: :inline_form_control,
|
9
|
+
pg_associable: :inline_form_control,
|
10
|
+
date: :inline_form_control,
|
11
|
+
datetime: :inline_form_control,
|
12
|
+
select: :inline_form_select
|
13
|
+
}
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_render
|
19
|
+
return unless controller.in_modal?
|
20
|
+
|
21
|
+
controller.instance_variable_set(:@using_modal, true)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
- if @model.class.inline_editable?(@attribute) && helpers.policy(@model).edit?
|
2
|
+
= helpers.turbo_frame_tag(@frame_id, class: 'inline-edit')
|
3
|
+
span = @model.decorate.send(@attribute)
|
4
|
+
= link_to users_inline_edit_path(model: @model.to_gid, attribute: @attribute),
|
5
|
+
class: 'text-body-tertiary ms-1', style: 'font-size: 0.8em' do
|
6
|
+
i.bi.bi-pencil
|
7
|
+
- else
|
8
|
+
= @model.decorate.send(@attribute)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class InlineShowComponent < ViewComponent::Base
|
2
|
+
def initialize(model, attribute)
|
3
|
+
@model = model
|
4
|
+
@attribute = attribute
|
5
|
+
@frame_id = dom_id(model, "#{attribute}_inline_edit")
|
6
|
+
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def before_render
|
11
|
+
return unless controller.in_modal?
|
12
|
+
|
13
|
+
controller.instance_variable_set(:@using_modal, true)
|
14
|
+
end
|
15
|
+
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
|
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
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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)
|
@@ -8,6 +8,7 @@ module PgEngine
|
|
8
8
|
def show
|
9
9
|
check_redis
|
10
10
|
check_postgres
|
11
|
+
check_websocket
|
11
12
|
render_up
|
12
13
|
end
|
13
14
|
|
@@ -25,6 +26,35 @@ module PgEngine
|
|
25
26
|
raise PgEngine::Error, 'redis is down'
|
26
27
|
end
|
27
28
|
|
29
|
+
# rubocop:disable Metrics/MethodLength
|
30
|
+
def check_websocket
|
31
|
+
result = nil
|
32
|
+
begin
|
33
|
+
Timeout.timeout(5) do
|
34
|
+
EM.run do
|
35
|
+
url = Rails.application.config.action_cable.url
|
36
|
+
ws = Faye::WebSocket::Client.new(url)
|
37
|
+
|
38
|
+
ws.on :message do |event|
|
39
|
+
type = JSON.parse(event.data)['type']
|
40
|
+
if type == 'welcome'
|
41
|
+
result = :success
|
42
|
+
ws.close
|
43
|
+
EM.stop
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
rescue Timeout::Error
|
49
|
+
raise PgEngine::Error, 'websocket server is down'
|
50
|
+
end
|
51
|
+
|
52
|
+
return if result == :success
|
53
|
+
|
54
|
+
raise PgEngine::Error, 'websocket server is down'
|
55
|
+
end
|
56
|
+
# rubocop:enable Metrics/MethodLength
|
57
|
+
|
28
58
|
def render_up
|
29
59
|
render html: html_status(color: '#005500')
|
30
60
|
end
|
@@ -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
|
@@ -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
|
-
|
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
|
@@ -16,6 +16,11 @@ es:
|
|
16
16
|
index:
|
17
17
|
empty: 'No hay %{model} que mostrar'
|
18
18
|
empty_but_filtered: 'No hay %{model} para los filtros aplicados'
|
19
|
+
gender:
|
20
|
+
reset_password_token: m
|
21
|
+
confirmation_token: m
|
22
|
+
unlock_token: m
|
23
|
+
current_password: f
|
19
24
|
attributes:
|
20
25
|
external_labels: Etiquetas externas
|
21
26
|
external_source: Fuente externa
|
data/pg_engine/config/routes.rb
CHANGED
@@ -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 :
|
273
|
+
config.wrappers :inline_form_control, class: '' do |b|
|
274
274
|
b.use :html5
|
275
275
|
b.use :placeholder
|
276
276
|
b.optional :maxlength
|
@@ -280,7 +280,22 @@ 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_select, 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-select form-select-sm', error_class: 'is-invalid'
|
284
299
|
b.use :error, wrap_with: { class: 'invalid-feedback' }
|
285
300
|
b.optional :hint, wrap_with: { class: 'form-text' }
|
286
301
|
end
|
data/pg_engine/lib/pg_engine.rb
CHANGED
@@ -84,22 +84,7 @@ describe DummyBaseController do
|
|
84
84
|
|
85
85
|
it do
|
86
86
|
subject
|
87
|
-
expect(response).to
|
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(:
|
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
|
@@ -69,6 +69,25 @@ describe 'registrations controller' do
|
|
69
69
|
expect { subject }.not_to change(Account, :count)
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
context 'cuando hay tenant' do
|
74
|
+
before do
|
75
|
+
host! 'bien.localhost.com'
|
76
|
+
create :account, subdomain: 'bien'
|
77
|
+
end
|
78
|
+
|
79
|
+
it do
|
80
|
+
expect { subject }.to change(User, :count).by(1)
|
81
|
+
end
|
82
|
+
|
83
|
+
it do
|
84
|
+
expect { subject }.to change(UserAccount, :count).by(1)
|
85
|
+
end
|
86
|
+
|
87
|
+
it do
|
88
|
+
expect { subject }.not_to change(Account, :count)
|
89
|
+
end
|
90
|
+
end
|
72
91
|
end
|
73
92
|
|
74
93
|
describe '#edit' do
|
@@ -7,23 +7,23 @@ import './tooltips'
|
|
7
7
|
import 'trix'
|
8
8
|
import '@rails/actiontext'
|
9
9
|
|
10
|
-
function bindListingClick () {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
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>
|
data/pg_rails/lib/version.rb
CHANGED
data/pg_rails/scss/pg_rails.scss
CHANGED
@@ -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
|
-
|
94
|
-
|
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
|
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.
|
4
|
+
version: 7.6.3
|
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-
|
11
|
+
date: 2024-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '5.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: faye-websocket
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.11'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.11'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: acts_as_tenant
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -660,6 +674,10 @@ files:
|
|
660
674
|
- pg_engine/app/components/date_selector_component.html.slim
|
661
675
|
- pg_engine/app/components/date_selector_component.rb
|
662
676
|
- pg_engine/app/components/flash_container_component.rb
|
677
|
+
- pg_engine/app/components/inline_edit/inline_edit_component.html.slim
|
678
|
+
- pg_engine/app/components/inline_edit/inline_edit_component.rb
|
679
|
+
- pg_engine/app/components/inline_edit/inline_show_component.html.slim
|
680
|
+
- pg_engine/app/components/inline_edit/inline_show_component.rb
|
663
681
|
- pg_engine/app/components/internal_error_component.rb
|
664
682
|
- pg_engine/app/components/modal_component.html.slim
|
665
683
|
- pg_engine/app/components/modal_component.rb
|
@@ -693,6 +711,7 @@ files:
|
|
693
711
|
- pg_engine/app/controllers/users/confirmations_controller.rb
|
694
712
|
- pg_engine/app/controllers/users/dashboard_controller.rb
|
695
713
|
- pg_engine/app/controllers/users/date_jumper_controller.rb
|
714
|
+
- pg_engine/app/controllers/users/inline_edit_controller.rb
|
696
715
|
- pg_engine/app/controllers/users/notifications_controller.rb
|
697
716
|
- pg_engine/app/controllers/users/registrations_controller.rb
|
698
717
|
- pg_engine/app/decorators/account_decorator.rb
|
@@ -888,6 +907,7 @@ files:
|
|
888
907
|
- pg_engine/spec/requests/users/base_controller_spec.rb
|
889
908
|
- pg_engine/spec/requests/users/dashboard_spec.rb
|
890
909
|
- pg_engine/spec/requests/users/date_jumper_spec.rb
|
910
|
+
- pg_engine/spec/requests/users/inline_edit_spec.rb
|
891
911
|
- pg_engine/spec/requests/users/registrations_spec.rb
|
892
912
|
- pg_engine/spec/requests/users/switcher_spec.rb
|
893
913
|
- pg_engine/spec/system/alerts_spec.rb
|