pg_rails 7.6.31 → 7.6.32

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b315989e816d61e3a75b72845fc50ab94b4393b538f208c43cfcd6ff078a9bf
4
- data.tar.gz: 66b62128b94690c25f37213bc6f4b2958b2218c3d001ae2f1a664f694dfe0efc
3
+ metadata.gz: 6d75733bf10e7940a7914ee54582c39139416f47cd224f434a4ba1908ff31eb7
4
+ data.tar.gz: 7f1d1c1487db6d3973584d9e6ee2469de9487602ef3bc72e14b13be1db8baa09
5
5
  SHA512:
6
- metadata.gz: b1092c6d4cceb0201e86b490124eebab80d3303da02e01c26f185ccaab629950d7f5c6ac069904079e3e243987a9e09d743a778dd207328d4a6033db71e3a95e
7
- data.tar.gz: 94f283edbc6474c4fffcec0045e66af213e3ac698e5f4ba1293a9d373892651ffaec3ba54600d0e0e5352358b704eda07452a9d9791f6119194f3158e46aa58c
6
+ metadata.gz: df27b04686fb2bc10de1250bb59c14fc362cedfa6eb8cfcb3d397235726539ac33ba9cc03b12db9e0080b0eb0fe38d06eb9c59e2cd4aa9e9082dbe57f47aa6e0
7
+ data.tar.gz: f7aaf775879bc4b4a675f4c485c641eb815a00b89e203e6fd2dc1aff686b6ae489e341d8e71b50e330cadf91347be17a48edb3abf4edec907f08fd3c8c918ed5
@@ -22,8 +22,8 @@ $values: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100;
22
22
  }
23
23
  }
24
24
 
25
- // Table row clickable
26
- // .listado tr:has(td:hover):has(.bi-eye-fill) td {
27
- // background-color: #f2f2f2;
28
- // cursor: pointer;
29
- // }
25
+ // Table row clickable (bindListingClick)
26
+ .listado tr:has(td:hover):has(.bi-eye-fill):not(:has(.actions-wrapper:hover)):not(:has(a:hover)):not(:has(.inline-edit:hover)) td {
27
+ background-color: #f2f2f2;
28
+ cursor: pointer;
29
+ }
@@ -0,0 +1,19 @@
1
+ #bulk_form style="max-width: 40em"
2
+ - @attributes.each do |attr|
3
+ - active = @active_fields.present? && @active_fields.include?(attr.to_s)
4
+ .row
5
+ .col-auto
6
+ .form-check.form-check-lg
7
+ = check_box_tag 'active_fields[]', attr, active, class: 'form-check-input', \
8
+ data: { controller: 'bulk-edit-field-activator' }
9
+ .col
10
+ - attr = attr.to_s.gsub(/_id$/, '')
11
+ / html5 solo aplica a datetime
12
+ / date_selector solo aplica a date
13
+ / ignore_date y prompt solo aplica a time
14
+ / cada caso es inocuo para el resto de los types
15
+ = @f.field attr, disabled: !active, date_selector: true, minute_step: 15,
16
+ ignore_date: true, prompt: { hour: 'hh', minute: 'mm' }
17
+ p
18
+ = @f.button :submit, 'Confirmar'
19
+ = @f.button :button, 'refresh', class: 'd-none', name: 'refresh', value: '1'
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BulkEditComponent < BaseComponent
4
+ def initialize(clase_modelo, params:, form: nil)
5
+ @clase_modelo = clase_modelo
6
+ @attributes = @clase_modelo.bulky_attributes
7
+ @key = @clase_modelo.model_name.param_key
8
+ @model = if params[@key].present?
9
+ attrs = @clase_modelo.bulky_attributes.select { |bk| bk.to_s.in?(params[:active_fields] || []) }
10
+ @clase_modelo.new(params[@key].permit(attrs))
11
+ else
12
+ @clase_modelo.new
13
+ end
14
+ @active_fields = params[:active_fields]
15
+ @f = form
16
+
17
+ super
18
+ end
19
+
20
+ def before_render
21
+ @f ||= PgFormBuilder.new(@key, @model, view_context, {}) # rubocop:disable Naming/MemoizedInstanceVariableName
22
+ end
23
+ end
@@ -27,6 +27,8 @@ module PgEngine
27
27
  clazz.helper_method :column_options_for
28
28
  clazz.helper_method :instancia_modelo
29
29
 
30
+ # clazz.skip_before_action :save_and_load_filters, only: [:bulk_edit, :bulk_update]
31
+
30
32
  clazz.before_action do
31
33
  # TODO: quitar esto, que se use el attr_accessor
32
34
  # o sea, quitar todas las referencias a @clase_modelo
@@ -229,6 +231,63 @@ module PgEngine
229
231
  def restore
230
232
  discard_undiscard(:undiscard)
231
233
  end
234
+
235
+ def set_session_key_identifier
236
+ return unless action_name.in?(%w[index bulk_edit bulk_update])
237
+
238
+ ::RansackMemory::Core.config[:session_key_format]
239
+ .gsub('%controller_name%', controller_path.parameterize.underscore)
240
+ .gsub('%action_name%', 'index')
241
+ .gsub('%request_format%', request.format.symbol.to_s)
242
+ .gsub('%turbo_frame%', request.headers['Turbo-Frame'] || 'top')
243
+ end
244
+
245
+ def bulk_edit
246
+ # @no_main_frame = true
247
+
248
+ @collection = filtros_y_policy(atributos_para_buscar, default_sort)
249
+ @ids = @collection.map(&:to_key).join(',')
250
+ @form_target = [:bulk_update, pg_namespace, nested_record, @clase_modelo].compact
251
+ @model = @clase_modelo.new
252
+
253
+ render 'bulk_edit'
254
+ end
255
+
256
+ def bulk_update
257
+ if params[:refresh].present?
258
+ bulk_component = BulkEditComponent.new(@clase_modelo, params:)
259
+ render turbo_stream: turbo_stream.replace('bulk_form', bulk_component)
260
+
261
+ return
262
+ end
263
+ # params = params.delete_if { |k,v| v.empty? or Hash === v && delete_blank(v).empty? }
264
+
265
+ # TODO: test
266
+ # :nocov:
267
+ if params[:ids].blank?
268
+ flash[:alert] = I18n.t('pg_engine.base.index.bulk_edit.blank_ids', model: @clase_modelo)
269
+ flash[:toast] = true
270
+ render turbo_stream: render_turbo_stream_flash_messages
271
+ return
272
+ end
273
+
274
+ key = @clase_modelo.model_name.param_key
275
+ unless params[key].is_a?(ActionController::Parameters)
276
+ flash[:alert] = I18n.t('pg_engine.base.index.bulk_edit.bulk_not_hash')
277
+ flash[:toast] = true
278
+ render turbo_stream: render_turbo_stream_flash_messages
279
+ return
280
+ end
281
+ # :nocov:
282
+
283
+ ids = params[:ids]
284
+
285
+ target = [pg_namespace, nested_record, @clase_modelo].compact
286
+ Bulky.enqueue_update(@clase_modelo, ids, params[key])
287
+ redirect_to target, notice: I18n.t('pg_engine.base.index.bulk_edit.enqueue_update')
288
+
289
+ # FIXME: revisar cuando es embedded index
290
+ end
232
291
  # End public endpoints
233
292
 
234
293
  protected
@@ -2,9 +2,9 @@ module PgEngine
2
2
  module FlashHelper
3
3
  def render_turbo_stream_flash_messages(to: nil)
4
4
  if to.present?
5
- turbo_stream.prepend_all to, partial: 'pg_layout/flash'
5
+ turbo_stream.append_all to, partial: 'pg_layout/flash'
6
6
  else
7
- turbo_stream.prepend 'flash', partial: 'pg_layout/flash'
7
+ turbo_stream.append 'flash', partial: 'pg_layout/flash'
8
8
  end
9
9
  end
10
10
 
@@ -5,6 +5,7 @@ module PgEngine
5
5
  class BaseRecord < ActiveRecord::Base
6
6
  # rubocop:enable Rails/ApplicationRecord
7
7
  extend Enumerize
8
+ extend Bulky::Model
8
9
  include PrintHelper
9
10
  include PostgresHelper
10
11
  include Naming
@@ -37,6 +37,14 @@ module PgEngine
37
37
  puede_editar? && !record_discarded?
38
38
  end
39
39
 
40
+ def bulk_edit?
41
+ bulk_update?
42
+ end
43
+
44
+ def bulk_update?
45
+ record.respond_to?(:bulky_attributes) && record.bulky_attributes.present?
46
+ end
47
+
40
48
  def edit?
41
49
  update?
42
50
  end
@@ -0,0 +1,27 @@
1
+ h3 = t('pg_engine.base.index.bulk_edit.title', model: @clase_modelo)
2
+
3
+ - if @filtros.present?
4
+ = render SearchBarComponent.new(@q, @filtros)
5
+ .py-2
6
+ = pg_form_for @model, url: url_for(@form_target), html: { method: :put } do |f|
7
+ .row
8
+ .col-auto
9
+ p.text-center.fw-bold
10
+ = t('pg_engine.base.index.bulk_edit.count', model: @clase_modelo, count: @collection.count)
11
+ table.table style="min-width: 20em"
12
+ - @collection.each do |model|
13
+ tr
14
+ td style="width: 1em"
15
+ .form-check.xform-check-lg
16
+ = check_box_tag 'ids[]', model.to_key, true, class: 'form-check-input'
17
+ td
18
+ = link_to model, model.decorate.object_url, target: :_blank, rel: :noopener
19
+ / = hidden_field_tag 'ids[]', model.to_key
20
+ .col.border-start
21
+ = render BulkEditComponent.new(@clase_modelo, params:, form: f)
22
+
23
+ css:
24
+ .form-check-lg .form-check-input {
25
+ width: 1.5em;
26
+ height: 1.5em;
27
+ }
@@ -23,6 +23,12 @@
23
23
  li = render SearchBarTogglerComponent.new
24
24
  - unless @export_link == false
25
25
  li = @clase_modelo.new.decorate.export_link(request.url, text: 'Exportar en excel')
26
+ - if policy(clase_modelo).bulk_edit? && action_name != 'archived'
27
+ li = link_to url_for([:bulk_edit, pg_namespace, nested_record,
28
+ @clase_modelo].compact) + '?' + request.query_string,
29
+ class: 'icon-link dropdown-item' do
30
+ i.bi.bi-pencil.lh-1
31
+ = t('pg_engine.base.index.bulk_edit.link', model: clase_modelo)
26
32
 
27
33
  - if action_name == 'archived'
28
34
  .text-center.p-3.text-warning-emphasis.border-bottom
@@ -5,10 +5,13 @@ module PgEngine
5
5
  male = options[:model].gender == 'm'
6
6
  model_plural = options[:model].nombre_plural
7
7
  model_singular = options[:model].nombre_singular
8
+ pluralized_model = options[:count].present? && options[:count] > 1 ? model_plural : model_singular
8
9
  text.gsub(/^%{plural_model}/, model_plural)
9
10
  .gsub(/^%{singular_model}/, model_singular)
11
+ .gsub(/^%{pluralized_model}/, pluralized_model)
10
12
  .gsub('%{plural_model}', model_plural.downcase)
11
13
  .gsub('%{singular_model}', model_singular.downcase)
14
+ .gsub('%{pluralized_model}', pluralized_model.downcase)
12
15
  .gsub(/%{genderize\((?<female>(?:(?!%{).)+),(?<male>(?:(?!%{).)+)\)}/, male ? '\k<male>' : '\k<female>' )
13
16
  end
14
17
  end
@@ -36,7 +39,15 @@ end
36
39
  },
37
40
  youre_in_archived_index: PgEngine::I18nRules.rule("Estás viendo el listado de %{plural_model} %{genderize(archivadas,archivados)}"),
38
41
  see_archived: PgEngine::I18nRules.rule("%{plural_model} %{genderize(archivadas,archivados)}"),
39
- back_to_index: 'Volver al listado principal'
42
+ back_to_index: 'Volver al listado principal',
43
+ bulk_edit: {
44
+ enqueue_update: "Modificación en proceso (podría demorar algunos segundos en completarse)",
45
+ blank_ids: PgEngine::I18nRules.rule("No hay %{genderize(ninguna,ningún)} %{singular_model} seleccionada"),
46
+ bulk_not_hash: "Debés seleccionar al menos un campo",
47
+ title: PgEngine::I18nRules.rule("Modificación masiva de %{plural_model}"),
48
+ link: PgEngine::I18nRules.rule("Modificar masivamente"),
49
+ count: PgEngine::I18nRules.rule("%{count} %{pluralized_model} en total"),
50
+ }
40
51
  }
41
52
  }
42
53
  }
@@ -2,12 +2,14 @@ module PgEngine
2
2
  module ActiveJobExtensions
3
3
  def serialize
4
4
  super.merge(
5
- 'app_name' => ::Current.app_name
5
+ 'app_name' => ::Current.app_name,
6
+ 'user_id' => ::Current.user&.id
6
7
  )
7
8
  end
8
9
 
9
10
  def deserialize(job_data)
10
11
  ::Current.app_name = job_data.delete('app_name')
12
+ ::Current.user = User.find(job_data.delete('user_id')) if job_data['user_id'].present?
11
13
 
12
14
  super
13
15
  end
@@ -9,6 +9,8 @@ module PgEngine
9
9
  collection do
10
10
  get :archived
11
11
  get :abrir_modal
12
+ get :bulk_edit
13
+ put :bulk_update
12
14
  post :buscar
13
15
  end
14
16
  yield if block_given?
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe BulkEditComponent, type: :component do
6
+ pending "add some examples to (or delete) #{__FILE__}"
7
+
8
+ # it "renders something useful" do
9
+ # expect(
10
+ # render_inline(described_class.new(attr: "value")) { "Hello, components!" }.css("p").to_html
11
+ # ).to include(
12
+ # "Hello, components!"
13
+ # )
14
+ # end
15
+ end
@@ -0,0 +1,37 @@
1
+ # Initially generated with PgRails::SystemSpecGenerator
2
+ # https://github.com/martin-rosso/pg_rails
3
+
4
+ require 'rails_helper'
5
+
6
+ # By default uses selenium_chrome_headless_iphone driver
7
+ # run with DRIVER & BROWSER environment variables to override, eg:
8
+ #
9
+ # DRIVER=selenium BROWSER=firefox rspec
10
+ describe 'Bulk edit' do
11
+ subject(:visitar) do
12
+ visit '/u/t/cosas'
13
+ end
14
+
15
+ let(:logged_user) { create :user, :owner }
16
+ let(:account) { ActsAsTenant.current_tenant }
17
+
18
+ before do
19
+ login_as logged_user
20
+ create_list :cosa, 2
21
+ end
22
+
23
+ describe 'bulk edit' do
24
+ it do
25
+ visitar
26
+ page.find('[data-bs-title="Más opciones"]').click
27
+ click_on 'Modificar masivamente'
28
+ page.find('input[value=nombre]').click
29
+ page.find_by_id('cosa_nombre').set('Nuevo valor')
30
+ page.find('input[value=tipo]').click
31
+ page.find_by_id('cosa_tipo').set('completar')
32
+ click_on 'Confirmar'
33
+ # expect(Cosa.pluck(:nombre)).to eq ["Nuevo valor", "Nuevo valor"]
34
+ expect(page).to have_text 'Modificación en proceso'
35
+ end
36
+ end
37
+ end
@@ -7,23 +7,24 @@ 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('.inline-edit')) return
14
+ if (ev.target.closest('.listado')) {
15
+ const row = ev.target.closest('tr')
16
+ if (row) {
17
+ const show = row.querySelector('.bi-eye-fill')
18
+ if (show) {
19
+ const link = show.closest('a')
20
+ if (link) {
21
+ link.click()
22
+ }
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ bindListingClick()
29
+ document.addEventListener('turbo:load', bindListingClick)
30
+ document.addEventListener('turbo:render', bindListingClick)
@@ -0,0 +1,10 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ // Connects to data-controller="bulk-edit-field-activator"
4
+ export default class extends Controller {
5
+ connect () {
6
+ this.element.addEventListener('change', function (ev) {
7
+ ev.target.closest('form').querySelector('button[name=refresh]').click()
8
+ })
9
+ }
10
+ }
@@ -15,6 +15,7 @@ import PopoverController from './popover_controller'
15
15
  import PopoverTogglerController from './popover_toggler_controller'
16
16
  import DateSelectorController from './date_selector_controller'
17
17
  import EmbeddedFrameController from './embedded_frame_controller'
18
+ import BulkEditFieldActivator from './bulk_edit_field_activator'
18
19
 
19
20
  application.register('navbar', NavbarController)
20
21
  application.register('nested', NestedController)
@@ -31,5 +32,6 @@ application.register('popover', PopoverController)
31
32
  application.register('popover-toggler', PopoverTogglerController)
32
33
  application.register('date-selector', DateSelectorController)
33
34
  application.register('embedded-frame', EmbeddedFrameController)
35
+ application.register('bulk-edit-field-activator', BulkEditFieldActivator)
34
36
 
35
37
  // TODO: testear con capybara todo lo que se pueda
@@ -2,6 +2,6 @@
2
2
 
3
3
  # :nocov:
4
4
  module PgRails
5
- VERSION = '7.6.31'
5
+ VERSION = '7.6.32'
6
6
  end
7
7
  # :nocov:
@@ -4,9 +4,9 @@
4
4
  require 'rails_helper'
5
5
 
6
6
  # By default uses selenium_chrome_headless_iphone driver
7
- # run with DRIVER environment variable to override, eg:
7
+ # run with DRIVER & BROWSER environment variables to override, eg:
8
8
  #
9
- # DRIVER=selenium rspec
9
+ # DRIVER=selenium BROWSER=firefox rspec
10
10
  describe '<%= name %>' do
11
11
  subject(:visitar) do
12
12
  visit 'some url'
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.31
4
+ version: 7.6.32
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: 2025-02-27 00:00:00.000000000 Z
11
+ date: 2025-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -698,6 +698,8 @@ files:
698
698
  - pg_engine/app/components/bad_request_component.rb
699
699
  - pg_engine/app/components/bad_user_input_component.rb
700
700
  - pg_engine/app/components/base_component.rb
701
+ - pg_engine/app/components/bulk_edit_component.html.slim
702
+ - pg_engine/app/components/bulk_edit_component.rb
701
703
  - pg_engine/app/components/date_selector_component.html.slim
702
704
  - pg_engine/app/components/date_selector_component.rb
703
705
  - pg_engine/app/components/flash_container_component.rb
@@ -824,6 +826,7 @@ files:
824
826
  - pg_engine/app/views/layouts/_logo.html.slim
825
827
  - pg_engine/app/views/layouts/action_text/contents/_content.html.erb
826
828
  - pg_engine/app/views/pg_engine/admin_mailer/admin_mail.html.slim
829
+ - pg_engine/app/views/pg_engine/base/bulk_edit.html.slim
827
830
  - pg_engine/app/views/pg_engine/base/download.xlsx.axlsx
828
831
  - pg_engine/app/views/pg_engine/base/edit.html.slim
829
832
  - pg_engine/app/views/pg_engine/base/index.html.slim
@@ -896,6 +899,7 @@ files:
896
899
  - pg_engine/lib/pg_engine/utils/ssl_verifier.rb
897
900
  - pg_engine/lib/tasks/auto_anotar_modelos.rake
898
901
  - pg_engine/spec/components/alert_component_spec.rb
902
+ - pg_engine/spec/components/bulk_edit_component_spec.rb
899
903
  - pg_engine/spec/components/internal_error_component_spec.rb
900
904
  - pg_engine/spec/components/previews/alert_component_preview.rb
901
905
  - pg_engine/spec/components/previews/alert_component_preview/colours.html.slim
@@ -963,6 +967,7 @@ files:
963
967
  - pg_engine/spec/requests/users/user_accounts_spec.rb
964
968
  - pg_engine/spec/system/alerts_spec.rb
965
969
  - pg_engine/spec/system/breadcrumbs_spec.rb
970
+ - pg_engine/spec/system/bulk_edit_spec.rb
966
971
  - pg_engine/spec/system/date_selector_spec.rb
967
972
  - pg_engine/spec/system/destroy_spec.rb
968
973
  - pg_engine/spec/system/login_spec.rb
@@ -987,6 +992,7 @@ files:
987
992
  - pg_layout/app/javascript/config/turbo_rails/progress_bar.js
988
993
  - pg_layout/app/javascript/config/turbo_rails/set_consumer.js
989
994
  - pg_layout/app/javascript/controllers/application.js
995
+ - pg_layout/app/javascript/controllers/bulk_edit_field_activator.js
990
996
  - pg_layout/app/javascript/controllers/clear_timeout_controller.js
991
997
  - pg_layout/app/javascript/controllers/date_selector_controller.js
992
998
  - pg_layout/app/javascript/controllers/embedded_frame_controller.js