pg_rails 7.0.7 → 7.0.8.pre.alpha.6
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/README.md +3 -0
- data/pg_associable/app/assets/{css → stylesheets}/pg_associable.scss +40 -41
- data/pg_associable/app/helpers/pg_associable/form_builder_methods.rb +36 -9
- data/pg_associable/app/helpers/pg_associable/helpers.rb +6 -3
- data/pg_associable/app/inputs/pg_associable_input.rb +53 -0
- data/pg_associable/app/javascript/asociable_controller.tsx +247 -0
- data/pg_associable/app/javascript/modal_controller.js +29 -0
- data/pg_associable/app/views/pg_associable/_resultados_inline.html.slim +9 -8
- data/pg_associable/app/views/pg_engine/base/_pg_associable_modal.html.slim +5 -32
- data/pg_associable/index.js +2 -4
- data/pg_associable/lib/pg_associable/engine.rb +0 -4
- data/pg_engine/app/assets/stylesheets/pg_rails_b5.scss +49 -41
- data/pg_engine/app/controllers/pg_engine/resource_helper.rb +6 -2
- data/pg_engine/app/decorators/pg_engine/base_decorator.rb +2 -2
- data/pg_engine/app/helpers/pg_engine/flash_helper.rb +2 -2
- data/pg_engine/app/helpers/pg_engine/form_helper.rb +70 -0
- data/pg_engine/app/helpers/pg_engine/route_helper.rb +14 -6
- data/pg_engine/app/views/admin/accounts/_form.html.slim +1 -1
- data/pg_engine/app/views/admin/user_accounts/_form.html.slim +3 -3
- data/pg_engine/app/views/admin/users/_form.html.slim +1 -1
- data/pg_engine/app/views/pg_engine/base/index.html.slim +3 -3
- data/pg_engine/config/initializers/active_admin.rb +1 -4
- data/pg_engine/config/simple_form/simple_form_bootstrap.rb +17 -9
- data/pg_engine/db/migrate/20240222115722_create_active_storage_tables.active_storage.rb +57 -0
- data/pg_engine/db/seeds.rb +7 -4
- data/pg_engine/lib/pg_engine/engine.rb +1 -1
- data/pg_engine/lib/pg_engine/route_helpers.rb +1 -0
- data/pg_engine/lib/pg_engine/utils/pdf_preview_generator.rb +50 -0
- data/pg_engine/lib/pg_engine.rb +3 -0
- data/pg_engine/lib/tasks/auto_anotar_modelos.rake +1 -1
- data/pg_engine/spec/fixtures/test.pdf +0 -0
- data/pg_engine/spec/pg_engine/pdf_preview_generator_spec.rb +12 -0
- data/pg_layout/app/assets/stylesheets/sidebar.scss +10 -2
- data/pg_layout/app/javascript/nested_controller.js +48 -0
- data/pg_layout/app/javascript/pg_form_controller.js +13 -0
- data/pg_layout/app/javascript/utils.ts +34 -0
- data/pg_layout/app/views/layouts/pg_layout/devise.html.slim +1 -1
- data/pg_layout/app/views/layouts/pg_layout/layout.html.slim +14 -10
- data/pg_layout/app/views/pg_layout/_flash.html.slim +2 -2
- data/pg_layout/app/views/pg_layout/_navbar.html.erb +10 -0
- data/pg_layout/app/views/pg_layout/_sidebar.html.erb +3 -3
- data/pg_layout/index.js +4 -0
- data/pg_rails/lib/version.rb +1 -1
- data/pg_rails/scss/pg_rails.scss +1 -1
- data/pg_scaffold/lib/generators/pg_slim/templates/_form.html.slim +3 -3
- metadata +15 -13
- data/pg_associable/app/assets/js/asociable_controller.js +0 -58
- data/pg_associable/app/assets/js/asociable_inline_controller.js +0 -142
- data/pg_associable/app/assets/js/modal_controller.js +0 -117
- data/pg_associable/app/inputs/pg_associable/pg_associable_inline_input.rb +0 -39
- data/pg_associable/app/inputs/pg_associable/pg_associable_input.rb +0 -41
- data/pg_associable/app/views/pg_associable/_resultados.html.slim +0 -9
- data/pg_associable/lib/pg_associable/simple_form_initializer.rb +0 -34
- data/pg_associable/lib/tasks/pg_associable_tasks.rake +0 -4
@@ -6,48 +6,44 @@
|
|
6
6
|
--bs-form-invalid-border-color: #b50000;
|
7
7
|
}
|
8
8
|
|
9
|
+
// Toasts
|
10
|
+
.toast.show {
|
11
|
+
display: inline-block;
|
12
|
+
}
|
9
13
|
|
10
14
|
// FORMS
|
11
|
-
|
12
|
-
|
15
|
+
input[disabled] {
|
16
|
+
background-color: #e9e9ed;
|
17
|
+
color: black;
|
18
|
+
}
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
}
|
20
|
+
.form-control,
|
21
|
+
.form-select {
|
22
|
+
border: 1px solid #a7b7bb;
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
&:focus, &:focus-visible {
|
25
|
+
outline: 1px solid color.adjust(#a7b7bb, $saturation: +30%);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
select[multiple] {
|
29
|
+
height: inherit;
|
30
|
+
}
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
}
|
32
|
+
input[type=date] {
|
33
|
+
max-width: 12em;
|
34
|
+
}
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
}
|
36
|
+
input[type=datetime-local], input[type=datetime] {
|
37
|
+
max-width: 15em;
|
38
|
+
}
|
35
39
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
}
|
40
|
-
select[multiple] {
|
41
|
-
height: inherit;
|
42
|
-
}
|
43
|
-
.form-control:focus {
|
44
|
-
box-shadow: none!important; /* override bootstrap forms */
|
45
|
-
}
|
40
|
+
.form-select:not(:has(option)) {
|
41
|
+
background-color: #d5d5d5;
|
42
|
+
}
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
// }
|
44
|
+
.form-control.is-invalid, .form-select.is-invalid {
|
45
|
+
background-color: #fff3f3;
|
46
|
+
}
|
51
47
|
|
52
48
|
// LISTADOS
|
53
49
|
.listado {
|
@@ -56,9 +52,7 @@
|
|
56
52
|
}
|
57
53
|
}
|
58
54
|
.listado .btn-sm {
|
59
|
-
|
60
|
-
height: 25px;
|
61
|
-
padding: 1px;
|
55
|
+
padding: 0em 0.3em;
|
62
56
|
margin-right: 4px;
|
63
57
|
}
|
64
58
|
|
@@ -66,9 +60,23 @@
|
|
66
60
|
.filter {
|
67
61
|
display: inline-block;
|
68
62
|
vertical-align: top;
|
69
|
-
|
63
|
+
max-width: 17em;
|
64
|
+
}
|
70
65
|
|
71
|
-
|
72
|
-
|
73
|
-
|
66
|
+
// Modal
|
67
|
+
.modal-content {
|
68
|
+
box-shadow: 15px 15px 9px 0px rgba(0, 0, 0, 0.6);
|
69
|
+
}
|
70
|
+
|
71
|
+
// Nested
|
72
|
+
.link-to-add:hover {
|
73
|
+
background-color: #f4f4f4;
|
74
|
+
}
|
75
|
+
|
76
|
+
.link-to-add {
|
77
|
+
display: inline-block;
|
78
|
+
width: 100%;
|
79
|
+
text-align: center;
|
80
|
+
border-radius: var(--bs-border-radius);
|
81
|
+
padding: 0.6em 0.4em;
|
74
82
|
}
|
@@ -93,10 +93,12 @@ module PgEngine
|
|
93
93
|
if params[:asociable]
|
94
94
|
format.turbo_stream do
|
95
95
|
render turbo_stream:
|
96
|
-
|
96
|
+
# rubocop:disable Rails/SkipsModelValidations
|
97
|
+
turbo_stream.update_all('.modal.show .pg-associable-form', <<~HTML
|
97
98
|
<div data-modal-target="response" data-response='#{object.decorate.to_json}'></div>
|
98
99
|
HTML
|
99
100
|
)
|
101
|
+
# rubocop:enable Rails/SkipsModelValidations
|
100
102
|
end
|
101
103
|
end
|
102
104
|
format.html do
|
@@ -113,8 +115,10 @@ module PgEngine
|
|
113
115
|
# self.instancia_modelo = instancia_modelo.decorate
|
114
116
|
if params[:asociable]
|
115
117
|
format.turbo_stream do
|
118
|
+
# rubocop:disable Rails/SkipsModelValidations
|
116
119
|
render turbo_stream:
|
117
|
-
turbo_stream.
|
120
|
+
turbo_stream.update_all('.modal.show .pg-associable-form', partial: 'form', locals: { asociable: true })
|
121
|
+
# rubocop:enable Rails/SkipsModelValidations
|
118
122
|
end
|
119
123
|
end
|
120
124
|
format.html { render :new, status: :unprocessable_entity }
|
@@ -12,8 +12,8 @@ module PgEngine
|
|
12
12
|
|
13
13
|
delegate_all
|
14
14
|
|
15
|
-
def as_json(
|
16
|
-
object.as_json.tap { |o| o[:to_s] = to_s }
|
15
|
+
def as_json(options = {})
|
16
|
+
object.as_json(options).tap { |o| o[:to_s] = to_s }
|
17
17
|
end
|
18
18
|
|
19
19
|
# rubocop:disable Style/MissingRespondToMissing
|
@@ -29,5 +29,75 @@ module PgEngine
|
|
29
29
|
uri.path = "#{uri.path}.#{formato}"
|
30
30
|
uri.to_s
|
31
31
|
end
|
32
|
+
|
33
|
+
# This method creates a link with `data-id` `data-fields` attributes.
|
34
|
+
# These attributes are used to create new instances of the nested fields through Javascript.
|
35
|
+
def link_to_add_fields(name, form, association, required: false)
|
36
|
+
# Takes an object (@person) and creates a new instance of its associated model (:addresses)
|
37
|
+
# To better understand, run the following in your terminal:
|
38
|
+
# rails c --sandbox
|
39
|
+
# @person = Person.new
|
40
|
+
# new_object = @person.send(:addresses).klass.new
|
41
|
+
new_object = form.object.send(association).klass.new
|
42
|
+
|
43
|
+
# Saves the unique ID of the object into a variable.
|
44
|
+
# This is needed to ensure the key of the associated array is unique.
|
45
|
+
# This is makes parsing the content in the `data-fields` attribute easier through Javascript.
|
46
|
+
# We could use another method to achive this.
|
47
|
+
id = new_object.object_id
|
48
|
+
|
49
|
+
# https://api.rubyonrails.org/ fields_for(record_name, record_object = nil, fields_options = {}, &block)
|
50
|
+
# record_name = :addresses
|
51
|
+
# record_object = new_object
|
52
|
+
# fields_options = { child_index: id }
|
53
|
+
# child_index` is used to ensure the key of the associated array is unique,
|
54
|
+
# and that it matched the value in the `data-id` attribute.
|
55
|
+
# `person[addresses_attributes][child_index_value][_destroy]`
|
56
|
+
fields =
|
57
|
+
form.fields_for(association, new_object, child_index: id) do |builder|
|
58
|
+
# `association.to_s.singularize + "_fields"` ends up evaluating to `address_fields`
|
59
|
+
# The render function will then look for `views/people/_address_fields.html.erb`
|
60
|
+
# The render function also needs to be passed the value of 'builder', because
|
61
|
+
# `views/people/_address_fields.html.erb` needs this to render the form tags.
|
62
|
+
render("#{association.to_s.singularize}_fields", f: builder)
|
63
|
+
end
|
64
|
+
|
65
|
+
# This renders a simple link, but passes information into `data` attributes.
|
66
|
+
# This info can be named anything we want, but in this case we chose `data-id:` and `data-fields:`.
|
67
|
+
# The `id:` is from `new_object.object_id`.
|
68
|
+
# The `fields:` are rendered from the `fields` blocks.
|
69
|
+
# We use `gsub("\n", "")` to remove anywhite space from the rendered partial.
|
70
|
+
# The `id:` value needs to match the value used in `child_index: id`.
|
71
|
+
link_to(
|
72
|
+
'javascript:void(0)',
|
73
|
+
class: 'link-to-add',
|
74
|
+
data: {
|
75
|
+
controller: 'nested',
|
76
|
+
action: 'nested#addItem',
|
77
|
+
id:,
|
78
|
+
required:,
|
79
|
+
fields: fields.gsub("\n", '')
|
80
|
+
}
|
81
|
+
) do
|
82
|
+
# rubocop:disable Rails/OutputSafety
|
83
|
+
"<i class=\"bi bi-plus-lg\"></i> #{name}".html_safe
|
84
|
+
# rubocop:enable Rails/OutputSafety
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def link_to_remove(text = nil, &)
|
89
|
+
if block_given?
|
90
|
+
link_to('javascript:void(0)', class: 'link-to-remove text-danger-emphasis', title: 'Quitar',
|
91
|
+
data: { controller: 'nested', action: 'nested#quitar' }, &)
|
92
|
+
elsif text.present?
|
93
|
+
link_to text, 'javascript:void(0)', class: 'link-to-remove text-danger-emphasis', title: 'Quitar',
|
94
|
+
data: { controller: 'nested', action: 'nested#quitar' }
|
95
|
+
else
|
96
|
+
link_to 'javascript:void(0)', class: 'link-to-remove text-danger-emphasis', title: 'Quitar',
|
97
|
+
data: { controller: 'nested', action: 'nested#quitar' } do
|
98
|
+
'<i class="bi bi-x-lg"></i>'.html_safe
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
32
102
|
end
|
33
103
|
end
|
@@ -18,7 +18,7 @@ module PgEngine
|
|
18
18
|
|
19
19
|
def self.namespace(context)
|
20
20
|
req = request(context)
|
21
|
-
route = Rails.application.routes.recognize_path(req.path)
|
21
|
+
route = Rails.application.routes.recognize_path(req.path, method: req.env['REQUEST_METHOD'])
|
22
22
|
parts = route[:controller].split('/')
|
23
23
|
return unless parts.length > 1
|
24
24
|
|
@@ -32,12 +32,20 @@ module PgEngine
|
|
32
32
|
NamespaceDeductor.namespace(self)
|
33
33
|
end
|
34
34
|
|
35
|
-
def namespaced_path(object,
|
35
|
+
def namespaced_path(object, options = {})
|
36
36
|
target = [pg_namespace, object]
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
|
38
|
+
if options[:prefix]
|
39
|
+
target.prepend options[:prefix]
|
40
|
+
options.delete(:prefix)
|
41
|
+
end
|
42
|
+
|
43
|
+
if options[:suffix]
|
44
|
+
target.append options[:suffix]
|
45
|
+
options.delete(:suffix)
|
46
|
+
end
|
47
|
+
|
48
|
+
polymorphic_url(target.flatten.compact, options.merge(only_path: true))
|
41
49
|
end
|
42
50
|
end
|
43
51
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
/ # locals: (object: nil, asociable: false)
|
2
2
|
|
3
|
-
div style="max-width:
|
3
|
+
div style="max-width: 22em"
|
4
4
|
= pg_form_for(@user_account || object) do |f|
|
5
5
|
= f.mensajes_de_error
|
6
6
|
|
7
7
|
= hidden_field_tag :asociable, true if asociable
|
8
|
-
= f.
|
9
|
-
= f.
|
8
|
+
= f.pg_associable :user
|
9
|
+
= f.pg_associable :account
|
10
10
|
= f.input :profiles
|
11
11
|
.mt-2
|
12
12
|
= f.button :submit
|
@@ -9,8 +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.
|
13
|
-
.d-flex.align-items-center
|
12
|
+
.collapse.border-bottom#filtros class="#{ 'show' if any_filter? }"
|
13
|
+
.d-flex.align-items-center.p-2
|
14
14
|
.px-2.d-none.d-sm-inline-block
|
15
15
|
span.bi.bi-funnel-fill
|
16
16
|
= form_tag nil, class: '', method: :get do
|
@@ -20,7 +20,7 @@
|
|
20
20
|
= button_tag class: 'btn btn-sm btn-primary col-auto' do
|
21
21
|
span.bi.bi-search
|
22
22
|
.col-auto
|
23
|
-
= link_to namespaced_path(@clase_modelo),
|
23
|
+
= link_to namespaced_path(@clase_modelo, clean: true),
|
24
24
|
class: 'btn btn-sm btn-secondary col-auto' do
|
25
25
|
| Limpiar
|
26
26
|
|
@@ -34,10 +34,7 @@ ActiveAdmin.setup do |config|
|
|
34
34
|
# File.join(Rails.root, 'app', 'admin'),
|
35
35
|
# File.join(Rails.root, 'app', 'cashier')
|
36
36
|
# ]
|
37
|
-
config.load_paths
|
38
|
-
File.join(Rails.root, 'app', 'admin'),
|
39
|
-
File.join(PgEngine::Engine.root, 'app', 'admin')
|
40
|
-
]
|
37
|
+
config.load_paths.push(File.join(PgEngine::Engine.root, 'app', 'admin'))
|
41
38
|
# == Default Namespace
|
42
39
|
#
|
43
40
|
# Set the default namespace each administration resource
|
@@ -46,7 +46,7 @@ SimpleForm.setup do |config|
|
|
46
46
|
# vertical forms
|
47
47
|
#
|
48
48
|
# vertical default_wrapper
|
49
|
-
|
49
|
+
control_wrapper = lambda do |b|
|
50
50
|
b.use :html5
|
51
51
|
b.use :placeholder
|
52
52
|
b.optional :maxlength
|
@@ -60,6 +60,21 @@ SimpleForm.setup do |config|
|
|
60
60
|
b.use :hint, wrap_with: { class: 'form-text' }
|
61
61
|
end
|
62
62
|
|
63
|
+
select_wrapper = lambda do |b|
|
64
|
+
b.use :html5
|
65
|
+
b.optional :readonly
|
66
|
+
b.use :label, class: 'form-label'
|
67
|
+
b.use :input, class: 'form-select', error_class: 'is-invalid'
|
68
|
+
b.use :full_error, wrap_with: { class: 'invalid-feedback' }
|
69
|
+
b.use :hint, wrap_with: { class: 'form-text' }
|
70
|
+
end
|
71
|
+
|
72
|
+
config.wrappers :vertical_no_margin_control, &control_wrapper
|
73
|
+
|
74
|
+
config.wrappers :vertical_no_margin_select, &select_wrapper
|
75
|
+
|
76
|
+
config.wrappers :vertical_form, class: 'mb-3', &control_wrapper
|
77
|
+
|
63
78
|
# vertical input for boolean
|
64
79
|
config.wrappers :vertical_boolean, tag: 'fieldset', class: 'mb-3' do |b|
|
65
80
|
b.use :html5
|
@@ -112,14 +127,7 @@ SimpleForm.setup do |config|
|
|
112
127
|
end
|
113
128
|
|
114
129
|
# vertical select input
|
115
|
-
config.wrappers :vertical_select, class: 'mb-3'
|
116
|
-
b.use :html5
|
117
|
-
b.optional :readonly
|
118
|
-
b.use :label, class: 'form-label'
|
119
|
-
b.use :input, class: 'form-select', error_class: 'is-invalid'
|
120
|
-
b.use :full_error, wrap_with: { class: 'invalid-feedback' }
|
121
|
-
b.use :hint, wrap_with: { class: 'form-text' }
|
122
|
-
end
|
130
|
+
config.wrappers :vertical_select, class: 'mb-3', &select_wrapper
|
123
131
|
|
124
132
|
# vertical multi select
|
125
133
|
config.wrappers :vertical_multi_select, class: 'mb-3' do |b|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# This migration comes from active_storage (originally 20170806125915)
|
2
|
+
class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
|
3
|
+
def change
|
4
|
+
# Use Active Record's configured type for primary and foreign keys
|
5
|
+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
6
|
+
|
7
|
+
create_table :active_storage_blobs, id: primary_key_type do |t|
|
8
|
+
t.string :key, null: false
|
9
|
+
t.string :filename, null: false
|
10
|
+
t.string :content_type
|
11
|
+
t.text :metadata
|
12
|
+
t.string :service_name, null: false
|
13
|
+
t.bigint :byte_size, null: false
|
14
|
+
t.string :checksum
|
15
|
+
|
16
|
+
if connection.supports_datetime_with_precision?
|
17
|
+
t.datetime :created_at, precision: 6, null: false
|
18
|
+
else
|
19
|
+
t.datetime :created_at, null: false
|
20
|
+
end
|
21
|
+
|
22
|
+
t.index [ :key ], unique: true
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table :active_storage_attachments, id: primary_key_type do |t|
|
26
|
+
t.string :name, null: false
|
27
|
+
t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
|
28
|
+
t.references :blob, null: false, type: foreign_key_type
|
29
|
+
|
30
|
+
if connection.supports_datetime_with_precision?
|
31
|
+
t.datetime :created_at, precision: 6, null: false
|
32
|
+
else
|
33
|
+
t.datetime :created_at, null: false
|
34
|
+
end
|
35
|
+
|
36
|
+
t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
|
37
|
+
t.foreign_key :active_storage_blobs, column: :blob_id
|
38
|
+
end
|
39
|
+
|
40
|
+
create_table :active_storage_variant_records, id: primary_key_type do |t|
|
41
|
+
t.belongs_to :blob, null: false, index: false, type: foreign_key_type
|
42
|
+
t.string :variation_digest, null: false
|
43
|
+
|
44
|
+
t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
|
45
|
+
t.foreign_key :active_storage_blobs, column: :blob_id
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def primary_and_foreign_key_types
|
51
|
+
config = Rails.configuration.generators
|
52
|
+
setting = config.options[config.orm][:primary_key_type]
|
53
|
+
primary_key_type = setting || :primary_key
|
54
|
+
foreign_key_type = setting || :bigint
|
55
|
+
[primary_key_type, foreign_key_type]
|
56
|
+
end
|
57
|
+
end
|
data/pg_engine/db/seeds.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
DatabaseCleaner.clean_with(:truncation, except: %w(ar_internal_metadata users accounts user_accounts))
|
2
|
+
|
3
|
+
MAIL = 'mrosso10@gmail.com'
|
4
|
+
|
5
|
+
unless User.where(email: MAIL).exists?
|
6
|
+
FactoryBot.create :user, email: MAIL, password: 'admin123',
|
7
|
+
confirmed_at: Time.now, developer: true
|
5
8
|
end
|
@@ -14,7 +14,7 @@ module PgEngine
|
|
14
14
|
end
|
15
15
|
|
16
16
|
if Rails.env.local?
|
17
|
-
initializer '
|
17
|
+
initializer 'pg_engine.set_factory_paths', after: 'factory_bot.set_factory_paths' do
|
18
18
|
# Para que tome las factories de pg_engine/spec/factories
|
19
19
|
# además de las de dummy/spec/factories
|
20
20
|
FactoryBot.definition_file_paths << "#{root}/spec/factories"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'English'
|
2
|
+
|
3
|
+
module PgEngine
|
4
|
+
class PdfPreviewGenerator
|
5
|
+
def open_tempfile
|
6
|
+
tempfile = Tempfile.open('PgEnginePdfPreview-', 'tmp')
|
7
|
+
|
8
|
+
begin
|
9
|
+
yield tempfile
|
10
|
+
ensure
|
11
|
+
tempfile.close
|
12
|
+
tempfile.unlink
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def capture(*argv, to:)
|
17
|
+
to.binmode
|
18
|
+
|
19
|
+
open_tempfile do |err|
|
20
|
+
IO.popen(argv, err:) { |out| IO.copy_stream(out, to) }
|
21
|
+
err.rewind
|
22
|
+
|
23
|
+
unless $CHILD_STATUS.success?
|
24
|
+
raise "#{argv.first} failed (status #{$CHILD_STATUS.exitstatus}): #{err.read.to_s.chomp}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
to.rewind
|
29
|
+
end
|
30
|
+
|
31
|
+
def draw(*argv)
|
32
|
+
open_tempfile do |file|
|
33
|
+
capture(*argv, to: file)
|
34
|
+
|
35
|
+
yield file
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def run(pdf_string)
|
40
|
+
open_tempfile do |tmp_pdf_file|
|
41
|
+
tmp_pdf_file.binmode
|
42
|
+
tmp_pdf_file.write pdf_string
|
43
|
+
tmp_pdf_file.close
|
44
|
+
draw 'pdftoppm', '-singlefile', '-cropbox', '-r', '72', '-png', tmp_pdf_file.path do |file|
|
45
|
+
return file.read
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/pg_engine/lib/pg_engine.rb
CHANGED
@@ -5,6 +5,9 @@ require_relative 'pg_engine/core_ext'
|
|
5
5
|
require_relative 'pg_engine/configuracion'
|
6
6
|
require_relative 'pg_engine/route_helpers'
|
7
7
|
require_relative 'pg_engine/utils/pg_logger'
|
8
|
+
require_relative 'pg_engine/utils/pdf_preview_generator'
|
9
|
+
|
10
|
+
require_relative '../app/helpers/pg_engine/print_helper'
|
8
11
|
|
9
12
|
module PgEngine
|
10
13
|
class << self
|
@@ -11,7 +11,7 @@ if Rails.env.development?
|
|
11
11
|
'additional_file_patterns' => [],
|
12
12
|
'routes' => 'true',
|
13
13
|
'models' => 'true',
|
14
|
-
'position_in_routes' => '
|
14
|
+
'position_in_routes' => 'after',
|
15
15
|
'position_in_class' => 'before',
|
16
16
|
'position_in_test' => 'before',
|
17
17
|
'position_in_fixture' => 'before',
|
Binary file
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe PgEngine::PdfPreviewGenerator do
|
4
|
+
let(:pdf_string) { File.read("#{PgEngine::Engine.root}/spec/fixtures/test.pdf") }
|
5
|
+
let(:instancia) { described_class.new }
|
6
|
+
|
7
|
+
describe '#run' do
|
8
|
+
subject { instancia.run(pdf_string) }
|
9
|
+
|
10
|
+
it { is_expected.to be_a String }
|
11
|
+
end
|
12
|
+
end
|
@@ -54,6 +54,7 @@ $chevron-color: 200,200,200,.5;
|
|
54
54
|
font-weight: bold;
|
55
55
|
--bs-link-color-rgb: white!important;
|
56
56
|
}
|
57
|
+
// Los small-items están deprecados
|
57
58
|
#sidebar {
|
58
59
|
&.opened {
|
59
60
|
.sidebar--small-items {
|
@@ -68,7 +69,7 @@ $chevron-color: 200,200,200,.5;
|
|
68
69
|
display: block;
|
69
70
|
}
|
70
71
|
.sidebar--large-items {
|
71
|
-
display: none;
|
72
|
+
// display: none;
|
72
73
|
}
|
73
74
|
}
|
74
75
|
}
|
@@ -84,11 +85,18 @@ $chevron-color: 200,200,200,.5;
|
|
84
85
|
// display: none!important;
|
85
86
|
flex-basis: 0px;
|
86
87
|
transition: flex-basis 0.5s;
|
88
|
+
|
89
|
+
// Para que al cerrar y abrir no se vean los textos por fuera de la sidebar
|
90
|
+
clip-path: inset(0 0 0 0);
|
87
91
|
// flex-grow: 1;
|
88
92
|
|
89
93
|
&.opened {
|
90
94
|
// display: block!important;
|
91
|
-
flex-basis:
|
95
|
+
flex-basis: 9em;
|
96
|
+
}
|
97
|
+
& > * {
|
98
|
+
width: 9em;
|
99
|
+
position:fixed;
|
92
100
|
}
|
93
101
|
}
|
94
102
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
connect () {
|
5
|
+
this.showRemove()
|
6
|
+
}
|
7
|
+
|
8
|
+
addItem () {
|
9
|
+
// Save a unique timestamp to ensure the key of the associated array is unique.
|
10
|
+
const time = new Date().getTime()
|
11
|
+
// Save the data id attribute into a variable. This corresponds to `new_object.object_id`.
|
12
|
+
const linkId = this.element.dataset.id
|
13
|
+
// Create a new regular expression needed to find any instance of the `new_object.object_id` used in the fields data attribute if there's a value in `linkId`.
|
14
|
+
const regexp = linkId ? new RegExp(linkId, 'g') : null
|
15
|
+
// Replace all instances of the `new_object.object_id` with `time`, and save markup into a variable if there's a value in `regexp`.
|
16
|
+
const newFields = regexp ? this.element.dataset.fields.replace(regexp, time) : null
|
17
|
+
// Add the new markup to the form if there are fields to add.
|
18
|
+
if (newFields) {
|
19
|
+
this.element.insertAdjacentHTML('beforebegin', newFields)
|
20
|
+
}
|
21
|
+
this.element.closest('form').dispatchEvent(new Event('nestedField:added'))
|
22
|
+
this.showRemove()
|
23
|
+
}
|
24
|
+
|
25
|
+
quitar () {
|
26
|
+
const parent = this.element.closest('.nested-fields')
|
27
|
+
parent.style.display = 'none'
|
28
|
+
parent.classList.add('removed')
|
29
|
+
parent.querySelector('[name*=destroy]').value = 'true'
|
30
|
+
this.element.closest('form').dispatchEvent(new Event('nestedField:removed'))
|
31
|
+
this.showRemove()
|
32
|
+
}
|
33
|
+
|
34
|
+
showRemove () {
|
35
|
+
const container = this.element.closest('.nested-container')
|
36
|
+
if (container.dataset.required === 'true') {
|
37
|
+
if (container.querySelectorAll('.nested-fields:not(.removed)').length === 1) {
|
38
|
+
container.querySelectorAll('.link-to-remove').forEach((e) => {
|
39
|
+
e.style.visibility = 'hidden'
|
40
|
+
})
|
41
|
+
} else {
|
42
|
+
container.querySelectorAll('.link-to-remove').forEach((e) => {
|
43
|
+
e.style.visibility = ''
|
44
|
+
})
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|