erd 0.6.4 → 0.7.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.
- 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:
|