pg_rails 7.1.1.pre.4 → 7.1.1.pre.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34465452a5982269db6136a0000c16c78bb9576b57f7d4f3476940a76d28cae7
4
- data.tar.gz: 77ecad87cb6e8ae5f99b5d73a40bbf60efb8f94a56782d253294904382b8ac3b
3
+ metadata.gz: b95efca3ae2b2ec3c5779300bbfd6cc00ba9cac453b4fd07395803eb5010a726
4
+ data.tar.gz: 87811da5c11b5ec8bfb15e45e8b43ed5c606bceb23804bc473990f9f46ab13ed
5
5
  SHA512:
6
- metadata.gz: 7b790cb222b1a4ed7acae49253e7a55700584e612750ad763449d68089dc294f66822a8eb9db4dc89303dcf3a3d20e2360944a222191fa53413ba3182806e8a8
7
- data.tar.gz: cea1c5777acd0791fc8d32c3e28815881334e753f43e3608542e1d1181b03bfa980c154cfd2662d3c9927b30dab3a4acf0d3d2efeb3d2af0bb5b5a875d1d2bb3
6
+ metadata.gz: 4da052d189d685cd90c2aed939bfebd8d3e4809f6e3db671d686a034d597b32b03a2f52f3b3413c9277566329822cbf4a520ab33531cc40ef8873a2b8c51850a
7
+ data.tar.gz: fddd0362fab8db6f74816b583372fbc10fbd4d6ad68f48adbbe635579b28339603e1f09358a16563d9d9e6909573009ec6111c84f50d9c28f109758e402f6495
@@ -53,7 +53,7 @@ module Admin
53
53
  end
54
54
 
55
55
  def atributos_para_buscar
56
- %i[email nombre apellido developer]
56
+ %i[email_cont nombre_cont apellido_cont developer]
57
57
  end
58
58
 
59
59
  def atributos_para_listar
@@ -5,7 +5,7 @@ module PgEngine
5
5
  clazz.helper_method :atributos_para_listar
6
6
  clazz.helper_method :atributos_para_mostrar
7
7
  clazz.helper_method :current_page_size
8
- clazz.helper_method :any_filter?
8
+ clazz.helper_method :show_filters?
9
9
  end
10
10
 
11
11
  # Public endpoints
@@ -19,6 +19,15 @@ module PgEngine
19
19
 
20
20
  def index
21
21
  @collection = filtros_y_policy atributos_para_buscar
22
+
23
+ shared_context = Ransack::Context.for(clase_modelo)
24
+
25
+ @q = @clase_modelo.ransack(params[:q], context: shared_context)
26
+ # @collection = @q.result(distinct: true)
27
+ @collection = @collection.joins(shared_context.join_sources)
28
+ vis = Ransack::Visitor.new.accept(@q.base)
29
+ @collection = @collection.where(vis)
30
+
22
31
  @collection = sort_collection(@collection)
23
32
  pg_respond_index
24
33
  end
@@ -53,8 +62,17 @@ module PgEngine
53
62
 
54
63
  protected
55
64
 
56
- def any_filter?
57
- params.keys.reject { |a| a.in? %w[controller action page page_size order_by order_direction] }.any?
65
+ def show_filters?
66
+ cur_route = pg_current_route
67
+ idtf = cur_route[:controller] + '#' + cur_route[:action] + '#open-filters'
68
+
69
+ if params[:ocultar_filtros]
70
+ session[idtf] = nil
71
+ elsif params[:mostrar_filtros]
72
+ session[idtf] = true
73
+ end
74
+
75
+ session[idtf]
58
76
  end
59
77
 
60
78
  def current_page_size
@@ -160,7 +178,9 @@ module PgEngine
160
178
  end
161
179
  else
162
180
  format.turbo_stream do
163
- render turbo_stream: turbo_stream.remove(model)
181
+ # Esto no es totalmente limpio pero funciona tanto en los listados como en los
182
+ # modal show
183
+ render turbo_stream: turbo_stream.remove(model) + turbo_stream.remove_all('.modal')
164
184
  end
165
185
  format.html do
166
186
  redirect_back(fallback_location: root_path, notice: msg, status: 303)
@@ -94,6 +94,7 @@ module PgEngine
94
94
  @notifications = Current.user.notifications.order(id: :desc)
95
95
  .where(type: 'SimpleUserNotifier::Notification')
96
96
  unseen = @notifications.unseen.any?
97
+ # FIXME: testear y fixear, buscar el primero que esté present
97
98
  tooltip = @notifications.unseen.map(&:tooltip).first
98
99
  @notifications_bell = NotificationsBellComponent.new(
99
100
  unseen:,
@@ -112,8 +113,13 @@ module PgEngine
112
113
 
113
114
  protected
114
115
 
115
- # rubocop:disable Metrics/AbcSize
116
116
  def render_my_component(component, status)
117
+ # Esto es para que saltee los turbo frames y genere
118
+ # un full reload. El turbo_no_cache no es estrictamente necesario
119
+ # pero lo dejo por las dudas
120
+ @turbo_page_requires_reload = true
121
+ @turbo_no_cache = true
122
+
117
123
  respond_to do |format|
118
124
  format.html do
119
125
  render component.alert_wrapped(view_context),
@@ -139,7 +145,6 @@ module PgEngine
139
145
  end
140
146
  end
141
147
  end
142
- # rubocop:enable Metrics/AbcSize
143
148
 
144
149
  def not_authorized(_arg_required_for_active_admin)
145
150
  respond_to do |format|
@@ -1,7 +1,7 @@
1
1
  module Users
2
2
  class ConfirmationsController < Devise::ConfirmationsController
3
3
  # GET /resource/confirmation?confirmation_token=abcdef
4
- def show # rubocop:disable Metrics/AbcSize
4
+ def show
5
5
  self.resource = resource_class.confirm_by_token(params[:confirmation_token])
6
6
  yield resource if block_given?
7
7
 
@@ -16,11 +16,15 @@ module PgEngine
16
16
  end
17
17
  end
18
18
 
19
+ def self.current_route(context)
20
+ req = request(context)
21
+ Rails.application.routes.recognize_path(req.path, method: req.env['REQUEST_METHOD'])
22
+ end
23
+
19
24
  def self.namespace(context)
20
25
  return Current.namespace if Current.namespace.present?
21
26
 
22
- req = request(context)
23
- route = Rails.application.routes.recognize_path(req.path, method: req.env['REQUEST_METHOD'])
27
+ route = current_route(context)
24
28
  parts = route[:controller].split('/')
25
29
  return unless parts.length > 1
26
30
 
@@ -30,6 +34,10 @@ module PgEngine
30
34
  end
31
35
  end
32
36
 
37
+ def pg_current_route
38
+ NamespaceDeductor.current_route(self)
39
+ end
40
+
33
41
  def pg_namespace
34
42
  NamespaceDeductor.namespace(self)
35
43
  end
@@ -186,6 +186,9 @@ module PgEngine
186
186
  end
187
187
 
188
188
  def filtros_html(options = {})
189
+ @form = options[:form]
190
+ raise PgEngine::Error, 'se debe setear el form' if @form.blank?
191
+
189
192
  res = ''
190
193
  @filtros.each do |campo, opciones|
191
194
  if opciones[:oculto] ||
@@ -253,42 +256,35 @@ module PgEngine
253
256
 
254
257
  map = scope.map { |o| [o.to_s, o.id] }
255
258
 
256
- unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
257
- map.unshift ["Seleccionar #{@clase_modelo.human_attribute_name(campo.to_sym).downcase}",
258
- nil]
259
- end
260
-
261
- default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
262
259
  content_tag :div, class: 'col-auto' do
263
260
  content_tag :div, class: 'filter' do
264
261
  if multiple
265
- select_tag campo, options_for_select(map, default), multiple: true,
266
- class: 'form-select form-select-sm selectize pg-input-lg'
262
+ @form.select campo, map, { multiple: true }, 'data-controller': 'selectize',
263
+ class: 'form-select form-select-sm pg-input-lg'
267
264
  else
268
- select_tag campo, options_for_select(map, default),
269
- class: 'form-select form-select-sm chosen-select pg-input-lg'
265
+ campo = campo.to_s + '_id_in'
266
+ placeholder = ransack_placeholder(campo)
267
+ @form.select campo, map, { multiple: true }, placeholder:, 'data-controller': 'selectize',
268
+ class: 'form-control form-control-sm pg-input-lg'
270
269
  end
271
270
  end
272
271
  end
273
272
  end
274
273
 
275
274
  def filtro_select(campo, placeholder = '')
276
- map = @clase_modelo.send(campo).values.map do |key|
275
+ map = @clase_modelo.send(sin_sufijo(campo)).values.map do |key|
277
276
  [I18n.t("#{@clase_modelo.to_s.underscore}.#{campo}.#{key}", default: key.humanize),
278
277
  key.value]
279
278
  end
280
- unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
281
- map.unshift ["Seleccionar #{placeholder.downcase}",
282
- nil]
283
- end
284
- default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
285
279
  content_tag :div, class: 'col-auto' do
286
280
  content_tag :div, class: 'filter' do
287
- select_tag campo, options_for_select(map, default), class: 'form-select form-select-sm pg-input-lg'
281
+ placeholder = ransack_placeholder(campo)
282
+ @form.select(campo, map, { multiple: true }, placeholder:, class: 'form-control form-control-sm pg-input-lg', 'data-controller': 'selectize')
288
283
  end
289
284
  end
290
285
  end
291
286
 
287
+ # DEPRECADO
292
288
  def filtro_select_custom(campo, placeholder = '')
293
289
  map = @filtros[campo.to_sym][:opciones]
294
290
  unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
@@ -306,8 +302,9 @@ module PgEngine
306
302
  def filtro_texto(campo, placeholder = '')
307
303
  content_tag :div, class: 'col-auto' do
308
304
  content_tag :div, class: 'filter' do
309
- text_field_tag(
310
- campo, parametros_controller[campo], class: 'form-control form-control-sm allow-enter-submit', placeholder:, autocomplete: 'off'
305
+ placeholder = ransack_placeholder(campo)
306
+ @form.search_field(
307
+ campo, class: 'form-control form-control-sm allow-enter-submit', placeholder:, autocomplete: 'off'
311
308
  )
312
309
  end
313
310
  end
@@ -330,14 +327,19 @@ module PgEngine
330
327
  def filtro_fecha(campo, placeholder = '')
331
328
  content_tag :div, class: 'col-auto' do
332
329
  content_tag :div, class: 'filter' do
330
+ placeholder = ransack_placeholder(campo)
333
331
  label_tag(nil, placeholder, class: 'text-body-secondary') +
334
- date_field_tag(
335
- campo, parametros_controller[campo], class: 'form-control form-control-sm d-inline-block w-auto ms-1', placeholder:, autocomplete: 'off'
332
+ @form.date_field(
333
+ campo, class: 'form-control form-control-sm d-inline-block w-auto ms-1', placeholder:, autocomplete: 'off'
336
334
  )
337
335
  end
338
336
  end
339
337
  end
340
338
 
339
+ def ransack_placeholder(campo)
340
+ @form.object.translate(campo, include_associations: true)
341
+ end
342
+
341
343
  def parametros_controller
342
344
  params
343
345
  end
@@ -6,7 +6,7 @@
6
6
  = f.input :message, as: :text
7
7
  - else
8
8
  = f.rich_text_area :message
9
- = f.input :message_text, as: :text
9
+ = f.input :message_text, as: :text, hint: 'Solo para emails, para la plain/text part'
10
10
  = f.input :tooltip
11
11
  = f.input :subject
12
12
  = f.input :record_type
@@ -3,37 +3,34 @@
3
3
  - @actions&.each do |link_args|
4
4
  = link_to(*link_args)
5
5
  - if @filtros.present?
6
- button.btn.btn-sm.btn-outline-primary[
7
- type="button" data-bs-toggle="collapse"
8
- data-bs-target="#filtros" aria-expanded="#{any_filter? ? 'true' : 'false'}"
9
- aria-controls="filtros" data-controller="filtros" data-expanded-text="Ocultar filtros"
10
- ]
11
- span.bi.bi-funnel-fill
12
- span.d-none.d-sm-inline
13
- | &nbsp
14
- span.text Filtrar
6
+ - if show_filters?
7
+ = link_to namespaced_path(@clase_modelo, ocultar_filtros: 1),
8
+ class: 'btn btn-sm btn-outline-primary col-auto' do
9
+ | Ocultar filtros
10
+ - else
11
+ = link_to namespaced_path(@clase_modelo, mostrar_filtros: 1),
12
+ class: 'btn btn-sm btn-outline-primary col-auto' do
13
+ | Filtrar
15
14
  .ms-1
16
15
  = @clase_modelo.new.decorate.new_link
17
16
 
18
- - if @filtros.present?
19
- .collapse.border-bottom#filtros class="#{ 'show' if any_filter? }"
17
+ - if @filtros.present? && show_filters?
18
+ .border-bottom#filtros
20
19
  .d-flex.align-items-center.p-2
21
20
  .px-2.d-none.d-sm-inline-block
22
21
  span.bi.bi-funnel-fill
23
- = form_tag nil, class: '', method: :get do
22
+ = search_form_for @q, url: namespaced_path(@clase_modelo) do |f|
24
23
  .row.g-1
25
- = @filtros.filtros_html
26
- .col-auto
24
+ = @filtros.filtros_html(form: f)
25
+ .col-auto.gap-1.d-flex.align-items-start
27
26
  = button_tag class: 'btn btn-sm btn-primary col-auto' do
28
27
  span.bi.bi-search
29
28
  span.d-none.d-sm-inline
30
29
  | &nbsp
31
30
  span.text Buscar
32
- .col-auto
33
- = link_to namespaced_path(@clase_modelo, clean: true),
31
+ = link_to namespaced_path(@clase_modelo, mostrar_filtros: 1),
34
32
  class: 'btn btn-sm btn-secondary col-auto' do
35
33
  | Limpiar
36
-
37
34
  div
38
35
  - if @collection.any?
39
36
  .table-responsive
@@ -67,7 +64,7 @@ div
67
64
  = t(i18n_key, default: :'.empty_but_filtered', model: @clase_modelo.nombre_plural.downcase)
68
65
  | :
69
66
  span.ms-2
70
- = link_to namespaced_path(@clase_modelo, clean: true) do
67
+ = link_to namespaced_path(@clase_modelo, mostrar_filtros: 1) do
71
68
  | Limpiar búsqueda
72
69
  - else
73
70
  - i18n_key = "#{controller_key}.#{action_name}.index.empty"
@@ -1,4 +1,9 @@
1
1
  es:
2
+ ransack:
3
+ predicates:
4
+ cont: ''
5
+ in: ''
6
+ eq: ''
2
7
  pg_engine:
3
8
  base:
4
9
  index:
@@ -1,8 +1,6 @@
1
1
  DatabaseCleaner.clean_with(:truncation, except: %w(ar_internal_metadata))
2
2
 
3
- MAIL = 'mrosso10@gmail.com'
3
+ FactoryBot.create :user, email: 'mrosso10@gmail.com', nombre: 'Martín', apellido: 'Rosso', password: 'admin123',
4
+ confirmed_at: Time.now, developer: true
4
5
 
5
- unless User.where(email: MAIL).exists?
6
- FactoryBot.create :user, email: MAIL, nombre: 'Martín', apellido: 'Rosso', password: 'admin123',
7
- confirmed_at: Time.now, developer: true
8
- end
6
+ Account.first.users << FactoryBot.create(:user, orphan: true)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module PgEngine
4
4
  class EmailObserver
5
- def self.delivered_email(message) # rubocop:disable Metrics/AbcSize
5
+ def self.delivered_email(message)
6
6
  message_id = message.message_id
7
7
  mailer = message.delivery_handler.to_s
8
8
  status = get_status(message)
@@ -37,8 +37,8 @@
37
37
 
38
38
  FactoryBot.define do
39
39
  factory :user, class: 'User' do
40
- nombre { Faker::Name.name }
41
- apellido { Faker::Name.name }
40
+ nombre { Faker::Name.first_name }
41
+ apellido { Faker::Name.last_name }
42
42
  email { Faker::Internet.email }
43
43
  password { "password#{rand(99_999)}" }
44
44
  confirmed_at { Faker::Date.backward }
@@ -1,5 +1,7 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
2
 
3
+ // DEPRECATED.
4
+ //
3
5
  // Connects to data-controller="switcher"
4
6
  export default class extends Controller {
5
7
  originalText = null
@@ -8,6 +8,7 @@ import ClearTimeoutController from './clear_timeout_controller'
8
8
  import SwitcherController from './switcher_controller'
9
9
  import FiltrosController from './filtros_controller'
10
10
  import NotificationsController from './notifications_controller'
11
+ import SelectizeController from './selectize_controller'
11
12
 
12
13
  application.register('navbar', NavbarController)
13
14
  application.register('nested', NestedController)
@@ -17,5 +18,6 @@ application.register('clear-timeout', ClearTimeoutController)
17
18
  application.register('switcher', SwitcherController)
18
19
  application.register('filtros', FiltrosController)
19
20
  application.register('notifications', NotificationsController)
21
+ application.register('selectize', SelectizeController)
20
22
 
21
23
  // TODO: testear con capybara todo lo que se pueda
@@ -0,0 +1,10 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import TomSelect from 'tom-select'
3
+
4
+ // Connects to data-controller="selectize"
5
+ export default class extends Controller {
6
+ connect () {
7
+ /* eslint no-new: 0 */
8
+ new TomSelect(this.element)
9
+ }
10
+ }
@@ -5,6 +5,9 @@ html
5
5
  meta charset="UTF-8"
6
6
  meta http-equiv="X-UA-Compatible" content="IE=edge"
7
7
  meta name="viewport" content="width=device-width,initial-scale=1"
8
+ - if @turbo_page_requires_reload
9
+ meta name="turbo-visit-control" content="reload"
10
+
8
11
  - cache :title_icon
9
12
  title = t('app_name')
10
13
  - begin
@@ -71,6 +74,7 @@ html
71
74
  = render FlashContainerComponent.new
72
75
  / TODO: si hay varios flashes toast, se superponen. habría que
73
76
  hacer un container con position absolute para los toasts
77
+ / FIXME: el yield(filtros)
74
78
  = content
75
79
  div style="width:100%; height: 10em"
76
80
  = render partial: 'layouts/footer'
@@ -1,9 +1,14 @@
1
- .modal.modal-lg.modal-asociable[tabindex="-1" data-controller="modal" data-remove-on-hide="true"]
1
+ .modal.modal-lg.modal-asociable[tabindex="-1" data-controller="modal"
2
+ data-remove-on-hide="true" data-turbo-temporary="true"]
2
3
  .modal-dialog
3
4
  .modal-content
4
5
  .modal-header
5
- .modal-title
6
- h3 Item
6
+ = link_to object.target_object do
7
+ | Ir al #{object.class.nombre_singular.downcase}
7
8
  a.btn-close[type="button" data-bs-dismiss="modal" aria-label="Close"]
8
9
  .modal-body
9
- = render object
10
+ = turbo_frame_tag :modal_generic, target: :_top do
11
+ .float-end
12
+ = object.edit_link
13
+ = object.destroy_link
14
+ = render object
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRails
4
- VERSION = '7.1.1-4'
4
+ VERSION = '7.1.1-6'
5
5
  end
@@ -39,7 +39,20 @@ $alert-margin-bottom: 0.5rem;
39
39
  @import 'bootstrap-icons/font/bootstrap-icons';
40
40
 
41
41
  @import 'trix/dist/trix';
42
+ @import 'tom-select/dist/scss/tom-select.bootstrap5';
42
43
 
44
+ .ts-control {
45
+ padding-top: 2px!important;
46
+ padding-bottom: 2px!important;
47
+ display: flex;
48
+ gap: 4px;
49
+ }
50
+ .input-group-sm > .ts-wrapper.multi.has-items .ts-control, .ts-wrapper.form-select-sm.multi.has-items .ts-control, .ts-wrapper.form-control-sm.multi.has-items .ts-control {
51
+ padding-top: 2px!important;
52
+ }
53
+ .ts-wrapper.multi .ts-control > div {
54
+ margin: 0!important;
55
+ }
43
56
  $warning-border-emphasis: shade-color($yellow, 60%);
44
57
  .bg-primary-subtle .btn-warning {
45
58
  border: 1px solid $warning-border-emphasis;
@@ -26,6 +26,7 @@ class <%= controller_class_name.split('::').last %>Controller < <%= parent_contr
26
26
  end
27
27
 
28
28
  def atributos_para_buscar
29
+ # FIXME: append _cont
29
30
  %i[<%= atributos_a_filtrar.map(&:name).join(' ') %>]
30
31
  end
31
32
 
@@ -9,7 +9,8 @@
9
9
  = @clase_modelo.new.decorate.new_link
10
10
  .ms-1
11
11
  = @clase_modelo.new.decorate.export_link(request.url)
12
- .collapse.p-2.border-bottom#filtros class="#{ 'show' if any_filter? }"
12
+ / FIXME: update
13
+ .collapse.p-2.border-bottom#filtros class="#{ 'show' if show_filters? }"
13
14
  .d-flex.align-items-center
14
15
  .px-2.d-none.d-sm-inline-block
15
16
  span.bi.bi-funnel-fill
@@ -20,7 +21,7 @@
20
21
  = button_tag class: 'btn btn-sm btn-primary col-auto' do
21
22
  span.bi.bi-search
22
23
  .col-auto
23
- = link_to <%= plural_route_name %>_path(clean: true),
24
+ = link_to <%= plural_route_name %>_path(mostrar_filtros: true),
24
25
  class: 'btn btn-sm btn-secondary col-auto' do
25
26
  | Limpiar
26
27
 
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.1.1.pre.4
4
+ version: 7.1.1.pre.6
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-07-21 00:00:00.000000000 Z
11
+ date: 2024-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -814,6 +814,7 @@ files:
814
814
  - pg_layout/app/javascript/controllers/nested_controller.js
815
815
  - pg_layout/app/javascript/controllers/notifications_controller.js
816
816
  - pg_layout/app/javascript/controllers/pg_form_controller.js
817
+ - pg_layout/app/javascript/controllers/selectize_controller.js
817
818
  - pg_layout/app/javascript/controllers/switcher_controller.js
818
819
  - pg_layout/app/javascript/utils/cookies.js
819
820
  - pg_layout/app/javascript/utils/utils.ts