erd 0.6.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/erd/erd_controller.rb +55 -48
- data/app/views/erd/erd/_column.html.erb +8 -4
- data/app/views/erd/erd/_model.html.erb +23 -17
- data/app/views/erd/erd/edit.html.erb +87 -0
- data/app/views/erd/erd/erd.html.erb +1 -1
- data/app/views/erd/erd/index.html.erb +12 -81
- data/config/routes.rb +1 -0
- data/lib/erd/version.rb +1 -1
- data/public/erd/erd.css +69 -20
- data/public/erd/erd.js +12 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35c1ad5ad3318d07d2faeb5836b2ec12e8132088994985d6d0f0342addd7685d
|
4
|
+
data.tar.gz: 77ce179c5b2c8cbe58095320d012e5aab188c3aa0d23d73e9de5036564e2cf1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c02778a0c99593cd9ae3b8f5c27ccb0ea11f8ad6aa719a023f8de9ad40a51352ac33d17e92035afec8faad65ad7f1944eb032a65c98d9570f4840843121f65d5
|
7
|
+
data.tar.gz: 5f227492c2234358069825ca797188e6ec92e74cab71172de589077c1e52d4e3d104e04eedbd3e3e3b84b54dea911c8e61970893fdf9c7b4cd7ada16a2b98d31
|
@@ -6,62 +6,64 @@ require 'erd/application_controller'
|
|
6
6
|
|
7
7
|
module Erd
|
8
8
|
class ErdController < ::Erd::ApplicationController
|
9
|
+
POSITIONS_JSON_FILE = Rails.root.join('tmp/erd_positions.json').freeze
|
10
|
+
|
9
11
|
def index
|
10
|
-
|
11
|
-
|
12
|
-
ActiveSupport::JSON.decode json.read
|
13
|
-
else
|
14
|
-
{}
|
15
|
-
end
|
16
|
-
@erd = render_plain plain, positions
|
12
|
+
@erd = render_plain generate_plain, saved_positions
|
13
|
+
end
|
17
14
|
|
15
|
+
def edit
|
16
|
+
@erd = render_plain generate_plain, saved_positions, true
|
18
17
|
@migrations = Erd::Migrator.status
|
19
18
|
end
|
20
19
|
|
21
20
|
def update
|
21
|
+
if params[:position_changes].present?
|
22
|
+
position_changes = ActiveSupport::JSON.decode(params[:position_changes])
|
23
|
+
positions = saved_positions
|
24
|
+
positions.merge! position_changes.transform_keys(&:tableize)
|
25
|
+
POSITIONS_JSON_FILE.open('w') {|f| f.write positions.to_json }
|
26
|
+
end
|
27
|
+
|
22
28
|
changes = params[:changes].present? ? ActiveSupport::JSON.decode(params[:changes]) : []
|
23
29
|
executed_migrations, failed_migrations = [], []
|
24
30
|
changes.each do |row|
|
25
31
|
begin
|
26
32
|
action, model, column, from, to = row['action'], row['model'], row['column'], row['from'], row['to']
|
27
|
-
|
33
|
+
|
34
|
+
case action
|
35
|
+
when 'create_model'
|
36
|
+
columns = column.split(' ').compact
|
37
|
+
generated_migration_file = Erd::GenaratorRunner.execute_generate_model model, columns
|
38
|
+
when 'remove_model'
|
28
39
|
model = model.tableize
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "drop_#{model}"
|
41
|
+
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n drop_table :#{model}\n end"
|
42
|
+
when 'rename_model'
|
43
|
+
_model, from, to = from.tableize, to.tableize, model.tableize
|
44
|
+
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{from}_to_#{to}"
|
45
|
+
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_table :#{from}, :#{to}\n end"
|
46
|
+
when 'add_column'
|
47
|
+
model = model.tableize
|
48
|
+
name_and_type = column.scan(/(.*)\((.*?)\)/).first
|
49
|
+
name, type = name_and_type[0], name_and_type[1]
|
50
|
+
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "add_#{name}_to_#{model}", ["#{name}:#{type}"]
|
51
|
+
when 'rename_column'
|
52
|
+
model = model.tableize
|
53
|
+
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{model}_#{from}_to_#{to}"
|
54
|
+
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_column :#{model}, :#{from}, :#{to}\n end"
|
55
|
+
when 'alter_column'
|
56
|
+
model = model.tableize
|
57
|
+
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "change_#{model}_#{column}_type_to_#{to}"
|
58
|
+
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n change_column :#{model}, :#{column}, :#{to}\n end"
|
59
|
+
when 'move'
|
60
|
+
# do nothing
|
33
61
|
else
|
34
|
-
|
35
|
-
when 'create_model'
|
36
|
-
columns = column.split(' ').compact
|
37
|
-
generated_migration_file = Erd::GenaratorRunner.execute_generate_model model, columns
|
38
|
-
when 'remove_model'
|
39
|
-
model = model.tableize
|
40
|
-
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "drop_#{model}"
|
41
|
-
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n drop_table :#{model}\n end"
|
42
|
-
when 'rename_model'
|
43
|
-
_model, from, to = from.tableize, to.tableize, model.tableize
|
44
|
-
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{from}_to_#{to}"
|
45
|
-
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_table :#{from}, :#{to}\n end"
|
46
|
-
when 'add_column'
|
47
|
-
model = model.tableize
|
48
|
-
name_and_type = column.scan(/(.*)\((.*?)\)/).first
|
49
|
-
name, type = name_and_type[0], name_and_type[1]
|
50
|
-
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "add_#{name}_to_#{model}", ["#{name}:#{type}"]
|
51
|
-
when 'rename_column'
|
52
|
-
model = model.tableize
|
53
|
-
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{model}_#{from}_to_#{to}"
|
54
|
-
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_column :#{model}, :#{from}, :#{to}\n end"
|
55
|
-
when 'alter_column'
|
56
|
-
model = model.tableize
|
57
|
-
generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "change_#{model}_#{column}_type_to_#{to}"
|
58
|
-
gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n change_column :#{model}, :#{column}, :#{to}\n end"
|
59
|
-
else
|
60
|
-
raise "unexpected action: #{action}"
|
61
|
-
end
|
62
|
-
Erd::Migrator.run_migrations :up => generated_migration_file
|
63
|
-
executed_migrations << generated_migration_file
|
62
|
+
raise "unexpected action: #{action}"
|
64
63
|
end
|
64
|
+
|
65
|
+
Erd::Migrator.run_migrations :up => generated_migration_file
|
66
|
+
executed_migrations << generated_migration_file
|
65
67
|
rescue ::Erd::MigrationError => e
|
66
68
|
failed_migrations << e.message
|
67
69
|
end
|
@@ -77,6 +79,10 @@ module Erd
|
|
77
79
|
|
78
80
|
private
|
79
81
|
|
82
|
+
def saved_positions
|
83
|
+
POSITIONS_JSON_FILE.exist? ? ActiveSupport::JSON.decode(POSITIONS_JSON_FILE.read) : {}
|
84
|
+
end
|
85
|
+
|
80
86
|
def generate_plain
|
81
87
|
if Rails.respond_to?(:autoloaders) && Rails.autoloaders.try(:zeitwerk_enabled?)
|
82
88
|
Zeitwerk::Loader.eager_load_all
|
@@ -115,20 +121,21 @@ module Erd
|
|
115
121
|
g.output('plain' => String)
|
116
122
|
end
|
117
123
|
|
118
|
-
def render_plain(plain, positions)
|
124
|
+
def render_plain(plain, positions, edit_mode = false)
|
119
125
|
_scale, svg_width, svg_height = plain.scan(/\Agraph ([\d\.]+) ([\d\.]+) ([\d\.]+)$/).first
|
120
126
|
# node name x y width height label style shape color fillcolor
|
121
|
-
max_model_x, max_model_y = 0, 0
|
122
127
|
models = plain.scan(/^node ([^ ]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([^ ]+) [^ ]+ [^ ]+ [^ ]+ [^ ]+\n/m).map {|model_name, x, y, width, height, label|
|
123
128
|
columns = label.gsub("\\\n", '').split('|')[1].split('\l').map {|name_and_type| name_and_type.scan(/(.*?)\((.*?)\)/).first }.map {|n, t| {:name => n, :type => t} }
|
124
129
|
custom_x, custom_y = positions[model_name.tableize].try(:split, ',')
|
125
|
-
|
126
|
-
max_model_x, max_model_y = [h[:x].to_i + h[:width].to_i, max_model_x, 1024].max, [h[:y].to_i + h[:height].to_i, max_model_y, 768].max
|
127
|
-
h
|
130
|
+
{:model => model_name, :x => (custom_x || (BigDecimal(x) * 72).round), :y => (custom_y || (BigDecimal(y) * 72).round), :width => (BigDecimal(width) * 72).round, :height => (BigDecimal(height) * 72).round, :columns => columns}
|
128
131
|
}.compact
|
132
|
+
max_model_x = models.map {|m| m[:x].to_f + m[:width].to_f }.max
|
133
|
+
erd_width = [[(BigDecimal(svg_width) * 72).round, max_model_x].min + 150, 1024].max
|
134
|
+
max_model_y = models.map {|m| m[:y].to_f + m[:height].to_f }.max
|
135
|
+
erd_height = [[(BigDecimal(svg_height) * 72).round, max_model_y].min + 150, 768].max
|
129
136
|
# edge tail head n x1 y1 .. xn yn [label xl yl] style color
|
130
137
|
edges = plain.scan(/^edge ([^ ]+)+ ([^ ]+)/).map {|from, to| {:from => from, :to => to}}
|
131
|
-
render_to_string 'erd/erd/erd', :layout => nil, :locals => {:width =>
|
138
|
+
render_to_string 'erd/erd/erd', :layout => nil, :locals => {:width => erd_width, :height => erd_height, :models => models, :edges => edges, :edit_mode => edit_mode}
|
132
139
|
end
|
133
140
|
|
134
141
|
def gsub_file(path, flag, *args, &block)
|
@@ -2,12 +2,16 @@
|
|
2
2
|
<table>
|
3
3
|
<tr>
|
4
4
|
<td>
|
5
|
-
<span class="column_name_text"><%= column[:name] %></span>
|
6
|
-
|
5
|
+
<span class="column_name_text<%= "#{' edit' if edit_mode}" %>"><%= column[:name] %></span>
|
6
|
+
<% if edit_mode %>
|
7
|
+
<form class="rename_column_form"><span><input name="model" type="hidden" value="<%= model[:model] %>" /><input name="column" type="hidden" value="<%= column[:name] %>" /><input name="to" type="text" /><input type="submit" value="Change" /></span><a href="#!" class="cancel">Cancel</a></form>
|
8
|
+
<% end %>
|
7
9
|
</td>
|
8
10
|
<td>
|
9
|
-
<span class="column_type_text <%= column[:type] %>"><%= column[:type] %></span>
|
10
|
-
|
11
|
+
<span class="column_type_text <%= column[:type] %><%= "#{' edit' if edit_mode}" %>"><%= column[:type] %></span>
|
12
|
+
<% if edit_mode %>
|
13
|
+
<form class="alter_column_form"><span><input name="model" type="hidden" value="<%= model[:model] %>" /><input name="column" type="hidden" value="<%= column[:name] %>" /><input name="type" type="hidden" value="<%= column[:type] %>" /><input name="to" type="text" /><input type="submit" value="Change" /></span><a href="#!" class="cancel">Cancel</a></form>
|
14
|
+
<% end %>
|
11
15
|
</td>
|
12
16
|
</tr>
|
13
17
|
</table>
|
@@ -1,28 +1,34 @@
|
|
1
1
|
<div id="erd-<%= model[:model] %>" class="model" style="top: <%= model[:y] %>px; left: <%= model[:x] %>px;" data-model_name="<%= model[:model] %>">
|
2
|
-
|
3
|
-
|
2
|
+
<% if edit_mode %>
|
3
|
+
<a href="#!" class="close"><%= image_tag '/erd/close.png' %></a>
|
4
|
+
<% end %>
|
5
|
+
<div class="model_name<%= "#{' edit' if edit_mode}" %>">
|
4
6
|
<div class="model_name_text"><%= model[:model] %></div>
|
5
|
-
|
6
|
-
<
|
7
|
-
<
|
8
|
-
<
|
9
|
-
<
|
10
|
-
|
11
|
-
|
12
|
-
<
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
7
|
+
<% if edit_mode %>
|
8
|
+
<form class="rename_model_form">
|
9
|
+
<table>
|
10
|
+
<tr>
|
11
|
+
<td>
|
12
|
+
<input name="model" type="hidden" value="<%= model[:model] %>"/>
|
13
|
+
</td>
|
14
|
+
<td>
|
15
|
+
<input name="to" type="text" /><input type="submit" value="Change"/>
|
16
|
+
</td>
|
17
|
+
</tr>
|
18
|
+
</table>
|
19
|
+
<a href="#!" class="cancel">Cancel</a>
|
20
|
+
</form>
|
21
|
+
<% end %>
|
18
22
|
</div>
|
19
23
|
<div class="columns">
|
20
24
|
<ul>
|
21
|
-
<%= render :partial => 'erd/erd/column', :collection => model[:columns], :locals => {:model => model} -%>
|
25
|
+
<%= render :partial => 'erd/erd/column', :collection => model[:columns], :locals => {:model => model, :edit_mode => edit_mode} -%>
|
22
26
|
</ul>
|
23
27
|
</div>
|
24
28
|
<div class="add_column_box">
|
25
|
-
|
29
|
+
<% if edit_mode %>
|
30
|
+
<a href="#!" class="add_column">add column</a>
|
31
|
+
<% end %>
|
26
32
|
<form class="add_column_form">
|
27
33
|
<input name="model" type="hidden" value="<%= model[:model] %>" />
|
28
34
|
<table>
|
@@ -0,0 +1,87 @@
|
|
1
|
+
<div id="erd_box">
|
2
|
+
<div id="erd_container">
|
3
|
+
<%=raw @erd %>
|
4
|
+
</div>
|
5
|
+
<div id="open_migration"><%= image_tag '/erd/angle-left.png' %></div>
|
6
|
+
<div id="migration">
|
7
|
+
<div id="close_migration"><%= image_tag '/erd/angle-right.png' %></div>
|
8
|
+
<%- if flash[:executed_migrations].present? -%>
|
9
|
+
<div id="executed">
|
10
|
+
<h2>Successfully executed following <%= flash[:executed_migrations].values.flatten.count %> migrations!</h2>
|
11
|
+
<%- [:up, :down].each do |direction| -%>
|
12
|
+
<%- if flash[:executed_migrations][direction].present? -%>
|
13
|
+
<h3><%= direction %></h3>
|
14
|
+
<ul>
|
15
|
+
<%- flash[:executed_migrations][direction].each do |m| -%>
|
16
|
+
<li><%= File.basename m.to_s %></li>
|
17
|
+
<%- end -%>
|
18
|
+
</ul>
|
19
|
+
<%- end -%>
|
20
|
+
<%- end -%>
|
21
|
+
</div>
|
22
|
+
<%- end -%>
|
23
|
+
<%- if flash[:failed_migrations].present? -%>
|
24
|
+
<div id="failed">
|
25
|
+
<h2>failed migrations</h2>
|
26
|
+
<ul>
|
27
|
+
<%- flash[:failed_migrations].each do |m| -%>
|
28
|
+
<li><%= m %></li>
|
29
|
+
<%- end -%>
|
30
|
+
</ul>
|
31
|
+
</div>
|
32
|
+
<%- end -%>
|
33
|
+
<table id="changes">
|
34
|
+
<caption>schema changes</caption>
|
35
|
+
<thead><tr><th>action</th><th>model</th><th>column</th><th>from</th><th>to</th></tr></thead>
|
36
|
+
<tbody></tbody>
|
37
|
+
</table>
|
38
|
+
<%= form_tag '/erd', :method => :put, :id => 'changes_form' do %>
|
39
|
+
<%= hidden_field_tag 'changes' %>
|
40
|
+
<%= hidden_field_tag 'position_changes' %>
|
41
|
+
<%= submit_tag 'save changes' %>
|
42
|
+
<% end %>
|
43
|
+
<%= form_tag '/erd/migrate', :method => :put, :id => 'migrate_form' do %>
|
44
|
+
<ul id="open_buttons">
|
45
|
+
<li><button id="open_up" type="button">up</button></li>
|
46
|
+
<li><button id="open_down" type="button">down</button></li>
|
47
|
+
<li><button id="close_all" type="button">close</button></li>
|
48
|
+
</ul>
|
49
|
+
<table id="migration_status">
|
50
|
+
<caption>migration status</caption>
|
51
|
+
<thead>
|
52
|
+
<tr><th class="status">status</th><th class="version">version</th><th class="name">name</th></tr>
|
53
|
+
<tr><td colspan="3" class="migrations">
|
54
|
+
<button>UNFOLD ALL</button>
|
55
|
+
<%= @migrations.count %> migrations in total (up: <%= @migrations.count {|m| m[:status] == 'up'} %>, down: <%= @migrations.count {|m| m[:status] == 'down'} %>)
|
56
|
+
</td></tr>
|
57
|
+
</thead>
|
58
|
+
<tbody>
|
59
|
+
<%- @migrations.each do |m| -%>
|
60
|
+
<tr class="<%= m[:status] %>">
|
61
|
+
<td><label><%= check_box_tag (m[:status] == 'up' ? 'down[]' : 'up[]'), m[:filename], false, :id => "check_#{m[:filename]}" %><%= m[:status] %></label></td>
|
62
|
+
<td><%= m[:version] %></td>
|
63
|
+
<td class="migration_file_name"><%= m[:name] %></td>
|
64
|
+
</tr>
|
65
|
+
<%- end -%>
|
66
|
+
</tbody>
|
67
|
+
</table>
|
68
|
+
<%= submit_tag 'run migrations' %>
|
69
|
+
<% end %>
|
70
|
+
</div>
|
71
|
+
<a href="#" id='open_create_model_dialog'%>Create Model</a>
|
72
|
+
<div id="create_model_form">
|
73
|
+
<form>
|
74
|
+
Model Name: <input id="new_model_name" name="new_model_name" type="text" /><br>
|
75
|
+
<table id="create_model_table">
|
76
|
+
<tbody>
|
77
|
+
<tr>
|
78
|
+
<td><input name="new_model_column_name_1" type="text" /></td>
|
79
|
+
<td class="separator">:</td>
|
80
|
+
<td><input name="new_model_column_type_1" type="text" value="string" /></td>
|
81
|
+
</tr>
|
82
|
+
</tbody>
|
83
|
+
</table>
|
84
|
+
<div><a href="#" id="new_model_add_column" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span class="ui-button-text">Add More Column</span></a></div>
|
85
|
+
</form>
|
86
|
+
</div>
|
87
|
+
</div>
|
@@ -1,4 +1,4 @@
|
|
1
1
|
<div id="erd" data-svg_width="<%= width %>" data-svg_height="<%= height %>">
|
2
|
-
<%= render :partial => 'erd/erd/model', :collection => models -%>
|
2
|
+
<%= render :partial => 'erd/erd/model', :collection => models, :locals => {:edit_mode => edit_mode} -%>
|
3
3
|
<script>window.raw_edges = <%= edges.to_json.html_safe %>;</script>
|
4
4
|
</div>
|
@@ -2,85 +2,16 @@
|
|
2
2
|
<div id="erd_container">
|
3
3
|
<%=raw @erd %>
|
4
4
|
</div>
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
<%- end -%>
|
18
|
-
</ul>
|
19
|
-
<%- end -%>
|
20
|
-
<%- end -%>
|
21
|
-
</div>
|
22
|
-
<%- end -%>
|
23
|
-
<%- if flash[:failed_migrations].present? -%>
|
24
|
-
<div id="failed">
|
25
|
-
<h2>failed migrations</h2>
|
26
|
-
<ul>
|
27
|
-
<%- flash[:failed_migrations].each do |m| -%>
|
28
|
-
<li><%= m %></li>
|
29
|
-
<%- end -%>
|
30
|
-
</ul>
|
31
|
-
</div>
|
32
|
-
<%- end -%>
|
33
|
-
<table id="changes">
|
34
|
-
<caption>schema changes</caption>
|
35
|
-
<thead><tr><th>action</th><th>model</th><th>column</th><th>from</th><th>to</th></tr></thead>
|
36
|
-
<tbody></tbody>
|
37
|
-
</table>
|
38
|
-
<%= form_tag '/erd', :method => :put, :id => 'changes_form' do %>
|
39
|
-
<%= hidden_field_tag 'changes' %>
|
40
|
-
<%= submit_tag 'save changes' %>
|
41
|
-
<% end %>
|
42
|
-
<%= form_tag '/erd/migrate', :method => :put, :id => 'migrate_form' do %>
|
43
|
-
<ul id="open_buttons">
|
44
|
-
<li><button id="open_up" type="button">up</button></li>
|
45
|
-
<li><button id="open_down" type="button">down</button></li>
|
46
|
-
<li><button id="close_all" type="button">close</button></li>
|
47
|
-
</ul>
|
48
|
-
<table id="migration_status">
|
49
|
-
<caption>migration status</caption>
|
50
|
-
<thead>
|
51
|
-
<tr><th class="status">status</th><th class="version">version</th><th class="name">name</th></tr>
|
52
|
-
<tr><td colspan="3" class="migrations">
|
53
|
-
<button>UNFOLD ALL</button>
|
54
|
-
<%= @migrations.count %> migrations in total (up: <%= @migrations.count {|m| m[:status] == 'up'} %>, down: <%= @migrations.count {|m| m[:status] == 'down'} %>)
|
55
|
-
</td></tr>
|
56
|
-
</thead>
|
57
|
-
<tbody>
|
58
|
-
<%- @migrations.each do |m| -%>
|
59
|
-
<tr class="<%= m[:status] %>">
|
60
|
-
<td><label><%= check_box_tag (m[:status] == 'up' ? 'down[]' : 'up[]'), m[:filename] %><%= m[:status] %></label></td>
|
61
|
-
<td><%= m[:version] %></td>
|
62
|
-
<td class="migration_file_name"><%= m[:name] %></td>
|
63
|
-
</tr>
|
64
|
-
<%- end -%>
|
65
|
-
</tbody>
|
66
|
-
</table>
|
67
|
-
<%= submit_tag 'run migrations' %>
|
68
|
-
<% end %>
|
69
|
-
</div>
|
70
|
-
<a href="#" id='open_create_model_dialog'%>Create Model</a>
|
71
|
-
<div id="create_model_form">
|
72
|
-
<form>
|
73
|
-
Model Name: <input id="new_model_name" name="new_model_name" type="text" /><br>
|
74
|
-
<table id="create_model_table">
|
75
|
-
<tbody>
|
76
|
-
<tr>
|
77
|
-
<td><input name="new_model_column_name_1" type="text" /></td>
|
78
|
-
<td class="separator">:</td>
|
79
|
-
<td><input name="new_model_column_type_1" type="text" value="string" /></td>
|
80
|
-
</tr>
|
81
|
-
</tbody>
|
82
|
-
</table>
|
83
|
-
<div><a href="#" id="new_model_add_column" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span class="ui-button-text">Add More Column</span></a></div>
|
84
|
-
</form>
|
85
|
-
</div>
|
5
|
+
<%= form_tag '/erd', :method => :put, :id => 'changes_form' do %>
|
6
|
+
<%= hidden_field_tag 'position_changes' %>
|
7
|
+
<% end %>
|
8
|
+
<input id="drawer_switch" type="checkbox">
|
9
|
+
<label id="drawer_hide_label" class="drawer_switch_label" for="drawer_switch">> Hide Buttons</label>
|
10
|
+
<label id="drawer_show_label" class="drawer_switch_label" for="drawer_switch"><</label>
|
11
|
+
<nav id="buttons">
|
12
|
+
<ul>
|
13
|
+
<li><a href="#!" id="save_position_changes" class="menu_button">Save Position Changes</a></li>
|
14
|
+
<li><%= link_to 'Edit the Database', :edit, :id => 'link_to_edit', :class => 'menu_button' %></li>
|
15
|
+
</ul>
|
16
|
+
</nav>
|
86
17
|
</div>
|
data/config/routes.rb
CHANGED
data/lib/erd/version.rb
CHANGED
data/public/erd/erd.css
CHANGED
@@ -219,8 +219,9 @@ li {
|
|
219
219
|
box-shadow: rgba(0, 0, 0, 0.7) 0 2px 2px; }
|
220
220
|
#erd .model .model_name {
|
221
221
|
border-bottom: 1px #444444 solid;
|
222
|
-
cursor: pointer;
|
223
222
|
margin: 1px 5px 0 5px auto; }
|
223
|
+
#erd .model .model_name.edit {
|
224
|
+
cursor: pointer; }
|
224
225
|
#erd .model .model_name .model_name_text {
|
225
226
|
text-align: center;
|
226
227
|
display: block;
|
@@ -229,10 +230,10 @@ li {
|
|
229
230
|
background: -ms-linear-gradient(top, #eeeeee 0%, #d0d0d0 88%);
|
230
231
|
background: -o-linear-gradient(top, #eeeeee 0%, #d0d0d0 88%);
|
231
232
|
background: linear-gradient(top, #eeeeee 0%, #d0d0d0 88%);
|
232
|
-
font-size:
|
233
|
+
font-size: 15px;
|
233
234
|
font-weight: bold;
|
234
235
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
|
235
|
-
line-height:
|
236
|
+
line-height: 1.6;
|
236
237
|
padding: 0 0.8em; }
|
237
238
|
#erd .model .model_name .model_name_text.unsaved {
|
238
239
|
background: #fffebe;
|
@@ -314,7 +315,7 @@ li {
|
|
314
315
|
font-size: small;
|
315
316
|
display: block;
|
316
317
|
padding: 0 5px;
|
317
|
-
line-height:
|
318
|
+
line-height: 1.6;
|
318
319
|
background: #444444;
|
319
320
|
color: white;
|
320
321
|
text-decoration: none; }
|
@@ -328,9 +329,9 @@ li {
|
|
328
329
|
|
329
330
|
.columns .column {
|
330
331
|
border-bottom: dotted 1px #cccccc;
|
331
|
-
padding: 0 0.
|
332
|
+
padding: 0 0.5em;
|
332
333
|
clear: both;
|
333
|
-
line-height:
|
334
|
+
line-height: 20px;
|
334
335
|
font-size: 14px; }
|
335
336
|
.columns .column table {
|
336
337
|
width: 100%; }
|
@@ -338,12 +339,12 @@ li {
|
|
338
339
|
background: #f9f9f9; }
|
339
340
|
.columns .column:last-child {
|
340
341
|
border-bottom: none; }
|
341
|
-
.columns .column .column_name_text,
|
342
|
-
.columns .column .column_type_text {
|
342
|
+
.columns .column .column_name_text.edit,
|
343
|
+
.columns .column .column_type_text.edit {
|
343
344
|
cursor: pointer; }
|
344
345
|
.columns .column .column_name_text {
|
345
346
|
margin: 0 1.4em 0 0; }
|
346
|
-
.columns .column .column_name_text:hover {
|
347
|
+
.columns .column .column_name_text.edit:hover {
|
347
348
|
text-decoration: underline; }
|
348
349
|
.columns .column.unsaved {
|
349
350
|
background: #fffebe;
|
@@ -377,11 +378,11 @@ li {
|
|
377
378
|
.columns .column .rename_column_form {
|
378
379
|
padding: 8px; }
|
379
380
|
.columns .column .column_type_text {
|
380
|
-
font-size:
|
381
|
+
font-size: 13px;
|
381
382
|
float: right;
|
382
383
|
display: block;
|
383
384
|
line-height: 16px;
|
384
|
-
margin:
|
385
|
+
margin: 1px 0 0;
|
385
386
|
-webkit-border-radius: 4px;
|
386
387
|
-moz-border-radius: 4px;
|
387
388
|
-ms-border-radius: 4px;
|
@@ -395,7 +396,7 @@ li {
|
|
395
396
|
background: #f9eee9;
|
396
397
|
color: #444444;
|
397
398
|
border-style: solid; }
|
398
|
-
.columns .column .column_type_text:hover {
|
399
|
+
.columns .column .column_type_text.edit:hover {
|
399
400
|
border-color: #e36c33;
|
400
401
|
background: #edd0c2; }
|
401
402
|
.columns .column .column_type_text.date, .columns .column .column_type_text.time, .columns .column .column_type_text.timestamp, .columns .column .column_type_text.datetime {
|
@@ -403,7 +404,7 @@ li {
|
|
403
404
|
background: #f3e2e4;
|
404
405
|
color: #444444;
|
405
406
|
border-style: solid; }
|
406
|
-
.columns .column .column_type_text.date:hover, .columns .column .column_type_text.time:hover, .columns .column .column_type_text.timestamp:hover, .columns .column .column_type_text.datetime:hover {
|
407
|
+
.columns .column .column_type_text.edit.date:hover, .columns .column .column_type_text.edit.time:hover, .columns .column .column_type_text.edit.timestamp:hover, .columns .column .column_type_text.edit.datetime:hover {
|
407
408
|
border-color: #d0394d;
|
408
409
|
background: #e4bec3; }
|
409
410
|
.columns .column .column_type_text.boolean {
|
@@ -411,7 +412,7 @@ li {
|
|
411
412
|
background: #c7dce6;
|
412
413
|
color: #444444;
|
413
414
|
border-style: solid; }
|
414
|
-
.columns .column .column_type_text.boolean:hover {
|
415
|
+
.columns .column .column_type_text.edit.boolean:hover {
|
415
416
|
border-color: #2e87b3;
|
416
417
|
background: #a3c6d7; }
|
417
418
|
.columns .column .column_type_text.text {
|
@@ -419,7 +420,7 @@ li {
|
|
419
420
|
background: #efe7d3;
|
420
421
|
color: #444444;
|
421
422
|
border-style: solid; }
|
422
|
-
.columns .column .column_type_text.text:hover {
|
423
|
+
.columns .column .column_type_text.edit.text:hover {
|
423
424
|
border-color: #cb9d2b;
|
424
425
|
background: #e1d2ae; }
|
425
426
|
.columns .column .column_type_text.decimal {
|
@@ -427,7 +428,7 @@ li {
|
|
427
428
|
background: #dfdf50;
|
428
429
|
color: #444444;
|
429
430
|
border-style: solid; }
|
430
|
-
.columns .column .column_type_text.decimal:hover {
|
431
|
+
.columns .column .column_type_text.edit.decimal:hover {
|
431
432
|
border-color: #5e5e05;
|
432
433
|
background: #d5d527; }
|
433
434
|
.columns .column .column_type_text.float {
|
@@ -435,7 +436,7 @@ li {
|
|
435
436
|
background: silver;
|
436
437
|
color: #444444;
|
437
438
|
border-style: solid; }
|
438
|
-
.columns .column .column_type_text.float:hover {
|
439
|
+
.columns .column .column_type_text.edit.float:hover {
|
439
440
|
border-color: #684b53;
|
440
441
|
background: #a6a6a6; }
|
441
442
|
.columns .column .column_type_text.integer {
|
@@ -443,7 +444,7 @@ li {
|
|
443
444
|
background: #dfdfe0;
|
444
445
|
color: #444444;
|
445
446
|
border-style: solid; }
|
446
|
-
.columns .column .column_type_text.integer:hover {
|
447
|
+
.columns .column .column_type_text.edit.integer:hover {
|
447
448
|
border-color: #606493;
|
448
449
|
background: #c5c5c7; }
|
449
450
|
.columns .column .column_type_text.primary_key {
|
@@ -451,7 +452,7 @@ li {
|
|
451
452
|
background: #f9efe7;
|
452
453
|
color: #444444;
|
453
454
|
border-style: solid; }
|
454
|
-
.columns .column .column_type_text.primary_key:hover {
|
455
|
+
.columns .column .column_type_text.edit.primary_key:hover {
|
455
456
|
border-color: #e47e30;
|
456
457
|
background: #eed3bf; }
|
457
458
|
.columns .column .column_type_text.string {
|
@@ -459,7 +460,7 @@ li {
|
|
459
460
|
background: #d3e09e;
|
460
461
|
color: #444444;
|
461
462
|
border-style: solid; }
|
462
|
-
.columns .column .column_type_text.string:hover {
|
463
|
+
.columns .column .column_type_text.edit.string:hover {
|
463
464
|
border-color: #7f9919;
|
464
465
|
background: #c1d477; }
|
465
466
|
.columns .column .column_type_text.unsaved {
|
@@ -510,6 +511,54 @@ li {
|
|
510
511
|
#model_name_changes, #column_name_changes {
|
511
512
|
display: none; }
|
512
513
|
|
514
|
+
#drawer_switch {
|
515
|
+
display: none; }
|
516
|
+
#drawer_switch:checked ~ #buttons {
|
517
|
+
right: -400px; }
|
518
|
+
#drawer_switch:checked ~ #drawer_hide_label {
|
519
|
+
visibility: hidden; }
|
520
|
+
#drawer_switch:checked ~ #drawer_show_label {
|
521
|
+
visibility: visible; }
|
522
|
+
|
523
|
+
#buttons {
|
524
|
+
position: fixed;
|
525
|
+
top: 70px;
|
526
|
+
right: 15px;
|
527
|
+
-webkit-transition: all 0.5s;
|
528
|
+
transition: all 0.5s; }
|
529
|
+
|
530
|
+
.drawer_switch_label {
|
531
|
+
position: fixed;
|
532
|
+
right: 15px;
|
533
|
+
top: 10px;
|
534
|
+
background: rgba(0, 0, 0, 0.6);
|
535
|
+
padding: 12px 20px;
|
536
|
+
color: white;
|
537
|
+
cursor: pointer;
|
538
|
+
text-decoration: none;
|
539
|
+
font-size: 13px; }
|
540
|
+
.drawer_switch_label:hover {
|
541
|
+
background: rgba(0, 0, 0, 0.8); }
|
542
|
+
#drawer_show_label {
|
543
|
+
visibility: hidden; }
|
544
|
+
|
545
|
+
.menu_button {
|
546
|
+
position: relative;
|
547
|
+
right: 0;
|
548
|
+
background: rgba(0, 0, 0, 0.6);
|
549
|
+
padding: 12px 20px;
|
550
|
+
color: white;
|
551
|
+
text-decoration: none;
|
552
|
+
font-size: 13px; }
|
553
|
+
.menu_button:hover {
|
554
|
+
background: rgba(0, 0, 0, 0.8); }
|
555
|
+
#save_position_changes {
|
556
|
+
visibility: hidden;
|
557
|
+
top: 70px;
|
558
|
+
background: rgba(191, 0, 0, 0.6); }
|
559
|
+
#save_position_changes:hover {
|
560
|
+
background: rgba(191, 0, 0, 0.8); }
|
561
|
+
|
513
562
|
#open_create_model_dialog {
|
514
563
|
position: fixed;
|
515
564
|
right: 15px;
|
data/public/erd/erd.js
CHANGED
@@ -19,10 +19,12 @@ class ERD {
|
|
19
19
|
this.handle_new_model_add_column_click = this.handle_new_model_add_column_click.bind(this);
|
20
20
|
this.handle_open_migration_click = this.handle_open_migration_click.bind(this);
|
21
21
|
this.handle_close_migration_click = this.handle_close_migration_click.bind(this);
|
22
|
+
this.handle_save_position_changes_click = this.handle_save_position_changes_click.bind(this);
|
22
23
|
this.name = name;
|
23
24
|
this.elem = elem;
|
24
25
|
this.edges = edges;
|
25
26
|
this.paper = Raphael(this.name, this.elem.data('svg_width'), this.elem.data('svg_height'));
|
27
|
+
this.position_changes = {};
|
26
28
|
this.setup_handlers();
|
27
29
|
const models = this.elem.find('.model');
|
28
30
|
this.models = {};
|
@@ -122,11 +124,13 @@ class ERD {
|
|
122
124
|
const from = target.data('original_position');
|
123
125
|
const to = [target.css('left').replace(/px$/, ''), target.css('top').replace(/px$/, '')].join();
|
124
126
|
this.upsert_change('move', model_name, '', '', to);
|
127
|
+
this.position_changes[model_name] = to;
|
125
128
|
this.connect_arrows(this.edges.filter(e=> (e.from === model_name) || (e.to === model_name)));
|
129
|
+
document.getElementById("save_position_changes").style.visibility = "visible";
|
126
130
|
}
|
127
131
|
|
128
132
|
setup_click_handlers() {
|
129
|
-
$('div.model_name_text, span.column_name_text, span.column_type_text').on('click', this.handle_text_elem_click);
|
133
|
+
$('div.model_name_text.edit, span.column_name_text.edit, span.column_type_text.edit').on('click', this.handle_text_elem_click);
|
130
134
|
$('div.model a.add_column').on('click', this.handle_add_column_click);
|
131
135
|
$('div.model a.cancel').on('click', this.handle_cancel_click);
|
132
136
|
$('div.model a.close').on('click', this.handle_remove_model_click);
|
@@ -134,6 +138,7 @@ class ERD {
|
|
134
138
|
$('div.model a.cancel').on('click', this.handle_cancel_click);
|
135
139
|
$('div#open_migration').on('click', this.handle_open_migration_click);
|
136
140
|
$('div#close_migration').on('click', this.handle_close_migration_click);
|
141
|
+
$('#save_position_changes').on('click', this.handle_save_position_changes_click);
|
137
142
|
}
|
138
143
|
|
139
144
|
setup_submit_handlers() {
|
@@ -165,6 +170,7 @@ class ERD {
|
|
165
170
|
return change;
|
166
171
|
}).toArray();
|
167
172
|
$('#changes_form').find('input[name=changes]').val(JSON.stringify(changes));
|
173
|
+
$('#changes_form').find('input[name=position_changes]').val(JSON.stringify(this.position_changes));
|
168
174
|
}
|
169
175
|
|
170
176
|
handle_add_column(ev) {
|
@@ -359,6 +365,11 @@ class ERD {
|
|
359
365
|
.parent().hide()
|
360
366
|
.prev('div').show();
|
361
367
|
}
|
368
|
+
|
369
|
+
handle_save_position_changes_click(ev) {
|
370
|
+
$('#changes_form').find('input[name=position_changes]').val(JSON.stringify(this.position_changes));
|
371
|
+
$('#changes_form').submit();
|
372
|
+
}
|
362
373
|
}
|
363
374
|
|
364
375
|
$(function() {
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akira Matsuda
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-graphviz
|
@@ -167,6 +167,7 @@ files:
|
|
167
167
|
- app/controllers/erd/erd_controller.rb
|
168
168
|
- app/views/erd/erd/_column.html.erb
|
169
169
|
- app/views/erd/erd/_model.html.erb
|
170
|
+
- app/views/erd/erd/edit.html.erb
|
170
171
|
- app/views/erd/erd/erd.html.erb
|
171
172
|
- app/views/erd/erd/index.html.erb
|
172
173
|
- app/views/layouts/erd/application.html.erb
|
@@ -210,7 +211,7 @@ homepage: https://github.com/amatsuda/erd
|
|
210
211
|
licenses:
|
211
212
|
- MIT
|
212
213
|
metadata: {}
|
213
|
-
post_install_message:
|
214
|
+
post_install_message:
|
214
215
|
rdoc_options: []
|
215
216
|
require_paths:
|
216
217
|
- lib
|
@@ -225,8 +226,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
226
|
- !ruby/object:Gem::Version
|
226
227
|
version: '0'
|
227
228
|
requirements: []
|
228
|
-
rubygems_version: 3.
|
229
|
-
signing_key:
|
229
|
+
rubygems_version: 3.1.4
|
230
|
+
signing_key:
|
230
231
|
specification_version: 4
|
231
232
|
summary: erd engine on Rails
|
232
233
|
test_files:
|