device.html 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. {% extends '_base.html' %}
  2. {% load static from staticfiles %}
  3. {% load helpers %}
  4. {% block title %}{{ device }}{% endblock %}
  5. {% block content %}
  6. {% include 'dcim/inc/device_header.html' with active_tab='info' %}
  7. <div class="row">
  8. <div class="col-md-6">
  9. <div class="panel panel-default">
  10. <div class="panel-heading">
  11. <strong>Device</strong>
  12. </div>
  13. <table class="table table-hover panel-body attr-table">
  14. <tr>
  15. <td>Site</td>
  16. <td>
  17. {% if device.site.region %}
  18. <a href="{{ device.site.region.get_absolute_url }}">{{ device.site.region }}</a>
  19. <i class="fa fa-angle-right"></i>
  20. {% endif %}
  21. <a href="{% url 'dcim:site' slug=device.site.slug %}">{{ device.site }}</a>
  22. </td>
  23. </tr>
  24. <tr>
  25. <td>Rack</td>
  26. <td>
  27. {% if device.rack %}
  28. {% if device.rack.group %}
  29. <a href="{{ device.rack.group.get_absolute_url }}">{{ device.rack.group }}</a>
  30. <i class="fa fa-angle-right"></i>
  31. {% endif %}
  32. <a href="{% url 'dcim:rack' pk=device.rack.pk %}">{{ device.rack }}</a>
  33. {% else %}
  34. <span class="text-muted">None</span>
  35. {% endif %}
  36. </td>
  37. </tr>
  38. <tr>
  39. <td>Position</td>
  40. <td>
  41. {% if device.parent_bay %}
  42. {% with device.parent_bay.device as parent %}
  43. <a href="{{ parent.get_absolute_url }}">{{ parent }}</a> <i class="fa fa-angle-right"></i> {{ device.parent_bay }}
  44. {% if parent.position %}
  45. (U{{ parent.position }} / {{ parent.get_face_display }})
  46. {% endif %}
  47. {% endwith %}
  48. {% elif device.rack and device.position %}
  49. <span>U{{ device.position }} / {{ device.get_face_display }}</span>
  50. {% elif device.rack and device.device_type.u_height %}
  51. <span class="label label-warning">Not racked</span>
  52. {% else %}
  53. <span class="text-muted">N/A</span>
  54. {% endif %}
  55. </td>
  56. </tr>
  57. <tr>
  58. <td>Tenant</td>
  59. <td>
  60. {% if device.tenant %}
  61. {% if device.tenant.group %}
  62. <a href="{{ device.tenant.group.get_absolute_url }}">{{ device.tenant.group }}</a>
  63. <i class="fa fa-angle-right"></i>
  64. {% endif %}
  65. <a href="{{ device.tenant.get_absolute_url }}">{{ device.tenant }}</a>
  66. {% else %}
  67. <span class="text-muted">None</span>
  68. {% endif %}
  69. </td>
  70. </tr>
  71. <tr>
  72. <td>Device Type</td>
  73. <td>
  74. <span><a href="{% url 'dcim:devicetype' pk=device.device_type.pk %}">{{ device.device_type.full_name }}</a> ({{ device.device_type.u_height }}U)</span>
  75. </td>
  76. </tr>
  77. <tr>
  78. <td>Serial Number</td>
  79. <td>
  80. {% if device.serial %}
  81. <span>{{ device.serial }}</span>
  82. {% else %}
  83. <span class="text-muted">N/A</span>
  84. {% endif %}
  85. </td>
  86. </tr>
  87. <tr>
  88. <td>Asset Tag</td>
  89. <td>
  90. {% if device.asset_tag %}
  91. <span>{{ device.asset_tag }}</span>
  92. {% else %}
  93. <span class="text-muted">N/A</span>
  94. {% endif %}
  95. </td>
  96. </tr>
  97. </table>
  98. </div>
  99. {% if vc_members %}
  100. <div class="panel panel-default">
  101. <div class="panel-heading">
  102. <strong>Virtual Chassis</strong>
  103. </div>
  104. <table class="table table-hover panel-body attr-table">
  105. <tr>
  106. <th>Device</th>
  107. <th>Position</th>
  108. <th>Master</th>
  109. <th>Priority</th>
  110. </tr>
  111. {% for vc_member in vc_members %}
  112. <tr{% if vc_member == device %} class="info"{% endif %}>
  113. <td>
  114. <a href="{{ vc_member.get_absolute_url }}">{{ vc_member }}</a>
  115. </td>
  116. <td><span class="badge badge-default">{{ vc_member.vc_position }}</span></td>
  117. <td>{% if device.virtual_chassis.master == vc_member %}<i class="fa fa-check"></i>{% endif %}</td>
  118. <td>{{ vc_member.vc_priority|default:"" }}</td>
  119. </tr>
  120. {% endfor %}
  121. </table>
  122. <div class="panel-footer text-right">
  123. {% if perms.dcim.change_virtualchassis %}
  124. <a href="{% url 'dcim:virtualchassis_add_member' pk=device.virtual_chassis.pk %}?site={{ device.site.pk }}&rack={{ device.rack.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  125. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Member
  126. </a>
  127. <a href="{% url 'dcim:virtualchassis_edit' pk=device.virtual_chassis.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  128. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit Virtual Chassis
  129. </a>
  130. {% endif %}
  131. {% if perms.dcim.delete_virtualchassis %}
  132. <a href="{% url 'dcim:virtualchassis_delete' pk=device.virtual_chassis.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  133. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete Virtual Chassis
  134. </a>
  135. {% endif %}
  136. </div>
  137. </div>
  138. {% endif %}
  139. <div class="panel panel-default">
  140. <div class="panel-heading">
  141. <strong>Management</strong>
  142. </div>
  143. <table class="table table-hover panel-body attr-table">
  144. <tr>
  145. <td>Role</td>
  146. <td>
  147. <a href="{% url 'dcim:device_list' %}?role={{ device.device_role.slug }}">{{ device.device_role }}</a>
  148. </td>
  149. </tr>
  150. <tr>
  151. <td>Platform</td>
  152. <td>
  153. {% if device.platform %}
  154. <span>{{ device.platform }}</span>
  155. {% else %}
  156. <span class="text-muted">None</span>
  157. {% endif %}
  158. </td>
  159. </tr>
  160. <tr>
  161. <td>Status</td>
  162. <td>
  163. <span class="label label-{{ device.get_status_class }}">{{ device.get_status_display }}</span>
  164. </td>
  165. </tr>
  166. <tr>
  167. <td>Primary IPv4</td>
  168. <td>
  169. {% if device.primary_ip4 %}
  170. <a href="{% url 'ipam:ipaddress' pk=device.primary_ip4.pk %}">{{ device.primary_ip4.address.ip }}</a>
  171. {% if device.primary_ip4.nat_inside %}
  172. <span>(NAT for {{ device.primary_ip4.nat_inside.address.ip }})</span>
  173. {% elif device.primary_ip4.nat_outside %}
  174. <span>(NAT: {{ device.primary_ip4.nat_outside.address.ip }})</span>
  175. {% endif %}
  176. {% else %}
  177. <span class="text-muted">N/A</span>
  178. {% endif %}
  179. </td>
  180. </tr>
  181. <tr>
  182. <td>Primary IPv6</td>
  183. <td>
  184. {% if device.primary_ip6 %}
  185. <a href="{% url 'ipam:ipaddress' pk=device.primary_ip6.pk %}">{{ device.primary_ip6.address.ip }}</a>
  186. {% if device.primary_ip6.nat_inside %}
  187. <span>(NAT for {{ device.primary_ip6.nat_inside.address.ip }})</span>
  188. {% elif device.primary_ip6.nat_outside %}
  189. <span>(NAT: {{ device.primary_ip6.nat_outside.address.ip }})</span>
  190. {% endif %}
  191. {% else %}
  192. <span class="text-muted">N/A</span>
  193. {% endif %}
  194. </td>
  195. </tr>
  196. {% if device.cluster %}
  197. <tr>
  198. <td>Cluster</td>
  199. <td>
  200. {% if device.cluster.group %}
  201. <a href="{{ device.cluster.group.get_absolute_url }}">{{ device.cluster.group }}</a>
  202. <i class="fa fa-angle-right"></i>
  203. {% endif %}
  204. <a href="{{ device.cluster.get_absolute_url }}">{{ device.cluster }}</a>
  205. </td>
  206. </tr>
  207. {% endif %}
  208. </table>
  209. </div>
  210. {% with device.get_custom_fields as custom_fields %}
  211. {% include 'inc/custom_fields_panel.html' %}
  212. {% endwith %}
  213. <div class="panel panel-default">
  214. <div class="panel-heading">
  215. <strong>Comments</strong>
  216. </div>
  217. <div class="panel-body">
  218. {% if device.comments %}
  219. {{ device.comments|gfm }}
  220. {% else %}
  221. <span class="text-muted">None</span>
  222. {% endif %}
  223. </div>
  224. </div>
  225. </div>
  226. <div class="col-md-6">
  227. <div class="panel panel-default">
  228. <div class="panel-heading">
  229. <strong>Console / Power</strong>
  230. </div>
  231. <table class="table table-hover panel-body component-list">
  232. {% for cp in console_ports %}
  233. {% include 'dcim/inc/consoleport.html' %}
  234. {% empty %}
  235. {% if device.device_type.console_port_templates.exists %}
  236. <tr>
  237. <td colspan="6" class="alert-warning">
  238. <i class="fa fa-fw fa-warning"></i> No console ports defined
  239. {% if perms.dcim.add_consoleport %}
  240. <a href="{% url 'dcim:consoleport_add' pk=device.pk %}" class="btn btn-primary btn-xs pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a>
  241. {% endif %}
  242. </td>
  243. </tr>
  244. {% endif %}
  245. {% endfor %}
  246. {% for pp in power_ports %}
  247. {% include 'dcim/inc/powerport.html' %}
  248. {% empty %}
  249. {% if device.device_type.power_port_templates.exists %}
  250. <tr>
  251. <td colspan="6" class="alert-warning">
  252. <i class="fa fa-fw fa-warning"></i> No power ports defined
  253. {% if perms.dcim.add_powerport %}
  254. <a href="{% url 'dcim:powerport_add' pk=device.pk %}" class="btn btn-primary btn-xs pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a>
  255. {% endif %}
  256. </td>
  257. </tr>
  258. {% endif %}
  259. {% endfor %}
  260. </table>
  261. {% if perms.dcim.add_interface or perms.dcim.add_consoleport or perms.dcim.add_powerport %}
  262. <div class="panel-footer text-right">
  263. {% if perms.dcim.add_consoleport %}
  264. <a href="{% url 'dcim:consoleport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
  265. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console port
  266. </a>
  267. {% endif %}
  268. {% if perms.dcim.add_powerport %}
  269. <a href="{% url 'dcim:powerport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
  270. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power port
  271. </a>
  272. {% endif %}
  273. </div>
  274. {% endif %}
  275. </div>
  276. {% if request.user.is_authenticated %}
  277. <div class="panel panel-default">
  278. <div class="panel-heading">
  279. <strong>Secrets</strong>
  280. </div>
  281. {% if secrets %}
  282. <table class="table table-hover panel-body">
  283. {% for secret in secrets %}
  284. {% include 'secrets/inc/secret_tr.html' %}
  285. {% endfor %}
  286. </table>
  287. {% else %}
  288. <div class="panel-body text-muted">
  289. None found
  290. </div>
  291. {% endif %}
  292. {% if perms.secrets.add_secret %}
  293. <form id="secret_form">
  294. {% csrf_token %}
  295. </form>
  296. <div class="panel-footer text-right">
  297. <a href="{% url 'dcim:device_addsecret' pk=device.pk %}" class="btn btn-xs btn-primary">
  298. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
  299. Add secret
  300. </a>
  301. </div>
  302. {% endif %}
  303. </div>
  304. {% endif %}
  305. <div class="panel panel-default">
  306. <div class="panel-heading">
  307. <strong>Services</strong>
  308. </div>
  309. {% if services %}
  310. <table class="table table-hover panel-body">
  311. {% for service in services %}
  312. {% include 'ipam/inc/service.html' %}
  313. {% endfor %}
  314. </table>
  315. {% else %}
  316. <div class="panel-body text-muted">
  317. None
  318. </div>
  319. {% endif %}
  320. {% if perms.ipam.add_service %}
  321. <div class="panel-footer text-right">
  322. <a href="{% url 'dcim:device_service_assign' device=device.pk %}" class="btn btn-xs btn-primary">
  323. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Assign service
  324. </a>
  325. </div>
  326. {% endif %}
  327. </div>
  328. <div class="panel panel-default">
  329. <div class="panel-heading">
  330. <strong>Images</strong>
  331. </div>
  332. {% include 'inc/image_attachments.html' with images=device.images.all %}
  333. {% if perms.extras.add_imageattachment %}
  334. <div class="panel-footer text-right">
  335. <a href="{% url 'dcim:device_add_image' object_id=device.pk %}" class="btn btn-primary btn-xs">
  336. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
  337. Attach an image
  338. </a>
  339. </div>
  340. {% endif %}
  341. </div>
  342. <div class="panel panel-default">
  343. <div class="panel-heading">
  344. <strong>Related Devices</strong>
  345. </div>
  346. {% if related_devices %}
  347. <table class="table table-hover panel-body">
  348. {% for rd in related_devices %}
  349. <tr>
  350. <td>
  351. <a href="{% url 'dcim:device' pk=rd.pk %}">{{ rd }}</a>
  352. </td>
  353. <td>
  354. {% if rd.rack %}
  355. <a href="{% url 'dcim:rack' pk=rd.rack.pk %}">Rack {{ rd.rack }}</a>
  356. {% else %}
  357. <span class="text-muted">&mdash;</span>
  358. {% endif %}
  359. </td>
  360. <td>{{ rd.device_type.full_name }}</td>
  361. </tr>
  362. {% endfor %}
  363. </table>
  364. {% else %}
  365. <div class="panel-body text-muted">None found</div>
  366. {% endif %}
  367. </div>
  368. </div>
  369. </div>
  370. <div class="row">
  371. <div class="col-md-12">
  372. {% if device_bays or device.device_type.is_parent_device %}
  373. {% if perms.dcim.delete_devicebay %}
  374. <form method="post" action="{% url 'dcim:devicebay_bulk_delete' pk=device.pk %}">
  375. {% csrf_token %}
  376. {% endif %}
  377. <div class="panel panel-default">
  378. <div class="panel-heading">
  379. <strong>Device Bays</strong>
  380. </div>
  381. <table class="table table-hover table-headings panel-body component-list">
  382. <thead>
  383. <tr>
  384. {% if perms.dcim.change_devicebay or perms.dcim.delete_devicebay %}
  385. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  386. {% endif %}
  387. <th>Name</th>
  388. <th>Status</th>
  389. <th colspan="2">Installed Device</th>
  390. <th></th>
  391. </tr>
  392. </thead>
  393. <tbody>
  394. {% for devicebay in device_bays %}
  395. {% include 'dcim/inc/devicebay.html' %}
  396. {% empty %}
  397. <tr>
  398. <td colspan="5" class="text-center text-muted">&mdash; No device bays defined &mdash;</td>
  399. </tr>
  400. {% endfor %}
  401. </tbody>
  402. </table>
  403. <div class="panel-footer">
  404. {% if device_bays and perms.dcim.change_devicebay %}
  405. <button type="submit" name="_rename" formaction="{% url 'dcim:devicebay_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  406. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  407. </button>
  408. {% endif %}
  409. {% if device_bays and perms.dcim.delete_devicebay %}
  410. <button type="submit" class="btn btn-danger btn-xs">
  411. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete selected
  412. </button>
  413. {% endif %}
  414. {% if perms.dcim.add_devicebay %}
  415. <div class="pull-right">
  416. <a href="{% url 'dcim:devicebay_add' pk=device.pk %}" class="btn btn-primary btn-xs">
  417. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add device bays
  418. </a>
  419. </div>
  420. <div class="clearfix"></div>
  421. {% endif %}
  422. </div>
  423. </div>
  424. {% if perms.dcim.delete_devicebay %}
  425. </form>
  426. {% endif %}
  427. {% endif %}
  428. {% if interfaces or device.device_type.is_network_device %}
  429. {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
  430. <form method="post">
  431. {% csrf_token %}
  432. <input type="hidden" name="device" value="{{ device.pk }}" />
  433. {% endif %}
  434. <div class="panel panel-default">
  435. <div class="panel-heading">
  436. <strong>Interfaces</strong>
  437. <div class="pull-right">
  438. <button class="btn btn-default btn-xs toggle-ips" selected="selected">
  439. <span class="glyphicon glyphicon-check" aria-hidden="true"></span> Show IPs
  440. </button>
  441. </div>
  442. </div>
  443. <table id="interfaces_table" class="table table-hover table-headings panel-body component-list">
  444. <thead>
  445. <tr>
  446. {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
  447. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  448. {% endif %}
  449. <th>Name</th>
  450. <th>LAG</th>
  451. <th>Description</th>
  452. <th>MTU</th>
  453. <th>MAC Address</th>
  454. <th colspan="2">Connection</th>
  455. <th></th>
  456. </tr>
  457. </thead>
  458. <tbody>
  459. {% for iface in interfaces %}
  460. {% include 'dcim/inc/interface.html' %}
  461. {% empty %}
  462. <tr>
  463. <td colspan="9" class="text-center text-muted">&mdash; No interfaces defined &mdash;</td>
  464. </tr>
  465. {% endfor %}
  466. </tbody>
  467. </table>
  468. <div class="panel-footer">
  469. {% if interfaces and perms.dcim.change_interface %}
  470. <button type="submit" name="_rename" formaction="{% url 'dcim:interface_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  471. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  472. </button>
  473. <button type="submit" name="_edit" formaction="{% url 'dcim:interface_bulk_edit' pk=device.pk %}" class="btn btn-warning btn-xs">
  474. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
  475. </button>
  476. {% endif %}
  477. {% if interfaces and perms.dcim.delete_interfaceconnection %}
  478. <button type="submit" name="_disconnect" formaction="{% url 'dcim:interface_bulk_disconnect' pk=device.pk %}" class="btn btn-danger btn-xs">
  479. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  480. </button>
  481. {% endif %}
  482. {% if interfaces and perms.dcim.delete_interface %}
  483. <button type="submit" name="_delete" formaction="{% url 'dcim:interface_bulk_delete' pk=device.pk %}" class="btn btn-danger btn-xs">
  484. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  485. </button>
  486. {% endif %}
  487. {% if perms.dcim.add_interface %}
  488. <div class="pull-right">
  489. <a href="{% url 'dcim:interface_add' pk=device.pk %}" class="btn btn-primary btn-xs">
  490. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add interfaces
  491. </a>
  492. </div>
  493. <div class="clearfix"></div>
  494. {% endif %}
  495. </div>
  496. </div>
  497. {% if perms.dcim.delete_interface %}
  498. </form>
  499. {% endif %}
  500. {% endif %}
  501. {% if cs_ports or device.device_type.is_console_server %}
  502. {% if perms.dcim.delete_consoleserverport %}
  503. <form method="post" action="{% url 'dcim:consoleserverport_bulk_delete' pk=device.pk %}">
  504. {% csrf_token %}
  505. {% endif %}
  506. <div class="panel panel-default">
  507. <div class="panel-heading">
  508. <strong>Console Server Ports</strong>
  509. </div>
  510. <table class="table table-hover table-headings panel-body component-list">
  511. <thead>
  512. <tr>
  513. {% if perms.dcim.change_consoleserverport or perms.dcim.delete_consoleserverport %}
  514. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  515. {% endif %}
  516. <th>Name</th>
  517. <th colspan="2">Connection</th>
  518. <th></th>
  519. </tr>
  520. </thead>
  521. <tbody>
  522. {% for csp in cs_ports %}
  523. {% include 'dcim/inc/consoleserverport.html' %}
  524. {% empty %}
  525. <tr>
  526. <td colspan="5" class="text-center text-muted">&mdash; No console server ports defined &mdash;</td>
  527. </tr>
  528. {% endfor %}
  529. </tbody>
  530. </table>
  531. <div class="panel-footer">
  532. {% if cs_ports and perms.dcim.change_consoleport %}
  533. <button type="submit" name="_rename" formaction="{% url 'dcim:consoleserverport_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  534. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  535. </button>
  536. <button type="submit" name="_disconnect" formaction="{% url 'dcim:consoleserverport_bulk_disconnect' pk=device.pk %}" class="btn btn-danger btn-xs">
  537. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  538. </button>
  539. {% endif %}
  540. {% if cs_ports and perms.dcim.delete_consoleserverport %}
  541. <button type="submit" class="btn btn-danger btn-xs">
  542. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  543. </button>
  544. {% endif %}
  545. {% if perms.dcim.add_consoleserverport %}
  546. <div class="pull-right">
  547. <a href="{% url 'dcim:consoleserverport_add' pk=device.pk %}" class="btn btn-primary btn-xs">
  548. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console server ports
  549. </a>
  550. </div>
  551. <div class="clearfix"></div>
  552. {% endif %}
  553. </div>
  554. </div>
  555. {% if perms.dcim.delete_consoleserverport %}
  556. </form>
  557. {% endif %}
  558. {% endif %}
  559. {% if power_outlets or device.device_type.is_pdu %}
  560. {% if perms.dcim.delete_poweroutlet %}
  561. <form method="post" action="{% url 'dcim:poweroutlet_bulk_delete' pk=device.pk %}">
  562. {% csrf_token %}
  563. {% endif %}
  564. <div class="panel panel-default">
  565. <div class="panel-heading">
  566. <strong>Power Outlets</strong>
  567. </div>
  568. <table class="table table-hover table-headings panel-body component-list">
  569. <thead>
  570. <tr>
  571. {% if perms.dcim.change_poweroutlet or perms.dcim.delete_poweroutlet %}
  572. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  573. {% endif %}
  574. <th>Name</th>
  575. <th colspan="2">Connection</th>
  576. <th></th>
  577. </tr>
  578. </thead>
  579. <tbody>
  580. {% for po in power_outlets %}
  581. {% include 'dcim/inc/poweroutlet.html' %}
  582. {% empty %}
  583. <tr>
  584. <td colspan="5" class="text-center text-muted">&mdash; No power outlets defined &mdash;</td>
  585. </tr>
  586. {% endfor %}
  587. </tbody>
  588. </table>
  589. <div class="panel-footer">
  590. {% if power_outlets and perms.dcim.change_powerport %}
  591. <button type="submit" name="_rename" formaction="{% url 'dcim:poweroutlet_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  592. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  593. </button>
  594. <button type="submit" name="_disconnect" formaction="{% url 'dcim:poweroutlet_bulk_disconnect' pk=device.pk %}" class="btn btn-danger btn-xs">
  595. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  596. </button>
  597. {% endif %}
  598. {% if power_outlets and perms.dcim.delete_poweroutlet %}
  599. <button type="submit" class="btn btn-danger btn-xs">
  600. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  601. </button>
  602. {% endif %}
  603. {% if perms.dcim.add_poweroutlet %}
  604. <div class="pull-right">
  605. <a href="{% url 'dcim:poweroutlet_add' pk=device.pk %}" class="btn btn-primary btn-xs">
  606. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power outlets
  607. </a>
  608. </div>
  609. <div class="clearfix"></div>
  610. {% endif %}
  611. </div>
  612. </div>
  613. {% if perms.dcim.delete_poweroutlet %}
  614. </form>
  615. {% endif %}
  616. {% endif %}
  617. </div>
  618. </div>
  619. {% include 'inc/graphs_modal.html' %}
  620. {% include 'secrets/inc/private_key_modal.html' %}
  621. {% endblock %}
  622. {% block javascript %}
  623. <script type="text/javascript">
  624. function toggleConnection(elem, api_url) {
  625. var url = netbox_api_path + api_url + elem.attr('data') + "/";
  626. if (elem.hasClass('connected')) {
  627. $.ajax({
  628. url: url,
  629. method: 'PATCH',
  630. dataType: 'json',
  631. beforeSend: function(xhr, settings) {
  632. xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
  633. },
  634. data: {
  635. 'connection_status': 'False'
  636. },
  637. context: this,
  638. success: function() {
  639. elem.parents('tr').removeClass('success').addClass('info');
  640. elem.removeClass('connected btn-warning').addClass('btn-success');
  641. elem.attr('title', 'Mark installed');
  642. elem.children('i').removeClass('glyphicon glyphicon-ban-circle').addClass('fa fa-plug')
  643. }
  644. });
  645. } else {
  646. $.ajax({
  647. url: url,
  648. method: 'PATCH',
  649. dataType: 'json',
  650. beforeSend: function(xhr, settings) {
  651. xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
  652. },
  653. data: {
  654. 'connection_status': 'True'
  655. },
  656. context: this,
  657. success: function() {
  658. elem.parents('tr').removeClass('info').addClass('success');
  659. elem.removeClass('btn-success').addClass('connected btn-warning');
  660. elem.attr('title', 'Mark planned');
  661. elem.children('i').removeClass('fa fa-plug').addClass('glyphicon glyphicon-ban-circle')
  662. }
  663. });
  664. }
  665. return false;
  666. }
  667. $(".consoleport-toggle").click(function() {
  668. return toggleConnection($(this), "dcim/console-ports/");
  669. });
  670. $(".powerport-toggle").click(function() {
  671. return toggleConnection($(this), "dcim/power-ports/");
  672. });
  673. $(".interface-toggle").click(function() {
  674. return toggleConnection($(this), "dcim/interface-connections/");
  675. });
  676. // Toggle the display of IP addresses under interfaces
  677. $('button.toggle-ips').click(function() {
  678. var selected = $(this).attr('selected');
  679. if (selected) {
  680. $('#interfaces_table tr.ipaddress').hide();
  681. } else {
  682. $('#interfaces_table tr.ipaddress').show();
  683. }
  684. $(this).attr('selected', !selected);
  685. $(this).children('span').toggleClass('glyphicon-check glyphicon-unchecked');
  686. return false;
  687. });
  688. </script>
  689. <script src="{% static 'js/graphs.js' %}?v{{ settings.VERSION }}"></script>
  690. <script src="{% static 'js/secrets.js' %}?v{{ settings.VERSION }}"></script>
  691. {% endblock %}