localtower 0.4.2 → 1.0.0

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -46
  3. data/app/controllers/localtower/pages_controller.rb +28 -42
  4. data/app/helpers/localtower/application_helper.rb +0 -18
  5. data/app/views/layouts/localtower/application.html.erb +20 -79
  6. data/app/views/localtower/pages/_alert_no_models.html.erb +3 -0
  7. data/app/views/localtower/pages/migrations.html.erb +50 -120
  8. data/app/views/localtower/pages/models.html.erb +53 -68
  9. data/app/views/localtower/pages/new_migration.html.erb +103 -0
  10. data/app/views/localtower/pages/new_model.html.erb +87 -0
  11. data/config/routes.rb +8 -17
  12. data/lib/localtower/generators/migration.rb +53 -181
  13. data/lib/localtower/generators/model.rb +53 -32
  14. data/lib/localtower/generators/service_objects/insert_array.rb +23 -0
  15. data/lib/localtower/generators/service_objects/insert_defaults.rb +15 -43
  16. data/lib/localtower/generators/service_objects/insert_indexes.rb +80 -0
  17. data/lib/localtower/generators/service_objects/insert_nullable.rb +23 -0
  18. data/lib/localtower/status.rb +12 -7
  19. data/lib/localtower/tools.rb +29 -24
  20. data/lib/localtower/version.rb +1 -1
  21. data/lib/localtower.rb +0 -1
  22. data/public/css/app.css +0 -49
  23. data/public/js/app.js +216 -86
  24. data/public/light-bootstrap-dashboard-master/assets/css/light-bootstrap-dashboard.css +9 -35
  25. data/public/screenshots/v1.0.0/migrations.png +0 -0
  26. data/public/screenshots/v1.0.0/models.png +0 -0
  27. data/public/screenshots/v1.0.0/new_migration.png +0 -0
  28. data/public/screenshots/v1.0.0/new_model.png +0 -0
  29. data/public/vendor/font-awesome.min.css +4 -0
  30. data/public/vendor/highlight-js-default.min.css +9 -0
  31. data/public/vendor/highlight.min.js +1198 -0
  32. data/public/{js → vendor}/masonry.pkgd.min.js +0 -0
  33. data/spec/dummy/Gemfile +0 -3
  34. data/spec/dummy/Gemfile.lock +78 -95
  35. data/spec/dummy/app/controllers/pages_controller.rb +0 -2
  36. data/spec/dummy/app/models/post.rb +3 -0
  37. data/spec/dummy/app/models/user.rb +3 -0
  38. data/spec/dummy/app/views/pages/home.html.erb +0 -1
  39. data/spec/dummy/config/database.yml +1 -1
  40. data/spec/dummy/config/environments/development.rb +3 -1
  41. data/spec/dummy/config/puma.rb +1 -1
  42. data/spec/dummy/db/migrate/20230119221452_create_users.rb +14 -0
  43. data/spec/dummy/db/migrate/20230119221751_change_users_at1674166670.rb +7 -0
  44. data/spec/dummy/db/migrate/20230119222054_create_posts.rb +11 -0
  45. data/spec/dummy/db/migrate/20230119222106_change_posts_at1674166865.rb +5 -0
  46. data/spec/dummy/db/schema.rb +41 -0
  47. data/spec/dummy/log/development.log +16030 -10038
  48. data/spec/dummy/log/localtower.log +1878 -439
  49. data/spec/dummy/log/test.log +0 -281
  50. data/spec/dummy/test/index.html +38 -0
  51. data/spec/dummy/tmp/pids/server.pid +1 -1
  52. data/spec/factories/migration.rb +25 -41
  53. data/spec/factories/model.rb +39 -25
  54. data/spec/lib/localtower/generators/migration_spec.rb +36 -63
  55. data/spec/lib/localtower/generators/model_spec.rb +43 -34
  56. data/spec/lib/localtower/generators/service_objects/insert_array_spec.rb +47 -0
  57. data/spec/lib/localtower/generators/service_objects/insert_defaults_spec.rb +30 -35
  58. data/spec/lib/localtower/generators/service_objects/insert_indexes_spec.rb +90 -0
  59. data/spec/lib/localtower/generators/service_objects/insert_nullable_spec.rb +61 -0
  60. data/spec/lib/localtower/tools_spec.rb +1 -11
  61. data/spec/spec_helper.rb +25 -5
  62. metadata +38 -30
  63. data/app/views/localtower/pages/dashboard.html.erb +0 -67
  64. data/app/views/localtower/pages/logs.html.erb +0 -84
  65. data/app/views/localtower/pages/relations.html.erb +0 -66
  66. data/app/views/localtower/pages/tasks.html.erb +0 -48
  67. data/lib/localtower/generators/relation.rb +0 -59
  68. data/lib/localtower/plugins/capture.rb +0 -197
  69. data/lib/tasks/localtower_tasks.rake +0 -4
  70. data/spec/dummy/lib/playground.rb +0 -0
  71. data/spec/dummy/log/localtower_capture_d8979d360722798f7b6eb1a2694a3791.json +0 -1
  72. data/spec/lib/localtower/generators/relation_spec.rb +0 -65
@@ -2,21 +2,26 @@ module Localtower
2
2
  class Status
3
3
  def run
4
4
  files = Dir["#{Rails.root}/db/migrate/*.rb"].sort.reverse
5
-
6
- names = files.map do |file_full_path|
7
- file_full_path.split("/")[-1]
5
+ db_migrations = begin
6
+ ActiveRecord::Base.connection.execute("select * from schema_migrations;")
7
+ rescue => e
8
+ []
8
9
  end
9
10
 
10
- db_migrations = ActiveRecord::Base.connection.execute("select * from schema_migrations;").map { |e| e["version"].to_s }.sort.reverse
11
+ db_migrations = db_migrations.map { |e| e["version"].to_s }
11
12
 
12
- names.map do |name|
13
- time = name.split("_")[0]
13
+ files.map do |file_full_path|
14
+ name = file_full_path.split("/")[-1] # add_email_to_user.rb
15
+ time = name.split("_")[0] # 201203890987
14
16
  status = db_migrations.include?(time) ? :done : :todo
17
+ content = File.open(file_full_path).read
15
18
 
16
19
  {
20
+ "file_full_path" => file_full_path,
17
21
  "name" => name,
18
- "time" => time,
22
+ "time" => time.to_i,
19
23
  "status" => status,
24
+ "content" => content
20
25
  }
21
26
  end
22
27
  end
@@ -45,7 +45,14 @@ module Localtower
45
45
  self.models.each do |model|
46
46
  attributes_list = []
47
47
 
48
- model.columns_hash.each do |_k, v|
48
+ # Using this trick because the model might exist but not migrated yet
49
+ columns_hash = begin
50
+ model.columns_hash
51
+ rescue
52
+ []
53
+ end
54
+
55
+ columns_hash.each do |_k, v|
49
56
 
50
57
  belongs_to = nil
51
58
 
@@ -117,32 +124,29 @@ module Localtower
117
124
  end
118
125
 
119
126
  def all_columns
120
- models.map { |model| model.columns.map { |column| column.name }.flatten }.flatten.uniq.sort
121
- end
127
+ models.map do |model|
128
+ columns = begin
129
+ model.columns
130
+ rescue
131
+ []
132
+ end
122
133
 
123
- def sql_drop_all_tables
124
- ::ActiveRecord::Base.connection.tables.each do |table|
125
- cmd = "DROP TABLE if exists #{table.upcase} cascade;"
126
- ::ActiveRecord::Base.connection.execute(cmd)
127
- end
134
+ columns.map { |column| column.name }.flatten
135
+ end.flatten.uniq.sort
128
136
  end
129
137
 
130
- def perform_migration(str, standalone = false)
131
- self.perform_cmd("rails g migration #{str}", false)
132
-
133
- if not standalone
134
- self.perform_cmd('rake db:migrate')
135
- end
138
+ def perform_migration(str)
139
+ self.perform_cmd("rails g migration #{str}")
136
140
  end
137
141
 
138
- def perform_cmd(cmd_str, standalone = true)
139
- self.perform_raw_cmd("bundle exec #{cmd_str}", standalone)
142
+ def perform_cmd(cmd_str)
143
+ self.perform_raw_cmd("bundle exec #{cmd_str}")
140
144
  end
141
145
 
142
- def perform_raw_cmd(cmd_str, standalone = false, root_dir = false)
143
- root_dir ||= ::Rails.root
146
+ def perform_raw_cmd(cmd_str)
147
+ root_dir = ::Rails.root
144
148
 
145
- cmd = standalone ? cmd_str : "cd \"#{root_dir}\" && #{cmd_str}"
149
+ cmd = "cd \"#{root_dir}\" && #{cmd_str}"
146
150
  cmd = cmd.strip
147
151
 
148
152
  self.log("DOING...: #{cmd}")
@@ -166,17 +170,18 @@ module Localtower
166
170
  end
167
171
 
168
172
  def log_file
169
- Rails.root.join('log', 'localtower.log')
173
+ @log_file ||= Rails.root.join('log', 'localtower.log')
174
+ end
175
+
176
+ def last_migration
177
+ Dir["#{Rails.root}/db/migrate/*.rb"].sort.last
170
178
  end
171
179
 
172
180
  # PRIVATE ==============
173
181
  def create_log
174
182
  return nil if File.exist?(self.log_file)
175
- File.open(self.log_file, 'w') { |f| f.write('') }
176
- end
177
183
 
178
- def word_in_file?(file, word_or_exp)
179
- File.readlines(file).grep(word_or_exp).size > 0
184
+ File.open(self.log_file, 'w') { |f| f.write('') }
180
185
  end
181
186
  end
182
187
  end
@@ -1,3 +1,3 @@
1
1
  module Localtower
2
- VERSION = '0.4.2'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
data/lib/localtower.rb CHANGED
@@ -4,7 +4,6 @@ end
4
4
  # EXTERNAL GEM
5
5
  require 'thor'
6
6
  require 'active_link_to'
7
- require 'zip'
8
7
 
9
8
  begin
10
9
  require "pry"
data/public/css/app.css CHANGED
@@ -1,50 +1,3 @@
1
-
2
- .tower-nav{
3
- display: none;
4
- justify-content: space-around;
5
- padding: 10px 0 0;
6
- background-color: #1F77D0;
7
- text-align: center;
8
- }
9
-
10
- .tower-nav div{
11
- display: inline;
12
- border-radius: 4px;
13
- padding: 5px;
14
- margin-bottom: 10px;
15
- }
16
-
17
- .tower-nav div:hover{
18
- background: rgba(255, 255, 255, 0.23);
19
- }
20
-
21
- .tower-a{
22
- display: inline-block;
23
- color: white;
24
- }
25
-
26
- .alert {
27
- padding: 20px 30px;
28
- }
29
-
30
- .tower-a:hover{
31
- color: white;
32
- }
33
-
34
- .tower-nav p{
35
- margin: 0;
36
- line-height: 30px;
37
- font-size: 12px;
38
- font-weight: 600;
39
- text-transform: uppercase;
40
- }
41
-
42
- @media (max-width: 991px) {
43
- .tower-nav{
44
- display: flex;
45
- }
46
- }
47
-
48
1
  .full-message {
49
2
  z-index: 999;
50
3
  position: fixed;
@@ -77,12 +30,10 @@
77
30
 
78
31
  /*=========================*/
79
32
 
80
-
81
33
  .table-condensed>tbody>tr>td, .table-condensed>tbody>tr>th, .table-condensed>tfoot>tr>td, .table-condensed>tfoot>tr>th, .table-condensed>thead>tr>td, .table-condensed>thead>tr>th {
82
34
  padding: 5px;
83
35
  }
84
36
 
85
-
86
37
  .grid-sizer, .grid-item {
87
38
  box-sizing: border-box;
88
39
  width: 45%;
data/public/js/app.js CHANGED
@@ -1,104 +1,187 @@
1
1
  window.MainApp = {};
2
2
 
3
+ Array.prototype.unique = function () {
4
+ return this.filter(function (value, index, self) {
5
+ return self.indexOf(value) === index;
6
+ });
7
+ };
8
+
3
9
  MainApp = {
4
- init: function() {
5
- },
10
+ init: function () {},
11
+
12
+ ready: function () {
13
+ $(".grid").masonry({
14
+ itemSelector: ".grid-item",
15
+ percentPosition: true,
16
+ columnWidth: ".grid-sizer",
17
+ });
18
+
19
+ MainApp.whenActionOnElement("click", "duplicateLineNewModel", function (e) {
20
+ e.preventDefault();
6
21
 
7
- ready: function() {
22
+ if (MainApp.modelNameAndAttributesAreFilled()) {
23
+ MainApp.duplicateLine();
24
+ } else {
25
+ MainApp.notFilled();
26
+ }
8
27
 
9
- $(".json").each(function() {
10
- var $el = $(this);
11
- var done = MainApp.syntaxHighlight($el.text());
12
- $el.html(done);
28
+ return false;
13
29
  });
14
30
 
15
- MainApp.whenActionOnElement("click", "duplicate", function(e) {
31
+ MainApp.whenActionOnElement(
32
+ "click",
33
+ "duplicateLineNewMigration",
34
+ function (e) {
35
+ e.preventDefault();
36
+ MainApp.duplicateLineMigration();
37
+ return false;
38
+ }
39
+ );
40
+
41
+ MainApp.whenActionOnElement("click", "removeLineModel", function (e) {
16
42
  e.preventDefault();
17
- MainApp.duplicateLine();
43
+ MainApp.removeLineModel(e.currentTarget);
18
44
  return false;
19
45
  });
20
46
 
21
- MainApp.whenActionOnElement("click", "remove", function(e) {
47
+ MainApp.whenActionOnElement("click", "removeLineMigration", function (e) {
22
48
  e.preventDefault();
23
- MainApp.removeLine(e.currentTarget);
49
+ MainApp.removeLineMigration(e.currentTarget);
24
50
  return false;
25
51
  });
26
52
 
27
- MainApp.whenActionOnElement("click", "submit", function(e) {
53
+ // New Model
54
+ MainApp.whenActionOnElement("click", "submitNewModel", function (e) {
55
+ if (!MainApp.modelNameAndAttributesAreFilled()) {
56
+ MainApp.notFilled();
57
+ e.preventDefault();
58
+ return false;
59
+ }
60
+
28
61
  var current = $(e.currentTarget);
29
62
  $(".full-message").show();
30
63
 
31
64
  if (current.val() === "false") {
32
65
  $(".full-message-migrate").show();
33
66
  }
67
+ });
68
+
69
+ // New Migration
70
+ MainApp.whenActionOnElement("click", "submitNewMigration", function (e) {
71
+ var current = $(e.currentTarget);
72
+ $(".full-message").show();
34
73
 
74
+ if (current.val() === "false") {
75
+ $(".full-message-migrate").show();
76
+ }
35
77
  });
36
78
 
37
- MainApp.whenActionOnElement("change", "action", function(e) {
79
+ MainApp.whenActionOnElement("change", "action", function (e) {
38
80
  MainApp.adaptLines();
39
81
  });
40
82
 
41
83
  MainApp.adaptLines();
42
-
43
- $('.grid').masonry({
44
- itemSelector: '.grid-item',
45
- percentPosition: true,
46
- columnWidth: '.grid-sizer',
47
- });
84
+ MainApp.sanitizeInputs();
85
+ hljs.highlightAll();
48
86
  },
49
87
 
50
88
  // INSTANCE --------------------------------------------------
89
+ sanitizeInputs: function () {
90
+ function camelize(str) {
91
+ return str
92
+ .replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
93
+ return word.toUpperCase();
94
+ })
95
+ .replace(/\s+/g, "");
96
+ }
51
97
 
52
- syntaxHighlight: function(json) {
53
- json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
54
- return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
55
- var cls = 'number';
56
- if (/^"/.test(match)) {
57
- if (/:$/.test(match)) {
58
- cls = 'key';
59
- } else {
60
- cls = 'string';
61
- }
62
- } else if (/true|false/.test(match)) {
63
- cls = 'boolean';
64
- } else if (/null/.test(match)) {
65
- cls = 'null';
66
- }
67
- return '<span class="' + cls + '">' + match + '</span>';
98
+ function snakeCase(str) {
99
+ return str
100
+ .replace(/\ /g, "_")
101
+ .replace(/[^a-zA-Z0-9\_]/g, "")
102
+ .replace(/\_\_/g, "_")
103
+ .toLowerCase();
104
+ }
105
+
106
+ // Model name
107
+ MainApp.whenActionOnElement("keyup", "modelName", function (e) {
108
+ var currentInputValue = $(e.currentTarget).val();
109
+ var cleanInputValue = currentInputValue.replace(/[^a-zA-Z0-9]/g, "");
110
+ cleanInputValue = camelize(cleanInputValue);
111
+ $(e.currentTarget).val(cleanInputValue);
112
+ });
113
+
114
+ // Model attributes
115
+ MainApp.whenActionOnElement("keyup", "attributeName", function (e) {
116
+ var currentInputValue = $(e.currentTarget).val();
117
+ $(e.currentTarget).val(snakeCase(currentInputValue));
118
+ });
119
+
120
+ // Migration
121
+ MainApp.whenActionOnElement("keyup", "column_text", function (e) {
122
+ var currentInputValue = $(e.currentTarget).val();
123
+ $(e.currentTarget).val(snakeCase(currentInputValue));
68
124
  });
69
125
  },
70
126
 
127
+ modelNameAndAttributesAreFilled: function () {
128
+ // attributes name:
129
+ var valuesForAttributes = [];
130
+ MainApp.bySelector("attributeName").each(function (el) {
131
+ valuesForAttributes.push($(this).val());
132
+ });
133
+ // model name:
134
+ valuesForAttributes.push(MainApp.bySelector("modelName").first().val());
135
+
136
+ return (
137
+ valuesForAttributes.filter(function (n) {
138
+ return n === "";
139
+ }).length === 0
140
+ );
141
+ },
71
142
 
143
+ notFilled: function () {
144
+ alert("Please fill all the fields");
145
+ },
72
146
 
73
147
  // This is a little bit dirty but it works well for the moment:
74
148
  // We dynamically show/hide fields
75
- adaptLines: function() {
76
- $.each(MainApp.bySelector("tr"), function() {
77
- var $tr = $(this);
149
+ adaptLines: function () {
150
+ $.each(MainApp.bySelector("table").find("table"), function (table) {
151
+ var $table = $(this);
78
152
 
79
- var action_input = $tr.find("[data-selector='action']");
153
+ var action_input = $table.find("[data-selector='action']");
80
154
  var action = action_input.val();
81
155
 
82
- var belongs_to_input = $tr.find("[data-selector='belongs_to']");
83
- var belongs_to_label = MainApp.bySelector('belongs_to_label');
156
+ var belongs_to_input = $table.find("[data-selector='belongs_to']");
157
+ var belongs_to_label = $table.find("[data-selector='belongs_to_label']");
84
158
 
85
- var column_text_input = $tr.find("[data-selector='column_text']");
86
- var column_text_label = MainApp.bySelector('column_text_label');
159
+ var column_text_input = $table.find("[data-selector='column_text']");
160
+ var column_input = $table.find("[data-selector='column_list']");
161
+ var column_label = $table.find("[data-selector='column_label']");
87
162
 
88
- var column_input = $tr.find("[data-selector='column_list']");
89
- var column_label = MainApp.bySelector('column_label');
163
+ var new_column_name_input = $table.find(
164
+ "[data-selector='new_column_name']"
165
+ );
166
+ var new_column_name_label = $table.find(
167
+ "[data-selector='new_column_name_label']"
168
+ );
90
169
 
91
- var new_column_name_input = $tr.find("[data-selector='new_column_name']");
92
- var new_column_name_label = MainApp.bySelector('new_column_name_label');
170
+ var column_type_input = $table.find("[data-selector='column_type']");
171
+ var column_type_label = $table.find(
172
+ "[data-selector='column_type_label']"
173
+ );
93
174
 
94
- var column_type_input = $tr.find("[data-selector='column_type']");
95
- var column_type_label = MainApp.bySelector('column_type_label');
175
+ var index_options_inputs = $table.find("[data-selector='index_options']");
176
+ var index_options_label = $table.find(
177
+ "[data-selector='index_options_label']"
178
+ );
96
179
 
97
- var index_input = $tr.find("[data-selector='index']");
98
- var index_label = MainApp.bySelector('index_label');
180
+ var default_input = $table.find("[data-selector='default_input']");
181
+ var default_label = $table.find("[data-selector='default_label']");
99
182
 
100
- var nullable_input = $tr.find("[data-selector='nullable']");
101
- var nullable_label = MainApp.bySelector('nullable_label');
183
+ var nullable_input = $table.find("[data-selector='nullable_input']");
184
+ var nullable_label = $table.find("[data-selector='nullable_label']");
102
185
 
103
186
  $.each(
104
187
  [
@@ -106,8 +189,6 @@ MainApp = {
106
189
  belongs_to_label,
107
190
 
108
191
  column_text_input,
109
- column_text_label,
110
-
111
192
  column_input,
112
193
  column_label,
113
194
 
@@ -117,31 +198,32 @@ MainApp = {
117
198
  column_type_input,
118
199
  column_type_label,
119
200
 
120
- index_input,
121
- index_label,
201
+ index_options_inputs,
202
+ index_options_label,
203
+
204
+ default_input,
205
+ default_label,
122
206
 
123
207
  nullable_input,
124
208
  nullable_label,
125
209
  ],
126
- function(i, el) {
210
+ function (i, el) {
127
211
  el.hide();
128
- });
212
+ }
213
+ );
129
214
 
130
215
  var mapping = {
131
216
  add_column: [
132
217
  column_text_input,
133
- column_text_label,
218
+ column_label,
134
219
  column_type_input,
135
220
  column_type_label,
136
- index_input,
137
- index_label,
221
+ default_input,
222
+ default_label,
138
223
  nullable_input,
139
224
  nullable_label,
140
225
  ],
141
- remove_column: [
142
- column_input,
143
- column_label,
144
- ],
226
+ remove_column: [column_input, column_label],
145
227
  rename_column: [
146
228
  column_input,
147
229
  column_label,
@@ -154,54 +236,102 @@ MainApp = {
154
236
  column_type_input,
155
237
  column_type_label,
156
238
  ],
157
- belongs_to: [
158
- belongs_to_input,
159
- belongs_to_label,
160
- ],
239
+ belongs_to: [belongs_to_input, belongs_to_label],
161
240
  add_index_to_column: [
162
241
  column_input,
163
242
  column_label,
243
+ index_options_inputs,
244
+ index_options_label,
164
245
  ],
165
- remove_index_to_column: [
166
- column_input,
167
- column_label,
168
- ],
246
+ remove_index_to_column: [column_input, column_label],
169
247
  drop_table: [],
170
- }
248
+ };
171
249
 
172
250
  inputs_to_show = mapping[action];
173
251
 
174
252
  if (inputs_to_show) {
175
- $.each(inputs_to_show, function(i, el) {
253
+ $.each(inputs_to_show, function (i, el) {
176
254
  el.show();
177
255
  });
178
256
  }
179
257
  });
180
258
  },
181
259
 
182
- duplicateLine: function() {
183
- var tr = MainApp.bySelector("tbody").find("tr").first().clone();
260
+ duplicateLine: function () {
261
+ var tr = MainApp.bySelector("tbody").find("tr").last().clone();
184
262
  MainApp.bySelector("tbody").append(tr);
263
+ MainApp.bySelector("tbody")
264
+ .find("tr")
265
+ .last()
266
+ .find('[name="model[attributes][][attribute_name]"]')
267
+ .val("")
268
+ .focus();
269
+ },
270
+
271
+ duplicateLineMigration: function () {
272
+ var table = MainApp.bySelector("table").find("table").last().clone();
273
+ MainApp.bySelector("table").append(table);
274
+ MainApp.adaptLines();
275
+
276
+ // Populate select/option for column list:
277
+ var allAttributes = [];
278
+ MainApp.bySelector("table")
279
+ .find('[data-selector="column_text"]')
280
+ .each(function (i, el) {
281
+ allAttributes.push(el.value);
282
+ });
283
+ allAttributes = allAttributes.unique();
284
+
285
+ var columnSelector = MainApp.bySelector("table")
286
+ .find("table")
287
+ .last()
288
+ .find('[data-selector="column_list"]')
289
+ .last();
290
+
291
+ var currentValues = [];
292
+ columnSelector.find("option").each(function (i, el) {
293
+ currentValues.push(el.value);
294
+ });
295
+
296
+ currentValues = currentValues.concat(allAttributes).unique().sort();
297
+
298
+ columnSelector.empty(); // remove old options
299
+ $.each(currentValues, function (i, value) {
300
+ columnSelector.append(
301
+ $("<option></option>").attr("value", value).text(value)
302
+ );
303
+ });
304
+
305
+ MainApp.bySelector("table")
306
+ .find("table")
307
+ .last()
308
+ .find('[name="migrations[][column]"]')
309
+ .val("")
310
+ .focus();
185
311
  },
186
312
 
187
- removeLine: function(target) {
313
+ removeLineModel: function (target) {
188
314
  if ($(target).parents("tbody").find("tr").length > 1) {
189
315
  $(target).parents("tr").remove();
190
316
  }
191
317
  },
192
318
 
319
+ removeLineMigration: function (target) {
320
+ if ($(target).parents(".container-table").find("table").length > 1) {
321
+ $(target).parents("table").remove();
322
+ }
323
+ },
324
+
193
325
  // PRIVATE
194
- bySelector: function(selector) {
326
+ bySelector: function (selector) {
195
327
  return $("[data-selector='" + selector + "']");
196
328
  },
197
329
 
198
- whenActionOnElement: function(action, selector, callback) {
330
+ whenActionOnElement: function (action, selector, callback) {
199
331
  $(document).on(action, "[data-selector='" + selector + "']", callback);
200
- }
201
- }
202
-
203
- MainApp.init();
332
+ },
333
+ };
204
334
 
205
- $(document).ready(function() {
335
+ $(document).ready(function () {
206
336
  MainApp.ready();
207
337
  });
@@ -1,17 +1,17 @@
1
1
  /*!
2
-
2
+
3
3
  =========================================================
4
4
  * Light Bootstrap Dashboard - v1.3.1.0
5
5
  =========================================================
6
-
6
+
7
7
  * Product Page: http://www.creative-tim.com/product/light-bootstrap-dashboard
8
8
  * Copyright 2017 Creative Tim (http://www.creative-tim.com)
9
9
  * Licensed under MIT (https://github.com/creativetimofficial/light-bootstrap-dashboard/blob/master/LICENSE.md)
10
-
10
+
11
11
  =========================================================
12
-
12
+
13
13
  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14
-
14
+
15
15
  */
16
16
  /* light colors */
17
17
  @keyframes spin {
@@ -144,33 +144,6 @@ input[type="file"] > input[type="button"]::-moz-focus-inner {
144
144
  input:focus {
145
145
  outline: 0 !important; }
146
146
 
147
- /* Animations */
148
- .form-control,
149
- .input-group-addon,
150
- .tagsinput,
151
- .navbar,
152
- .navbar .alert {
153
- -webkit-transition: all 300ms linear;
154
- -moz-transition: all 300ms linear;
155
- -o-transition: all 300ms linear;
156
- -ms-transition: all 300ms linear;
157
- transition: all 300ms linear; }
158
-
159
- .sidebar .nav a,
160
- .table > tbody > tr .td-actions .btn {
161
- -webkit-transition: all 150ms ease-in;
162
- -moz-transition: all 150ms ease-in;
163
- -o-transition: all 150ms ease-in;
164
- -ms-transition: all 150ms ease-in;
165
- transition: all 150ms ease-in; }
166
-
167
- .btn {
168
- -webkit-transition: all 100ms ease-in;
169
- -moz-transition: all 100ms ease-in;
170
- -o-transition: all 100ms ease-in;
171
- -ms-transition: all 100ms ease-in;
172
- transition: all 100ms ease-in; }
173
-
174
147
  .fa {
175
148
  width: 18px;
176
149
  text-align: center; }
@@ -448,11 +421,12 @@ body > .navbar-collapse {
448
421
  height: 100%;
449
422
  -webkit-transition-property: top,bottom;
450
423
  transition-property: top,bottom;
451
- -webkit-transition-duration: .2s,.2s;
452
- transition-duration: .2s,.2s;
424
+ -webkit-transition-duration: .0s,.0s;
425
+ transition-duration: .0s,.0s;
453
426
  -webkit-transition-timing-function: linear,linear;
454
427
  transition-timing-function: linear,linear;
455
- -webkit-overflow-scrolling: touch; }
428
+ -webkit-overflow-scrolling: touch;
429
+ }
456
430
 
457
431
  .btn {
458
432
  border-width: 2px;