pg_rails 7.2.0 → 7.2.2
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_engine/app/assets/stylesheets/pg_rails_b5.scss +7 -2
- data/pg_engine/app/components/bad_user_input_component.rb +16 -0
- data/pg_engine/app/components/date_selector_component.html.slim +14 -0
- data/pg_engine/app/components/date_selector_component.rb +19 -0
- data/pg_engine/app/controllers/pg_engine/base_controller.rb +5 -0
- data/pg_engine/app/controllers/users/date_jumper_controller.rb +50 -0
- data/pg_engine/app/controllers/users/notifications_controller.rb +1 -1
- data/pg_engine/app/inputs/pg_engine/fecha_input.rb +25 -1
- data/pg_engine/app/lib/pg_engine/date_jumper.rb +74 -0
- data/pg_engine/app/views/pg_engine/base/index.html.slim +1 -1
- data/pg_engine/config/routes.rb +1 -0
- data/pg_engine/config/simple_form/simple_form_bootstrap.rb +0 -16
- data/pg_engine/lib/pg_engine/configuracion.rb +11 -2
- data/pg_engine/lib/pg_engine/error.rb +3 -0
- data/pg_engine/lib/pg_engine.rb +1 -0
- data/pg_engine/spec/components/previews/alert_component_preview/list_group.html.slim +12 -0
- data/pg_engine/spec/components/previews/alert_component_preview.rb +2 -0
- data/pg_engine/spec/lib/pg_engine/date_jumper_spec.rb +55 -0
- data/pg_engine/spec/requests/users/date_jumper_spec.rb +148 -0
- data/pg_engine/spec/system/date_selector_spec.rb +35 -0
- data/pg_layout/app/javascript/controllers/date_selector_controller.js +69 -0
- data/pg_layout/app/javascript/controllers/index.js +6 -0
- data/pg_layout/app/javascript/controllers/popover_controller.js +10 -0
- data/pg_layout/app/javascript/controllers/popover_toggler_controller.js +29 -0
- data/pg_rails/lib/version.rb +1 -1
- metadata +28 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20cb7ade648f78aa73ed631d9732326edc5a251a36141d054084366d9a6b9859
|
4
|
+
data.tar.gz: 38c923c5650e20ecb6be91b304ec3014cbd189976b254500275f5d2bf77ea9a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 156c1e465ab38406145f7d3bddf65fa0e40bf28a16109c15eb41f623735032dd23f7ddfb4a3341abbe8167ffd065082aef10945c8181c38bb01c4c368aa1853e
|
7
|
+
data.tar.gz: 7691712c1641cceb9ed53b6740ad9650844b69056c8433c4b65eb149cc9014ebce8870583306ebe7ed55c23209ec6b762b1a6961225fd65281aa5ddeec133dad
|
@@ -74,8 +74,8 @@ input[type=datetime-local], input[type=datetime] {
|
|
74
74
|
}
|
75
75
|
|
76
76
|
.list-group-item {
|
77
|
-
--bs-list-group-item-padding-y:
|
78
|
-
--bs-list-group-item-padding-x:
|
77
|
+
--bs-list-group-item-padding-y: 0.3em;
|
78
|
+
--bs-list-group-item-padding-x: 1em;
|
79
79
|
}
|
80
80
|
|
81
81
|
// FILTROS
|
@@ -103,6 +103,11 @@ input[type=datetime-local], input[type=datetime] {
|
|
103
103
|
width: min-content;
|
104
104
|
}
|
105
105
|
|
106
|
+
// Popover
|
107
|
+
.modal-content, .popover {
|
108
|
+
box-shadow: 4px 4px 8px 0px rgba(0, 0, 0, 0.3);
|
109
|
+
}
|
110
|
+
|
106
111
|
// Modal
|
107
112
|
.modal-content {
|
108
113
|
box-shadow: 15px 15px 9px 0px rgba(0, 0, 0, 0.6);
|
@@ -0,0 +1,14 @@
|
|
1
|
+
.d-flex.flex-column.align-items-start.gap-2[
|
2
|
+
data-controller="date-selector" data-field-id="#{@field_id}"
|
3
|
+
]
|
4
|
+
= number_field_tag 'quantity', nil,
|
5
|
+
placeholder: 'Cantidad', class: 'form-control form-control-sm'
|
6
|
+
= select_tag 'type', options_for_select(@types),
|
7
|
+
class: 'form-select form-select-sm'
|
8
|
+
= select_tag 'direction', options_for_select(@directions),
|
9
|
+
class: 'form-select form-select-sm'
|
10
|
+
.d-flex.justify-content-between.w-100
|
11
|
+
= button_tag 'Aceptar', class: 'btn btn-sm btn-primary',
|
12
|
+
'data-action': 'date-selector#submit'
|
13
|
+
= button_tag 'Hoy', class: 'btn btn-sm btn-link float-end',
|
14
|
+
'data-action': 'date-selector#today'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class DateSelectorComponent < ViewComponent::Base
|
2
|
+
def initialize(field_id)
|
3
|
+
@field_id = field_id
|
4
|
+
|
5
|
+
@types = [
|
6
|
+
['Días corridos (L a D)', 'calendar_days'],
|
7
|
+
['Días hábiles (L a V)', 'business_days'],
|
8
|
+
['Días hábiles no feriados', 'business_days_excluding_holidays'],
|
9
|
+
['Semanas', 'weeks'],
|
10
|
+
['Meses', 'months']
|
11
|
+
]
|
12
|
+
|
13
|
+
@directions = [
|
14
|
+
['Hacia adelante', 'forward'],
|
15
|
+
['Hacia atrás', 'backward']
|
16
|
+
]
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
@@ -23,6 +23,7 @@ module PgEngine
|
|
23
23
|
protect_from_forgery with: :exception
|
24
24
|
|
25
25
|
rescue_from StandardError, with: :internal_error
|
26
|
+
rescue_from PgEngine::BadUserInput, with: :bad_user_input
|
26
27
|
rescue_from ActionController::InvalidAuthenticityToken,
|
27
28
|
with: :invalid_authenticity_token
|
28
29
|
|
@@ -32,6 +33,10 @@ module PgEngine
|
|
32
33
|
redirect_to e.url
|
33
34
|
end
|
34
35
|
|
36
|
+
def bad_user_input(error)
|
37
|
+
render_my_component(BadUserInputComponent.new(error_msg: error.message), :bad_request)
|
38
|
+
end
|
39
|
+
|
35
40
|
def internal_error(error)
|
36
41
|
pg_err error
|
37
42
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Users
|
2
|
+
class DateJumperController < PgEngine.config.users_controller
|
3
|
+
before_action only: :jump do
|
4
|
+
if params[:quantity].blank?
|
5
|
+
raise PgEngine::BadUserInput, 'Cantidad incorrecta'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def jump
|
10
|
+
start_date = Date.parse(params[:start_date])
|
11
|
+
quantity = params[:quantity].to_i
|
12
|
+
|
13
|
+
date =
|
14
|
+
case params[:type]
|
15
|
+
when 'calendar_days'
|
16
|
+
start_date + (multiplier * quantity.days)
|
17
|
+
when 'business_days', 'business_days_excluding_holidays'
|
18
|
+
resolve_business_days(start_date, quantity)
|
19
|
+
when 'weeks'
|
20
|
+
start_date + (multiplier * quantity.weeks)
|
21
|
+
when 'months'
|
22
|
+
start_date + (multiplier * quantity.months)
|
23
|
+
else
|
24
|
+
# :nocov:
|
25
|
+
raise PgEngine::Error, 'type no soportado'
|
26
|
+
# :nocov:
|
27
|
+
end
|
28
|
+
|
29
|
+
render json: { date: }
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def resolve_business_days(start_date, quantity)
|
35
|
+
exclude_holidays = params[:type].include?('excluding_holidays')
|
36
|
+
options = { direction: params[:direction], exclude_holidays: }
|
37
|
+
|
38
|
+
PgEngine::DateJumper.new(start_date)
|
39
|
+
.business_days(quantity, **options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def multiplier
|
43
|
+
if params[:direction] == 'forward'
|
44
|
+
1
|
45
|
+
else
|
46
|
+
-1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -10,11 +10,35 @@ module PgEngine
|
|
10
10
|
else
|
11
11
|
object.public_send(attribute_name)
|
12
12
|
end
|
13
|
+
|
13
14
|
@input_type = 'date'
|
14
15
|
|
15
16
|
options = merge_wrapper_options({ value:, class: '', autocomplete: 'off' },
|
16
17
|
wrapper_options)
|
17
|
-
|
18
|
+
if input_options[:date_selector]
|
19
|
+
content_tag 'div', class: 'd-flex align-items-center' do
|
20
|
+
super(options) + date_selector
|
21
|
+
end
|
22
|
+
else
|
23
|
+
super(options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
include ActionView::Helpers::FormTagHelper
|
28
|
+
def date_selector
|
29
|
+
field_id = @builder.field_id(attribute_name)
|
30
|
+
html = DateSelectorComponent.new(field_id).render_in(@builder.template)
|
31
|
+
# tabindex required: https://getbootstrap.com/docs/5.3/components/popovers/#dismiss-on-next-click
|
32
|
+
link_to 'javascript:void(0)',
|
33
|
+
class: 'btn btn-link', tabindex: 0,
|
34
|
+
data: {
|
35
|
+
controller: 'popover-toggler',
|
36
|
+
'bs-html': true,
|
37
|
+
'bs-title': 'Cambiar la fecha',
|
38
|
+
'bs-content': html
|
39
|
+
} do
|
40
|
+
'<i class="bi bi-magic"></i>'.html_safe
|
41
|
+
end
|
18
42
|
end
|
19
43
|
end
|
20
44
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module PgEngine
|
2
|
+
class DateJumper
|
3
|
+
def initialize(start_date)
|
4
|
+
@start_date = start_date
|
5
|
+
end
|
6
|
+
|
7
|
+
def business_days(days, direction:, exclude_holidays: false)
|
8
|
+
case direction
|
9
|
+
when :forward, 'forward'
|
10
|
+
business_forward(days, exclude_holidays:)
|
11
|
+
when :backward, 'backward'
|
12
|
+
business_backward(days, exclude_holidays:)
|
13
|
+
else
|
14
|
+
# :nocov:
|
15
|
+
raise PgEngine::Error, 'direction not supported'
|
16
|
+
# :nocov:
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def business_forward(days, exclude_holidays: false)
|
21
|
+
days.times.inject(@start_date) do |acc, _|
|
22
|
+
if exclude_holidays
|
23
|
+
find_excluding_holidays(method: :next_business_day, from: acc)
|
24
|
+
else
|
25
|
+
next_business_day(acc)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def business_backward(days, exclude_holidays: false)
|
31
|
+
days.times.inject(@start_date) do |acc, _|
|
32
|
+
if exclude_holidays
|
33
|
+
find_excluding_holidays(method: :prev_business_day, from: acc)
|
34
|
+
else
|
35
|
+
prev_business_day(acc)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def find_excluding_holidays(method:, from:)
|
43
|
+
aux = from
|
44
|
+
safe_counter = 0
|
45
|
+
loop do
|
46
|
+
safe_counter += 1
|
47
|
+
aux = send(method, aux)
|
48
|
+
if safe_counter > 10
|
49
|
+
# :nocov:
|
50
|
+
raise 'las cosas'
|
51
|
+
# :nocov:
|
52
|
+
end
|
53
|
+
break unless Holidays.on(aux, :ar).any?
|
54
|
+
end
|
55
|
+
aux
|
56
|
+
end
|
57
|
+
|
58
|
+
def next_business_day(date)
|
59
|
+
if date.wday.in? [0, 5, 6]
|
60
|
+
date.next_occurring(:monday)
|
61
|
+
else
|
62
|
+
date.advance(days: 1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def prev_business_day(date)
|
67
|
+
if date.wday.in? [0, 1, 6]
|
68
|
+
date.prev_occurring(:friday)
|
69
|
+
else
|
70
|
+
date.advance(days: -1)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -43,7 +43,7 @@ div
|
|
43
43
|
- available_page_sizes.each do |page_size|
|
44
44
|
= link_to page_size,
|
45
45
|
namespaced_path(@clase_modelo, page_size:),
|
46
|
-
class: "list-group-item #{'active' if current_page_size == page_size}"
|
46
|
+
class: "list-group-item py-0 px-1 #{'active' if current_page_size == page_size}"
|
47
47
|
- elsif @records_filtered
|
48
48
|
- i18n_key = "#{controller_key}.#{action_name}.index.empty_but_filtered"
|
49
49
|
p.m-3
|
data/pg_engine/config/routes.rb
CHANGED
@@ -20,6 +20,7 @@ Rails.application.routes.draw do
|
|
20
20
|
namespace :users, path: 'u' do
|
21
21
|
post 'notifications/mark_as_seen', to: 'notifications#mark_as_seen'
|
22
22
|
post 'notifications/mark_as_unseen', to: 'notifications#mark_as_unseen'
|
23
|
+
get 'date_jumper/jump'
|
23
24
|
end
|
24
25
|
namespace :admin, path: 'a' do
|
25
26
|
pg_resource(:emails)
|
@@ -69,22 +69,6 @@ SimpleForm.setup do |config|
|
|
69
69
|
b.use :hint, wrap_with: { class: 'form-text' }
|
70
70
|
end
|
71
71
|
|
72
|
-
config.wrappers :vertical_form_inline_wrap, class: 'mb-3' do |b|
|
73
|
-
b.use :html5
|
74
|
-
b.use :placeholder
|
75
|
-
b.optional :maxlength
|
76
|
-
b.optional :minlength
|
77
|
-
b.optional :pattern
|
78
|
-
b.optional :min_max
|
79
|
-
b.optional :readonly
|
80
|
-
b.use :label, class: 'form-label d-block'
|
81
|
-
b.wrapper class: 'd-inline-block' do |bb|
|
82
|
-
bb.use :input, class: 'form-control', error_class: 'is-invalid'
|
83
|
-
end
|
84
|
-
b.use :error, wrap_with: { class: 'invalid-feedback' }
|
85
|
-
b.use :hint, wrap_with: { class: 'form-text' }
|
86
|
-
end
|
87
|
-
|
88
72
|
config.wrappers :vertical_no_margin_control, &control_wrapper
|
89
73
|
|
90
74
|
config.wrappers :vertical_no_margin_select, &select_wrapper
|
@@ -4,8 +4,11 @@
|
|
4
4
|
|
5
5
|
module PgEngine
|
6
6
|
class Configuracion
|
7
|
-
attr_accessor :sistema_iconos, :clase_botones_chicos,
|
8
|
-
:
|
7
|
+
attr_accessor :sistema_iconos, :clase_botones_chicos,
|
8
|
+
:boton_destroy, :boton_edit, :boton_show,
|
9
|
+
:boton_light, :icono_destroy, :icono_edit,
|
10
|
+
:icono_show, :boton_export, :bootstrap_version,
|
11
|
+
:users_controller
|
9
12
|
|
10
13
|
def initialize
|
11
14
|
@sistema_iconos = 'bi'
|
@@ -19,6 +22,12 @@ module PgEngine
|
|
19
22
|
@icono_edit = 'pencil'
|
20
23
|
@icono_show = 'eye-fill'
|
21
24
|
@bootstrap_version = 5
|
25
|
+
|
26
|
+
if defined? UsersController
|
27
|
+
@users_controller = UsersController
|
28
|
+
elsif defined? FrontendController
|
29
|
+
@users_controller = FrontendController
|
30
|
+
end
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
data/pg_engine/lib/pg_engine.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe PgEngine::DateJumper do
|
4
|
+
subject do
|
5
|
+
jumper.send(method, days, exclude_holidays:)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:method) { self.class.metadata[:method] }
|
9
|
+
let(:jumper) { described_class.new(start_date) }
|
10
|
+
let(:start_date) { Date.new(2024, 8, 16) }
|
11
|
+
let(:days) { 5 }
|
12
|
+
let(:exclude_holidays) { false }
|
13
|
+
|
14
|
+
def fake_holiday(date)
|
15
|
+
allow(Holidays).to receive(:on).and_call_original
|
16
|
+
allow(Holidays).to receive(:on).with(date, anything)
|
17
|
+
.and_return([:some_fake_holiday])
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'business_forward', method: 'business_forward' do
|
21
|
+
it do
|
22
|
+
expect(subject).to eq Date.new(2024, 8, 23)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'excluding holidays' do
|
26
|
+
before do
|
27
|
+
fake_holiday(Date.new(2024, 8, 23))
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:exclude_holidays) { true }
|
31
|
+
|
32
|
+
it do
|
33
|
+
expect(subject).to eq Date.new(2024, 8, 26)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'business_forward', method: 'business_backward' do
|
39
|
+
it do
|
40
|
+
expect(subject).to eq Date.new(2024, 8, 9)
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'excluding holidays' do
|
44
|
+
before do
|
45
|
+
fake_holiday(Date.new(2024, 8, 14))
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:exclude_holidays) { true }
|
49
|
+
|
50
|
+
it do
|
51
|
+
expect(subject).to eq Date.new(2024, 8, 8)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Users::DateJumpers' do
|
4
|
+
before do
|
5
|
+
user = create :user
|
6
|
+
sign_in user
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'GET /jump' do
|
10
|
+
before do
|
11
|
+
stubs if defined? stubs
|
12
|
+
get '/u/date_jumper/jump', params: {
|
13
|
+
start_date:,
|
14
|
+
quantity:,
|
15
|
+
type:,
|
16
|
+
direction:
|
17
|
+
}, headers: { accept: 'application/json' }
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:start_date) { Date.new(2024, 8, 16) }
|
21
|
+
let(:quantity) { 5 }
|
22
|
+
|
23
|
+
context 'when quantity is blank' do
|
24
|
+
let(:quantity) { '' }
|
25
|
+
let(:type) { 'calendar_days' }
|
26
|
+
let(:direction) { 'forward' }
|
27
|
+
|
28
|
+
it do
|
29
|
+
expect(response).to have_http_status(:bad_request)
|
30
|
+
expect(JSON.parse(response.body)['html']).to include 'Cantidad incorrecta'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when moving calendar days' do
|
35
|
+
let(:type) { 'calendar_days' }
|
36
|
+
|
37
|
+
context 'forward' do
|
38
|
+
let(:direction) { 'forward' }
|
39
|
+
|
40
|
+
it do
|
41
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-08-21'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'backward' do
|
46
|
+
let(:direction) { 'backward' }
|
47
|
+
|
48
|
+
it do
|
49
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-08-11'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when moving business days' do
|
55
|
+
let(:type) { 'business_days' }
|
56
|
+
|
57
|
+
context 'forward' do
|
58
|
+
let(:direction) { 'forward' }
|
59
|
+
|
60
|
+
it do
|
61
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-08-23'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'backward' do
|
66
|
+
let(:direction) { 'backward' }
|
67
|
+
|
68
|
+
it do
|
69
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-08-09'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when moving business days excluding holidays' do
|
75
|
+
def fake_holiday(date)
|
76
|
+
allow(Holidays).to receive(:on).and_call_original
|
77
|
+
allow(Holidays).to receive(:on).with(date, anything)
|
78
|
+
.and_return([:some_fake_holiday])
|
79
|
+
end
|
80
|
+
|
81
|
+
let(:type) { 'business_days_excluding_holidays' }
|
82
|
+
|
83
|
+
context 'forward' do
|
84
|
+
let(:stubs) do
|
85
|
+
fake_holiday(Date.new(2024, 8, 23))
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:direction) { 'forward' }
|
89
|
+
|
90
|
+
it do
|
91
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-08-26'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'backward' do
|
96
|
+
let(:stubs) do
|
97
|
+
fake_holiday(Date.new(2024, 8, 14))
|
98
|
+
end
|
99
|
+
|
100
|
+
let(:direction) { 'backward' }
|
101
|
+
|
102
|
+
it do
|
103
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-08-08'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when moving weeks' do
|
109
|
+
let(:type) { 'weeks' }
|
110
|
+
|
111
|
+
context 'forward' do
|
112
|
+
let(:direction) { 'forward' }
|
113
|
+
|
114
|
+
it do
|
115
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-09-20'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'backward' do
|
120
|
+
let(:direction) { 'backward' }
|
121
|
+
|
122
|
+
it do
|
123
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-07-12'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when moving months' do
|
129
|
+
let(:type) { 'months' }
|
130
|
+
|
131
|
+
context 'forward' do
|
132
|
+
let(:direction) { 'forward' }
|
133
|
+
|
134
|
+
it do
|
135
|
+
expect(JSON.parse(response.body)['date']).to eq '2025-01-16'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'backward' do
|
140
|
+
let(:direction) { 'backward' }
|
141
|
+
|
142
|
+
it do
|
143
|
+
expect(JSON.parse(response.body)['date']).to eq '2024-03-16'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,35 @@
|
|
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 environment variable to override, eg:
|
8
|
+
#
|
9
|
+
# DRIVER=selenium rspec
|
10
|
+
describe 'Date selector' do
|
11
|
+
subject(:visitar) do
|
12
|
+
visit edit_admin_categoria_de_cosa_path(categoria_de_cosa)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:logged_user) { create :user }
|
16
|
+
let(:account) { logged_user.current_account }
|
17
|
+
let(:categoria_de_cosa) { create :categoria_de_cosa, fecha: }
|
18
|
+
let(:fecha) { Date.new(2024, 8, 12) }
|
19
|
+
|
20
|
+
before do
|
21
|
+
login_as logged_user
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'jump N days' do
|
25
|
+
it do
|
26
|
+
visitar
|
27
|
+
find('.categoria_de_cosa_fecha [data-controller="popover-toggler"]').click
|
28
|
+
fill_in 'quantity', with: '3'
|
29
|
+
select 'Días hábiles (L a V)'
|
30
|
+
click_on 'Aceptar'
|
31
|
+
click_on 'Actualizar Categoría de cosa'
|
32
|
+
expect(page).to have_text '15/08/2024'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import { flashMessage } from '../utils/utils'
|
3
|
+
import { get } from '@rails/request.js'
|
4
|
+
import Rollbar from 'rollbar'
|
5
|
+
|
6
|
+
export default class extends Controller {
|
7
|
+
today () {
|
8
|
+
const fechaEl = document.getElementById(this.element.dataset.fieldId)
|
9
|
+
let today = new Date()
|
10
|
+
const dd = String(today.getDate()).padStart(2, '0')
|
11
|
+
const mm = String(today.getMonth() + 1).padStart(2, '0') // January is 0!
|
12
|
+
const yyyy = today.getFullYear()
|
13
|
+
|
14
|
+
today = yyyy + '-' + mm + '-' + dd
|
15
|
+
fechaEl.value = today
|
16
|
+
return fechaEl.value
|
17
|
+
}
|
18
|
+
|
19
|
+
closePopover () {
|
20
|
+
const popover = this.element.closest('.popover')
|
21
|
+
this.application.getControllerForElementAndIdentifier(popover, 'popover').close()
|
22
|
+
}
|
23
|
+
|
24
|
+
async submit () {
|
25
|
+
const fechaEl = document.getElementById(this.element.dataset.fieldId)
|
26
|
+
let startDate = fechaEl.value
|
27
|
+
if (!startDate) {
|
28
|
+
startDate = this.today()
|
29
|
+
}
|
30
|
+
|
31
|
+
const quantity = this.element.querySelector('input[name=quantity]').value
|
32
|
+
if (!quantity) {
|
33
|
+
this.closePopover()
|
34
|
+
return
|
35
|
+
}
|
36
|
+
const type = this.element.querySelector('select[name=type]').value
|
37
|
+
const direction = this.element.querySelector('select[name=direction]').value
|
38
|
+
// console.log(quantity, type, direction)
|
39
|
+
this.element.querySelector('button').setAttribute('disabled', 'true')
|
40
|
+
// let input = this
|
41
|
+
const response = await get('/u/date_jumper/jump', {
|
42
|
+
query: {
|
43
|
+
start_date: startDate,
|
44
|
+
quantity,
|
45
|
+
type,
|
46
|
+
direction
|
47
|
+
},
|
48
|
+
responseKind: 'json'
|
49
|
+
})
|
50
|
+
|
51
|
+
if (response.ok) {
|
52
|
+
const json = await response.json
|
53
|
+
fechaEl.value = json.date
|
54
|
+
this.element.querySelector('button').removeAttribute('disabled')
|
55
|
+
this.closePopover()
|
56
|
+
} else {
|
57
|
+
let message = 'Hubo un error'
|
58
|
+
try {
|
59
|
+
const json = await response.json
|
60
|
+
message = json.html || 'Hubo un error'
|
61
|
+
} catch {
|
62
|
+
// JSON parser error
|
63
|
+
}
|
64
|
+
flashMessage(message, 'warning', true)
|
65
|
+
this.element.querySelector('button').removeAttribute('disabled')
|
66
|
+
Rollbar.error('date jumper error', json)
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
@@ -11,6 +11,9 @@ import NotificationsController from './notifications_controller'
|
|
11
11
|
import SelectizeController from './selectize_controller'
|
12
12
|
import ThemeController from './theme_controller'
|
13
13
|
import TooltipController from './tooltip_controller'
|
14
|
+
import PopoverController from './popover_controller'
|
15
|
+
import PopoverTogglerController from './popover_toggler_controller'
|
16
|
+
import DateSelectorController from './date_selector_controller'
|
14
17
|
|
15
18
|
application.register('navbar', NavbarController)
|
16
19
|
application.register('nested', NestedController)
|
@@ -23,5 +26,8 @@ application.register('notifications', NotificationsController)
|
|
23
26
|
application.register('selectize', SelectizeController)
|
24
27
|
application.register('theme', ThemeController)
|
25
28
|
application.register('tooltip', TooltipController)
|
29
|
+
application.register('popover', PopoverController)
|
30
|
+
application.register('popover-toggler', PopoverTogglerController)
|
31
|
+
application.register('date-selector', DateSelectorController)
|
26
32
|
|
27
33
|
// TODO: testear con capybara todo lo que se pueda
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import * as bootstrap from 'bootstrap'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
close () {
|
6
|
+
const toggler = document.querySelector('[aria-describedby="' + this.element.id + '"]')
|
7
|
+
const instance = bootstrap.Popover.getInstance(toggler)
|
8
|
+
instance.hide()
|
9
|
+
}
|
10
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import * as bootstrap from 'bootstrap'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
popover = null
|
6
|
+
|
7
|
+
connect () {
|
8
|
+
this.popover = new bootstrap.Popover(this.element, {
|
9
|
+
// WARNING: don't use for user input html
|
10
|
+
sanitize: false,
|
11
|
+
template: `
|
12
|
+
<div class="popover" role="tooltip" data-controller="popover">
|
13
|
+
<div class="popover-arrow"></div>
|
14
|
+
<div class="popover-header"></div>
|
15
|
+
<button type="button" class="btn-close position-absolute" data-action="popover#close" style="top: 1em; right: 1em;" aria-label="Close"></button>
|
16
|
+
<div class="popover-body">
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
`,
|
20
|
+
container: 'body'
|
21
|
+
})
|
22
|
+
}
|
23
|
+
|
24
|
+
disconnect () {
|
25
|
+
if (this.popover) {
|
26
|
+
this.popover.dispose()
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
data/pg_rails/lib/version.rb
CHANGED
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.2.
|
4
|
+
version: 7.2.2
|
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-08-
|
11
|
+
date: 2024-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -584,6 +584,20 @@ dependencies:
|
|
584
584
|
- - "~>"
|
585
585
|
- !ruby/object:Gem::Version
|
586
586
|
version: '2.3'
|
587
|
+
- !ruby/object:Gem::Dependency
|
588
|
+
name: holidays
|
589
|
+
requirement: !ruby/object:Gem::Requirement
|
590
|
+
requirements:
|
591
|
+
- - "~>"
|
592
|
+
- !ruby/object:Gem::Version
|
593
|
+
version: '8.8'
|
594
|
+
type: :runtime
|
595
|
+
prerelease: false
|
596
|
+
version_requirements: !ruby/object:Gem::Requirement
|
597
|
+
requirements:
|
598
|
+
- - "~>"
|
599
|
+
- !ruby/object:Gem::Version
|
600
|
+
version: '8.8'
|
587
601
|
description: Rails goodies.
|
588
602
|
email:
|
589
603
|
- mrosso10@gmail.com
|
@@ -625,7 +639,10 @@ files:
|
|
625
639
|
- pg_engine/app/components/alert_component.html.slim
|
626
640
|
- pg_engine/app/components/alert_component.rb
|
627
641
|
- pg_engine/app/components/bad_request_component.rb
|
642
|
+
- pg_engine/app/components/bad_user_input_component.rb
|
628
643
|
- pg_engine/app/components/base_component.rb
|
644
|
+
- pg_engine/app/components/date_selector_component.html.slim
|
645
|
+
- pg_engine/app/components/date_selector_component.rb
|
629
646
|
- pg_engine/app/components/flash_container_component.rb
|
630
647
|
- pg_engine/app/components/internal_error_component.rb
|
631
648
|
- pg_engine/app/components/notification_component.rb
|
@@ -649,6 +666,7 @@ files:
|
|
649
666
|
- pg_engine/app/controllers/public/mensaje_contactos_controller.rb
|
650
667
|
- pg_engine/app/controllers/public/webhooks_controller.rb
|
651
668
|
- pg_engine/app/controllers/users/confirmations_controller.rb
|
669
|
+
- pg_engine/app/controllers/users/date_jumper_controller.rb
|
652
670
|
- pg_engine/app/controllers/users/notifications_controller.rb
|
653
671
|
- pg_engine/app/controllers/users/registrations_controller.rb
|
654
672
|
- pg_engine/app/decorators/account_decorator.rb
|
@@ -668,6 +686,7 @@ files:
|
|
668
686
|
- pg_engine/app/helpers/pg_engine/print_helper.rb
|
669
687
|
- pg_engine/app/helpers/pg_engine/route_helper.rb
|
670
688
|
- pg_engine/app/inputs/pg_engine/fecha_input.rb
|
689
|
+
- pg_engine/app/lib/pg_engine/date_jumper.rb
|
671
690
|
- pg_engine/app/lib/pg_engine/devise_failure_app.rb
|
672
691
|
- pg_engine/app/lib/pg_engine/error_helper.rb
|
673
692
|
- pg_engine/app/lib/pg_engine/filtros_builder.rb
|
@@ -781,6 +800,7 @@ files:
|
|
781
800
|
- pg_engine/spec/components/previews/alert_component_preview/colours.html.slim
|
782
801
|
- pg_engine/spec/components/previews/alert_component_preview/default.html.slim
|
783
802
|
- pg_engine/spec/components/previews/alert_component_preview/dismisible.html.slim
|
803
|
+
- pg_engine/spec/components/previews/alert_component_preview/list_group.html.slim
|
784
804
|
- pg_engine/spec/components/previews/alert_component_preview/tooltips.html.slim
|
785
805
|
- pg_engine/spec/components/previews/internal_error_preview.rb
|
786
806
|
- pg_engine/spec/components/previews/internal_error_preview/default.html.slim
|
@@ -806,6 +826,7 @@ files:
|
|
806
826
|
- pg_engine/spec/fixtures/test.pdf
|
807
827
|
- pg_engine/spec/helpers/pg_engine/pg_rails_helper_spec.rb
|
808
828
|
- pg_engine/spec/helpers/pg_engine/print_helper_spec.rb
|
829
|
+
- pg_engine/spec/lib/pg_engine/date_jumper_spec.rb
|
809
830
|
- pg_engine/spec/lib/pg_engine/error_helper_spec.rb
|
810
831
|
- pg_engine/spec/lib/pg_engine/mailgun/log_sync_spec.rb
|
811
832
|
- pg_engine/spec/lib/pg_engine/utils/pg_engine/pg_logger_spec.rb
|
@@ -821,7 +842,9 @@ files:
|
|
821
842
|
- pg_engine/spec/pg_engine/pdf_preview_generator_spec.rb
|
822
843
|
- pg_engine/spec/requests/admin/eventos_spec.rb
|
823
844
|
- pg_engine/spec/requests/base_controller_requests_spec.rb
|
845
|
+
- pg_engine/spec/requests/users/date_jumper_spec.rb
|
824
846
|
- pg_engine/spec/system/alerts_spec.rb
|
847
|
+
- pg_engine/spec/system/date_selector_spec.rb
|
825
848
|
- pg_engine/spec/system/destroy_spec.rb
|
826
849
|
- pg_engine/spec/system/login_spec.rb
|
827
850
|
- pg_engine/spec/system/noticed_spec.rb
|
@@ -844,6 +867,7 @@ files:
|
|
844
867
|
- pg_layout/app/javascript/config/turbo_rails/set_consumer.js
|
845
868
|
- pg_layout/app/javascript/controllers/application.js
|
846
869
|
- pg_layout/app/javascript/controllers/clear_timeout_controller.js
|
870
|
+
- pg_layout/app/javascript/controllers/date_selector_controller.js
|
847
871
|
- pg_layout/app/javascript/controllers/fadein_onload_controller.js
|
848
872
|
- pg_layout/app/javascript/controllers/filtros_controller.js
|
849
873
|
- pg_layout/app/javascript/controllers/index.js
|
@@ -851,6 +875,8 @@ files:
|
|
851
875
|
- pg_layout/app/javascript/controllers/nested_controller.js
|
852
876
|
- pg_layout/app/javascript/controllers/notifications_controller.js
|
853
877
|
- pg_layout/app/javascript/controllers/pg_form_controller.js
|
878
|
+
- pg_layout/app/javascript/controllers/popover_controller.js
|
879
|
+
- pg_layout/app/javascript/controllers/popover_toggler_controller.js
|
854
880
|
- pg_layout/app/javascript/controllers/selectize_controller.js
|
855
881
|
- pg_layout/app/javascript/controllers/switcher_controller.js
|
856
882
|
- pg_layout/app/javascript/controllers/theme_controller.js
|