pg_rails 7.2.0 → 7.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 +60 -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: 7685689c316550976fd129e2d10357ce1a4e3242bc5a2468d69bcbfbefe58d6c
|
4
|
+
data.tar.gz: d23282693ed8d1dbbd0552b5212bf8c7a56f9846cfcd491bedc4f4753a4f7fbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4f384000a2f7955bf91658d863bb1d52c6997cf9eeb0e775b0b4fa236af21f6eee9e5730170ba24f15a64cd8f0a2883db1aac208b5e06413a619547d73de46f
|
7
|
+
data.tar.gz: 10f9768f3f69b517839b03da38197b27e4c37adbd6cd9490cddab952ed077884548c648b7d16a4f6f1713dd2e8f59b91b91c31b1f1364df813f5b60e9c5aea24
|
@@ -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,60 @@
|
|
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
|
+
}
|
17
|
+
|
18
|
+
closePopover () {
|
19
|
+
const popover = this.element.closest('.popover')
|
20
|
+
this.application.getControllerForElementAndIdentifier(popover, 'popover').close()
|
21
|
+
}
|
22
|
+
|
23
|
+
async submit () {
|
24
|
+
const quantity = this.element.querySelector('input[name=quantity]').value
|
25
|
+
if (!quantity) {
|
26
|
+
this.closePopover()
|
27
|
+
return
|
28
|
+
}
|
29
|
+
const type = this.element.querySelector('select[name=type]').value
|
30
|
+
const direction = this.element.querySelector('select[name=direction]').value
|
31
|
+
const fechaEl = document.getElementById(this.element.dataset.fieldId)
|
32
|
+
const startDate = fechaEl.value
|
33
|
+
// console.log(quantity, type, direction)
|
34
|
+
this.element.querySelector('button').setAttribute('disabled', 'true')
|
35
|
+
// let input = this
|
36
|
+
const response = await get('/u/date_jumper/jump', {
|
37
|
+
query: {
|
38
|
+
start_date: startDate,
|
39
|
+
quantity,
|
40
|
+
type,
|
41
|
+
direction
|
42
|
+
},
|
43
|
+
responseKind: 'json'
|
44
|
+
})
|
45
|
+
|
46
|
+
if (response.ok) {
|
47
|
+
const json = await response.json
|
48
|
+
fechaEl.value = json.date
|
49
|
+
this.element.querySelector('button').removeAttribute('disabled')
|
50
|
+
this.closePopover()
|
51
|
+
} else {
|
52
|
+
const json = await response.json
|
53
|
+
// FIXME: handle JSON parse error
|
54
|
+
const message = json.html || 'Hubo un error'
|
55
|
+
flashMessage(message, 'warning', true)
|
56
|
+
this.element.querySelector('button').removeAttribute('disabled')
|
57
|
+
Rollbar.error('date jumper error', json)
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
@@ -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.1
|
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
|