site.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. {% extends 'generic/object.html' %}
  2. {% load helpers %}
  3. {% load plugins %}
  4. {% load tz %}
  5. {% block breadcrumbs %}
  6. {{ block.super }}
  7. {% if object.region %}
  8. {% for region in object.region.get_ancestors %}
  9. <li class="breadcrumb-item"><a href="{% url 'dcim:site_list' %}?region_id={{ region.pk }}">{{ region }}</a></li>
  10. {% endfor %}
  11. <li class="breadcrumb-item"><a href="{% url 'dcim:site_list' %}?region_id={{ object.region.pk }}">{{ object.region }}</a></li>
  12. {% elif object.group %}
  13. {% for group in object.group.get_ancestors %}
  14. <li class="breadcrumb-item"><a href="{% url 'dcim:site_list' %}?group_id={{ group.pk }}">{{ group }}</a></li>
  15. {% endfor %}
  16. <li class="breadcrumb-item"><a href="{% url 'dcim:site_list' %}?group_id={{ object.group.pk }}">{{ object.group }}</a></li>
  17. {% endif %}
  18. {% endblock %}
  19. {% block content %}
  20. <div class="row">
  21. <div class="col col-md-6">
  22. <div class="card">
  23. <h5 class="card-header">Site</h5>
  24. <div class="card-body">
  25. <table class="table table-hover attr-table">
  26. <tr>
  27. <th scope="row">Region</th>
  28. <td>
  29. {% if object.region %}
  30. {% for region in object.region.get_ancestors %}
  31. <a href="{{ region.get_absolute_url }}">{{ region }}</a> /
  32. {% endfor %}
  33. <a href="{{ object.region.get_absolute_url }}">{{ object.region }}</a>
  34. {% else %}
  35. <span class="text-muted">None</span>
  36. {% endif %}
  37. </td>
  38. </tr>
  39. <tr>
  40. <th scope="row">Group</th>
  41. <td>
  42. {% if object.group %}
  43. {% for group in object.group.get_ancestors %}
  44. <a href="{{ group.get_absolute_url }}">{{ group }}</a> /
  45. {% endfor %}
  46. <a href="{{ object.group.get_absolute_url }}">{{ object.group }}</a>
  47. {% else %}
  48. <span class="text-muted">None</span>
  49. {% endif %}
  50. </td>
  51. </tr>
  52. <tr>
  53. <th scope="row">Status</th>
  54. <td>
  55. <span class="badge bg-{{ object.get_status_class }}">{{ object.get_status_display }}</span>
  56. </td>
  57. </tr>
  58. <tr>
  59. <th scope="row">Tenant</th>
  60. <td>
  61. {% if object.tenant %}
  62. {% if object.tenant.group %}
  63. <a href="{{ object.tenant.group.get_absolute_url }}">{{ object.tenant.group }}</a> /
  64. {% endif %}
  65. <a href="{{ object.tenant.get_absolute_url }}">{{ object.tenant }}</a>
  66. {% else %}
  67. <span class="text-muted">None</span>
  68. {% endif %}
  69. </td>
  70. </tr>
  71. <tr>
  72. <th scope="row">Facility</th>
  73. <td>{{ object.facility|placeholder }}</td>
  74. </tr>
  75. <tr>
  76. <th scope="row">Description</th>
  77. <td>{{ object.description|placeholder }}</td>
  78. </tr>
  79. <tr>
  80. <th scope="row">AS Number</th>
  81. <td>{{ object.asn|placeholder }}</td>
  82. </tr>
  83. <tr>
  84. <th scope="row">Time Zone</th>
  85. <td>
  86. {% if object.time_zone %}
  87. {{ object.time_zone }} (UTC {{ object.time_zone|tzoffset }})<br />
  88. <small class="text-muted">Site time: {% timezone object.time_zone %}{% annotated_now %}{% endtimezone %}</small>
  89. {% else %}
  90. <span class="text-muted">&mdash;</span>
  91. {% endif %}
  92. </td>
  93. </tr>
  94. <tr>
  95. <th scope="row">Physical Address</th>
  96. <td>
  97. {% if object.physical_address %}
  98. <div class="float-end noprint">
  99. <a href="{{ config.MAPS_URL }}{{ object.physical_address|urlencode }}" target="_blank" class="btn btn-primary btn-sm">
  100. <i class="mdi mdi-map-marker"></i> Map It
  101. </a>
  102. </div>
  103. <span>{{ object.physical_address|linebreaksbr }}</span>
  104. {% else %}
  105. <span class="text-muted">&mdash;</span>
  106. {% endif %}
  107. </td>
  108. </tr>
  109. <tr>
  110. <th scope="row">Shipping Address</th>
  111. <td>{{ object.shipping_address|linebreaksbr|placeholder }}</td>
  112. </tr>
  113. <tr>
  114. <th scope="row">GPS Coordinates</th>
  115. <td>
  116. {% if object.latitude and object.longitude %}
  117. <div class="float-end noprint">
  118. <a href="{{ config.MAPS_URL }}{{ object.latitude }},{{ object.longitude }}" target="_blank" class="btn btn-primary btn-sm">
  119. <i class="mdi mdi-map-marker"></i> Map It
  120. </a>
  121. </div>
  122. <span>{{ object.latitude }}, {{ object.longitude }}</span>
  123. {% else %}
  124. <span class="text-muted">&mdash;</span>
  125. {% endif %}
  126. </td>
  127. </tr>
  128. {# Legacy contact fields #}
  129. {% with deprecation_warning="This field will be removed in a future release. Please migrate this data to contact objects." %}
  130. {% if object.contact_name %}
  131. <tr>
  132. <th scope="row">Contact Name</th>
  133. <td>
  134. {% if object.contact_name %}
  135. <div class="float-end text-warning">
  136. <i class="mdi mdi-alert" title="{{ deprecation_warning }}"></i>
  137. </div>
  138. {% endif %}
  139. {{ object.contact_name|placeholder }}
  140. </td>
  141. </tr>
  142. {% endif %}
  143. {% if object.contact_phone %}
  144. <tr>
  145. <th scope="row">Contact Phone</th>
  146. <td>
  147. {% if object.contact_phone %}
  148. <div class="float-end text-warning">
  149. <i class="mdi mdi-alert" title="{{ deprecation_warning }}"></i>
  150. </div>
  151. <a href="tel:{{ object.contact_phone }}">{{ object.contact_phone }}</a>
  152. {% else %}
  153. <span class="text-muted">&mdash;</span>
  154. {% endif %}
  155. </td>
  156. </tr>
  157. {% endif %}
  158. {% if object.contact_email %}
  159. <tr>
  160. <th scope="row">Contact E-Mail</th>
  161. <td>
  162. {% if object.contact_email %}
  163. <div class="float-end text-warning">
  164. <i class="mdi mdi-alert" title="{{ deprecation_warning }}"></i>
  165. </div>
  166. <a href="mailto:{{ object.contact_email }}">{{ object.contact_email }}</a>
  167. {% else %}
  168. <span class="text-muted">&mdash;</span>
  169. {% endif %}
  170. </td>
  171. </tr>
  172. {% endif %}
  173. {% endwith %}
  174. </table>
  175. </div>
  176. </div>
  177. {% include 'inc/panels/custom_fields.html' %}
  178. {% include 'inc/panels/tags.html' %}
  179. {% include 'inc/panels/comments.html' %}
  180. {% plugin_left_page object %}
  181. </div>
  182. <div class="col col-md-6">
  183. <div class="card">
  184. <h5 class="card-header">Related Objects</h5>
  185. <div class="card-body">
  186. <table class="table table-hover attr-table">
  187. <tr>
  188. <th scope="row">Locations</th>
  189. <td class="text-end">
  190. {% if stats.location_count %}
  191. <a href="{% url 'dcim:location_list' %}?site_id={{ object.pk }}">{{ stats.location_count }}</a>
  192. {% else %}
  193. {{ ''|placeholder }}
  194. {% endif %}
  195. </td>
  196. </tr>
  197. <tr>
  198. <th scope="row">Racks</th>
  199. <td class="text-end">
  200. {% if stats.rack_count %}
  201. <div class="dropdown">
  202. <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
  203. {{ stats.rack_count }}
  204. </button>
  205. <ul class="dropdown-menu">
  206. <li><a class="dropdown-item" href="{% url 'dcim:rack_list' %}?site_id={{ object.pk }}">View Racks</a></li>
  207. <li><a class="dropdown-item" href="{% url 'dcim:rack_elevation_list' %}?site_id={{ object.pk }}">View Elevations</a></li>
  208. </ul>
  209. </div>
  210. {% else %}
  211. {{ ''|placeholder }}
  212. {% endif %}
  213. </td>
  214. </tr>
  215. <tr>
  216. <th scope="row">Devices</th>
  217. <td class="text-end">
  218. {% if stats.device_count %}
  219. <a href="{% url 'dcim:device_list' %}?site_id={{ object.pk }}">{{ stats.device_count }}</a>
  220. {% else %}
  221. {{ ''|placeholder }}
  222. {% endif %}
  223. </td>
  224. </tr>
  225. <tr>
  226. <th scope="row">Virtual Machines</th>
  227. <td class="text-end">
  228. {% if stats.vm_count %}
  229. <a href="{% url 'virtualization:virtualmachine_list' %}?site_id={{ object.pk }}">{{ stats.vm_count }}</a>
  230. {% else %}
  231. {{ ''|placeholder }}
  232. {% endif %}
  233. </td>
  234. </tr>
  235. <tr>
  236. <th scope="row">Prefixes</th>
  237. <td class="text-end">
  238. {% if stats.prefix_count %}
  239. <a href="{% url 'ipam:prefix_list' %}?site_id={{ object.pk }}">{{ stats.prefix_count }}</a>
  240. {% else %}
  241. {{ ''|placeholder }}
  242. {% endif %}
  243. </td>
  244. </tr>
  245. <tr>
  246. <th scope="row">VLANs</th>
  247. <td class="text-end">
  248. {% if stats.vlan_count %}
  249. <a href="{% url 'ipam:vlan_list' %}?site_id={{ object.pk }}">{{ stats.vlan_count }}</a>
  250. {% else %}
  251. {{ ''|placeholder }}
  252. {% endif %}
  253. </td>
  254. </tr>
  255. <tr>
  256. <th scope="row">ASNs</th>
  257. <td class="text-end">
  258. {% if stats.asn_count %}
  259. <a href="{% url 'ipam:asn_list' %}?site_id={{ object.pk }}">{{ stats.asn_count }}</a>
  260. {% else %}
  261. {{ ''|placeholder }}
  262. {% endif %}
  263. </td>
  264. </tr>
  265. <tr>
  266. <th scope="row">Circuits</th>
  267. <td class="text-end">
  268. {% if stats.circuit_count %}
  269. <a href="{% url 'circuits:circuit_list' %}?site_id={{ object.pk }}">{{ stats.circuit_count }}</a>
  270. {% else %}
  271. {{ ''|placeholder }}
  272. {% endif %}
  273. </td>
  274. </tr>
  275. </table>
  276. </div>
  277. </div>
  278. {% include 'dcim/inc/nonracked_devices.html' %}
  279. {% include 'inc/panels/contacts.html' %}
  280. <div class="card">
  281. <h5 class="card-header">Locations</h5>
  282. <div class='card-body'>
  283. {% if locations %}
  284. <table class="table table-hover">
  285. <tr>
  286. <th>Location</th>
  287. <th>Racks</th>
  288. <th>Devices</th>
  289. <th></th>
  290. </tr>
  291. {% for location in locations %}
  292. <tr>
  293. <td>
  294. {% for i in location.level|as_range %}<i class="mdi mdi-circle-small"></i>{% endfor %}
  295. <a href="{{ location.get_absolute_url }}">{{ location }}</a>
  296. </td>
  297. <td>
  298. <a href="{% url 'dcim:rack_list' %}?location_id={{ location.pk }}">{{ location.rack_count }}</a>
  299. </td>
  300. <td>
  301. <a href="{% url 'dcim:device_list' %}?location_id={{ location.pk }}">{{ location.device_count }}</a>
  302. </td>
  303. <td class="text-end noprint">
  304. <a href="{% url 'dcim:rack_elevation_list' %}?location_id={{ location.pk }}" class="btn btn-sm btn-primary" title="View Elevations">
  305. <i class="mdi mdi-server"></i>
  306. </a>
  307. </td>
  308. </tr>
  309. {% endfor %}
  310. </table>
  311. {% else %}
  312. <span class="text-muted">None</span>
  313. {% endif %}
  314. </div>
  315. {% if perms.dcim.add_location %}
  316. <div class="card-footer text-end noprint">
  317. <a href="{% url 'dcim:location_add' %}?site={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
  318. <i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a location
  319. </a>
  320. </div>
  321. {% endif %}
  322. </div>
  323. <div class="card">
  324. <h5 class="card-header">ASNs</h5>
  325. <div class='card-body'>
  326. {% if asns %}
  327. <table class="table table-hover">
  328. <tr>
  329. <th>ASN</th>
  330. <th>Description</th>
  331. </tr>
  332. {% for asn in asns %}
  333. <tr>
  334. <td><a href="{{ asn.get_absolute_url }}">{{ asn }}</a></td>
  335. <td>{{ asn.description|placeholder }}</td>
  336. </tr>
  337. {% endfor %}
  338. </table>
  339. {% else %}
  340. <span class="text-muted">None</span>
  341. {% endif %}
  342. </div>
  343. {% if perms.ipam.add_asn %}
  344. <div class="card-footer text-end noprint">
  345. <a href="{% url 'ipam:asn_add' %}?sites={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
  346. <i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add an ASN
  347. </a>
  348. </div>
  349. {% endif %}
  350. </div>
  351. {% include 'inc/panels/image_attachments.html' %}
  352. {% plugin_right_page object %}
  353. </div>
  354. </div>
  355. <div class="row">
  356. <div class="col col-md-12">
  357. {% plugin_full_width_page object %}
  358. </div>
  359. </div>
  360. {% endblock %}