foreman_datacenter 1.23.0 → 1.24.3
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/assets/stylesheets/foreman_datacenter/rack_show.css +56 -0
- data/app/controllers/foreman_datacenter/application_controller.rb +2 -0
- data/app/controllers/foreman_datacenter/rack_groups_controller.rb +1 -0
- data/app/controllers/foreman_datacenter/racks_controller.rb +9 -1
- data/app/helpers/foreman_datacenter/racks_helper.rb +96 -0
- data/app/models/foreman_datacenter/device.rb +38 -0
- data/app/models/foreman_datacenter/rack.rb +103 -1
- data/app/views/foreman_datacenter/devices/show.html.erb +1 -1
- data/app/views/foreman_datacenter/racks/_device_position.html.erb +10 -1
- data/app/views/foreman_datacenter/racks/_device_position_new.html.erb +91 -0
- data/app/views/foreman_datacenter/racks/show.html.erb +6 -4
- data/config/routes.rb +21 -1
- data/lib/foreman_datacenter/version.rb +1 -1
- data/test/controllers/foreman_datacenter/device_roles_controller_test.rb +133 -0
- data/test/controllers/foreman_datacenter/device_types_contoller_test.rb +108 -47
- data/test/controllers/foreman_datacenter/devices_controller_test.rb +132 -0
- data/test/controllers/foreman_datacenter/manufacturers_controller_test.rb +133 -0
- data/test/controllers/foreman_datacenter/platforms_contoller_test.rb +91 -48
- data/test/controllers/foreman_datacenter/rack_groups_contoller_test.rb +90 -43
- data/test/controllers/foreman_datacenter/racks_contoller_test.rb +111 -42
- data/test/controllers/foreman_datacenter/sites_contoller_test.rb +108 -81
- data/test/datacenter_helper.rb +8 -1
- data/test/factories/device.rb +5 -0
- data/test/factories/device_role.rb +6 -0
- data/test/factories/device_type.rb +30 -0
- data/test/factories/rack_group.rb +13 -14
- data/test/fixtures/foreman_datacenter/device_roles.yml +0 -1
- data/test/integration/foreman_datacenter/device_role_test.rb +35 -0
- data/test/integration/foreman_datacenter/device_type_test.rb +33 -0
- data/test/integration/foreman_datacenter/manufacturer_test.rb +33 -0
- data/test/integration/foreman_datacenter/platform_test.rb +35 -0
- data/test/integration/foreman_datacenter/rack_group_test.rb +35 -25
- data/test/integration/foreman_datacenter/rack_test.rb +37 -25
- data/test/integration/foreman_datacenter/site_test.rb +39 -29
- data/test/unit/foreman_datacenter_test.rb +1 -1
- metadata +60 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b77182c1385f10fbeb5506db376a8fa29a079b4cebae2945ce99d07a3350aa7
|
4
|
+
data.tar.gz: 36f47250116e01a60c30a1be2503ff7c636e18bf7408fc75b00fd130b9eabc99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73e0482bff2ae27ec2b2f59ad59946c89ec6bc712362952e1f2fb77095b1953f0cce0e943506fae0814b94ccb4188172a50106e23b4b2789358886a1c9ffef04
|
7
|
+
data.tar.gz: a3ff1c963f5f22c2902a25e503b3218aa408b27edf7da7417545010b4faf3eaaeb81ae3c460d73fd6e08acd6496beceb9f0b1893f42589f3fe6e188de86b21a3
|
@@ -0,0 +1,56 @@
|
|
1
|
+
.rack-grid {
|
2
|
+
width: 100%;
|
3
|
+
border-bottom: 1px solid #d1d1d1;
|
4
|
+
border-left: 1px solid #d1d1d1;
|
5
|
+
display: inline-grid;
|
6
|
+
}
|
7
|
+
|
8
|
+
.item {
|
9
|
+
justify-content: center;
|
10
|
+
padding: 2px 10px 3px;
|
11
|
+
border-top: 1px solid #d1d1d1;
|
12
|
+
border-right: 1px solid #d1d1d1;
|
13
|
+
}
|
14
|
+
|
15
|
+
.item-dev {
|
16
|
+
position: relative;
|
17
|
+
text-align: center;
|
18
|
+
}
|
19
|
+
|
20
|
+
.dev-cell {
|
21
|
+
overflow: hidden;
|
22
|
+
text-overflow: ellipsis;
|
23
|
+
white-space: nowrap;
|
24
|
+
position: absolute;
|
25
|
+
height: inherit;
|
26
|
+
width: 90%;
|
27
|
+
text-align: center;
|
28
|
+
}
|
29
|
+
|
30
|
+
.a:hover {
|
31
|
+
overflow: visible;
|
32
|
+
}
|
33
|
+
|
34
|
+
.no-border {
|
35
|
+
border: none !important;
|
36
|
+
}
|
37
|
+
|
38
|
+
.panel-head-border {
|
39
|
+
border-top: 1px solid #ddd !important;
|
40
|
+
border-left: 1px solid #ddd !important;
|
41
|
+
border-right: 1px solid #ddd !important;
|
42
|
+
border-bottom: none !important;
|
43
|
+
}
|
44
|
+
|
45
|
+
.item-row {
|
46
|
+
white-space: nowrap;
|
47
|
+
text-overflow: ellipsis;
|
48
|
+
overflow: hidden;
|
49
|
+
}
|
50
|
+
|
51
|
+
.item-row:hover {
|
52
|
+
overflow: visible;
|
53
|
+
}
|
54
|
+
|
55
|
+
.item-empty-cell {
|
56
|
+
}
|
@@ -61,6 +61,7 @@ module ForemanDatacenter
|
|
61
61
|
def racks
|
62
62
|
@racks = @rack_group.racks.includes(devices: [:device_role])
|
63
63
|
process_error redirect: rack_groups_path(@rack_group), error_msg: 'Current Rack Group haven\'t any Racks.' if @racks.empty?
|
64
|
+
@order = params[:order] || "desc"
|
64
65
|
end
|
65
66
|
|
66
67
|
def update_associated_objects
|
@@ -3,7 +3,7 @@ module ForemanDatacenter
|
|
3
3
|
include Foreman::Controller::AutoCompleteSearch
|
4
4
|
include ForemanDatacenter::Controller::Parameters::Rack
|
5
5
|
|
6
|
-
before_action :find_resource, only: [:show, :edit, :update, :destroy, :devices, :move]
|
6
|
+
before_action :find_resource, only: [:show, :edit, :update, :destroy, :devices, :move, :export_to_csv]
|
7
7
|
|
8
8
|
def index
|
9
9
|
@racks = resource_base_search_and_page.includes(:site, :rack_group)
|
@@ -17,6 +17,7 @@ module ForemanDatacenter
|
|
17
17
|
|
18
18
|
def show
|
19
19
|
@rack = resource_base.includes(devices: [:device_role]).find(params[:id])
|
20
|
+
@order = params[:order] || "desc"
|
20
21
|
end
|
21
22
|
|
22
23
|
def new
|
@@ -64,6 +65,13 @@ module ForemanDatacenter
|
|
64
65
|
process_error object: @rack, error_msg: 'Current Rack haven\'t any Devices.' if @devices.empty?
|
65
66
|
end
|
66
67
|
|
68
|
+
def export_to_csv
|
69
|
+
data = @rack.format_for_csv
|
70
|
+
file = File.open("#{@rack.name}.csv", "r")
|
71
|
+
send_file(file)
|
72
|
+
file.close
|
73
|
+
end
|
74
|
+
|
67
75
|
def update_associated_objects
|
68
76
|
begin
|
69
77
|
@rack = ForemanDatacenter::Rack.find(request.env['HTTP_REFERER'].split('/')[-2])
|
@@ -4,5 +4,101 @@ module ForemanDatacenter
|
|
4
4
|
collection = rack.site ? rack.site.rack_groups : []
|
5
5
|
options_from_collection_for_select(collection, 'id', 'name', rack.rack_group_id)
|
6
6
|
end
|
7
|
+
|
8
|
+
def grid_u_desc(rack)
|
9
|
+
i = rack.height + 1
|
10
|
+
limit = 0
|
11
|
+
result = ""
|
12
|
+
|
13
|
+
while limit <= i do
|
14
|
+
if i == 0 && !rack.unpositioned_devices.empty?
|
15
|
+
concat content_tag(:div, "Unpositioned Devices")
|
16
|
+
else
|
17
|
+
if i != 0
|
18
|
+
if rack.child_devices.any? { |d| d.position == i }
|
19
|
+
concat content_tag :div, &-> do
|
20
|
+
concat "#{i}U"
|
21
|
+
rack.child_devices.each do |d|
|
22
|
+
if d.position == i
|
23
|
+
concat content_tag :strong, &-> do
|
24
|
+
concat link_to("Child", device_path(d))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
concat content_tag(:div, "#{i}U")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
i -= 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def grid_empty_style(cell, id)
|
39
|
+
case cell[1]
|
40
|
+
when ["right"]
|
41
|
+
column = "grid-area: rack-#{id}-row-#{cell[0]}-right-empty"
|
42
|
+
when ["left"]
|
43
|
+
column = "grid-area: rack-#{id}-row-#{cell[0]}-left-empty"
|
44
|
+
when ["left", "right"] || ["right", "left"]
|
45
|
+
column = "grid-area: rack-#{id}-row-#{cell[0]}-full-empty"
|
46
|
+
end
|
47
|
+
return column
|
48
|
+
end
|
49
|
+
|
50
|
+
def margin_style(height)
|
51
|
+
result = "top: "
|
52
|
+
case height
|
53
|
+
when 1
|
54
|
+
result += "7%"
|
55
|
+
when 2
|
56
|
+
result += "30%"
|
57
|
+
when 3
|
58
|
+
result += "35%"
|
59
|
+
when 4
|
60
|
+
result += "40%"
|
61
|
+
else
|
62
|
+
result += "45%"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def grid_rack_style(device)
|
67
|
+
css_class_name = device.name.gsub(/[.@#\s]/, "_")
|
68
|
+
return "grid-area: #{css_class_name}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def grid_rack_height(height)
|
72
|
+
return (height + 1)
|
73
|
+
end
|
74
|
+
|
75
|
+
def grid_template(grid, id, order)
|
76
|
+
result = []
|
77
|
+
gr = JSON.parse(grid)
|
78
|
+
gr = gr.to_a.reverse.to_h if order == "desc"
|
79
|
+
|
80
|
+
gr.each do |k,v|
|
81
|
+
row = "rack-#{id}-u#{k}"
|
82
|
+
if v.instance_of? Array
|
83
|
+
if k == "0"
|
84
|
+
row += " rack-#{id}-unpos-devs rack-#{id}-unpos-devs"
|
85
|
+
else
|
86
|
+
row += " rack-#{id}-row-#{k}-full-empty rack-#{id}-row-#{k}-full-empty"
|
87
|
+
end
|
88
|
+
else
|
89
|
+
if v.size > 1
|
90
|
+
row += " #{v['left']} #{v['right']}"
|
91
|
+
else
|
92
|
+
row += " #{v['left']} rack-#{id}-row-#{k}-right-empty" if v.key?("left")
|
93
|
+
row += " rack-#{id}-row-#{k}-left-empty #{v['right']}" if v.key?("right")
|
94
|
+
row += " #{v['full']} #{v['full']}" if v.key?("full")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
result << row
|
98
|
+
end
|
99
|
+
final = result.join("' '").prepend("'") + "'"
|
100
|
+
return "grid-template-areas: #{final}; grid-template-columns: 22% 39% 39%"
|
101
|
+
end
|
102
|
+
|
7
103
|
end
|
8
104
|
end
|
@@ -34,6 +34,7 @@ module ForemanDatacenter
|
|
34
34
|
validates :serial, length: { maximum: 50 }
|
35
35
|
validates :rack_id, presence: true
|
36
36
|
validates :position, numericality: { only_integer: true }, allow_nil: true
|
37
|
+
validate :correct_position
|
37
38
|
|
38
39
|
after_create :create_interfaces
|
39
40
|
after_create :import_interfaces_from_host
|
@@ -72,6 +73,10 @@ module ForemanDatacenter
|
|
72
73
|
device_type.try(:subdevice_role) == 'Parent'
|
73
74
|
end
|
74
75
|
|
76
|
+
def child?
|
77
|
+
device_type.try(:subdevice_role) == 'Child'
|
78
|
+
end
|
79
|
+
|
75
80
|
def free_interfaces
|
76
81
|
interfaces.where(mgmt_only: false).reject(&:connected?)
|
77
82
|
end
|
@@ -139,6 +144,39 @@ module ForemanDatacenter
|
|
139
144
|
end
|
140
145
|
end
|
141
146
|
|
147
|
+
def correct_position
|
148
|
+
if position > 0
|
149
|
+
grid_template = JSON.parse(self.rack.grid_template_areas)
|
150
|
+
correct_pos = true
|
151
|
+
pos = []
|
152
|
+
sz = (size == 0 || size == 1) ? [position] : [*position..(position + (size - 1))]
|
153
|
+
sd = (side.nil?) ? "full" : side
|
154
|
+
sz.each do |i|
|
155
|
+
if grid_template["#{i}"].is_a?(Hash)
|
156
|
+
if grid_template["#{i}"].key?("full") && grid_template["#{i}"]["full"] != "device-#{self.id}"
|
157
|
+
correct_pos = false
|
158
|
+
pos << "#{i}(full)"
|
159
|
+
end
|
160
|
+
if sd == "full"
|
161
|
+
["left", "right"].each do |s|
|
162
|
+
if grid_template["#{i}"].key?("#{s}") && grid_template["#{i}"]["#{s}"] != "device-#{self.id}"
|
163
|
+
correct_pos = false
|
164
|
+
pos << "#{i}(#{s})"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
else
|
168
|
+
if grid_template["#{i}"].key?("#{sd}") && grid_template["#{i}"]["#{sd}"] != "device-#{self.id}"
|
169
|
+
correct_pos = false
|
170
|
+
pos << "#{i}(#{sd})"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
pos.uniq!
|
176
|
+
errors.add(:position, "Positions: #{pos.join(', ')} already taken") if correct_pos == false
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
142
180
|
private
|
143
181
|
|
144
182
|
def create_interfaces
|
@@ -12,6 +12,7 @@ module ForemanDatacenter
|
|
12
12
|
validates :facility_id, length: { maximum: 30 }
|
13
13
|
validates :height, presence: true
|
14
14
|
validates_numericality_of :height, only_integer: true, greater_than: 0
|
15
|
+
validate :correct_position
|
15
16
|
|
16
17
|
scoped_search on: :name, complete_value: true
|
17
18
|
scoped_search on: :height, validator: ScopedSearch::Validators::INTEGER
|
@@ -22,6 +23,7 @@ module ForemanDatacenter
|
|
22
23
|
scoped_search in: :site, on: :name, complete_value: true, rename: :site
|
23
24
|
scoped_search in: :rack_group, on: :name, complete_value: true, rename: :rack_group
|
24
25
|
|
26
|
+
|
25
27
|
def device_at(position)
|
26
28
|
devices.where(position: position).to_a
|
27
29
|
end
|
@@ -43,7 +45,7 @@ module ForemanDatacenter
|
|
43
45
|
end
|
44
46
|
|
45
47
|
def unpositioned_devices
|
46
|
-
devices.where(position: nil).to_a
|
48
|
+
devices.where(position: nil).or(devices.where(position: "0")).to_a
|
47
49
|
end
|
48
50
|
|
49
51
|
def devices_count
|
@@ -52,8 +54,108 @@ module ForemanDatacenter
|
|
52
54
|
count
|
53
55
|
end
|
54
56
|
|
57
|
+
def format_for_csv
|
58
|
+
positioned_devices = self.positioned_devices
|
59
|
+
unpositioned_devices = self.unpositioned_devices
|
60
|
+
csv_string = CSV.generate do |csv|
|
61
|
+
csv << ["positions", "left", "full", "right", "no side"]
|
62
|
+
positioned_devices.each do |i|
|
63
|
+
pos = i[0].map{|p| "#{p}"+"U"}.join(",")
|
64
|
+
if i[1].size > 0
|
65
|
+
sort = sort_for_csv(i[1])
|
66
|
+
csv << [pos, sort[0], sort[1], sort[2], sort[3]]
|
67
|
+
else
|
68
|
+
csv << [pos]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
unless unpositioned_devices.empty?
|
72
|
+
csv << []
|
73
|
+
csv << ["Unpositioned", unpositioned_devices.map(&:name).join(",")]
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
File.open("#{self.name}.csv", "w") {|f| f << csv_string}
|
78
|
+
end
|
79
|
+
|
80
|
+
# Finding all empty cells for grid layout
|
81
|
+
def empty_cells
|
82
|
+
cells = {} # all cells of grid
|
83
|
+
devices_cells = {} # cells with devices
|
84
|
+
height.times.each do |i|
|
85
|
+
cells[i+1] = ["left", "right"]
|
86
|
+
end
|
87
|
+
devices.each do |d|
|
88
|
+
if d.size > 0
|
89
|
+
if !d.position.nil? && d.position != 0
|
90
|
+
s = (d.size == 0 || d.size == 1) ? 0 : (d.size - 1)
|
91
|
+
places = [*d.position..d.position+s]
|
92
|
+
places.each do |p|
|
93
|
+
devices_cells[p] = [] unless devices_cells.key?(p)
|
94
|
+
if (d.side == "full" || d.side.nil?)
|
95
|
+
["left", "right"].each {|side| devices_cells[p] << side}
|
96
|
+
else
|
97
|
+
devices_cells[p] << d.side
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
devices_cells.each do |k,v|
|
104
|
+
v.each {|c| cells[k].delete(c)}
|
105
|
+
end
|
106
|
+
cells.each {|k,v| cells.except!(k) if cells[k] == []}
|
107
|
+
return cells
|
108
|
+
end
|
109
|
+
|
110
|
+
def grid_template_areas
|
111
|
+
result = {}
|
112
|
+
(height+1).times.each do |i|
|
113
|
+
if i == 0
|
114
|
+
result[0] = unpositioned_devices.map{|d| "device-#{d.id}"}
|
115
|
+
else
|
116
|
+
dev = {}
|
117
|
+
devices.each do |d|
|
118
|
+
if d.size > 0
|
119
|
+
if !d.position.nil? && d.position != 0
|
120
|
+
css_class_name = "device-#{d.id}"
|
121
|
+
s = (d.size == 1 || d.size == 0) ? 0 : (d.size - 1)
|
122
|
+
if [*d.position..(d.position + s)].include?(i)
|
123
|
+
if d.side.nil?
|
124
|
+
dev["full"] = css_class_name
|
125
|
+
else
|
126
|
+
dev["#{d.side}"] = css_class_name
|
127
|
+
end
|
128
|
+
result[i] = dev
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
(height+1).times.each do |i|
|
136
|
+
result[i] = [] if result[i].nil?
|
137
|
+
end
|
138
|
+
# result[0].reject! if result[0].empty?
|
139
|
+
return result.sort_by{|k,v| k}.to_h.to_json
|
140
|
+
end
|
141
|
+
|
142
|
+
def child_devices
|
143
|
+
devices.joins(:device_type).where("device_types.subdevice_role = ?", "Child")
|
144
|
+
end
|
145
|
+
|
55
146
|
private
|
56
147
|
|
148
|
+
def sort_for_csv(device_array)
|
149
|
+
left, full, right, no_side = "", "", "", []
|
150
|
+
device_array.each do |d|
|
151
|
+
left = d.name if d.side == "left"
|
152
|
+
right = d.name if d.side == "right"
|
153
|
+
full = d.name if d.side == "full"
|
154
|
+
no_side << d.name if d.side == nil
|
155
|
+
end
|
156
|
+
[left, full, right, no_side.join(",")]
|
157
|
+
end
|
158
|
+
|
57
159
|
def device_sorting(devices)
|
58
160
|
devices.reverse.map { |d| [d[0].reverse, d[1]] }
|
59
161
|
end
|
@@ -70,7 +70,7 @@
|
|
70
70
|
</tr>
|
71
71
|
<tr>
|
72
72
|
<td><%= _("Position") %></td>
|
73
|
-
<td><%= @device.positions.join(", ") %> / <%= @device.face %> / <%= @device.side %></td>
|
73
|
+
<td><%= (@device.position > 0) ? (@device.child? ? "#{@device.position} (Child)" : @device.positions.join(", ")) : 0 %> / <%= @device.face %> / <%= @device.side %></td>
|
74
74
|
</tr>
|
75
75
|
<tr>
|
76
76
|
<td><%= _("Device Type") %></td>
|
@@ -1,5 +1,14 @@
|
|
1
1
|
<div class="panel panel-default">
|
2
|
-
<div class="panel-heading text-center"
|
2
|
+
<div class="panel-heading text-center">
|
3
|
+
<h4 class="nonmargintop nonmarginbottom">
|
4
|
+
<strong>
|
5
|
+
<%= link_to _("#{rack.name}"), rack_path(rack) %>
|
6
|
+
</strong>
|
7
|
+
<strong>
|
8
|
+
<%= link_to 'Export to CSV', export_to_csv_rack_path(rack.id), class: "btn btn-primary btn-xs pull-right" %>
|
9
|
+
</strong>
|
10
|
+
</h4>
|
11
|
+
</div>
|
3
12
|
<table class="<%= table_css_classes 'table-hover panel-body nonmarginbottom' %>">
|
4
13
|
<tbody>
|
5
14
|
<% rack.positioned_devices.each do |positions, devices| %>
|
@@ -0,0 +1,91 @@
|
|
1
|
+
<div class="panel panel-default no-border">
|
2
|
+
<div class="panel-heading text-center panel-head-border">
|
3
|
+
<h4 class="nonmargintop nonmarginbottom">
|
4
|
+
<strong>
|
5
|
+
<%= link_to rack.name, rack_path(rack) %>
|
6
|
+
</strong>
|
7
|
+
<strong>
|
8
|
+
<%= link_to 'Export to CSV', export_to_csv_rack_path(rack.id), class: "btn btn-primary btn-xs pull-right" %>
|
9
|
+
</strong>
|
10
|
+
<strong>
|
11
|
+
<% if @order == "asc" %>
|
12
|
+
<%= link_to 'DESC', url_for(), class: "btn btn-success btn-xs pull-left" %>
|
13
|
+
<% else %>
|
14
|
+
<%= link_to 'ASC', url_for(order: "asc"), class: "btn btn-success btn-xs pull-left" %>
|
15
|
+
<% end %>
|
16
|
+
</strong>
|
17
|
+
</h4>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<!-- Grid -->
|
21
|
+
<div class="rack-grid rack-<%= rack.id %>" style="<%= grid_template(rack.grid_template_areas, rack.id, @order) %>">
|
22
|
+
|
23
|
+
<!-- Rows -->
|
24
|
+
<% (rack.height+1).times.each do |i| %>
|
25
|
+
<% if i == 0 && !rack.unpositioned_devices.empty? %>
|
26
|
+
<div class="item item-row" style="grid-area: rack-<%= rack.id %>-u<%= i %>">
|
27
|
+
<%= i == 0 ? "Unpositioned Devices" : "#{i}U"%>
|
28
|
+
</div>
|
29
|
+
<% else %>
|
30
|
+
<% if i != 0 %>
|
31
|
+
<div class="item item-row" style="grid-area: rack-<%= rack.id %>-u<%= i %>">
|
32
|
+
<%= "#{i}U" %>
|
33
|
+
<% rack.child_devices.each do |d| %>
|
34
|
+
<% if d.position == i %>
|
35
|
+
<strong>
|
36
|
+
<%= link_to "Child", device_path(d), class: "btn btn-primary btn-xs pull-right" %>
|
37
|
+
</strong>
|
38
|
+
<% end %>
|
39
|
+
<% end %>
|
40
|
+
</div>
|
41
|
+
<% else %>
|
42
|
+
<% next %>
|
43
|
+
<% end %>
|
44
|
+
<% end %>
|
45
|
+
<% end %>
|
46
|
+
|
47
|
+
<!-- Empty cells -->
|
48
|
+
<% rack.empty_cells.each do |c| %>
|
49
|
+
<div class="item item-empty-cell" style="<%= grid_empty_style(c, rack.id)%>">
|
50
|
+
|
51
|
+
</div>
|
52
|
+
<% end %>
|
53
|
+
|
54
|
+
<!-- Devices -->
|
55
|
+
<% rack.devices.each do |d| %>
|
56
|
+
<% if !d.position.nil? && d.size != 0 && d.position != 0 %>
|
57
|
+
<div class="item item-dev" style="grid-area: device-<%= d.id %>">
|
58
|
+
<div class="dev-cell" style="<%= margin_style(d.size) %>">
|
59
|
+
<div class="<%= "label " + d.device_role.color.downcase.gsub(" ","") %>" style="border-radius:40px;border:0px;"> </div>
|
60
|
+
<%= link_to d.name, device_path(d) %>
|
61
|
+
<% if d.side.nil? %>
|
62
|
+
*
|
63
|
+
<% end %>
|
64
|
+
<% if d.size.nil? %>
|
65
|
+
**
|
66
|
+
<% end %>
|
67
|
+
</div>
|
68
|
+
</div>
|
69
|
+
<% end %>
|
70
|
+
<% end %>
|
71
|
+
|
72
|
+
<!-- Unpositioned devices -->
|
73
|
+
<% if rack.unpositioned_devices.count != 0 %>
|
74
|
+
<div class="item item-dev" style="grid-area: rack-<%= rack.id %>-unpos-devs">
|
75
|
+
<% rack.unpositioned_devices.each do |d| %>
|
76
|
+
<div class="<%= "label " + d.device_role.color.downcase.gsub(" ","") %>" style="border-radius:40px;border:0px;"> </div>
|
77
|
+
<%= link_to d.name, device_path(d) %>
|
78
|
+
<% if d.side.nil? %>
|
79
|
+
*
|
80
|
+
<% end %>
|
81
|
+
<% if d.size.nil? %>
|
82
|
+
**
|
83
|
+
<% end %>
|
84
|
+
<br>
|
85
|
+
<% end %>
|
86
|
+
</div>
|
87
|
+
<% end %>
|
88
|
+
|
89
|
+
</div>
|
90
|
+
|
91
|
+
</div>
|