brick 1.0.172 → 1.0.174
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/brick/config.rb +2 -1
- data/lib/brick/extensions.rb +47 -15
- data/lib/brick/frameworks/rails/engine.rb +50 -143
- data/lib/brick/frameworks/rails/form_builder.rb +1 -2
- data/lib/brick/frameworks/rails/form_tags.rb +196 -31
- data/lib/brick/frameworks/rails.rb +2 -2
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +35 -4
- data/lib/generators/brick/install_generator.rb +2 -0
- data/lib/generators/brick/migration_builder.rb +3 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c4dedcd4841e168876c88839c56a60b23a8d3d8799a350dc9d2445cde293b5e
|
4
|
+
data.tar.gz: 46063c6afaf4d2025c1f1b3e74481391a737ab00a710b0e1ef0e51aac3994871
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61b711584141e7625b996cf0406a4b50bc6fadb45379d6d321e94fed7b2b219a90d3007ac52514ed29316caacd5150d57bebff3ac7a92e059ed69b01c8f992c5
|
7
|
+
data.tar.gz: 88c00b72167ec0dddfa525937dcd9e6451fec52f85a64d91de46ad53d073a8d12c3f38e44e093b01f30a22fc56ef363a60d70f416dbca5329b5350965d5666d4
|
data/lib/brick/config.rb
CHANGED
@@ -21,10 +21,11 @@ module Brick
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def mode
|
24
|
+
rails_env = Object.const_defined?('Rails') && ::Rails.env
|
24
25
|
@mutex.synchronize do
|
25
26
|
case @brick_mode
|
26
27
|
when nil, :development
|
27
|
-
(
|
28
|
+
(rails_env == 'development' || ENV.key?('BRICK')) ? :on : nil
|
28
29
|
when :diag_env
|
29
30
|
ENV.key?('BRICK') ? :on : nil
|
30
31
|
else
|
data/lib/brick/extensions.rb
CHANGED
@@ -1288,6 +1288,7 @@ end
|
|
1288
1288
|
end
|
1289
1289
|
# puts "#{self.name} - #{args.first}"
|
1290
1290
|
# Unless it's a Brick prefix looking for a TNP that should create a module ...
|
1291
|
+
relations = ::Brick.relations
|
1291
1292
|
unless (is_tnp_module = (is_brick_prefix && !is_controller && ::Brick.config.table_name_prefixes.values.include?(requested)))
|
1292
1293
|
# ... first look around for an existing module or class.
|
1293
1294
|
desired_classname = (self == Object || !name) ? requested : "#{name}::#{requested}"
|
@@ -1309,12 +1310,16 @@ end
|
|
1309
1310
|
(possible.instance_of?(Class) && possible == self)) && # Are we simply searching for ourselves?
|
1310
1311
|
# Skip when what we found as `possible` is not related to the base class of an STI model
|
1311
1312
|
(!sti_base || possible.is_a?(sti_base))
|
1313
|
+
# if possible.is_a?(ActiveRecord::Base) && !possible.abstract_class? && (pk = possible.primary_key) &&
|
1314
|
+
# !(relation = relations.fetch(possible.table_name, nil))&.fetch(:pks, nil)
|
1315
|
+
# binding.pry
|
1316
|
+
# x = 5
|
1317
|
+
# end
|
1312
1318
|
return possible
|
1313
1319
|
end
|
1314
1320
|
end
|
1315
1321
|
end
|
1316
1322
|
class_name = ::Brick.namify(requested)
|
1317
|
-
relations = ::Brick.relations
|
1318
1323
|
# CONTROLLER
|
1319
1324
|
result = if ::Brick.enable_controllers? &&
|
1320
1325
|
is_controller && (plural_class_name = class_name[0..-11]).length.positive?
|
@@ -1885,7 +1890,7 @@ class Object
|
|
1885
1890
|
cspd.select! { |val| val == "'self'" }
|
1886
1891
|
cspd << style_value
|
1887
1892
|
else
|
1888
|
-
cspd << "'sha256-
|
1893
|
+
cspd << "'sha256-Q8t+pETkz0RtyV4XprwdP+uEkVaFyMnx1mXif0wDoxw='"
|
1889
1894
|
end
|
1890
1895
|
cspd << 'https://cdn.jsdelivr.net'
|
1891
1896
|
end
|
@@ -1908,6 +1913,8 @@ class Object
|
|
1908
1913
|
end
|
1909
1914
|
self.define_method :crosstab do
|
1910
1915
|
@relations = ::Brick.relations.each_with_object({}) do |r, s|
|
1916
|
+
next if r.first.is_a?(Symbol)
|
1917
|
+
|
1911
1918
|
cols = r.last[:cols].each_with_object([]) do |c, s2|
|
1912
1919
|
s2 << [c.first] + c.last
|
1913
1920
|
end
|
@@ -2030,8 +2037,10 @@ class Object
|
|
2030
2037
|
}
|
2031
2038
|
unless ::Brick.config.enable_api == false
|
2032
2039
|
json['paths'] = relations.each_with_object({}) do |relation, s|
|
2033
|
-
next if
|
2034
|
-
|
2040
|
+
next if relation.first.is_a?(Symbol) || (
|
2041
|
+
(api_vers = relation.last.fetch(:api, nil)) &&
|
2042
|
+
!(api_ver_paths = api_vers[current_api_ver] || api_vers[nil])
|
2043
|
+
)
|
2035
2044
|
|
2036
2045
|
schema_tag = {}
|
2037
2046
|
if (schema_name = relation.last&.fetch(:schema, nil))
|
@@ -2278,10 +2287,15 @@ class Object
|
|
2278
2287
|
else
|
2279
2288
|
@_lookup_context.instance_variable_set("@#{singular_table_name}".to_sym,
|
2280
2289
|
(created_obj = model.send(:create, send(params_name_sym))))
|
2281
|
-
# %%% Surface any errors to the user in a flash message
|
2282
2290
|
@_lookup_context.instance_variable_set(:@_brick_model, model)
|
2283
|
-
|
2284
|
-
|
2291
|
+
if created_obj.errors.empty?
|
2292
|
+
index
|
2293
|
+
render :index
|
2294
|
+
else # Surface errors to the user in a flash message
|
2295
|
+
flash.alert = (created_obj.errors.errors.map { |err| "<b>#{err.attribute}</b> #{err.message}" }.join(', '))
|
2296
|
+
new
|
2297
|
+
render :new
|
2298
|
+
end
|
2285
2299
|
end
|
2286
2300
|
end
|
2287
2301
|
|
@@ -2350,6 +2364,9 @@ class Object
|
|
2350
2364
|
upd_hash[model.inheritance_column] = nil
|
2351
2365
|
end
|
2352
2366
|
obj.send(:update, upd_hash || upd_params)
|
2367
|
+
if obj.errors.any? # Surface errors to the user in a flash message
|
2368
|
+
flash.alert = (obj.errors.errors.map { |err| "<b>#{err.attribute}</b> #{err.message}" }.join(', '))
|
2369
|
+
end
|
2353
2370
|
end
|
2354
2371
|
|
2355
2372
|
code << " def destroy\n"
|
@@ -2587,14 +2604,14 @@ end.class_exec do
|
|
2587
2604
|
# return if ActiveRecord::Base.connection.current_database == 'postgres'
|
2588
2605
|
|
2589
2606
|
orig_schema = nil
|
2590
|
-
if (relations = ::Brick.relations).
|
2607
|
+
if (relations = ::Brick.relations).keys == [:db_name]
|
2591
2608
|
::Brick.remove_instance_variable(:@_additional_references_loaded) if ::Brick.instance_variable_defined?(:@_additional_references_loaded)
|
2592
2609
|
# Very first thing, load inflections since we'll be using .pluralize and .singularize on table and model names
|
2593
|
-
if File.exist?(inflections = ::Rails.root
|
2610
|
+
if File.exist?(inflections = ::Rails.root&.join('config/initializers/inflections.rb') || '')
|
2594
2611
|
load inflections
|
2595
2612
|
end
|
2596
2613
|
# Now the Brick initializer since there may be important schema things configured
|
2597
|
-
if !::Brick.initializer_loaded && File.exist?(brick_initializer = ::Rails.root
|
2614
|
+
if !::Brick.initializer_loaded && File.exist?(brick_initializer = ::Rails.root&.join('config/initializers/brick.rb') || '')
|
2598
2615
|
::Brick.initializer_loaded = load brick_initializer
|
2599
2616
|
|
2600
2617
|
# After loading the initializer, add compatibility for ActiveStorage and ActionText if those haven't already been
|
@@ -2660,10 +2677,9 @@ end.class_exec do
|
|
2660
2677
|
s[row.first] = { dt: row.last } unless ['information_schema', 'pg_catalog', 'pg_toast', 'heroku_ext',
|
2661
2678
|
'INFORMATION_SCHEMA', 'sys'].include?(row.first)
|
2662
2679
|
end
|
2663
|
-
|
2664
|
-
|
2665
|
-
|
2666
|
-
if (possible_schema = possible_schemas.find { |ps| ::Brick.db_schemas.key?(ps) })
|
2680
|
+
possible_schema, possible_schemas, multitenancy = ::Brick.get_possible_schemas
|
2681
|
+
if possible_schemas
|
2682
|
+
if possible_schema
|
2667
2683
|
::Brick.default_schema = ::Brick.apartment_default_tenant
|
2668
2684
|
schema = possible_schema
|
2669
2685
|
orig_schema = ActiveRecord::Base.execute_sql('SELECT current_schemas(true)').first['current_schemas'][1..-2].split(',')
|
@@ -2742,7 +2758,14 @@ end.class_exec do
|
|
2742
2758
|
relation[:ukeys][r['key'] || "#{relation_name}.#{col_name}"] ||= []
|
2743
2759
|
# key = (relation[:ukeys] = Hash.new { |h, k| h[k] = [] }) if key.is_a?(Array)
|
2744
2760
|
# key[r['key']]
|
2761
|
+
else
|
2762
|
+
if r['data_type'] == 'uuid'
|
2763
|
+
# && r['column_name'] == ::Brick.ar_base.primary_key
|
2764
|
+
# binding.pry
|
2765
|
+
relation[:pkey][r['key'] || relation_name] ||= []
|
2766
|
+
end
|
2745
2767
|
end
|
2768
|
+
# binding.pry if key && r['data_type'] == 'uuid'
|
2746
2769
|
key << col_name if key
|
2747
2770
|
cols = relation[:cols] # relation.fetch(:cols) { relation[:cols] = [] }
|
2748
2771
|
cols[col_name] = [r['data_type'], r['max_length'], measures&.include?(col_name), r['is_nullable'] == 'NO']
|
@@ -2909,6 +2932,8 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2909
2932
|
end
|
2910
2933
|
|
2911
2934
|
relations.each do |k, v|
|
2935
|
+
next if k.is_a?(Symbol)
|
2936
|
+
|
2912
2937
|
rel_name = k.split('.').map { |rel_part| ::Brick.namify(rel_part, :underscore) }
|
2913
2938
|
schema_names = rel_name[0..-2]
|
2914
2939
|
schema_names.shift if ::Brick.apartment_multitenant && schema_names.first == ::Brick.apartment_default_tenant
|
@@ -3145,6 +3170,10 @@ module Brick
|
|
3145
3170
|
assoc_bt[:inverse] = assoc_hm
|
3146
3171
|
end
|
3147
3172
|
|
3173
|
+
def ar_base
|
3174
|
+
@ar_base ||= Object.const_defined?(:ApplicationRecord) ? ApplicationRecord : Class.new(ActiveRecord::Base)
|
3175
|
+
end
|
3176
|
+
|
3148
3177
|
# Identify built out routes, migrations, models,
|
3149
3178
|
# (and also soon controllers and views!)
|
3150
3179
|
# for each resource
|
@@ -3171,6 +3200,8 @@ module Brick
|
|
3171
3200
|
abstract_activerecord_bases = ::Brick.eager_load_classes(true)
|
3172
3201
|
rails_root = ::Rails.root.to_s
|
3173
3202
|
models = ::Brick.relations.each_with_object({}) do |rel, s|
|
3203
|
+
next if rel.first.is_a?(Symbol)
|
3204
|
+
|
3174
3205
|
begin
|
3175
3206
|
if (model = rel.last[:class_name]&.constantize) &&
|
3176
3207
|
(inh = ActiveRecord::Base._brick_inheriteds[model]&.join(':'))
|
@@ -3223,7 +3254,8 @@ module Brick
|
|
3223
3254
|
is_default_schema = multi_schema&.==(::Brick.apartment_default_tenant)
|
3224
3255
|
relations.each_with_object([]) do |v, s|
|
3225
3256
|
frn_tbl = v.first
|
3226
|
-
next if
|
3257
|
+
next if frn_tbl.is_a?(Symbol) || # Skip internal metadata entries
|
3258
|
+
(relation = v.last).key?(:isView) || config.exclude_tables.include?(frn_tbl) ||
|
3227
3259
|
!(for_pk = (relation[:pkey].values.first&.first))
|
3228
3260
|
|
3229
3261
|
is_default_frn_schema = !is_default_schema && multi_schema &&
|
@@ -6,7 +6,7 @@ module Brick
|
|
6
6
|
def display_value(col_type, val, lat_lng = nil)
|
7
7
|
is_mssql_geography = nil
|
8
8
|
# Some binary thing that really looks like a Microsoft-encoded WGS84 point? (With the first two bytes, E6 10, indicating an EPSG code of 4326)
|
9
|
-
if col_type == :binary && val &&
|
9
|
+
if col_type == :binary && val && ::Brick.is_geography?(val)
|
10
10
|
col_type = 'geography'
|
11
11
|
is_mssql_geography = true
|
12
12
|
end
|
@@ -19,7 +19,7 @@ module Brick
|
|
19
19
|
|
20
20
|
if @is_mysql || (is_mssql_geography ||=
|
21
21
|
(@is_mssql ||
|
22
|
-
(val &&
|
22
|
+
(val && ::Brick.is_geography?(val))
|
23
23
|
)
|
24
24
|
)
|
25
25
|
# MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
|
@@ -204,7 +204,7 @@ function linkSchemas() {
|
|
204
204
|
<polygon style=\"fill:#894747;\" points=\"58,31.559 19,52 19,35 58,15.831\"/>
|
205
205
|
</g>
|
206
206
|
</svg>
|
207
|
-
"
|
207
|
+
"
|
208
208
|
|
209
209
|
# paths['app/models'] << 'lib/brick/frameworks/active_record/models'
|
210
210
|
config.brick = ActiveSupport::OrderedOptions.new
|
@@ -335,20 +335,16 @@ function linkSchemas() {
|
|
335
335
|
def eager_load(entity)
|
336
336
|
_brick_eager_load(entity)
|
337
337
|
if entity == :resources
|
338
|
-
|
339
|
-
if
|
340
|
-
|
341
|
-
|
342
|
-
if (possible_schema = possible_schemas.find { |ps| ::Brick.db_schemas.key?(ps) })
|
343
|
-
orig_tenant = Apartment::Tenant.current
|
344
|
-
Apartment::Tenant.switch!(possible_schema)
|
345
|
-
end
|
338
|
+
possible_schema, _x1, _x2 = ::Brick.get_possible_schemas
|
339
|
+
if possible_schema
|
340
|
+
orig_tenant = Apartment::Tenant.current
|
341
|
+
Apartment::Tenant.switch!(possible_schema)
|
346
342
|
end
|
347
343
|
existing = Avo::BaseResource.descendants.each_with_object({}) do |r, s|
|
348
344
|
s[r.name[0..-9]] = nil if r.name.end_with?('Resource')
|
349
345
|
end
|
350
346
|
::Brick.relations.each do |k, v|
|
351
|
-
unless existing.key?(class_name = v[:class_name]) || Brick.config.exclude_tables.include?(k) ||
|
347
|
+
unless k.is_a?(Symbol) || existing.key?(class_name = v[:class_name]) || Brick.config.exclude_tables.include?(k) ||
|
352
348
|
class_name.blank? || class_name.include?('::')
|
353
349
|
Object.const_get("#{class_name}Resource")
|
354
350
|
end
|
@@ -403,7 +399,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
403
399
|
end
|
404
400
|
def to_s
|
405
401
|
@_name.to_s.html_safe + @vc.instance_variable_get(:@__vc_helpers)&.link_to_brick(nil,
|
406
|
-
BRICK_SVG,
|
402
|
+
BRICK_SVG.html_safe,
|
407
403
|
{ title: "#{@_name} in Brick" }
|
408
404
|
)
|
409
405
|
end
|
@@ -468,7 +464,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
468
464
|
alias _brick_routes routes
|
469
465
|
def routes(*args)
|
470
466
|
::Brick.relations.each do |k, v|
|
471
|
-
next if k == 'active_admin_comments'
|
467
|
+
next if k.is_a?(Symbol) || k == 'active_admin_comments'
|
472
468
|
|
473
469
|
begin
|
474
470
|
if (class_name = Object.const_get(v.fetch(:class_name, nil)))
|
@@ -490,7 +486,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
490
486
|
rescue
|
491
487
|
end
|
492
488
|
h2((@title + link_to_brick(nil,
|
493
|
-
BRICK_SVG, # This would do well to be sized a bit smaller
|
489
|
+
BRICK_SVG.html_safe, # This would do well to be sized a bit smaller
|
494
490
|
{ title: "#{@_name} in Brick" }
|
495
491
|
)).html_safe)
|
496
492
|
else
|
@@ -522,7 +518,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
522
518
|
def fetch_models
|
523
519
|
# Auto-create Brick models
|
524
520
|
::Brick.relations.each do |k, v|
|
525
|
-
next if k == 'active_admin_comments'
|
521
|
+
next if k.is_a?(Symbol) || k == 'active_admin_comments'
|
526
522
|
|
527
523
|
begin
|
528
524
|
v[:class_name].constantize
|
@@ -558,7 +554,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
558
554
|
(::Brick.config.json_columns['motor_audits'] ||= []) << 'audited_changes' if mar_tables.include?('motor_audits')
|
559
555
|
(::Brick.config.json_columns['motor_configs'] ||= []) << 'value' if mar_tables.include?('motor_configs')
|
560
556
|
::Brick.relations.each do |k, v|
|
561
|
-
next if mar_tables.include?(k) || k == 'motor_audits'
|
557
|
+
next if k.is_a?(Symbol) || mar_tables.include?(k) || k == 'motor_audits'
|
562
558
|
|
563
559
|
v[:class_name].constantize
|
564
560
|
end
|
@@ -611,7 +607,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
611
607
|
alias :_brick_lookup_context :lookup_context
|
612
608
|
def lookup_context(*args)
|
613
609
|
ret = _brick_lookup_context(*args)
|
614
|
-
@_lookup_context.instance_variable_set(:@_brick_req_params, params)
|
610
|
+
@_lookup_context.instance_variable_set(:@_brick_req_params, params) if request
|
615
611
|
ret
|
616
612
|
end
|
617
613
|
end
|
@@ -777,7 +773,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
777
773
|
# environment or whatever, then get either the controllers or routes list instead
|
778
774
|
prefix = "#{::Brick.config.path_prefix}/" if ::Brick.config.path_prefix
|
779
775
|
table_options = ::Brick.relations.each_with_object({}) do |rel, s|
|
780
|
-
next if ::Brick.config.exclude_tables.include?(rel.first)
|
776
|
+
next if rel.first.is_a?(Symbol) || ::Brick.config.exclude_tables.include?(rel.first)
|
781
777
|
|
782
778
|
tbl_parts = rel.first.split('.')
|
783
779
|
if (aps = rel.last.fetch(:auto_prefixed_schema, nil))
|
@@ -803,15 +799,26 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
803
799
|
position: sticky;
|
804
800
|
display: inline-block;
|
805
801
|
left: 0;
|
802
|
+
z-index: 2;
|
806
803
|
}
|
807
804
|
|
808
805
|
.flashNotice {
|
809
806
|
color: green;
|
810
807
|
}
|
808
|
+
.flashAlert {
|
809
|
+
color: red;
|
810
|
+
}
|
811
811
|
|
812
812
|
h1, h3 {
|
813
813
|
margin-bottom: 0;
|
814
814
|
}
|
815
|
+
#rowCount {
|
816
|
+
display: table-cell;
|
817
|
+
height: 32px;
|
818
|
+
vertical-align: middle;
|
819
|
+
font-size: 0.9em;
|
820
|
+
font-family: sans-serif;
|
821
|
+
}
|
815
822
|
#imgErd {
|
816
823
|
display: table-cell;
|
817
824
|
background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAABNCAMAAADU1xmCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAARxaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyPC90aWZmOllSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHhtcE1NOkRlcml2ZWRGcm9tIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgPHN0UmVmOmluc3RhbmNlSUQ+eG1wLmlpZDoxN0U3OEI3RjAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwvc3RSZWY6aW5zdGFuY2VJRD4KICAgICAgICAgICAgPHN0UmVmOmRvY3VtZW50SUQ+eG1wLmRpZDoxN0U3OEI4MDAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwvc3RSZWY6ZG9jdW1lbnRJRD4KICAgICAgICAgPC94bXBNTTpEZXJpdmVkRnJvbT4KICAgICAgICAgPHhtcE1NOkRvY3VtZW50SUQ+eG1wLmRpZDoxN0U3OEI4MjAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwveG1wTU06RG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkluc3RhbmNlSUQ+eG1wLmlpZDoxN0U3OEI4MTAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwveG1wTU06SW5zdGFuY2VJRD4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3M8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+ChMBcXgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAL9UExURUdwTDRRc1EVG6ioqFJSUmJiYn+AgURWa2uEkauorszGwmtrawonUKzY7DMRIlFTVWV9m4qKiwaN0G1raJSQiJjV7jWh2HmizPLs6CaV0QohSmdoaVdXWLWsomFdYmIgD4WCfQWa2WIoFUxylldpekeRuGtrajhztIuLizV3qc3DvThDVEyFs31+fiRViVRNViVWjwsvWxIzXxZEekeL1FZIVVRdeEZrk359fj52ppubm3l6e4qbqJOTlBlGfM3k3Nzc3K6lnk9RWaenp0FjikGDyJGRkWJiYk2L0Li4uJubnH5+flFbeNPT02tpac3NzVBGJkCCyMvLy9LS0oxETk2U3tLS0tXV1cPDw+Xl5amDftbX19na2uLj4+jo6dzd3OXl511dXd/g31paWlZXV9TU1HBwcOvr687OzdDQ0u/u7fTx79PSzcrJx6KiooWFhujn5NvW05WUk7S1t3R1d7y9vcLCv37J68vMzVJTVOLY1gMiSpmamnt7e7K6zHq+43LQ9Vyez+Pf3LGyscXGybzD1sXDw46v02vI8I+Pj7vEtNvIx7q4ubnZ54a3it3f5s+8vGS/6L6trK+6qICs1H+33cXc6KiuwAOr48fN20ee0Fao0lyz4W6s1qyrrKKlt3XdkoqnyyFoqzuTy6ixosuVeobA4YHNl8TOv3/Ck9bc4I3P7Uqq3tDIxz2FwzN/vF+VxdDe59mIfU+OxJmovxl+wX7S9WjbhovW9jihyKGalIq31uNyY36exJCatJONhTm36nKj0B2q4Mqxsae2zc/U3tvf1cqKa7zAyJS4npqyyTh2tUhMT1drj5ixtN98cEfC8U2Y5vf39355cSN0s4mDfKaomlrG8b2cmcFvaGx/m2CeZge68HG64YCNntSgoVHUdJzKnIHIh6c+BalVVaPM5qrG2CZZkyaHH3WRtYrdn5nH2rxoP22+gN1VQTyxW1aXl0iO2GaxtFuzaCCAQyXSWDOKlDZwkxIINVZPP52Io3uldtIoC1uGVxmzRP6PHn8AAADVdFJOUwAmEf6t/v4EAQVR/oT+Hl4U/v1bR/7+Kf7+a/76Q4Y2Wf1b4j71sXm0y2hF/bBwbtXN/fyGl8Sxiu382Preqfzia9iIkdP51/Povnineu+9n6H7ov5ksLfYy/7////////+/////////////////////v/////////////////////////////////////////////////////////////////////////////+/////////////////////////////////////////////////////r5xM8kAAA0qSURBVFjDpZh3WFNnG8YDMZOiLEFEsVhn1Vq1Vq1abWv3br+dc5IQsklCSEiIyAoJyAhb9h4ishVQcCAIOLC4UBFxr7bu0X6dX6/vec8JikIptecPVrh+576f5z3vez+HQmGyKBSK28eT4SsL/fiXLiaFwmD/E5NzPmU7wG8s5l/DOXy8+vhxLg8TcN5/yw0JZPwV2GoJH+fjPI7UHBWV/8HzwGIynlkgm+vv788RiURSs06bT6WuJAQynlEgO+JaUzoWhGAWE1X1mkqlmYUEMp5JIBs7ejYz3L4iyN+gy1epVMGvaYI1K5faIIF/nsfuPDr325LMo5XpvCCFThUMrHccY2L85j2TQHZna11kZFGd19lo+4oI/yiqJiYmxtGP7kdf/gwC2bLWuix1RWTX7uzMo+PTI4KkJo0fXPSQkBDxDOc/KZBtaK3P4uLqrPXri+rcz4YjgbpgegidHhIgDhC/6/mnBLLNVTWdclzdmbYTeAMClVS6OCAgQGxnZ0cbM4dBPDKjoh2oqo309ZV3ppWV7UTAur1nw+MrIhRaRzsPsdiDRqN5v+lpO0oc0OrrirLkiWGVZVYeIXBLRFBUsNiH5kHz9vHxeZMxOhxb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);
|
@@ -1037,21 +1044,8 @@ callbacks = {} %>"
|
|
1037
1044
|
poly_cols = #{poly_cols.inspect} %>"
|
1038
1045
|
end
|
1039
1046
|
|
1040
|
-
addNewLink = if !@_brick_model&.is_view?
|
1041
|
-
"<% if respond_to?(:#{new_path_name = "new_#{path_obj_name}_path"}) %>
|
1042
|
-
var addNew = document.createElement(\"A\");
|
1043
|
-
addNew.id = \"addNew\";
|
1044
|
-
addNew.href = \"<%= send(:#{new_path_name}) %>\";
|
1045
|
-
addNew.title = \"New #{obj_name}\";
|
1046
|
-
addNew.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"#fff\" d=\"M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z\"/></svg>';
|
1047
|
-
document.getElementById(\"headerButtonBox\").append(addNew);
|
1048
|
-
<% end %>"
|
1049
|
-
end
|
1050
|
-
|
1051
1047
|
# %%% When doing schema select, if we're on a new page go to index
|
1052
1048
|
script = "<script>
|
1053
|
-
var #{table_name}HtColumns;
|
1054
|
-
|
1055
1049
|
// Add \"Are you sure?\" behaviour to any data-confirm buttons out there
|
1056
1050
|
document.querySelectorAll(\"input[type=submit][data-confirm]\").forEach(function (btn) {
|
1057
1051
|
btn.addEventListener(\"click\", function (evt) {
|
@@ -1062,108 +1056,11 @@ document.querySelectorAll(\"input[type=submit][data-confirm]\").forEach(function
|
|
1062
1056
|
});
|
1063
1057
|
});
|
1064
1058
|
|
1059
|
+
<%= @_brick_javascripts&.fetch(:grid_scripts, nil)&.html_safe
|
1060
|
+
%>
|
1065
1061
|
#{JS_CHANGEOUT}#{
|
1066
1062
|
"\nbrickTestSchema = \"#{::Brick.test_schema}\";" if ::Brick.test_schema
|
1067
1063
|
}
|
1068
|
-
// Snag first TR for sticky header
|
1069
|
-
var grid = document.getElementById(\"#{table_name}\");
|
1070
|
-
#{table_name}HtColumns = grid && [grid.getElementsByTagName(\"TR\")[0]];
|
1071
|
-
var headerTop = document.getElementById(\"headerTop\");
|
1072
|
-
var headerCols;
|
1073
|
-
if (grid) {
|
1074
|
-
// COLUMN HEADER AND TABLE CELL HIGHLIGHTING
|
1075
|
-
var gridHighHeader = null,
|
1076
|
-
gridHighCell = null;
|
1077
|
-
grid.addEventListener(\"mouseenter\", gridMove);
|
1078
|
-
grid.addEventListener(\"mousemove\", gridMove);
|
1079
|
-
grid.addEventListener(\"mouseleave\", function (evt) {
|
1080
|
-
if (gridHighCell) gridHighCell.classList.remove(\"highlight\");
|
1081
|
-
gridHighCell = null;
|
1082
|
-
if (gridHighHeader) gridHighHeader.classList.remove(\"highlight\");
|
1083
|
-
gridHighHeader = null;
|
1084
|
-
});
|
1085
|
-
function gridMove(evt) {
|
1086
|
-
var lastHighCell = gridHighCell;
|
1087
|
-
gridHighCell = document.elementFromPoint(evt.x, evt.y);
|
1088
|
-
while (gridHighCell && gridHighCell.tagName !== \"TD\" && gridHighCell.tagName !== \"TH\")
|
1089
|
-
gridHighCell = gridHighCell.parentElement;
|
1090
|
-
if (gridHighCell) {
|
1091
|
-
if (lastHighCell !== gridHighCell) {
|
1092
|
-
gridHighCell.classList.add(\"highlight\");
|
1093
|
-
if (lastHighCell) lastHighCell.classList.remove(\"highlight\");
|
1094
|
-
}
|
1095
|
-
var lastHighHeader = gridHighHeader;
|
1096
|
-
if ((gridHighHeader = headerCols[gridHighCell.cellIndex]) && lastHighHeader !== gridHighHeader) {
|
1097
|
-
if (gridHighHeader) gridHighHeader.classList.add(\"highlight\");
|
1098
|
-
if (lastHighHeader) lastHighHeader.classList.remove(\"highlight\");
|
1099
|
-
}
|
1100
|
-
}
|
1101
|
-
}
|
1102
|
-
// // LESS TOUCHY NAVIGATION BACK OR FORWARD IN HISTORY WHEN USING MOUSE WHEEL
|
1103
|
-
// grid.addEventListener(\"wheel\", function (evt) {
|
1104
|
-
// grid.scrollLeft += evt.deltaX;
|
1105
|
-
// document.body.scrollTop += (evt.deltaY * 0.6);
|
1106
|
-
// evt.preventDefault();
|
1107
|
-
// return false;
|
1108
|
-
// });
|
1109
|
-
}
|
1110
|
-
function setHeaderSizes() {
|
1111
|
-
if (grid.clientWidth > window.outerWidth)
|
1112
|
-
document.getElementById(\"titleBox\").style.width = grid.clientWidth;
|
1113
|
-
// console.log(\"start\");
|
1114
|
-
// See if the headerTop is already populated
|
1115
|
-
// %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
|
1116
|
-
headerTop.innerHTML = \"\"; // %%% Would love to not have to clear it out like this every time! (Currently doing this to support resize events.)
|
1117
|
-
var isEmpty = headerTop.childElementCount === 0;
|
1118
|
-
var numFixed = parseInt(grid.getAttribute(\"x-num-frozen\")) || 0;
|
1119
|
-
var fixedColLefts = [0];
|
1120
|
-
|
1121
|
-
// Set up proper sizings of sticky column header
|
1122
|
-
var node;
|
1123
|
-
for (var j = 0; j < #{table_name}HtColumns.length; ++j) {
|
1124
|
-
var row = #{table_name}HtColumns[j];
|
1125
|
-
var tr = isEmpty ? document.createElement(\"TR\") : headerTop.childNodes[j];
|
1126
|
-
tr.innerHTML = row.innerHTML.trim();
|
1127
|
-
var curLeft = 0.0;
|
1128
|
-
// Match up widths from the original column headers
|
1129
|
-
for (var i = 0; i < row.childNodes.length; ++i) {
|
1130
|
-
node = row.childNodes[i];
|
1131
|
-
if (node.nodeType === 1) {
|
1132
|
-
var th = tr.childNodes[i];
|
1133
|
-
th.style.minWidth = th.style.maxWidth = getComputedStyle(node).width;
|
1134
|
-
// Add \"left: __px\" style to the fixed-width column THs
|
1135
|
-
if (i <= numFixed) {
|
1136
|
-
th.style.position = \"sticky\";
|
1137
|
-
th.style.backgroundColor = \"#008061\";
|
1138
|
-
th.style.zIndex = \"1\";
|
1139
|
-
th.style.left = curLeft + \"px\";
|
1140
|
-
fixedColLefts.push(curLeft += node.clientWidth);
|
1141
|
-
}
|
1142
|
-
if (#{pk&.present? ? 'i > 0' : 'true'}) {
|
1143
|
-
// Add <span> at the end
|
1144
|
-
var span = document.createElement(\"SPAN\");
|
1145
|
-
span.className = \"exclude\";
|
1146
|
-
span.innerHTML = \"X\";
|
1147
|
-
span.addEventListener(\"click\", function (e) {
|
1148
|
-
e.stopPropagation();
|
1149
|
-
doFetch(\"POST\", {_brick_exclude: this.parentElement.getAttribute(\"x-order\")});
|
1150
|
-
});
|
1151
|
-
th.appendChild(span);
|
1152
|
-
}
|
1153
|
-
}
|
1154
|
-
}
|
1155
|
-
headerCols = tr.childNodes;
|
1156
|
-
if (isEmpty) headerTop.appendChild(tr);
|
1157
|
-
}
|
1158
|
-
// Add \"left: __px\" style to all fixed-width column TDs
|
1159
|
-
[...grid.children[1].children].forEach(function (row) {
|
1160
|
-
for (var j = 1; j <= numFixed; ++j) {
|
1161
|
-
row.children[j].style.left = fixedColLefts[j] + 'px';
|
1162
|
-
}
|
1163
|
-
});
|
1164
|
-
grid.style.marginTop = \"-\" + getComputedStyle(headerTop).height;
|
1165
|
-
// console.log(\"end\");
|
1166
|
-
}
|
1167
1064
|
function doFetch(method, payload, success) {
|
1168
1065
|
payload.authenticity_token = <%= session[:_csrf_token].inspect.html_safe %>;
|
1169
1066
|
if (!success) {
|
@@ -1176,13 +1073,7 @@ function doFetch(method, payload, success) {
|
|
1176
1073
|
if (payload) options.body = JSON.stringify(payload);
|
1177
1074
|
return fetch(location.href, options).then(success);
|
1178
1075
|
}
|
1179
|
-
|
1180
|
-
setHeaderSizes();
|
1181
|
-
window.addEventListener('resize', function(event) {
|
1182
|
-
setHeaderSizes();
|
1183
|
-
}, true);#{
|
1184
|
-
addNewLink}
|
1185
|
-
}
|
1076
|
+
|
1186
1077
|
// Cause descriptive text to use the same font as the resource
|
1187
1078
|
var brickFontFamily = document.getElementById(\"resourceName\").computedStyleMap().get(\"font-family\");
|
1188
1079
|
if (window.brickFontFamily) {
|
@@ -1402,7 +1293,14 @@ erDiagram
|
|
1402
1293
|
</head>
|
1403
1294
|
<body>
|
1404
1295
|
<div id=\"titleBox\"><div id=\"titleSticky\">
|
1405
|
-
|
1296
|
+
<% if request.respond_to?(:flash)
|
1297
|
+
if (alert)
|
1298
|
+
%><p class=\"flashAlert\"><%= alert.html_safe %></p><%
|
1299
|
+
end
|
1300
|
+
if (notice)
|
1301
|
+
%><p class=\"flashNotice\"><%= notice.html_safe %></p><%
|
1302
|
+
end
|
1303
|
+
end %>#{"
|
1406
1304
|
#{schema_options}" if schema_options}
|
1407
1305
|
<select id=\"tbl\">#{table_options}</select>
|
1408
1306
|
<table id=\"resourceName\"><tr>
|
@@ -1620,13 +1518,20 @@ end
|
|
1620
1518
|
c23.141-70.188,89.141-120.906,167.063-120.906c97.25,0,176,78.813,176,176C511.828,227.078,404.391,119.641,271.844,119.641z\" />
|
1621
1519
|
</svg>
|
1622
1520
|
|
1623
|
-
|
1521
|
+
<% if request.respond_to?(:flash)
|
1522
|
+
if (alert)
|
1523
|
+
%><p class=\"flashAlert\"><%= alert.html_safe %></p><%
|
1524
|
+
end
|
1525
|
+
if (notice)
|
1526
|
+
%><p class=\"flashNotice\"><%= notice.html_safe %></p><%
|
1527
|
+
end
|
1528
|
+
end %>#{"
|
1624
1529
|
#{schema_options}" if schema_options}
|
1625
1530
|
<select id=\"tbl\">#{table_options}</select>
|
1626
1531
|
<table id=\"resourceName\"><td><h1><%= page_title %></h1></td>
|
1627
1532
|
<% if Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) %>
|
1628
1533
|
<td><%= link_to_brick(
|
1629
|
-
::Brick::Rails::AVO_SVG,
|
1534
|
+
::Brick::Rails::AVO_SVG.html_safe,
|
1630
1535
|
{ show_proc: Proc.new do |obj, relation|
|
1631
1536
|
path_helper = \"resources_#\{relation.fetch(:auto_prefixed_schema, nil)}#\{obj.class.base_class.model_name.singular_route_key}_path\".to_sym
|
1632
1537
|
::Avo.railtie_routes_url_helpers.send(path_helper, obj) if ::Avo.railtie_routes_url_helpers.respond_to?(path_helper)
|
@@ -1638,7 +1543,7 @@ end
|
|
1638
1543
|
if Object.const_defined?('ActiveAdmin')
|
1639
1544
|
ActiveAdmin.application.namespaces.names.each do |ns| %>
|
1640
1545
|
<td><%= link_to_brick(
|
1641
|
-
::Brick::Rails::AA_PNG,
|
1546
|
+
::Brick::Rails::AA_PNG.html_safe,
|
1642
1547
|
{ show_proc: Proc.new do |aa_model, relation|
|
1643
1548
|
path_helper = \"#\{ns}_#\{relation.fetch(:auto_prefixed_schema, nil)}#\{rk = aa_model.model_name.singular_route_key}_path\".to_sym
|
1644
1549
|
send(path_helper, obj) if respond_to?(path_helper)
|
@@ -1694,12 +1599,14 @@ end
|
|
1694
1599
|
end
|
1695
1600
|
s << "<table id=\"#{hm_name}\" class=\"shadow\">
|
1696
1601
|
<tr><th>#{hm[1]}#{' poly' if hm[0].options[:as]} #{hm[3]}
|
1602
|
+
<% if respond_to?(:new_#{partial_new_path_name = hm.first.klass._brick_index(:singular)}_path) %>
|
1697
1603
|
<span class = \"add-hm-related\"><%=
|
1698
1604
|
pk_val = (obj_pk = model.primary_key).is_a?(String) ? obj.send(obj_pk) : obj_pk.map { |pk_part| obj.send(pk_part) }
|
1699
1605
|
pk_val_arr = [pk_val] unless pk_val.is_a?(Array)
|
1700
1606
|
link_to('<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"#fff\" d=\"M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z\"/></svg>'.html_safe,
|
1701
|
-
new_#{
|
1607
|
+
new_#{partial_new_path_name}_path(predicates))
|
1702
1608
|
%></span>
|
1609
|
+
<% end %>
|
1703
1610
|
</th></tr>
|
1704
1611
|
<% if (assoc = @#{obj_name}.class.reflect_on_association(:#{hm_name})).macro == :has_one &&
|
1705
1612
|
assoc.options&.fetch(:through, nil).nil?
|
@@ -91,8 +91,7 @@ module Brick::Rails::FormBuilder
|
|
91
91
|
when :binary
|
92
92
|
is_revert = false
|
93
93
|
if val
|
94
|
-
|
95
|
-
out << if val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
94
|
+
out << if ::Brick.is_geography?(val)
|
96
95
|
::Brick::Rails.display_value('geography', val)
|
97
96
|
else
|
98
97
|
::Brick::Rails.display_binary(val)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module Brick::Rails::FormTags
|
2
2
|
# Our super speedy grid
|
3
3
|
def brick_grid(relation = nil, bt_descrip = nil, sequence = nil, inclusions = nil, exclusions = nil,
|
4
|
-
cols = {}, poly_cols = nil, bts = {}, hms_keys = [], hms_cols = {}
|
4
|
+
cols = {}, poly_cols = nil, bts = {}, hms_keys = [], hms_cols = {},
|
5
|
+
show_header: nil, show_row_count: nil, show_erd_button: nil, show_new_button: nil, show_avo_button: nil, show_aa_button: nil)
|
5
6
|
# When a relation is not provided, first see if one exists which matches the controller name
|
6
7
|
unless (relation ||= instance_variable_get("@#{controller_name}".to_sym))
|
7
8
|
# Failing that, dig through the instance variables with hopes to find something that is an ActiveRecord::Relation
|
@@ -27,44 +28,57 @@ module Brick::Rails::FormTags
|
|
27
28
|
nfc = Brick.config.sidescroll.fetch(relation.table_name, nil)&.fetch(:num_frozen_columns, nil) ||
|
28
29
|
Brick.config.sidescroll.fetch(:num_frozen_columns, nil) ||
|
29
30
|
0
|
31
|
+
|
32
|
+
# HTML for brick_grid
|
30
33
|
out = +"<div id=\"headerTopContainer\"><table id=\"headerTop\"></table>
|
31
|
-
<div id=\"headerTopAddNew\">
|
32
|
-
<div id=\"headerButtonBox\">
|
33
|
-
<div id=\"imgErd\" title=\"Show ERD\"></div>
|
34
34
|
"
|
35
35
|
klass = relation.klass
|
36
|
-
|
37
|
-
out << "
|
36
|
+
unless show_header == false
|
37
|
+
out << " <div id=\"headerTopAddNew\">
|
38
|
+
<div id=\"headerButtonBox\">
|
39
|
+
"
|
40
|
+
unless show_row_count == false
|
41
|
+
out << " <div id=\"rowCount\"></div>
|
42
|
+
"
|
43
|
+
end
|
44
|
+
unless show_erd_button == false
|
45
|
+
out << " <div id=\"imgErd\" title=\"Show ERD\"></div>
|
46
|
+
"
|
47
|
+
end
|
48
|
+
if show_avo_button != false && Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) && klass.name.exclude?('::')
|
49
|
+
out << "
|
38
50
|
<td>#{link_to_brick(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
51
|
+
::Brick::Rails::AVO_SVG.html_safe,
|
52
|
+
{ index_proc: Proc.new do |_avo_model, relation|
|
53
|
+
path_helper = "resources_#{relation.fetch(:auto_prefixed_schema, nil)}#{klass.model_name.route_key}_path".to_sym
|
54
|
+
::Avo.railtie_routes_url_helpers.send(path_helper) if ::Avo.railtie_routes_url_helpers.respond_to?(path_helper)
|
55
|
+
end,
|
56
|
+
title: "#{klass.name} in Avo" }
|
45
57
|
)}</td>
|
46
58
|
"
|
47
|
-
|
59
|
+
end
|
48
60
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
61
|
+
if show_aa_button != false && Object.const_defined?('ActiveAdmin')
|
62
|
+
ActiveAdmin.application.namespaces.names.each do |ns|
|
63
|
+
out << "
|
64
|
+
<td>#{link_to_brick(
|
65
|
+
::Brick::Rails::AA_PNG.html_safe,
|
66
|
+
{ index_proc: Proc.new do |aa_model, relation|
|
67
|
+
path_helper = "#{ns}_#{relation.fetch(:auto_prefixed_schema, nil)}#{rk = aa_model.model_name.route_key}_path".to_sym
|
68
|
+
send(path_helper) if respond_to?(path_helper)
|
69
|
+
end,
|
70
|
+
title: "#{klass.name} in ActiveAdmin" }
|
59
71
|
)}</td>
|
60
72
|
"
|
73
|
+
end
|
61
74
|
end
|
62
|
-
end
|
63
|
-
|
64
75
|
out << " </div>
|
65
76
|
</div>
|
66
|
-
|
67
|
-
|
77
|
+
"
|
78
|
+
end
|
79
|
+
|
80
|
+
out << "</div>
|
81
|
+
<table id=\"#{table_name = relation.table_name.split('.').last}\" class=\"shadow\"#{ " x-num-frozen=\"#{nfc}\"" if nfc.positive? }>
|
68
82
|
<thead><tr>"
|
69
83
|
pk = klass.primary_key || []
|
70
84
|
pk = [pk] unless pk.is_a?(Array)
|
@@ -137,6 +151,7 @@ module Brick::Rails::FormTags
|
|
137
151
|
# ActiveRecord::StatementTimeout in Warehouse::ColdRoomTemperatures_Archive#index
|
138
152
|
# TinyTds::Error: Adaptive Server connection timed out
|
139
153
|
# (After restarting the server it worked fine again.)
|
154
|
+
rowCount = 0
|
140
155
|
relation.each do |obj|
|
141
156
|
out << "<tr>\n"
|
142
157
|
out << "<td class=\"col-sticky\">#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym,
|
@@ -152,16 +167,16 @@ module Brick::Rails::FormTags
|
|
152
167
|
out << " class=\"#{classes.join(' ')}\"" if classes&.present?
|
153
168
|
out << '>'
|
154
169
|
if (bt || composite_bt_names[col_name])
|
155
|
-
if bt[2] # Polymorphic?
|
156
|
-
if (poly_id = obj.send(
|
170
|
+
if bt[2] && obj.respond_to?(poly_id_col = "#{bt.first}_id") # Polymorphic?
|
171
|
+
if (poly_id = obj.send(poly_id_col))
|
157
172
|
bt_class = obj.send(klass.brick_foreign_type(bt.first))
|
158
173
|
base_class_underscored = (::Brick.existing_stis[bt_class] || bt_class).constantize.base_class._brick_index(:singular)
|
159
174
|
out << link_to("#{bt_class} ##{poly_id}", send("#{base_class_underscored}_path".to_sym, poly_id))
|
160
175
|
end
|
161
176
|
else # BT or HOT
|
162
177
|
bt_class = bt[1].first.first
|
163
|
-
if bt_descrip
|
164
|
-
descrips =
|
178
|
+
if bt_descrip && (this_bt_descrip = bt_descrip[bt.first])
|
179
|
+
descrips = this_bt_descrip[bt_class]
|
165
180
|
bt_id_col = if descrips.nil?
|
166
181
|
puts "Caught it in the act for obj / #{col_name}!"
|
167
182
|
elsif descrips.length == 1
|
@@ -237,10 +252,160 @@ module Brick::Rails::FormTags
|
|
237
252
|
out << '</td>'
|
238
253
|
end
|
239
254
|
out << '</tr>'
|
255
|
+
rowCount += 1
|
240
256
|
end
|
241
257
|
out << " </tbody>
|
242
258
|
</table>
|
259
|
+
<script>
|
260
|
+
var rowCount = document.getElementById(\"rowCount\");
|
261
|
+
if (rowCount) rowCount.innerHTML = \"#{pluralize(rowCount, "row")} \";
|
262
|
+
</script>
|
263
|
+
"
|
264
|
+
|
265
|
+
# Javascript for brick_grid
|
266
|
+
(@_brick_javascripts ||= {})[:grid_scripts] = "
|
267
|
+
var #{table_name}HtColumns;
|
268
|
+
|
269
|
+
// Snag first TR for sticky header
|
270
|
+
var grid = document.getElementById(\"#{table_name}\");
|
271
|
+
#{table_name}HtColumns = grid && [grid.getElementsByTagName(\"TR\")[0]];
|
272
|
+
var headerTop = document.getElementById(\"headerTop\");
|
273
|
+
var headerCols;
|
274
|
+
if (grid) {
|
275
|
+
// COLUMN HEADER AND TABLE CELL HIGHLIGHTING
|
276
|
+
var gridHighHeader = null,
|
277
|
+
gridHighCell = null;
|
278
|
+
grid.addEventListener(\"mouseenter\", gridMove);
|
279
|
+
grid.addEventListener(\"mousemove\", gridMove);
|
280
|
+
grid.addEventListener(\"mouseleave\", function (evt) {
|
281
|
+
if (gridHighCell) gridHighCell.classList.remove(\"highlight\");
|
282
|
+
gridHighCell = null;
|
283
|
+
if (gridHighHeader) gridHighHeader.classList.remove(\"highlight\");
|
284
|
+
gridHighHeader = null;
|
285
|
+
});
|
286
|
+
function gridMove(evt) {
|
287
|
+
var lastHighCell = gridHighCell;
|
288
|
+
gridHighCell = document.elementFromPoint(evt.x, evt.y);
|
289
|
+
while (gridHighCell && gridHighCell.tagName !== \"TD\" && gridHighCell.tagName !== \"TH\")
|
290
|
+
gridHighCell = gridHighCell.parentElement;
|
291
|
+
if (gridHighCell) {
|
292
|
+
if (lastHighCell !== gridHighCell) {
|
293
|
+
gridHighCell.classList.add(\"highlight\");
|
294
|
+
if (lastHighCell) lastHighCell.classList.remove(\"highlight\");
|
295
|
+
}
|
296
|
+
var lastHighHeader = gridHighHeader;
|
297
|
+
if ((gridHighHeader = headerCols[gridHighCell.cellIndex]) && lastHighHeader !== gridHighHeader) {
|
298
|
+
if (gridHighHeader) gridHighHeader.classList.add(\"highlight\");
|
299
|
+
if (lastHighHeader) lastHighHeader.classList.remove(\"highlight\");
|
300
|
+
}
|
301
|
+
}
|
302
|
+
}
|
303
|
+
// // LESS TOUCHY NAVIGATION BACK OR FORWARD IN HISTORY WHEN USING MOUSE WHEEL
|
304
|
+
// grid.addEventListener(\"wheel\", function (evt) {
|
305
|
+
// grid.scrollLeft += evt.deltaX;
|
306
|
+
// document.body.scrollTop += (evt.deltaY * 0.6);
|
307
|
+
// evt.preventDefault();
|
308
|
+
// return false;
|
309
|
+
// });
|
310
|
+
}
|
311
|
+
function setHeaderSizes() {
|
312
|
+
if (grid.clientWidth > window.outerWidth)
|
313
|
+
document.getElementById(\"titleBox\").style.width = grid.clientWidth;
|
314
|
+
// console.log(\"start\");
|
315
|
+
// See if the headerTop is already populated
|
316
|
+
// %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
|
317
|
+
headerTop.innerHTML = \"\"; // %%% Would love to not have to clear it out like this every time! (Currently doing this to support resize events.)
|
318
|
+
var isEmpty = headerTop.childElementCount === 0;
|
319
|
+
var numFixed = parseInt(grid.getAttribute(\"x-num-frozen\")) || 0;
|
320
|
+
var fixedColLefts = [0];
|
321
|
+
|
322
|
+
// Set up proper sizings of sticky column header
|
323
|
+
var node;
|
324
|
+
for (var j = 0; j < #{table_name}HtColumns.length; ++j) {
|
325
|
+
var row = #{table_name}HtColumns[j];
|
326
|
+
var tr = isEmpty ? document.createElement(\"TR\") : headerTop.childNodes[j];
|
327
|
+
tr.innerHTML = row.innerHTML.trim();
|
328
|
+
var curLeft = 0.0;
|
329
|
+
// Match up widths from the original column headers
|
330
|
+
for (var i = 0; i < row.childNodes.length; ++i) {
|
331
|
+
node = row.childNodes[i];
|
332
|
+
if (node.nodeType === 1) {
|
333
|
+
var th = tr.childNodes[i];
|
334
|
+
th.style.minWidth = th.style.maxWidth = getComputedStyle(node).width;
|
335
|
+
// Add \"left: __px\" style to the fixed-width column THs
|
336
|
+
if (i <= numFixed) {
|
337
|
+
th.style.position = \"sticky\";
|
338
|
+
th.style.backgroundColor = \"#008061\";
|
339
|
+
th.style.zIndex = \"1\";
|
340
|
+
th.style.left = curLeft + \"px\";
|
341
|
+
fixedColLefts.push(curLeft += node.clientWidth);
|
342
|
+
}
|
343
|
+
if (#{pk&.present? ? 'i > 0' : 'true'}) {
|
344
|
+
// Add <span> at the end
|
345
|
+
var span = document.createElement(\"SPAN\");
|
346
|
+
span.className = \"exclude\";
|
347
|
+
span.innerHTML = \"X\";
|
348
|
+
span.addEventListener(\"click\", function (e) {
|
349
|
+
e.stopPropagation();
|
350
|
+
doFetch(\"POST\", {_brick_exclude: this.parentElement.getAttribute(\"x-order\")});
|
351
|
+
});
|
352
|
+
th.appendChild(span);
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}
|
356
|
+
headerCols = tr.childNodes;
|
357
|
+
if (isEmpty) headerTop.appendChild(tr);
|
358
|
+
}
|
359
|
+
// Add \"left: __px\" style to all fixed-width column TDs
|
360
|
+
[...grid.children[1].children].forEach(function (row) {
|
361
|
+
for (var j = 1; j <= numFixed; ++j) {
|
362
|
+
row.children[j].style.left = fixedColLefts[j] + 'px';
|
363
|
+
}
|
364
|
+
});
|
365
|
+
grid.style.marginTop = \"-\" + getComputedStyle(headerTop).height;
|
366
|
+
// console.log(\"end\");
|
367
|
+
}
|
368
|
+
|
369
|
+
if (headerTop) {
|
370
|
+
onImagesLoaded(function() {
|
371
|
+
setHeaderSizes();
|
372
|
+
});
|
373
|
+
window.addEventListener(\"resize\", function(event) {
|
374
|
+
setHeaderSizes();
|
375
|
+
}, true);#{
|
376
|
+
if !klass.is_view? && respond_to?(new_path_name = "new_#{klass._brick_index(:singular)}_path")
|
377
|
+
"
|
378
|
+
var headerButtonBox = document.getElementById(\"headerButtonBox\");
|
379
|
+
if (headerButtonBox) {
|
380
|
+
var addNew = document.createElement(\"A\");
|
381
|
+
addNew.id = \"addNew\";
|
382
|
+
addNew.href = \"#{send(new_path_name)}\";
|
383
|
+
addNew.title = \"New #{table_name.singularize}\";
|
384
|
+
addNew.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"#fff\" d=\"M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z\"/></svg>';
|
385
|
+
headerButtonBox.append(addNew);
|
386
|
+
}
|
243
387
|
"
|
388
|
+
end}
|
389
|
+
}
|
390
|
+
|
391
|
+
function onImagesLoaded(event) {
|
392
|
+
var images = document.getElementsByTagName(\"IMG\");
|
393
|
+
var numLoaded = images.length;
|
394
|
+
for (var i = 0; i < images.length; ++i) {
|
395
|
+
if (images[i].complete)
|
396
|
+
--numLoaded;
|
397
|
+
else {
|
398
|
+
images[i].addEventListener(\"load\", function() {
|
399
|
+
if (--numLoaded <= 0)
|
400
|
+
event();
|
401
|
+
});
|
402
|
+
}
|
403
|
+
}
|
404
|
+
if (numLoaded <= 0)
|
405
|
+
event();
|
406
|
+
}
|
407
|
+
"
|
408
|
+
|
244
409
|
out.html_safe
|
245
410
|
end # brick_grid
|
246
411
|
|
@@ -11,8 +11,8 @@ module ::Brick::Rails
|
|
11
11
|
<path d=\"M82.812 76.8753C82.6905 76.694 82.3715 76.2207 82.2449 76.0444C82.2044 75.9739 82.2044 75.8782 82.1588 75.8127C82.1132 75.7473 82.1335 75.7724 82.1183 75.7573C79.0714 71.3971 75.1056 67.7497 70.4969 65.0692C65.8882 62.3886 60.7474 60.7393 55.4325 60.2361C54.3236 60.1354 53.1943 60.08 52.055 60.08C45.2173 60.1051 38.5214 62.022 32.7166 65.6161C26.9118 69.2102 22.2271 74.3397 19.1864 80.4308L19.151 80.5013C18.7358 81.3323 18.3458 82.1784 17.9914 83.0194L16.9786 85.2655C16.9077 85.3662 16.8419 85.472 16.771 85.5828C16.6647 85.7389 16.5584 85.9 16.4621 86.0612C15.3778 87.6439 13.8123 88.8397 11.995 89.4732C10.1776 90.1068 8.20406 90.1448 6.36344 89.5817C4.52281 89.0186 2.9119 87.884 1.76676 86.3442C0.621625 84.8044 0.00246102 82.9403 0 81.0251C0.00604053 80.0402 0.177178 79.0632 0.506372 78.1344L1.22036 76.5681C1.25084 76.5034 1.28639 76.4411 1.32669 76.3818C1.40265 76.2559 1.47861 76.135 1.56469 76.0192C1.58531 75.9789 1.60901 75.9401 1.63558 75.9034C7.06401 67.6054 14.947 61.1866 24.1977 57.5317C33.4485 53.8768 43.6114 53.166 53.2855 55.4971L48.9155 45.9286L41.9276 30.6188L33.8256 12.8263L33.6433 12.4285C32.7439 10.3058 32.6986 7.92067 33.5167 5.76573L34.0231 4.69304C34.8148 3.24136 35.9941 2.03525 37.431 1.20762C38.868 0.379997 40.5068 -0.0370045 42.1668 0.0025773C43.8268 0.0421591 45.4436 0.536787 46.839 1.43195C48.2345 2.32711 49.3543 3.58804 50.0751 5.07578L50.2523 5.47363L51.8474 8.96365L74.0974 57.708L82.812 76.8753Z\" fill=\"currentColor\" fill-opacity=\"0.22\"></path>
|
12
12
|
<path opacity=\"0.25\" d=\"M41.9129 30.649L35.3301 45.0422C35.2023 45.3204 35.0074 45.563 34.7627 45.7484C34.518 45.9337 34.2311 46.0562 33.9274 46.1048C27.3926 47.1897 21.1567 49.6166 15.617 53.2308C15.279 53.4505 14.8783 53.555 14.4753 53.5286C14.0723 53.5022 13.6889 53.3463 13.3827 53.0844C13.0765 52.8225 12.8642 52.4688 12.7777 52.0765C12.6911 51.6842 12.7351 51.2745 12.9029 50.9092L32.0285 8.99382L33.4869 5.7959C32.6687 7.95084 32.7141 10.336 33.6135 12.4586L33.7958 12.8565L41.9129 30.649Z\" fill=\"currentColor\" fill-opacity=\"0.22\"></path>
|
13
13
|
</svg>
|
14
|
-
"
|
14
|
+
"
|
15
15
|
|
16
16
|
AA_PNG = "<img src=\"data:image/png;base64,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\">
|
17
|
-
"
|
17
|
+
"
|
18
18
|
end
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -89,7 +89,7 @@ end
|
|
89
89
|
# is first established), and then automatically creates models, controllers, views,
|
90
90
|
# and routes based on those available relations.
|
91
91
|
require 'brick/config'
|
92
|
-
if Gem::Specification.all_names.any? { |g| g.start_with?('rails-') }
|
92
|
+
if Gem::Specification.all_names.any? { |g| g.start_with?('rails-') && g[6..-1] =~ /^([0-9]|\.)+$/ }
|
93
93
|
require 'rails'
|
94
94
|
require 'brick/frameworks/rails'
|
95
95
|
end
|
@@ -111,6 +111,15 @@ module Brick
|
|
111
111
|
:is_oracle, :is_eager_loading, :auto_models, :initializer_loaded
|
112
112
|
::Brick.auto_models = []
|
113
113
|
|
114
|
+
def get_possible_schemas
|
115
|
+
if (possible_schemas = (multitenancy = ::Brick.config.schema_behavior&.[](:multitenant)) &&
|
116
|
+
multitenancy&.[](:schema_to_analyse))
|
117
|
+
possible_schemas = [possible_schemas] unless possible_schemas.is_a?(Array)
|
118
|
+
possible_schema = possible_schemas.find { |ps| ::Brick.db_schemas.key?(ps) }
|
119
|
+
end
|
120
|
+
[possible_schema, possible_schemas, multitenancy]
|
121
|
+
end
|
122
|
+
|
114
123
|
def set_db_schema(params = nil)
|
115
124
|
# If Apartment::Tenant.current is not still the default (usually 'public') then an elevator has brought us into
|
116
125
|
# a different tenant. If so then don't allow schema navigation.
|
@@ -140,7 +149,19 @@ module Brick
|
|
140
149
|
ch.connection_pool_list.blank?
|
141
150
|
|
142
151
|
# Key our list of relations for this connection off of the connection pool's object_id
|
143
|
-
|
152
|
+
cp_objid = ActiveRecord::Base.connection_pool.object_id
|
153
|
+
@relations ||= {}
|
154
|
+
|
155
|
+
# Have we already seen this database? (Perhaps we're connecting to a replica?)
|
156
|
+
@relations[cp_objid] ||= if (db_name = ActiveRecord::Base.connection&.instance_variable_get(:@config)&.fetch(:database, nil)) &&
|
157
|
+
!@relations.key?(cp_objid) &&
|
158
|
+
(existing = @relations.find { |_k, v| v.fetch(:db_name, nil) == db_name })
|
159
|
+
existing.last
|
160
|
+
else
|
161
|
+
Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = {} } }.tap do |h|
|
162
|
+
h[:db_name] = db_name if db_name
|
163
|
+
end
|
164
|
+
end
|
144
165
|
end
|
145
166
|
|
146
167
|
def apartment_multitenant
|
@@ -297,6 +318,10 @@ module Brick
|
|
297
318
|
true
|
298
319
|
end
|
299
320
|
|
321
|
+
def is_geography?(val)
|
322
|
+
val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
323
|
+
end
|
324
|
+
|
300
325
|
# @api public
|
301
326
|
def mode=(setting)
|
302
327
|
Brick.config.mode = setting
|
@@ -611,7 +636,9 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
611
636
|
end
|
612
637
|
|
613
638
|
# Find associative tables that can be set up for has_many :through
|
614
|
-
::Brick.relations.each do |
|
639
|
+
::Brick.relations.each do |key, tbl|
|
640
|
+
next if key.is_a?(Symbol)
|
641
|
+
|
615
642
|
tbl_cols = tbl[:cols].keys
|
616
643
|
fks = tbl[:fks].each_with_object({}) { |fk, s| s[fk.last[:fk]] = [fk.last[:assoc_name], fk.last[:inverse_table]] if fk.last[:is_bt]; s }
|
617
644
|
# Aside from the primary key and the metadata columns created_at, updated_at, and deleted_at, if this table only has
|
@@ -706,6 +733,8 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
706
733
|
|
707
734
|
if res_names.empty?
|
708
735
|
::Brick.relations.each_with_object({}) do |v, s|
|
736
|
+
next if v.first.is_a?(Symbol)
|
737
|
+
|
709
738
|
v_parts = v.first.split('.')
|
710
739
|
v_parts.shift if v_parts.first == 'public'
|
711
740
|
res_names[v_parts.join('.')] = v.first
|
@@ -867,6 +896,8 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
867
896
|
end
|
868
897
|
versioned_views = {} # Track which views have already been done for each api_root
|
869
898
|
::Brick.relations.each do |k, v|
|
899
|
+
next if k.is_a?(Symbol)
|
900
|
+
|
870
901
|
if (schema_name = v.fetch(:schema, nil))
|
871
902
|
schema_prefix = "#{schema_name}."
|
872
903
|
end
|
@@ -894,7 +925,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
894
925
|
else
|
895
926
|
table_class_length = class_name.length if class_name.length > table_class_length
|
896
927
|
tables
|
897
|
-
end << [class_name, aps,
|
928
|
+
end << [class_name, aps, k.tr('.', '/')]
|
898
929
|
end
|
899
930
|
|
900
931
|
options = {}
|
@@ -35,6 +35,8 @@ module Brick
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
possible_additional_references = relations.each_with_object(Hash.new { |h, k| h[k] = [] }) do |relation, s|
|
38
|
+
next if relation.first.is_a?(Symbol)
|
39
|
+
|
38
40
|
this_tnp = tnps&.keys&.find { |tnp| relation.first.start_with?(tnp) }
|
39
41
|
model_filename = "app/models/#{ActiveSupport::Inflector.singularize(relation.first)}.rb"
|
40
42
|
relation.last[:cols].each do |col, type|
|
@@ -105,7 +105,6 @@ module Brick
|
|
105
105
|
built_schemas = {} # Track all built schemas so we can place an appropriate drop_schema command only in the first
|
106
106
|
# migration in which that schema is referenced, thereby allowing rollbacks to function properly.
|
107
107
|
versions_to_create = [] # Resulting versions to be used when updating the schema_migrations table
|
108
|
-
ar_base = Object.const_defined?(:ApplicationRecord) ? ApplicationRecord : Class.new(ActiveRecord::Base)
|
109
108
|
# Start by making migrations for fringe tables (those with no foreign keys).
|
110
109
|
# Continue layer by layer, creating migrations for tables that reference ones already done, until
|
111
110
|
# no more migrations can be created. (At that point hopefully all tables are accounted for.)
|
@@ -126,7 +125,7 @@ module Brick
|
|
126
125
|
fringe.each do |tbl|
|
127
126
|
next unless (relation = relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present?
|
128
127
|
|
129
|
-
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ar_base.primary_key].flatten.sort)
|
128
|
+
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [::Brick.ar_base.primary_key].flatten.sort)
|
130
129
|
# In case things aren't as standard
|
131
130
|
if pkey_cols.empty?
|
132
131
|
pkey_cols = if rpk.empty? && relation[:cols][arpk.first]&.first == key_type
|
@@ -239,9 +238,9 @@ module Brick
|
|
239
238
|
begin
|
240
239
|
primary_key = relations[fk[:inverse_table]][:class_name]&.constantize&.primary_key
|
241
240
|
rescue NameError => e
|
242
|
-
primary_key = ar_base.primary_key
|
241
|
+
primary_key = ::Brick.ar_base.primary_key
|
243
242
|
end
|
244
|
-
mig << " t.references :#{fk[:assoc_name]}#{suffix}, foreign_key: { to_table: #{to_table}#{", primary_key: :#{primary_key}" if primary_key != ar_base.primary_key} }\n"
|
243
|
+
mig << " t.references :#{fk[:assoc_name]}#{suffix}, foreign_key: { to_table: #{to_table}#{", primary_key: :#{primary_key}" if primary_key != ::Brick.ar_base.primary_key} }\n"
|
245
244
|
end
|
246
245
|
else
|
247
246
|
next if !id_option&.end_with?('id: false') && pkey_cols&.include?(col)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.174
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-09-
|
11
|
+
date: 2023-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|