brick 1.0.153 → 1.0.155
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/lib/brick/config.rb +16 -0
- data/lib/brick/frameworks/rails/engine.rb +32 -0
- data/lib/brick/frameworks/rails/form_tags.rb +7 -3
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +11 -0
- data/lib/generators/brick/install_generator.rb +9 -1
- data/lib/generators/brick/migrations_generator.rb +11 -4
- data/lib/generators/brick/seeds_generator.rb +116 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fceffbcf863eb9c03b64a0cb4420a33ded5eb7f3908b40b263a345ae9bf5c164
|
4
|
+
data.tar.gz: 81f9f96bd1463b8b7e7736ed4716bcf78609bae27485af4de15cb23ae12e27ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c41a59ca62c80012166225b0cf80505b81fe57ccdfeb92c4add7f227d6d4a9cc0c664aaf5209c31dabd54c3e471fe140fd3dc75bf1441bbed0fca67e9801ffd9
|
7
|
+
data.tar.gz: 83c874515b230b0b607da32e41366284b15e830ebd7f7022fb318db412fef94a0339495de54c9ab0277425af2635cc8ab235675074cbb50f703082979ebd28b5
|
data/lib/brick/config.rb
CHANGED
@@ -230,6 +230,14 @@ module Brick
|
|
230
230
|
@mutex.synchronize { @json_columns = cols }
|
231
231
|
end
|
232
232
|
|
233
|
+
def sidescroll
|
234
|
+
@mutex.synchronize { @sidescroll ||= {} }
|
235
|
+
end
|
236
|
+
|
237
|
+
def sidescroll=(scroll)
|
238
|
+
@mutex.synchronize { @sidescroll = scroll }
|
239
|
+
end
|
240
|
+
|
233
241
|
def model_descrips
|
234
242
|
@mutex.synchronize { @model_descrips ||= {} }
|
235
243
|
end
|
@@ -372,6 +380,14 @@ module Brick
|
|
372
380
|
@mutex.synchronize { @always_load_fields = field_set }
|
373
381
|
end
|
374
382
|
|
383
|
+
def ignore_migration_fks
|
384
|
+
@mutex.synchronize { @ignore_migration_fks || [] }
|
385
|
+
end
|
386
|
+
|
387
|
+
def ignore_migration_fks=(relations)
|
388
|
+
@mutex.synchronize { @ignore_migration_fks = relations }
|
389
|
+
end
|
390
|
+
|
375
391
|
# Add status page showing all resources and what files have been built out for them
|
376
392
|
def add_status
|
377
393
|
true
|
@@ -864,6 +864,10 @@ tr th {
|
|
864
864
|
color: #fff;
|
865
865
|
text-align: left;
|
866
866
|
}
|
867
|
+
.col-sticky {
|
868
|
+
position: sticky;
|
869
|
+
left: 0;
|
870
|
+
}
|
867
871
|
#headerTop tr th {
|
868
872
|
position: relative;
|
869
873
|
}
|
@@ -902,6 +906,10 @@ tr td.highlight {
|
|
902
906
|
background-color: #B0B0FF;
|
903
907
|
}
|
904
908
|
|
909
|
+
table tr .col-sticky {
|
910
|
+
background-color: #28B898;
|
911
|
+
}
|
912
|
+
|
905
913
|
.show-field {
|
906
914
|
background-color: #004998;
|
907
915
|
}
|
@@ -916,6 +924,12 @@ table.shadow > tbody > tr {
|
|
916
924
|
table tbody tr:nth-of-type(even) {
|
917
925
|
background-color: #f3f3f3;
|
918
926
|
}
|
927
|
+
table tbody tr:nth-of-type(even) .col-sticky {
|
928
|
+
background-color: #fff;
|
929
|
+
}
|
930
|
+
table tbody tr:nth-of-type(odd) .col-sticky {
|
931
|
+
background-color: #f3f3f3;
|
932
|
+
}
|
919
933
|
|
920
934
|
table.shadow > tbody > tr:last-of-type {
|
921
935
|
border-bottom: 2px solid #009879;
|
@@ -1080,18 +1094,30 @@ function setHeaderSizes() {
|
|
1080
1094
|
// %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
|
1081
1095
|
headerTop.innerHTML = \"\"; // %%% Would love to not have to clear it out like this every time! (Currently doing this to support resize events.)
|
1082
1096
|
var isEmpty = headerTop.childElementCount === 0;
|
1097
|
+
var numFixed = parseInt(grid.getAttribute(\"x-num-frozen\")) || 0;
|
1098
|
+
var fixedColLefts = [0];
|
1099
|
+
|
1083
1100
|
// Set up proper sizings of sticky column header
|
1084
1101
|
var node;
|
1085
1102
|
for (var j = 0; j < #{table_name}HtColumns.length; ++j) {
|
1086
1103
|
var row = #{table_name}HtColumns[j];
|
1087
1104
|
var tr = isEmpty ? document.createElement(\"TR\") : headerTop.childNodes[j];
|
1088
1105
|
tr.innerHTML = row.innerHTML.trim();
|
1106
|
+
var curLeft = 0.0;
|
1089
1107
|
// Match up widths from the original column headers
|
1090
1108
|
for (var i = 0; i < row.childNodes.length; ++i) {
|
1091
1109
|
node = row.childNodes[i];
|
1092
1110
|
if (node.nodeType === 1) {
|
1093
1111
|
var th = tr.childNodes[i];
|
1094
1112
|
th.style.minWidth = th.style.maxWidth = getComputedStyle(node).width;
|
1113
|
+
// Add \"left: __px\" style to the fixed-width column THs
|
1114
|
+
if (i <= numFixed) {
|
1115
|
+
th.style.position = \"sticky\";
|
1116
|
+
th.style.backgroundColor = \"#008061\";
|
1117
|
+
th.style.zIndex = \"1\";
|
1118
|
+
th.style.left = curLeft + \"px\";
|
1119
|
+
fixedColLefts.push(curLeft += node.clientWidth);
|
1120
|
+
}
|
1095
1121
|
if (#{pk&.present? ? 'i > 0' : 'true'}) {
|
1096
1122
|
// Add <span> at the end
|
1097
1123
|
var span = document.createElement(\"SPAN\");
|
@@ -1108,6 +1134,12 @@ function setHeaderSizes() {
|
|
1108
1134
|
headerCols = tr.childNodes;
|
1109
1135
|
if (isEmpty) headerTop.appendChild(tr);
|
1110
1136
|
}
|
1137
|
+
// Add \"left: __px\" style to all fixed-width column TDs
|
1138
|
+
[...grid.children[1].children].forEach(function (row) {
|
1139
|
+
for (var j = 1; j <= numFixed; ++j) {
|
1140
|
+
row.children[j].style.left = fixedColLefts[j] + 'px';
|
1141
|
+
}
|
1142
|
+
});
|
1111
1143
|
grid.style.marginTop = \"-\" + getComputedStyle(headerTop).height;
|
1112
1144
|
// console.log(\"end\");
|
1113
1145
|
}
|
@@ -24,8 +24,11 @@ module Brick::Rails::FormTags
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
nfc = Brick.config.sidescroll.fetch(relation.table_name, nil)&.fetch(:num_frozen_columns, nil) ||
|
28
|
+
Brick.config.sidescroll.fetch(:num_frozen_columns, nil) ||
|
29
|
+
0
|
27
30
|
out = "<table id=\"headerTop\"></table>
|
28
|
-
<table id=\"#{relation.table_name.split('.').last}\" class=\"shadow\">
|
31
|
+
<table id=\"#{relation.table_name.split('.').last}\" class=\"shadow\"#{ " x-num-frozen=\"#{nfc}\"" if nfc.positive? }>
|
29
32
|
<thead><tr>"
|
30
33
|
pk = (klass = relation.klass).primary_key || []
|
31
34
|
pk = [pk] unless pk.is_a?(Array)
|
@@ -95,12 +98,13 @@ module Brick::Rails::FormTags
|
|
95
98
|
# (After restarting the server it worked fine again.)
|
96
99
|
relation.each do |obj|
|
97
100
|
out << "<tr>\n"
|
98
|
-
out << "<td>#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym,
|
101
|
+
out << "<td class=\"col-sticky\">#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym,
|
99
102
|
pk.map { |pk_part| obj.send(pk_part.to_sym) }), { class: 'big-arrow' })}</td>\n" if pk.present?
|
100
|
-
sequence.
|
103
|
+
sequence.each_with_index do |col_name, idx|
|
101
104
|
val = obj.attributes[col_name]
|
102
105
|
bt = bts[col_name]
|
103
106
|
out << '<td'
|
107
|
+
(classes ||= []) << 'col-sticky' if idx < nfc
|
104
108
|
(classes ||= []) << 'dimmed' unless cols.key?(col_name) || (cust_col = cust_cols[col_name]) ||
|
105
109
|
(col_name.is_a?(Symbol) && bts.key?(col_name)) # HOT
|
106
110
|
(classes ||= []) << 'right' if val.is_a?(Numeric) && !bt
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -501,6 +501,11 @@ module Brick
|
|
501
501
|
Brick.config.json_columns = cols
|
502
502
|
end
|
503
503
|
|
504
|
+
# @api public
|
505
|
+
def sidescroll=(scroll)
|
506
|
+
Brick.config.sidescroll = scroll
|
507
|
+
end
|
508
|
+
|
504
509
|
# DSL templates for individual models to provide prettier descriptions of objects
|
505
510
|
# @api public
|
506
511
|
def model_descrips=(descrips)
|
@@ -1159,6 +1164,12 @@ ActiveSupport.on_load(:active_record) do
|
|
1159
1164
|
mattr_accessor :default_timezone, instance_writer: false
|
1160
1165
|
self.default_timezone = :utc
|
1161
1166
|
end
|
1167
|
+
|
1168
|
+
unless respond_to?(:primary_abstract_class)
|
1169
|
+
def self.primary_abstract_class
|
1170
|
+
self.abstract_class = true
|
1171
|
+
end
|
1172
|
+
end
|
1162
1173
|
end
|
1163
1174
|
|
1164
1175
|
# Rails < 4.0 cannot do #find_by, #find_or_create_by, or do #pluck on multiple columns, so here are the patches:
|
@@ -35,7 +35,7 @@ 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
|
-
this_tnp = tnps&.keys
|
38
|
+
this_tnp = tnps&.keys&.find { |tnp| relation.first.start_with?(tnp) }
|
39
39
|
model_filename = "app/models/#{ActiveSupport::Inflector.singularize(relation.first)}.rb"
|
40
40
|
relation.last[:cols].each do |col, type|
|
41
41
|
col_down = col.downcase
|
@@ -244,6 +244,14 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
|
|
244
244
|
# Brick.column_sequence = { 'users' => { include: ['email', 'profile.firstname', 'profile.lastname'] },
|
245
245
|
# 'profile' => { exclude: ['birthdate'] } }
|
246
246
|
|
247
|
+
# # When rendering the grid on index pages, a default number of columns to keep as \"sticky\" so that they remain
|
248
|
+
# # at the left of the grid while scrolling. By default this is 0 extra columns -- only the link to that
|
249
|
+
# # object's show / edit page is sticky. And this would add one extra column in the mix:
|
250
|
+
# Brick.sidescroll = { num_frozen_columns: 1 }
|
251
|
+
# # As well if you would like to customise this for specific resources, that is possible:
|
252
|
+
# Brick.sidescroll = { num_frozen_columns: 0,
|
253
|
+
# 'products' => { num_frozen_columns: 2 } }
|
254
|
+
|
247
255
|
# # EXTRA FOREIGN KEYS AND OTHER HAS_MANY SETTINGS
|
248
256
|
|
249
257
|
# # Additional table references which are used to create has_many / belongs_to associations inside auto-created
|
@@ -123,21 +123,27 @@ module Brick
|
|
123
123
|
built_schemas = {} # Track all built schemas so we can place an appropriate drop_schema command only in the first
|
124
124
|
# migration in which that schema is referenced, thereby allowing rollbacks to function properly.
|
125
125
|
versions_to_create = [] # Resulting versions to be used when updating the schema_migrations table
|
126
|
+
ar_base = Object.const_defined?(:ApplicationRecord) ? ApplicationRecord : Class.new(ActiveRecord::Base)
|
126
127
|
# Start by making migrations for fringe tables (those with no foreign keys).
|
127
128
|
# Continue layer by layer, creating migrations for tables that reference ones already done, until
|
128
129
|
# no more migrations can be created. (At that point hopefully all tables are accounted for.)
|
129
130
|
while (fringe = chosen.reject do |tbl|
|
131
|
+
snag_fks = []
|
130
132
|
snags = ::Brick.relations.fetch(tbl, nil)&.fetch(:fks, nil)&.select do |_k, v|
|
131
133
|
v[:is_bt] && !v[:polymorphic] &&
|
132
134
|
tbl != v[:inverse_table] && # Ignore self-referencing associations (stuff like "parent_id")
|
133
|
-
!done.include?(v[:inverse_table])
|
135
|
+
!done.include?(v[:inverse_table]) &&
|
136
|
+
::Brick.config.ignore_migration_fks.exclude?(snag_fk = "#{tbl}.#{v[:fk]}") &&
|
137
|
+
snag_fks << snag_fk
|
138
|
+
end
|
139
|
+
if snags&.present?
|
140
|
+
# puts snag_fks.inspect
|
141
|
+
stuck[tbl] = snags
|
134
142
|
end
|
135
|
-
stuck[tbl] = snags if snags&.present?
|
136
143
|
end).present?
|
137
144
|
fringe.each do |tbl|
|
138
145
|
next unless (relation = ::Brick.relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present?
|
139
146
|
|
140
|
-
ar_base = Object.const_defined?(:ApplicationRecord) ? ApplicationRecord : Class.new(ActiveRecord::Base)
|
141
147
|
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ar_base.primary_key].flatten.sort)
|
142
148
|
# In case things aren't as standard
|
143
149
|
if pkey_cols.empty?
|
@@ -246,7 +252,8 @@ module Brick
|
|
246
252
|
suffix << ", index: { name: '#{shorter || idx_name}' }"
|
247
253
|
indexes[shorter || idx_name] = nil
|
248
254
|
end
|
249
|
-
|
255
|
+
primary_key = ::Brick.relations[fk[:inverse_table]][:class_name]&.constantize&.primary_key
|
256
|
+
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"
|
250
257
|
end
|
251
258
|
else
|
252
259
|
next if !id_option&.end_with?('id: false') && pkey_cols&.include?(col)
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'fancy_gets'
|
5
|
+
|
6
|
+
module Brick
|
7
|
+
class SeedsGenerator < ::Rails::Generators::Base
|
8
|
+
include FancyGets
|
9
|
+
|
10
|
+
desc 'Auto-generates a seeds file from existing data.'
|
11
|
+
|
12
|
+
def brick_seeds
|
13
|
+
# %%% If Apartment is active and there's no schema_to_analyse, ask which schema they want
|
14
|
+
|
15
|
+
::Brick.mode = :on
|
16
|
+
ActiveRecord::Base.establish_connection
|
17
|
+
|
18
|
+
if (tables = ::Brick.relations.reject { |k, v| v.key?(:isView) && v[:isView] == true }.map(&:first).sort).empty?
|
19
|
+
puts "No tables found in database #{ActiveRecord::Base.connection.current_database}."
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
if File.exist?(seed_file_path = "#{::Rails.root}/db/seeds.rb")
|
24
|
+
puts "WARNING: seeds file #{seed_file_path} appears to already be present."
|
25
|
+
end
|
26
|
+
|
27
|
+
# Generate a list of tables that can be chosen
|
28
|
+
chosen = gets_list(list: tables, chosen: tables.dup)
|
29
|
+
schemas = chosen.each_with_object({}) do |v, s|
|
30
|
+
if (v_parts = v.split('.')).length > 1
|
31
|
+
s[v_parts.first] = nil unless [::Brick.default_schema, 'public'].include?(v_parts.first)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
seeds = +"# Seeds file for #{ActiveRecord::Base.connection.current_database}:"
|
35
|
+
done = []
|
36
|
+
fks = {}
|
37
|
+
stuck = {}
|
38
|
+
indexes = {} # Track index names to make sure things are unique
|
39
|
+
ar_base = Object.const_defined?(:ApplicationRecord) ? ApplicationRecord : Class.new(ActiveRecord::Base)
|
40
|
+
# Start by making entries for fringe models (those with no foreign keys).
|
41
|
+
# Continue layer by layer, creating entries for models that reference ones already done, until
|
42
|
+
# no more entries can be created. (At that point hopefully all models are accounted for.)
|
43
|
+
while (fringe = chosen.reject do |tbl|
|
44
|
+
snag_fks = []
|
45
|
+
snags = ::Brick.relations.fetch(tbl, nil)&.fetch(:fks, nil)&.select do |_k, v|
|
46
|
+
v[:is_bt] && !v[:polymorphic] &&
|
47
|
+
tbl != v[:inverse_table] && # Ignore self-referencing associations (stuff like "parent_id")
|
48
|
+
!done.include?(v[:inverse_table]) &&
|
49
|
+
::Brick.config.ignore_migration_fks.exclude?(snag_fk = "#{tbl}.#{v[:fk]}") &&
|
50
|
+
snag_fks << snag_fk
|
51
|
+
end
|
52
|
+
if snags&.present?
|
53
|
+
# puts snag_fks.inspect
|
54
|
+
stuck[tbl] = snags
|
55
|
+
end
|
56
|
+
end).present?
|
57
|
+
seeds << "\n"
|
58
|
+
fringe.each do |tbl|
|
59
|
+
next unless ::Brick.config.exclude_tables.exclude?(tbl) &&
|
60
|
+
(relation = ::Brick.relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present? &&
|
61
|
+
(klass = Object.const_get(class_name = relation[:class_name])).table_exists?
|
62
|
+
|
63
|
+
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ar_base.primary_key].flatten.sort)
|
64
|
+
# In case things aren't as standard
|
65
|
+
if pkey_cols.empty?
|
66
|
+
pkey_cols = if rpk.empty? # && relation[:cols][arpk.first]&.first == key_type
|
67
|
+
arpk
|
68
|
+
elsif rpk.first
|
69
|
+
rpk
|
70
|
+
end
|
71
|
+
end
|
72
|
+
schema = if (tbl_parts = tbl.split('.')).length > 1
|
73
|
+
if tbl_parts.first == (::Brick.default_schema || 'public')
|
74
|
+
tbl_parts.shift
|
75
|
+
nil
|
76
|
+
else
|
77
|
+
tbl_parts.first
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# %%% For the moment we're skipping polymorphics
|
82
|
+
fkeys = relation[:fks].values.select { |assoc| assoc[:is_bt] && !assoc[:polymorphic] }
|
83
|
+
# Refer to this table name as a symbol or dotted string as appropriate
|
84
|
+
# tbl_code = tbl_parts.length == 1 ? ":#{tbl_parts.first}" : "'#{tbl}'"
|
85
|
+
seeds << " # #{class_name}\n"
|
86
|
+
|
87
|
+
is_empty = true
|
88
|
+
klass.order(*pkey_cols).each do |obj|
|
89
|
+
is_empty = false
|
90
|
+
pk_val = obj.send(pkey_cols.first)
|
91
|
+
fk_vals = []
|
92
|
+
data = []
|
93
|
+
relation[:cols].each do |col, col_type|
|
94
|
+
next if !(fk = fkeys.find { |assoc| col == assoc[:fk] }) &&
|
95
|
+
pkey_cols.include?(col)
|
96
|
+
|
97
|
+
if (val = obj.send(col)) && (val.is_a?(Time) || val.is_a?(Date))
|
98
|
+
val = val.to_s
|
99
|
+
end
|
100
|
+
if fk
|
101
|
+
fk_vals << "#{fk[:assoc_name]}: #{fk[:inverse_table]}_#{val.inspect}" if val
|
102
|
+
else
|
103
|
+
data << "#{col}: #{val.inspect}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
seeds << "#{tbl}_#{pk_val} = #{class_name}.create(#{(fk_vals + data).join(', ')})\n"
|
107
|
+
end
|
108
|
+
File.open(seed_file_path, "w") { |f| f.write seeds }
|
109
|
+
end
|
110
|
+
done.concat(fringe)
|
111
|
+
chosen -= done
|
112
|
+
end
|
113
|
+
puts "\n*** Created seeds for #{done.length} models in db/seeds.rb ***"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
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.155
|
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-
|
11
|
+
date: 2023-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -257,6 +257,7 @@ files:
|
|
257
257
|
- lib/generators/brick/install_generator.rb
|
258
258
|
- lib/generators/brick/migrations_generator.rb
|
259
259
|
- lib/generators/brick/models_generator.rb
|
260
|
+
- lib/generators/brick/seeds_generator.rb
|
260
261
|
- lib/generators/brick/templates/add_object_changes_to_versions.rb.erb
|
261
262
|
- lib/generators/brick/templates/create_versions.rb.erb
|
262
263
|
homepage: https://github.com/lorint/brick
|