pg_rails 7.0.8.pre.alpha.13 → 7.0.8.pre.alpha.15
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/controllers/admin/accounts_controller.rb +2 -0
- data/pg_engine/app/controllers/admin/user_accounts_controller.rb +2 -0
- data/pg_engine/app/controllers/admin/users_controller.rb +2 -0
- data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +8 -3
- data/pg_engine/app/controllers/pg_engine/base_controller.rb +8 -7
- data/pg_engine/app/helpers/pg_engine/pg_rails_helper.rb +23 -0
- data/pg_engine/app/models/user.rb +18 -3
- data/pg_engine/config/initializers/anycable.rb +13 -0
- data/pg_engine/config/initializers/cable_ready.rb +29 -0
- data/pg_engine/config/initializers/rollbar.rb +78 -0
- data/pg_engine/db/seeds.rb +1 -1
- data/pg_engine/lib/pg_engine/error.rb +4 -0
- data/pg_engine/lib/pg_engine/utils/pg_logger.rb +76 -25
- data/pg_engine/lib/pg_engine.rb +1 -0
- data/pg_engine/lib/tasks/auto_anotar_modelos.rake +1 -3
- data/pg_engine/spec/controllers/admin/user_accounts_controller_spec.rb +2 -2
- data/pg_engine/spec/controllers/concerns/pg_engine/resource_helper_spec.rb +67 -0
- data/pg_engine/spec/factories/users.rb +1 -8
- data/pg_engine/spec/helpers/pg_engine/pg_rails_helper_spec.rb +38 -0
- data/pg_engine/spec/lib/pg_engine/utils/pg_engine/pg_logger_spec.rb +104 -0
- data/pg_engine/spec/models/user_spec.rb +39 -0
- data/pg_layout/app/assets/stylesheets/animations.scss +30 -0
- data/pg_layout/{index.js → app/javascript/application.js} +6 -10
- data/pg_layout/app/javascript/channels/consumer.js +8 -0
- data/pg_layout/app/javascript/channels/index.js +4 -0
- data/pg_layout/app/javascript/config/cable_ready.js +24 -0
- data/pg_layout/app/javascript/config/index.js +1 -0
- data/pg_layout/app/javascript/controllers/application.js +4 -0
- data/pg_layout/app/javascript/controllers/fadein_onload_controller.js +20 -0
- data/pg_layout/app/javascript/controllers/index.js +11 -0
- data/pg_layout/app/javascript/{navbar_controller.js → controllers/navbar_controller.js} +1 -1
- data/pg_layout/app/javascript/utils/utils.ts +43 -0
- data/pg_layout/app/views/layouts/pg_layout/devise.html.slim +2 -1
- data/pg_layout/app/views/layouts/pg_layout/layout.html.slim +6 -1
- data/pg_layout/app/views/pg_layout/_flash.html.slim +2 -0
- data/pg_layout/app/views/pg_layout/_rollbar.html.erb +28 -0
- data/pg_rails/js/index.js +1 -1
- data/pg_rails/lib/pg_rails/vcr_support.rb +28 -0
- data/pg_rails/lib/version.rb +1 -1
- data/pg_rails/scss/pg_rails.scss +1 -0
- data/pg_scaffold/lib/generators/pg_scaffold/templates/controller.rb +2 -0
- data/pg_scaffold/spec/generators_spec.rb +1 -1
- metadata +26 -9
- data/pg_layout/app/javascript/utils.ts +0 -19
- /data/pg_engine/spec/{controllers/concerns → lib}/pg_engine/error_helper_spec.rb +0 -0
- /data/pg_layout/app/javascript/{nested_controller.js → controllers/nested_controller.js} +0 -0
- /data/pg_layout/app/javascript/{pg_form_controller.js → controllers/pg_form_controller.js} +0 -0
- /data/pg_layout/app/javascript/{cookies.js → utils/cookies.js} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 917b686081345cf1d79fb59f3d05a3d288f71f6a9ac223cfa40100a5e897b1c3
|
4
|
+
data.tar.gz: c21bd06ca22bbabf0701fe3450c09e034d037b7fad3d4bddf4dd6fbd748f6c8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac9c3923a030194773608e8c1231b20044b835aed08b4d9e45705828de5dee18bd770f5736b1525044f0e8da7144ae210552ac5c4f475dea8f4e2e40d2ea4a9c
|
7
|
+
data.tar.gz: cf395aec16915d30e753bebe8120f8ee9255c8bcd8631b621b72bb12622a94aa26b9aa8e09cabce2d6990a6829e87695d946b1a7af7ce8443dcffd689fd40c83
|
@@ -210,7 +210,7 @@ module PgEngine
|
|
210
210
|
def buscar_instancia
|
211
211
|
if Object.const_defined?('FriendlyId') && @clase_modelo.is_a?(FriendlyId)
|
212
212
|
@clase_modelo.friendly.find(params[:id])
|
213
|
-
elsif @clase_modelo.respond_to? :find_by_hashid
|
213
|
+
elsif @clase_modelo.respond_to? :find_by_hashid!
|
214
214
|
# rubocop:disable Rails/DynamicFindBy
|
215
215
|
@clase_modelo.find_by_hashid!(params[:id])
|
216
216
|
# rubocop:enable Rails/DynamicFindBy
|
@@ -272,8 +272,13 @@ module PgEngine
|
|
272
272
|
end
|
273
273
|
|
274
274
|
def do_sort(scope, field, direction)
|
275
|
+
# TODO: restringir ciertos campos?
|
275
276
|
unless scope.model.column_names.include? field.to_s
|
276
|
-
PgLogger.
|
277
|
+
PgLogger.warn("No existe el campo \"#{field}\"", :warn)
|
278
|
+
return scope
|
279
|
+
end
|
280
|
+
unless direction.to_sym.in? %i[asc desc]
|
281
|
+
PgLogger.warn("Direction not valid: \"#{direction}\"", :warn)
|
277
282
|
return scope
|
278
283
|
end
|
279
284
|
scope = scope.order(field => direction)
|
@@ -281,7 +286,7 @@ module PgEngine
|
|
281
286
|
instance_variable_set(:@direction, direction)
|
282
287
|
scope
|
283
288
|
rescue ArgumentError => e
|
284
|
-
PgLogger.
|
289
|
+
PgLogger.warn(e, :warn)
|
285
290
|
scope
|
286
291
|
end
|
287
292
|
|
@@ -40,13 +40,14 @@ module PgEngine
|
|
40
40
|
|
41
41
|
protected
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
43
|
+
# TODO: ver qué pasa en producción
|
44
|
+
# def default_url_options(options = {})
|
45
|
+
# if Rails.env.production?
|
46
|
+
# options.merge(protocol: 'https')
|
47
|
+
# else
|
48
|
+
# options
|
49
|
+
# end
|
50
|
+
# end
|
50
51
|
|
51
52
|
def fecha_invalida
|
52
53
|
respond_to do |format|
|
@@ -7,5 +7,28 @@ module PgEngine
|
|
7
7
|
def current_account
|
8
8
|
current_user&.current_account
|
9
9
|
end
|
10
|
+
|
11
|
+
def img_placeholder(src: nil, width: '100%', height: '100%', fade_in: false, **img_opts)
|
12
|
+
if fade_in || src.nil?
|
13
|
+
img_opts = img_opts.merge(style: [img_opts[:style], 'display:none'].compact.join(';'))
|
14
|
+
do_placeholder(src, width:, height:, **img_opts)
|
15
|
+
else
|
16
|
+
image_tag src, **img_opts
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def do_placeholder(src = nil, width: '100%', height: '100%', **img_opts)
|
23
|
+
content_tag('div', class: 'placeholder-glow', style: "width: #{width}; height: #{height}") do
|
24
|
+
content_tag('div', class: 'placeholder w-100 h-100') do
|
25
|
+
if src.present?
|
26
|
+
image_tag src,
|
27
|
+
'data-controller': 'fadein_onload',
|
28
|
+
**img_opts
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
10
33
|
end
|
11
34
|
end
|
@@ -27,10 +27,8 @@
|
|
27
27
|
# created_at :datetime not null
|
28
28
|
# updated_at :datetime not null
|
29
29
|
#
|
30
|
-
class User < ApplicationRecord
|
31
|
-
# ApplicationRecord should be defined on Application
|
32
30
|
|
33
|
-
|
31
|
+
class User < ApplicationRecord
|
34
32
|
devise :database_authenticatable, :registerable,
|
35
33
|
:recoverable, :rememberable,
|
36
34
|
:lockable, :timeoutable, :trackable, :confirmable
|
@@ -51,6 +49,19 @@ class User < ApplicationRecord
|
|
51
49
|
validates_length_of :password, if: :password_required?, within: 6..128,
|
52
50
|
message: 'es demasiado corta (6 caracteres mínimo)'
|
53
51
|
|
52
|
+
attr_accessor :orphan
|
53
|
+
|
54
|
+
after_create do
|
55
|
+
# TODO: si fue invitado, sumar a la account del invitador
|
56
|
+
create_account unless orphan
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_account
|
60
|
+
account = Account.create(nombre: email, plan: 0)
|
61
|
+
ua = user_accounts.create(account:)
|
62
|
+
raise(ActiveRecord::Rollback) unless ua.persisted?
|
63
|
+
end
|
64
|
+
|
54
65
|
def password_required?
|
55
66
|
!persisted? || !password.nil? || !password_confirmation.nil?
|
56
67
|
end
|
@@ -65,7 +76,11 @@ class User < ApplicationRecord
|
|
65
76
|
"#{nombre} #{apellido}"
|
66
77
|
end
|
67
78
|
|
79
|
+
class Error < StandardError; end
|
80
|
+
|
68
81
|
def current_account
|
82
|
+
raise Error, 'El usuario debe tener cuenta' if accounts.empty?
|
83
|
+
|
69
84
|
accounts.first
|
70
85
|
end
|
71
86
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Add Warden middleware to AnyCable stack to allow accessing
|
4
|
+
# Devise current user via `env["warden"].user`.
|
5
|
+
#
|
6
|
+
# See https://docs.anycable.io/ruby/authentication
|
7
|
+
#
|
8
|
+
# NOTE: This is only needed in environments where you use AnyCable.
|
9
|
+
if defined?(AnyCable::Rails)
|
10
|
+
AnyCable::Rails::Rack.middleware.use Warden::Manager do |config|
|
11
|
+
Devise.warden_config = config
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Dotenv.load
|
3
|
+
|
4
|
+
CableReady.configure do |config|
|
5
|
+
# Enable/disable exiting / warning when the sanity checks fail options:
|
6
|
+
# `:exit` or `:warn` or `:ignore`
|
7
|
+
#
|
8
|
+
# config.on_failed_sanity_checks = :exit
|
9
|
+
|
10
|
+
# Enable/disable assets compilation
|
11
|
+
# `true` or `false`
|
12
|
+
#
|
13
|
+
# config.precompile_assets = true
|
14
|
+
|
15
|
+
# Define your own custom operations
|
16
|
+
# https://cableready.stimulusreflex.com/customization#custom-operations
|
17
|
+
#
|
18
|
+
# config.add_operation_name :jazz_hands
|
19
|
+
|
20
|
+
# Change the default Active Job queue used for broadcast_later and broadcast_later_to
|
21
|
+
#
|
22
|
+
# config.broadcast_job_queue = :default
|
23
|
+
|
24
|
+
# Specify a default debounce time for CableReady::Updatable callbacks
|
25
|
+
# Doing so is a best practice to avoid heavy ActionCable traffic
|
26
|
+
#
|
27
|
+
# config.updatable_debounce_time = 0.1.seconds
|
28
|
+
config.verifier_key = ENV.fetch('ANYCABLE_CABLE_READY_KEY')
|
29
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
Rollbar.configure do |config|
|
2
|
+
# Without configuration, Rollbar is enabled in all environments.
|
3
|
+
# To disable in specific environments, set config.enabled=false.
|
4
|
+
|
5
|
+
config.access_token = ENV['ROLLBAR_ACCESS_TOKEN']
|
6
|
+
|
7
|
+
# Here we'll disable in 'test':
|
8
|
+
if Rails.env.test?
|
9
|
+
config.enabled = false
|
10
|
+
end
|
11
|
+
|
12
|
+
# By default, Rollbar will try to call the `current_user` controller method
|
13
|
+
# to fetch the logged-in user object, and then call that object's `id`
|
14
|
+
# method to fetch this property. To customize:
|
15
|
+
# config.person_method = "my_current_user"
|
16
|
+
# config.person_id_method = "my_id"
|
17
|
+
|
18
|
+
# Additionally, you may specify the following:
|
19
|
+
# config.person_username_method = "username"
|
20
|
+
# config.person_email_method = "email"
|
21
|
+
|
22
|
+
# If you want to attach custom data to all exception and message reports,
|
23
|
+
# provide a lambda like the following. It should return a hash.
|
24
|
+
# config.custom_data_method = lambda { {:some_key => "some_value" } }
|
25
|
+
|
26
|
+
# Add exception class names to the exception_level_filters hash to
|
27
|
+
# change the level that exception is reported at. Note that if an exception
|
28
|
+
# has already been reported and logged the level will need to be changed
|
29
|
+
# via the rollbar interface.
|
30
|
+
# Valid levels: 'critical', 'error', 'warning', 'info', 'debug', 'ignore'
|
31
|
+
# 'ignore' will cause the exception to not be reported at all.
|
32
|
+
# config.exception_level_filters.merge!('MyCriticalException' => 'critical')
|
33
|
+
#
|
34
|
+
# You can also specify a callable, which will be called with the exception instance.
|
35
|
+
# config.exception_level_filters.merge!('MyCriticalException' => lambda { |e| 'critical' })
|
36
|
+
|
37
|
+
config.exception_level_filters.merge!({
|
38
|
+
'ActionController::RoutingError' => 'ignore',
|
39
|
+
'ActionDispatch::Http::MimeNegotiation::InvalidType' => 'ignore',
|
40
|
+
'MailDeliveryTemporalError' => 'warning',
|
41
|
+
})
|
42
|
+
|
43
|
+
|
44
|
+
# Enable asynchronous reporting (uses girl_friday or Threading if girl_friday
|
45
|
+
# is not installed)
|
46
|
+
# config.use_async = true
|
47
|
+
# Supply your own async handler:
|
48
|
+
# config.async_handler = Proc.new { |payload|
|
49
|
+
# Thread.new { Rollbar.process_from_async_handler(payload) }
|
50
|
+
# }
|
51
|
+
|
52
|
+
# Enable asynchronous reporting (using sucker_punch)
|
53
|
+
# config.use_sucker_punch
|
54
|
+
|
55
|
+
# Enable delayed reporting (using Sidekiq)
|
56
|
+
# config.use_sidekiq
|
57
|
+
# You can supply custom Sidekiq options:
|
58
|
+
# config.use_sidekiq 'queue' => 'default'
|
59
|
+
|
60
|
+
# If your application runs behind a proxy server, you can set proxy parameters here.
|
61
|
+
# If https_proxy is set in your environment, that will be used. Settings here have precedence.
|
62
|
+
# The :host key is mandatory and must include the URL scheme (e.g. 'http://'), all other fields
|
63
|
+
# are optional.
|
64
|
+
#
|
65
|
+
# config.proxy = {
|
66
|
+
# host: 'http://some.proxy.server',
|
67
|
+
# port: 80,
|
68
|
+
# user: 'username_if_auth_required',
|
69
|
+
# password: 'password_if_auth_required'
|
70
|
+
# }
|
71
|
+
|
72
|
+
# If you run your staging application instance in production environment then
|
73
|
+
# you'll want to override the environment reported by `Rails.env` with an
|
74
|
+
# environment variable like this: `ROLLBAR_ENV=staging`. This is a recommended
|
75
|
+
# setup for Heroku. See:
|
76
|
+
# https://devcenter.heroku.com/articles/deploying-to-a-custom-rails-environment
|
77
|
+
config.environment = ENV['ROLLBAR_ENV'].presence || Rails.env
|
78
|
+
end
|
data/pg_engine/db/seeds.rb
CHANGED
@@ -2,42 +2,93 @@
|
|
2
2
|
|
3
3
|
require 'rainbow'
|
4
4
|
|
5
|
+
# TODO: poder pasar blocks
|
6
|
+
|
7
|
+
def pg_err(obj)
|
8
|
+
PgEngine::PgLogger.error(obj)
|
9
|
+
end
|
10
|
+
|
11
|
+
def pg_warn(obj, type = :error)
|
12
|
+
PgEngine::PgLogger.warn(obj, type)
|
13
|
+
end
|
14
|
+
|
15
|
+
def pg_log(obj, type = :debug)
|
16
|
+
PgEngine::PgLogger.warn("#{obj.inspect} (#{obj.class})", type)
|
17
|
+
end
|
18
|
+
|
5
19
|
module PgEngine
|
6
20
|
class PgLogger
|
7
21
|
class << self
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
22
|
+
# DEPRECATED
|
23
|
+
# Muestro el caller[1] para saber dónde se llamó a la función deprecada
|
24
|
+
# def deprecated(mensaje)
|
25
|
+
# titulo = Rainbow(" WARNING en #{caller[1]}").yellow.bold
|
26
|
+
# detalles = Rainbow(" #{mensaje}").yellow
|
27
|
+
# Rails.logger.warn("#{titulo}\n#{detalles}")
|
28
|
+
# Rollbar.warning("#{mensaje}\n\n#{caller.join("\n")}")
|
29
|
+
# end
|
30
|
+
|
31
|
+
def error(obj)
|
32
|
+
# TODO: arreglar
|
33
|
+
# Si es dev o test lanzo el error y si no, lo logueo para que no le salte al usuario
|
34
|
+
# raise obj if Rails.env.local? && ENV.fetch('RAISE_ERRORS', nil).present?
|
35
|
+
|
36
|
+
mensaje = if obj.is_a?(Exception) && obj.backtrace.present?
|
37
|
+
"#{obj.inspect}\nBacktrace:\n#{cleaner.clean(obj.backtrace).join("\n")}"
|
38
|
+
else
|
39
|
+
obj
|
40
|
+
end
|
41
|
+
notify(mensaje, :error)
|
42
|
+
end
|
43
|
+
|
44
|
+
def warn(obj, type = :error)
|
45
|
+
mensaje = if obj.is_a?(Exception) && obj.backtrace.present?
|
46
|
+
"#{obj.inspect}\nBacktrace:\n#{cleaner.clean(obj.backtrace).join("\n")}"
|
47
|
+
else
|
48
|
+
obj
|
49
|
+
end
|
50
|
+
notify(mensaje, type)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def notify(mensaje, type)
|
56
|
+
Rails.logger.send(type, titulo(mensaje, type))
|
57
|
+
Rails.logger.send(type, detalles(type))
|
58
|
+
Rollbar.send(type, "#{mensaje}\n\n#{bktrc.join("\n")}")
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def titulo(mensaje, type)
|
63
|
+
Rainbow("#{type.to_s.upcase}: #{mensaje}").bold.send(color_for(type))
|
13
64
|
end
|
14
65
|
|
15
|
-
def
|
16
|
-
|
17
|
-
detalles = Rainbow(" #{exception.message}").red
|
18
|
-
Rails.logger.error("#{titulo}\n#{detalles}")
|
19
|
-
Rollbar.error(exception)
|
66
|
+
def detalles(type)
|
67
|
+
Rainbow(" called in #{bktrc[0]}").send(color_for(type))
|
20
68
|
end
|
21
69
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
70
|
+
def cleaner
|
71
|
+
bc = ActiveSupport::BacktraceCleaner.new
|
72
|
+
bc.add_filter { |line| line.gsub(%r{.*pg_rails/}, '') }
|
73
|
+
bc.add_silencer { |line| /pg_logger/.match?(line) }
|
74
|
+
bc
|
27
75
|
end
|
28
76
|
|
29
|
-
def
|
30
|
-
|
31
|
-
detalles = Rainbow(" #{mensaje}").yellow
|
32
|
-
Rails.logger.warn("#{titulo}\n#{detalles}")
|
33
|
-
Rollbar.warning("#{mensaje}\n\n#{caller.join("\n")}")
|
77
|
+
def bktrc
|
78
|
+
cleaner.clean(caller)
|
34
79
|
end
|
35
80
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
81
|
+
def color_for(type)
|
82
|
+
case type
|
83
|
+
when :info
|
84
|
+
:blue
|
85
|
+
when :warn
|
86
|
+
:yellow
|
87
|
+
when :debug
|
88
|
+
:orange
|
89
|
+
else # :error
|
90
|
+
:red
|
91
|
+
end
|
41
92
|
end
|
42
93
|
end
|
43
94
|
end
|
data/pg_engine/lib/pg_engine.rb
CHANGED
@@ -6,7 +6,7 @@ Dotenv.load
|
|
6
6
|
model_paths = begin
|
7
7
|
JSON.parse(ENV['MODEL_PATHS'])
|
8
8
|
rescue JSON::ParserError
|
9
|
-
ENV['MODEL_PATHS']
|
9
|
+
ENV['MODEL_PATHS'] || 'app/models'
|
10
10
|
end
|
11
11
|
|
12
12
|
if Rails.env.development?
|
@@ -30,8 +30,6 @@ if Rails.env.development?
|
|
30
30
|
'show_indexes' => 'false',
|
31
31
|
'simple_indexes' => 'true',
|
32
32
|
'model_dir' => model_paths,
|
33
|
-
# 'model_dir' => ['app/models', 'app/overrides'],
|
34
|
-
# 'model_dir' => 'app/models',
|
35
33
|
'root_dir' => '',
|
36
34
|
'include_version' => 'false',
|
37
35
|
'require' => '',
|
@@ -29,9 +29,9 @@ require 'rails_helper'
|
|
29
29
|
|
30
30
|
RSpec.describe Admin::UserAccountsController do
|
31
31
|
render_views
|
32
|
-
let(:user) { create :
|
32
|
+
let!(:user) { create :user }
|
33
33
|
|
34
|
-
let(:account) { create :account }
|
34
|
+
let!(:account) { create :account }
|
35
35
|
|
36
36
|
# This should return the minimal set of attributes required to create a valid
|
37
37
|
# UserAccount. As you add validations to UserAccount, be sure to
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe PgEngine::Resource do
|
4
|
+
let(:instancia) { Admin::CategoriaDeCosasController.new }
|
5
|
+
|
6
|
+
describe '#buscar_instancia' do
|
7
|
+
subject do
|
8
|
+
instancia.send(:buscar_instancia)
|
9
|
+
end
|
10
|
+
|
11
|
+
let!(:categoria_de_cosa) { create :categoria_de_cosa }
|
12
|
+
let(:request) { double }
|
13
|
+
|
14
|
+
before do
|
15
|
+
allow(request).to receive_messages(filtered_parameters: { id: categoria_de_cosa.to_param },
|
16
|
+
parameters: { id: categoria_de_cosa.to_param })
|
17
|
+
allow(instancia).to receive(:request).and_return(request)
|
18
|
+
instancia.set_clase_modelo
|
19
|
+
end
|
20
|
+
|
21
|
+
it do
|
22
|
+
allow(CategoriaDeCosa).to receive(:find_by_hashid!)
|
23
|
+
subject
|
24
|
+
expect(CategoriaDeCosa).to have_received(:find_by_hashid!)
|
25
|
+
end
|
26
|
+
|
27
|
+
it do
|
28
|
+
expect(subject).to eq categoria_de_cosa
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#do_sort' do
|
33
|
+
subject do
|
34
|
+
instancia.send(:do_sort, scope, param, direction)
|
35
|
+
end
|
36
|
+
|
37
|
+
let!(:categoria_de_cosa_ult) { create :categoria_de_cosa, nombre: 'Z' }
|
38
|
+
let!(:categoria_de_cosa_pri) { create :categoria_de_cosa, nombre: 'a' }
|
39
|
+
let(:scope) { CategoriaDeCosa.all }
|
40
|
+
let(:param) { :nombre }
|
41
|
+
let(:direction) { :desc }
|
42
|
+
|
43
|
+
context 'asc' do
|
44
|
+
let(:direction) { :asc }
|
45
|
+
|
46
|
+
it do
|
47
|
+
expect(subject.to_a).to eq [categoria_de_cosa_pri, categoria_de_cosa_ult]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'desc' do
|
52
|
+
let(:direction) { :desc }
|
53
|
+
|
54
|
+
it do
|
55
|
+
expect(subject.to_a).to eq [categoria_de_cosa_ult, categoria_de_cosa_pri]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'cuando no existe el param' do
|
60
|
+
let(:param) { :inexistente }
|
61
|
+
|
62
|
+
it do
|
63
|
+
expect(subject.to_a).to eq [categoria_de_cosa_ult, categoria_de_cosa_pri]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -36,7 +36,7 @@
|
|
36
36
|
#
|
37
37
|
|
38
38
|
FactoryBot.define do
|
39
|
-
factory :
|
39
|
+
factory :user, class: 'User' do
|
40
40
|
nombre { Faker::Name.name }
|
41
41
|
apellido { Faker::Name.name }
|
42
42
|
email { Faker::Internet.email }
|
@@ -50,12 +50,5 @@ FactoryBot.define do
|
|
50
50
|
trait :developer do
|
51
51
|
developer { true }
|
52
52
|
end
|
53
|
-
|
54
|
-
factory :user do
|
55
|
-
after(:create) do |user, _context|
|
56
|
-
account = create :account
|
57
|
-
create :user_account, user:, account:
|
58
|
-
end
|
59
|
-
end
|
60
53
|
end
|
61
54
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
# rubocop:disable RSpec/ExampleLength
|
3
|
+
describe PgEngine::PgRailsHelper do
|
4
|
+
describe '#img_placeholder' do
|
5
|
+
it 'si no es fade_in' do
|
6
|
+
asd = img_placeholder(src: 'bla', fade_in: false, class: 'img-fluid', style: 'color:red')
|
7
|
+
expectation = <<~HTML
|
8
|
+
<img class="img-fluid" style="color:red" src="/images/bla" />
|
9
|
+
HTML
|
10
|
+
expect(asd).to eq expectation.split("\n").map(&:strip).join
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'si tiene style' do
|
14
|
+
asd = img_placeholder(src: 'bla', fade_in: true, class: 'img-fluid', style: 'color:red')
|
15
|
+
expectation = <<~HTML
|
16
|
+
<div class="placeholder-glow" style="width: 100%; height: 100%">
|
17
|
+
<div class="placeholder w-100 h-100">
|
18
|
+
<img data-controller="fadein_onload" class="img-fluid" style="color:red;display:none" src="/images/bla" />
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
HTML
|
22
|
+
expect(asd).to eq expectation.split("\n").map(&:strip).join
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'si no tiene style' do
|
26
|
+
asd = img_placeholder(src: 'bla', fade_in: true, class: 'img-fluid')
|
27
|
+
expectation = <<~HTML
|
28
|
+
<div class="placeholder-glow" style="width: 100%; height: 100%">
|
29
|
+
<div class="placeholder w-100 h-100">
|
30
|
+
<img data-controller="fadein_onload" class="img-fluid" style="display:none" src="/images/bla" />
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
HTML
|
34
|
+
expect(asd).to eq expectation.split("\n").map(&:strip).join
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
# rubocop:enable RSpec/ExampleLength
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
TYPES = %i[error warn info debug].freeze
|
4
|
+
|
5
|
+
describe PgEngine::PgLogger do
|
6
|
+
describe '#pg_err' do
|
7
|
+
before do
|
8
|
+
TYPES.each do |type|
|
9
|
+
allow(Rails.logger).to receive(type)
|
10
|
+
allow(Rollbar).to receive(type)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
shared_examples 'logger' do |type|
|
15
|
+
it do
|
16
|
+
expect(Rails.logger).to have_received(type).twice
|
17
|
+
end
|
18
|
+
|
19
|
+
it do
|
20
|
+
expect(Rollbar).to have_received(type).once
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'con string' do
|
25
|
+
before { pg_err('bla') }
|
26
|
+
|
27
|
+
it_behaves_like 'logger', :error
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'con exception' do
|
31
|
+
before do
|
32
|
+
raise StandardError, 'bla'
|
33
|
+
rescue StandardError => e
|
34
|
+
pg_err(e)
|
35
|
+
end
|
36
|
+
|
37
|
+
it_behaves_like 'logger', :error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#pg_warn' do
|
42
|
+
before do
|
43
|
+
TYPES.each do |type|
|
44
|
+
allow(Rails.logger).to receive(type)
|
45
|
+
allow(Rollbar).to receive(type)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
shared_examples 'logger' do |type|
|
50
|
+
it do
|
51
|
+
expect(Rails.logger).to have_received(type).twice
|
52
|
+
end
|
53
|
+
|
54
|
+
it do
|
55
|
+
expect(Rollbar).to have_received(type).once
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
TYPES.each do |type|
|
60
|
+
context "con type #{type}" do
|
61
|
+
before { pg_warn('bla', type) }
|
62
|
+
|
63
|
+
it_behaves_like 'logger', type
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'con exception' do
|
68
|
+
before do
|
69
|
+
raise StandardError, 'bla'
|
70
|
+
rescue StandardError => e
|
71
|
+
pg_warn(e)
|
72
|
+
end
|
73
|
+
|
74
|
+
it_behaves_like 'logger', :error
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#pg_log' do
|
79
|
+
before do
|
80
|
+
TYPES.each do |type|
|
81
|
+
allow(Rails.logger).to receive(type)
|
82
|
+
allow(Rollbar).to receive(type)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
shared_examples 'logger' do |type|
|
87
|
+
it do
|
88
|
+
expect(Rails.logger).to have_received(type).twice
|
89
|
+
end
|
90
|
+
|
91
|
+
it do
|
92
|
+
expect(Rollbar).to have_received(type).once
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
TYPES.each do |type|
|
97
|
+
context "con type #{type}" do
|
98
|
+
before { pg_log('bla', type) }
|
99
|
+
|
100
|
+
it_behaves_like 'logger', type
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -10,4 +10,43 @@ RSpec.describe User do
|
|
10
10
|
it 'se persiste' do
|
11
11
|
expect(user).to be_persisted
|
12
12
|
end
|
13
|
+
|
14
|
+
it do
|
15
|
+
expect(user.current_account).to be_present
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'si es orphan' do
|
19
|
+
let(:user) { create(:user, orphan: true) }
|
20
|
+
|
21
|
+
it do
|
22
|
+
expect(user.accounts).to be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it do
|
26
|
+
expect { user.current_account }.to raise_error(User::Error)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'Si falla la creación de cuenta, que rollbackee la transaction de create user' do
|
31
|
+
let(:user) do
|
32
|
+
build(:user)
|
33
|
+
end
|
34
|
+
|
35
|
+
before do
|
36
|
+
# rubocop:disable RSpec/MessageChain
|
37
|
+
allow(user).to receive_message_chain(:user_accounts, :create) {
|
38
|
+
instance_double(UserAccount, persisted?: false)
|
39
|
+
}
|
40
|
+
# rubocop:enable RSpec/MessageChain
|
41
|
+
end
|
42
|
+
|
43
|
+
it do
|
44
|
+
expect { user.save }.not_to change(described_class, :count)
|
45
|
+
end
|
46
|
+
|
47
|
+
it do
|
48
|
+
user.save
|
49
|
+
expect(user).not_to be_persisted
|
50
|
+
end
|
51
|
+
end
|
13
52
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// Animations
|
2
|
+
.fade-in {
|
3
|
+
animation: fadeInAnimation 0.2s ease-in-out forwards;
|
4
|
+
}
|
5
|
+
|
6
|
+
.fade-out {
|
7
|
+
animation: fadeOutAnimation 0.2s ease forwards;
|
8
|
+
}
|
9
|
+
|
10
|
+
.init-invisible {
|
11
|
+
visibility: hidden;
|
12
|
+
}
|
13
|
+
|
14
|
+
.init-visible {
|
15
|
+
visibility: visible;
|
16
|
+
}
|
17
|
+
|
18
|
+
.animation-long {
|
19
|
+
animation-duration: 1s;
|
20
|
+
}
|
21
|
+
|
22
|
+
@keyframes fadeInAnimation {
|
23
|
+
0% { opacity: 0; visibility: visible; }
|
24
|
+
100% { opacity: 1; visibility: visible; }
|
25
|
+
}
|
26
|
+
|
27
|
+
@keyframes fadeOutAnimation {
|
28
|
+
0% { opacity: 1; visibility: visible; }
|
29
|
+
100% { opacity: 0; visibility: hidden; }
|
30
|
+
}
|
@@ -1,14 +1,10 @@
|
|
1
|
-
|
2
|
-
import
|
3
|
-
import
|
4
|
-
|
1
|
+
import './config'
|
2
|
+
import './channels'
|
3
|
+
import './controllers'
|
4
|
+
|
5
5
|
// Bootstrap's toasts
|
6
6
|
import * as bootstrap from 'bootstrap'
|
7
7
|
|
8
|
-
window.Stimulus.register('navbar', NavbarController)
|
9
|
-
window.Stimulus.register('nested', NestedController)
|
10
|
-
window.Stimulus.register('pg_form', PgFormController)
|
11
|
-
|
12
8
|
document.addEventListener('turbo:load', function () {
|
13
9
|
const toastElList = document.querySelectorAll('.toast:not(.hide):not(.show)')
|
14
10
|
Array.from(toastElList).map(toastEl => new bootstrap.Toast(toastEl).show())
|
@@ -23,11 +19,11 @@ document.addEventListener('turbo:load', function () {
|
|
23
19
|
const callback = (mutationList, observer) => {
|
24
20
|
for (const mutation of mutationList) {
|
25
21
|
if (mutation.type === 'childList') {
|
26
|
-
console.log('A child node has been added or removed.')
|
22
|
+
// console.log('A child node has been added or removed.')
|
27
23
|
const toastElList = document.querySelectorAll('.toast:not(.hide):not(.show)')
|
28
24
|
Array.from(toastElList).map(toastEl => new bootstrap.Toast(toastEl).show())
|
29
25
|
} else if (mutation.type === 'attributes') {
|
30
|
-
console.log(`The ${mutation.attributeName} attribute was modified.`)
|
26
|
+
// console.log(`The ${mutation.attributeName} attribute was modified.`)
|
31
27
|
}
|
32
28
|
}
|
33
29
|
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
// Action Cable provides the framework to deal with WebSockets in Rails.
|
2
|
+
// You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
|
3
|
+
|
4
|
+
import { createConsumer } from '@anycable/web'
|
5
|
+
|
6
|
+
export default createConsumer({
|
7
|
+
protocol: 'actioncable-v1-ext-json'
|
8
|
+
})
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import consumer from '../channels/consumer'
|
2
|
+
import CableReady from 'cable_ready'
|
3
|
+
|
4
|
+
const anycable = consumer.cable
|
5
|
+
|
6
|
+
if (anycable) {
|
7
|
+
anycable.on('connect', ev => {
|
8
|
+
if (ev.reconnect) {
|
9
|
+
console.log('Welcome back!')
|
10
|
+
} else {
|
11
|
+
console.log('Welcome!')
|
12
|
+
}
|
13
|
+
})
|
14
|
+
|
15
|
+
anycable.on('disconnect', ev => {
|
16
|
+
if (ev.reason) {
|
17
|
+
console.log(`Disconnected because: ${ev.reason}`)
|
18
|
+
} else {
|
19
|
+
console.log('Disconnected')
|
20
|
+
}
|
21
|
+
})
|
22
|
+
}
|
23
|
+
|
24
|
+
CableReady.initialize({ consumer })
|
@@ -0,0 +1 @@
|
|
1
|
+
import './cable_ready'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
|
3
|
+
// To be used by img_placeholder helper
|
4
|
+
export default class extends Controller {
|
5
|
+
connect () {
|
6
|
+
if (this.element.complete) {
|
7
|
+
this.loaded()
|
8
|
+
} else {
|
9
|
+
this.element.addEventListener('load', () => {
|
10
|
+
this.loaded()
|
11
|
+
}, { once: true })
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
loaded () {
|
16
|
+
this.element.classList.add('fade-in')
|
17
|
+
this.element.style.display = 'block'
|
18
|
+
this.element.parentElement.classList.remove('placeholder')
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { application } from './application'
|
2
|
+
|
3
|
+
import NavbarController from './navbar_controller'
|
4
|
+
import NestedController from './nested_controller'
|
5
|
+
import PgFormController from './pg_form_controller'
|
6
|
+
import FadeinOnloadController from './fadein_onload_controller'
|
7
|
+
|
8
|
+
application.register('navbar', NavbarController)
|
9
|
+
application.register('nested', NestedController)
|
10
|
+
application.register('pg_form', PgFormController)
|
11
|
+
application.register('fadein_onload', FadeinOnloadController)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
export function round (value) {
|
2
|
+
return Math.round(value * 100) / 100
|
3
|
+
}
|
4
|
+
|
5
|
+
export function printCurrency (value, simboloMoneda = '$') {
|
6
|
+
if (typeof value === 'string') {
|
7
|
+
value = parseFloat(value)
|
8
|
+
}
|
9
|
+
const decimals = (value % 1 > 0) ? 2 : 0
|
10
|
+
return simboloMoneda + ' ' + numberWithDots(value.toFixed(decimals).replace('.', ','))
|
11
|
+
}
|
12
|
+
|
13
|
+
export function showPercentage (value) {
|
14
|
+
return '% ' + value
|
15
|
+
}
|
16
|
+
|
17
|
+
export function numberWithDots (x) {
|
18
|
+
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.')
|
19
|
+
}
|
20
|
+
|
21
|
+
export function fadeOut (e) {
|
22
|
+
if (window.getComputedStyle(e).visibility !== 'hidden') {
|
23
|
+
e.classList.add('fade-out')
|
24
|
+
e.addEventListener('animationend', onAnimationEndHide, { once: true })
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
export function fadeIn (e) {
|
29
|
+
if (window.getComputedStyle(e).visibility !== 'visible') {
|
30
|
+
e.classList.add('fade-in')
|
31
|
+
e.addEventListener('animationend', onAnimationEndShow, { once: true })
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
function onAnimationEndShow (e) {
|
36
|
+
e.target.style.visibility = 'visible'
|
37
|
+
e.target.classList.remove('fade-in')
|
38
|
+
}
|
39
|
+
|
40
|
+
function onAnimationEndHide (e) {
|
41
|
+
e.target.style.visibility = 'hidden'
|
42
|
+
e.target.classList.remove('fade-out')
|
43
|
+
}
|
@@ -5,7 +5,8 @@ html
|
|
5
5
|
meta name="viewport" content="width=device-width,initial-scale=1"
|
6
6
|
= csrf_meta_tags
|
7
7
|
= csp_meta_tag
|
8
|
-
|
8
|
+
meta name="cable-history-timestamp" content="#{Time.now.to_i}"
|
9
|
+
= action_cable_with_jwt_meta_tag
|
9
10
|
= stylesheet_link_tag 'application', 'data-turbo-track': 'reload'
|
10
11
|
= javascript_include_tag 'application', 'data-turbo-track': 'reload', type: 'module'
|
11
12
|
body
|
@@ -3,16 +3,20 @@ html
|
|
3
3
|
head
|
4
4
|
title = Rails.application.class.module_parent_name
|
5
5
|
meta name="viewport" content="width=device-width,initial-scale=1"
|
6
|
-
|
6
|
+
- if @turbo_no_cache
|
7
|
+
meta name="turbo-cache-control" content="no-cache"
|
7
8
|
/ meta name="turbo-refresh-method" content="morph"
|
8
9
|
/ meta name="turbo-refresh-scroll" content="preserve"
|
9
10
|
/ meta name="turbo-prefetch" content="true"
|
10
11
|
meta name="view-transition" content="same-origin"
|
12
|
+
meta name="cable-history-timestamp" content="#{Time.now.to_i}"
|
11
13
|
= csrf_meta_tags
|
12
14
|
= csp_meta_tag
|
15
|
+
= action_cable_with_jwt_meta_tag
|
13
16
|
|
14
17
|
= stylesheet_link_tag 'application', 'data-turbo-track': 'reload'
|
15
18
|
= javascript_include_tag 'application', 'data-turbo-track': 'reload', type: 'module'
|
19
|
+
= render partial: 'pg_layout/rollbar'
|
16
20
|
body
|
17
21
|
div class="#{ @sidebar == false ? '' : 'with-sidebar' }"
|
18
22
|
- unless @sidebar == false
|
@@ -33,4 +37,5 @@ html
|
|
33
37
|
= yield(:actions)
|
34
38
|
hr.my-0
|
35
39
|
= yield
|
40
|
+
div style="width:100%; height: 10em"
|
36
41
|
= render_turbo_stream_title
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<% if ENV['ROLLBAR_ACCESS_TOKEN_CLIENT'].present? %>
|
2
|
+
<script>
|
3
|
+
var _rollbarConfig = {
|
4
|
+
accessToken: '<%= ENV['ROLLBAR_ACCESS_TOKEN_CLIENT'] %>',
|
5
|
+
captureUncaught: true,
|
6
|
+
captureUnhandledRejections: true,
|
7
|
+
payload: {
|
8
|
+
environment: "production",
|
9
|
+
//trace_id: 'abc',
|
10
|
+
client: {
|
11
|
+
javascript: {
|
12
|
+
code_version: '1.0.0',
|
13
|
+
//source_map_enabled: true,
|
14
|
+
//guess_uncaught_frames: true
|
15
|
+
}
|
16
|
+
},
|
17
|
+
//server: {
|
18
|
+
//root: 'http://localhost:8000/demo/',
|
19
|
+
//host: 'host-1',
|
20
|
+
//branch: 'HEAD',
|
21
|
+
//},
|
22
|
+
}
|
23
|
+
};
|
24
|
+
// Rollbar Snippet
|
25
|
+
!function(r){var e={};function o(n){if(e[n])return e[n].exports;var t=e[n]={i:n,l:!1,exports:{}};return r[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=e,o.d=function(r,e,n){o.o(r,e)||Object.defineProperty(r,e,{enumerable:!0,get:n})},o.r=function(r){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})},o.t=function(r,e){if(1&e&&(r=o(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var t in r)o.d(n,t,function(e){return r[e]}.bind(null,t));return n},o.n=function(r){var e=r&&r.__esModule?function(){return r.default}:function(){return r};return o.d(e,"a",e),e},o.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},o.p="",o(o.s=0)}([function(r,e,o){"use strict";var n=o(1),t=o(5);_rollbarConfig=_rollbarConfig||{},_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://cdn.rollbar.com/rollbarjs/refs/tags/v2.26.3/rollbar.min.js",_rollbarConfig.async=void 0===_rollbarConfig.async||_rollbarConfig.async;var a=n.setupShim(window,_rollbarConfig),l=t(_rollbarConfig);window.rollbar=n.Rollbar,a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,l)},function(r,e,o){"use strict";var n=o(2),t=o(3);function a(r){return function(){try{return r.apply(this,arguments)}catch(r){try{console.error("[Rollbar]: Internal error",r)}catch(r){}}}}var l=0;function i(r,e){this.options=r,this._rollbarOldOnError=null;var o=l++;this.shimId=function(){return o},"undefined"!=typeof window&&window._rollbarShims&&(window._rollbarShims[o]={handler:e,messages:[]})}var s=o(4),d=function(r,e){return new i(r,e)},c=function(r){return new s(d,r)};function u(r){return a((function(){var e=this,o=Array.prototype.slice.call(arguments,0),n={shim:e,method:r,args:o,ts:new Date};window._rollbarShims[this.shimId()].messages.push(n)}))}i.prototype.loadFull=function(r,e,o,n,t){var l=!1,i=e.createElement("script"),s=e.getElementsByTagName("script")[0],d=s.parentNode;i.crossOrigin="",i.src=n.rollbarJsUrl,o||(i.async=!0),i.onload=i.onreadystatechange=a((function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){i.onload=i.onreadystatechange=null;try{d.removeChild(i)}catch(r){}l=!0,function(){var e;if(void 0===r._rollbarDidLoad){e=new Error("rollbar.js did not load");for(var o,n,a,l,i=0;o=r._rollbarShims[i++];)for(o=o.messages||[];n=o.shift();)for(a=n.args||[],i=0;i<a.length;++i)if("function"==typeof(l=a[i])){l(e);break}}"function"==typeof t&&t(e)}()}})),d.insertBefore(i,s)},i.prototype.wrap=function(r,e,o){try{var n;if(n="function"==typeof e?e:function(){return e||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._rollbar_wrapped&&(r._rollbar_wrapped=function(){o&&"function"==typeof o&&o.apply(this,arguments);try{return r.apply(this,arguments)}catch(o){var e=o;throw e&&("string"==typeof e&&(e=new String(e)),e._rollbarContext=n()||{},e._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=e),e}},r._rollbar_wrapped._isWrap=!0,r.hasOwnProperty))for(var t in r)r.hasOwnProperty(t)&&(r._rollbar_wrapped[t]=r[t]);return r._rollbar_wrapped}catch(e){return r}};for(var p="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleAnonymousErrors,handleUnhandledRejection,captureEvent,captureDomContentLoaded,captureLoad".split(","),f=0;f<p.length;++f)i.prototype[p[f]]=u(p[f]);r.exports={setupShim:function(r,e){if(r){var o=e.globalAlias||"Rollbar";if("object"==typeof r[o])return r[o];r._rollbarShims={},r._rollbarWrappedError=null;var l=new c(e);return a((function(){e.captureUncaught&&(l._rollbarOldOnError=r.onerror,n.captureUncaughtExceptions(r,l,!0),e.wrapGlobalEventHandlers&&t(r,l,!0)),e.captureUnhandledRejections&&n.captureUnhandledRejections(r,l,!0);var a=e.autoInstrument;return!1!==e.enabled&&(void 0===a||!0===a||function(r){return!("object"!=typeof r||void 0!==r.page&&!r.page)}(a))&&r.addEventListener&&(r.addEventListener("load",l.captureLoad.bind(l)),r.addEventListener("DOMContentLoaded",l.captureDomContentLoaded.bind(l))),r[o]=l,l}))()}},Rollbar:c}},function(r,e,o){"use strict";function n(r,e,o,n){r._rollbarWrappedError&&(n[4]||(n[4]=r._rollbarWrappedError),n[5]||(n[5]=r._rollbarWrappedError._rollbarContext),r._rollbarWrappedError=null);var t=e.handleUncaughtException.apply(e,n);o&&o.apply(r,n),"anonymous"===t&&(e.anonymousErrorsPending+=1)}r.exports={captureUncaughtExceptions:function(r,e,o){if(r){var t;if("function"==typeof e._rollbarOldOnError)t=e._rollbarOldOnError;else if(r.onerror){for(t=r.onerror;t._rollbarOldOnError;)t=t._rollbarOldOnError;e._rollbarOldOnError=t}e.handleAnonymousErrors();var a=function(){var o=Array.prototype.slice.call(arguments,0);n(r,e,t,o)};o&&(a._rollbarOldOnError=t),r.onerror=a}},captureUnhandledRejections:function(r,e,o){if(r){"function"==typeof r._rollbarURH&&r._rollbarURH.belongsToShim&&r.removeEventListener("unhandledrejection",r._rollbarURH);var n=function(r){var o,n,t;try{o=r.reason}catch(r){o=void 0}try{n=r.promise}catch(r){n="[unhandledrejection] error getting `promise` from event"}try{t=r.detail,!o&&t&&(o=t.reason,n=t.promise)}catch(r){}o||(o="[unhandledrejection] error getting `reason` from event"),e&&e.handleUnhandledRejection&&e.handleUnhandledRejection(o,n)};n.belongsToShim=o,r._rollbarURH=n,r.addEventListener("unhandledrejection",n)}}}},function(r,e,o){"use strict";function n(r,e,o){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){for(var n=e.addEventListener;n._rollbarOldAdd&&n.belongsToShim;)n=n._rollbarOldAdd;var t=function(e,o,t){n.call(this,e,r.wrap(o),t)};t._rollbarOldAdd=n,t.belongsToShim=o,e.addEventListener=t;for(var a=e.removeEventListener;a._rollbarOldRemove&&a.belongsToShim;)a=a._rollbarOldRemove;var l=function(r,e,o){a.call(this,r,e&&e._rollbar_wrapped||e,o)};l._rollbarOldRemove=a,l.belongsToShim=o,e.removeEventListener=l}}r.exports=function(r,e,o){if(r){var t,a,l="EventTarget,Window,Node,ApplicationCache,AudioTrackList,ChannelMergerNode,CryptoOperation,EventSource,FileReader,HTMLUnknownElement,IDBDatabase,IDBRequest,IDBTransaction,KeyOperation,MediaController,MessagePort,ModalWindow,Notification,SVGElementInstance,Screen,TextTrack,TextTrackCue,TextTrackList,WebSocket,WebSocketWorker,Worker,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload".split(",");for(t=0;t<l.length;++t)r[a=l[t]]&&r[a].prototype&&n(e,r[a].prototype,o)}}},function(r,e,o){"use strict";function n(r,e){this.impl=r(e,this),this.options=e,function(r){for(var e=function(r){return function(){var e=Array.prototype.slice.call(arguments,0);if(this.impl[r])return this.impl[r].apply(this.impl,e)}},o="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleAnonymousErrors,handleUnhandledRejection,_createItem,wrap,loadFull,shimId,captureEvent,captureDomContentLoaded,captureLoad".split(","),n=0;n<o.length;n++)r[o[n]]=e(o[n])}(n.prototype)}n.prototype._swapAndProcessMessages=function(r,e){var o,n,t;for(this.impl=r(this.options);o=e.shift();)n=o.method,t=o.args,this[n]&&"function"==typeof this[n]&&("captureDomContentLoaded"===n||"captureLoad"===n?this[n].apply(this,[t[0],o.ts]):this[n].apply(this,t));return this},r.exports=n},function(r,e,o){"use strict";r.exports=function(r){return function(e){if(!e&&!window._rollbarInitialized){for(var o,n,t=(r=r||{}).globalAlias||"Rollbar",a=window.rollbar,l=function(r){return new a(r)},i=0;o=window._rollbarShims[i++];)n||(n=o.handler),o.handler._swapAndProcessMessages(l,o.messages);window[t]=n,window._rollbarInitialized=!0}}}}]);
|
26
|
+
// End Rollbar Snippet
|
27
|
+
</script>
|
28
|
+
<% end %>
|
data/pg_rails/js/index.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
import './../../pg_associable'
|
2
|
-
import './../../pg_layout'
|
2
|
+
import './../../pg_layout/app/javascript/application'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'vcr'
|
2
|
+
require 'webmock/rspec'
|
3
|
+
|
4
|
+
VCR.configure do |config|
|
5
|
+
config.cassette_library_dir = 'spec/cassettes'
|
6
|
+
config.default_cassette_options = {
|
7
|
+
match_requests_on: %i[uri method],
|
8
|
+
record: :once
|
9
|
+
}
|
10
|
+
config.hook_into :webmock
|
11
|
+
config.configure_rspec_metadata!
|
12
|
+
|
13
|
+
# * `ignore_localhost = true` is equivalent to `ignore_hosts 'localhost',
|
14
|
+
# '127.0.0.1', '0.0.0.0'`. It is particularly useful for when you use
|
15
|
+
# VCR with a javascript-enabled capybara driver, since capybara boots
|
16
|
+
# your rack app and makes localhost requests to it to check that it has
|
17
|
+
# booted.
|
18
|
+
config.ignore_localhost = true
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.around(:example, :vcr_cassettes) do |example|
|
23
|
+
cassettes = example.metadata[:vcr_cassettes].map { |cas_name| { name: cas_name } }
|
24
|
+
VCR.use_cassettes(cassettes) do
|
25
|
+
example.run
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/pg_rails/lib/version.rb
CHANGED
data/pg_rails/scss/pg_rails.scss
CHANGED
@@ -9,6 +9,8 @@ require_dependency "<%= namespaced_path %>/application_controller"
|
|
9
9
|
<% module_namespacing do -%>
|
10
10
|
<% module_namespacing_2 do -%>
|
11
11
|
class <%= controller_class_name.split('::').last %>Controller < <%= parent_controller %>
|
12
|
+
include PgEngine::Resource
|
13
|
+
|
12
14
|
before_action { @clase_modelo = <%= class_name.split('::').last %> }
|
13
15
|
|
14
16
|
before_action(only: :index) { authorize <%= class_name.split('::').last %> }
|
@@ -6,7 +6,7 @@ require 'generators/pg_active_record/model/model_generator'
|
|
6
6
|
|
7
7
|
DESTINATION_PATH = File.expand_path('./../../tmp/generator_testing', __dir__)
|
8
8
|
|
9
|
-
describe 'Generators' do
|
9
|
+
describe 'Generators', type: :generator do
|
10
10
|
describe 'PgDecoratorGenerator' do
|
11
11
|
destination DESTINATION_PATH
|
12
12
|
tests PgDecoratorGenerator
|
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.0.8.pre.alpha.
|
4
|
+
version: 7.0.8.pre.alpha.15
|
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-03-
|
11
|
+
date: 2024-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Rails goodies.
|
14
14
|
email:
|
@@ -89,7 +89,10 @@ files:
|
|
89
89
|
- pg_engine/app/views/pg_engine/base/index.html.slim
|
90
90
|
- pg_engine/app/views/pg_engine/base/new.html.slim
|
91
91
|
- pg_engine/config/initializers/active_admin.rb
|
92
|
+
- pg_engine/config/initializers/anycable.rb
|
93
|
+
- pg_engine/config/initializers/cable_ready.rb
|
92
94
|
- pg_engine/config/initializers/devise.rb
|
95
|
+
- pg_engine/config/initializers/rollbar.rb
|
93
96
|
- pg_engine/config/initializers/simple_form_monkey_patch.rb
|
94
97
|
- pg_engine/config/locales/devise.en.yml
|
95
98
|
- pg_engine/config/locales/es.yml
|
@@ -110,6 +113,7 @@ files:
|
|
110
113
|
- pg_engine/lib/pg_engine/configuracion.rb
|
111
114
|
- pg_engine/lib/pg_engine/core_ext.rb
|
112
115
|
- pg_engine/lib/pg_engine/engine.rb
|
116
|
+
- pg_engine/lib/pg_engine/error.rb
|
113
117
|
- pg_engine/lib/pg_engine/route_helpers.rb
|
114
118
|
- pg_engine/lib/pg_engine/utils/pdf_preview_generator.rb
|
115
119
|
- pg_engine/lib/pg_engine/utils/pg_logger.rb
|
@@ -117,25 +121,37 @@ files:
|
|
117
121
|
- pg_engine/spec/controllers/admin/accounts_controller_spec.rb
|
118
122
|
- pg_engine/spec/controllers/admin/user_accounts_controller_spec.rb
|
119
123
|
- pg_engine/spec/controllers/admin/users_controller_spec.rb
|
120
|
-
- pg_engine/spec/controllers/concerns/pg_engine/
|
124
|
+
- pg_engine/spec/controllers/concerns/pg_engine/resource_helper_spec.rb
|
121
125
|
- pg_engine/spec/controllers/devise/registrations_controller_spec.rb
|
122
126
|
- pg_engine/spec/controllers/devise/sessions_controller_spec.rb
|
123
127
|
- pg_engine/spec/factories/accounts.rb
|
124
128
|
- pg_engine/spec/factories/user_accounts.rb
|
125
129
|
- pg_engine/spec/factories/users.rb
|
126
130
|
- pg_engine/spec/fixtures/test.pdf
|
131
|
+
- pg_engine/spec/helpers/pg_engine/pg_rails_helper_spec.rb
|
132
|
+
- pg_engine/spec/lib/pg_engine/error_helper_spec.rb
|
133
|
+
- pg_engine/spec/lib/pg_engine/utils/pg_engine/pg_logger_spec.rb
|
127
134
|
- pg_engine/spec/lib/pg_form_builder_spec.rb
|
128
135
|
- pg_engine/spec/models/account_spec.rb
|
129
136
|
- pg_engine/spec/models/pg_engine/base_record_spec.rb
|
130
137
|
- pg_engine/spec/models/user_account_spec.rb
|
131
138
|
- pg_engine/spec/models/user_spec.rb
|
132
139
|
- pg_engine/spec/pg_engine/pdf_preview_generator_spec.rb
|
140
|
+
- pg_layout/app/assets/stylesheets/animations.scss
|
133
141
|
- pg_layout/app/assets/stylesheets/sidebar.scss
|
134
|
-
- pg_layout/app/javascript/
|
135
|
-
- pg_layout/app/javascript/
|
136
|
-
- pg_layout/app/javascript/
|
137
|
-
- pg_layout/app/javascript/
|
138
|
-
- pg_layout/app/javascript/
|
142
|
+
- pg_layout/app/javascript/application.js
|
143
|
+
- pg_layout/app/javascript/channels/consumer.js
|
144
|
+
- pg_layout/app/javascript/channels/index.js
|
145
|
+
- pg_layout/app/javascript/config/cable_ready.js
|
146
|
+
- pg_layout/app/javascript/config/index.js
|
147
|
+
- pg_layout/app/javascript/controllers/application.js
|
148
|
+
- pg_layout/app/javascript/controllers/fadein_onload_controller.js
|
149
|
+
- pg_layout/app/javascript/controllers/index.js
|
150
|
+
- pg_layout/app/javascript/controllers/navbar_controller.js
|
151
|
+
- pg_layout/app/javascript/controllers/nested_controller.js
|
152
|
+
- pg_layout/app/javascript/controllers/pg_form_controller.js
|
153
|
+
- pg_layout/app/javascript/utils/cookies.js
|
154
|
+
- pg_layout/app/javascript/utils/utils.ts
|
139
155
|
- pg_layout/app/lib/navbar.rb
|
140
156
|
- pg_layout/app/views/devise/confirmations/new.html.erb
|
141
157
|
- pg_layout/app/views/devise/mailer/confirmation_instructions.html.erb
|
@@ -162,13 +178,14 @@ files:
|
|
162
178
|
- pg_layout/app/views/layouts/pg_layout/layout.html.slim
|
163
179
|
- pg_layout/app/views/pg_layout/_flash.html.slim
|
164
180
|
- pg_layout/app/views/pg_layout/_navbar.html.erb
|
181
|
+
- pg_layout/app/views/pg_layout/_rollbar.html.erb
|
165
182
|
- pg_layout/app/views/pg_layout/_sidebar.html.erb
|
166
|
-
- pg_layout/index.js
|
167
183
|
- pg_layout/lib/pg_layout.rb
|
168
184
|
- pg_layout/lib/pg_layout/engine.rb
|
169
185
|
- pg_rails/js/index.js
|
170
186
|
- pg_rails/lib/pg_rails.rb
|
171
187
|
- pg_rails/lib/pg_rails/capybara_support.rb
|
188
|
+
- pg_rails/lib/pg_rails/vcr_support.rb
|
172
189
|
- pg_rails/lib/version.rb
|
173
190
|
- pg_rails/scss/pg_rails.scss
|
174
191
|
- pg_scaffold/lib/generators/pg_active_record/model/model_generator.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
export function round (value) {
|
2
|
-
return Math.round(value * 100) / 100
|
3
|
-
}
|
4
|
-
|
5
|
-
export function printCurrency (value, simboloMoneda = '$') {
|
6
|
-
if (typeof value === 'string') {
|
7
|
-
value = parseFloat(value)
|
8
|
-
}
|
9
|
-
const decimals = (value % 1 > 0) ? 2 : 0
|
10
|
-
return simboloMoneda + ' ' + numberWithDots(value.toFixed(decimals).replace('.', ','))
|
11
|
-
}
|
12
|
-
|
13
|
-
export function showPercentage (value) {
|
14
|
-
return '% ' + value
|
15
|
-
}
|
16
|
-
|
17
|
-
export function numberWithDots (x) {
|
18
|
-
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.')
|
19
|
-
}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|