Procházet zdrojové kódy

migrate templates to bootstrap 5

checktheroads před 4 roky
rodič
revize
125965b559

+ 12 - 10
netbox/templates/40x.html

@@ -1,17 +1,19 @@
-{% extends 'base.html' %}
+{% extends 'layout.html' %}
+
+{% block title %}{% endblock %}
 
 {% block content %}
-<div class="row" style="margin-top: 150px;">
-    <div class="col-sm-4 col-sm-offset-4">
-        <div class="panel panel-default">
-            <div class="panel-heading">
-                <strong>{% block icon %}{% endblock %} {% block title %}{% endblock %}</strong>
-            </div>
-            <div class="panel-body">
+<div class="row my-5">
+    <div class="col-6 offset-3">
+        <div class="card">
+            <h5 class="card-header text-danger">
+                {{ request_path }}
+            </h5>
+            <div class="card-body">
                 {% block message %}{% endblock %}
             </div>
-            <div class="panel-footer text-right">
-                <a href="{% url 'home' %}" class="btn btn-xs btn-primary">Home Page</a>
+            <div class="card-footer text-end">
+                <a href="{% url 'home' %}" class="btn btn-sm btn-primary">Home Page</a>
             </div>
         </div>
     </div>

+ 12 - 9
netbox/templates/dcim/connections_list.html

@@ -1,19 +1,22 @@
-{% extends 'base.html' %}
+{% extends 'layout.html' %}
 {% load buttons %}
 
 {% block title %}{{ title }}{% endblock %}
 
+{% block extra_controls %}{% export_button content_type %}{% endblock %}
+
 {% block content %}
-<div class="float-end noprint">
-    {% export_button content_type %}
-</div>
-<div class="row">
-	  <div class="col-md-12">
-        <div class="col-md-3 pull-right right-side-panel noprint">
-            {% include 'inc/search_panel.html' %}
+<div class="row mb-3">
+    <div class="col-md-9">
+        <div class="card">
+            <div class="card-body">
+                {% include 'responsive_table.html' %}
+            </div>
         </div>
-        {% include 'responsive_table.html' %}
         {% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
     </div>
+    <div class="col-md-3 float-end right-side-panel noprint">
+        {% include 'inc/search_panel.html' %}
+    </div>
 </div>
 {% endblock %}

+ 4 - 8
netbox/templates/dcim/device.html

@@ -285,7 +285,7 @@
                                 {% if perms.secrets.add_secret %}
                                 <div class="card-footer text-end noprint">
                                     <a href="{% url 'secrets:secret_add' %}?device={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-sm btn-primary">
-                                        <i class="bi bi-plus"></i> Add secret
+                                        <i class="mdi mdi-plus-thick"></i> Add Secret
                                     </a>
                                 </div>
                                 {% endif %}
@@ -311,7 +311,7 @@
                                 {% if perms.ipam.add_service %}
                                 <div class="card-footer text-end noprint">
                                     <a href="{% url 'dcim:device_service_assign' device=object.pk %}" class="btn btn-sm btn-primary">
-                                        <span class="bi bi-plus" aria-hidden="true"></span> Assign service
+                                        <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Assign Service
                                     </a>
                                 </div>
                                 {% endif %}
@@ -326,8 +326,8 @@
                                 {% if perms.extras.add_imageattachment %}
                                 <div class="card-footer text-end noprint">
                                     <a href="{% url 'dcim:device_add_image' object_id=object.pk %}" class="btn btn-primary btn-sm">
-                                        <span class="bi bi-plus" aria-hidden="true"></span>
-                                        Attach an image
+                                        <span class="mdi mdi-plus-thick" aria-hidden="true"></span>
+                                        Attach an Image
                                     </a>
                                 </div>
                                 {% endif %}
@@ -379,7 +379,3 @@
     </div>
     {% include 'secrets/inc/private_key_modal.html' %}
 {% endblock %}
-
-{% block javascript %}
-  <script src="{% static 'js/secrets.js' %}?v{{ settings.VERSION }}"></script>
-{% endblock %}

+ 33 - 29
netbox/templates/dcim/manufacturer.html

@@ -3,33 +3,35 @@
 {% load plugins %}
 
 {% block breadcrumbs %}
-  <li><a href="{% url 'dcim:manufacturer_list' %}">Manufacturers</a></li>
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item"><a href="{% url 'dcim:manufacturer_list' %}">Manufacturers</a></li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
 {% block content %}
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-6">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>Manufacturer</strong>
+    <div class="card">
+      <h5 class="card-header">
+        Manufacturer
+      </h5>
+      <div class="card-body">
+        <table class="table table-hover attr-table">
+          <tr>
+            <th scope="row">Name</th>
+            <td>{{ object.name }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Description</th>
+            <td>{{ object.description|placeholder }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Device types</th>
+            <td>
+              <a href="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}">{{ devicetypes_table.rows|length }}</a>
+            </td>
+          </tr>
+        </table>
       </div>
-      <table class="table table-hover panel-body attr-table">
-        <tr>
-          <td>Name</td>
-          <td>{{ object.name }}</td>
-        </tr>
-        <tr>
-          <td>Description</td>
-          <td>{{ object.description|placeholder }}</td>
-        </tr>
-        <tr>
-          <td>Device types</td>
-          <td>
-            <a href="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}">{{ devicetypes_table.rows|length }}</a>
-          </td>
-        </tr>
-      </table>
     </div>
     {% plugin_left_page object %}
 	</div>
@@ -38,16 +40,18 @@
     {% plugin_right_page object %}
   </div>
 </div>
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-12">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>Device Types</strong>
+    <div class="card">
+      <h5 class="card-header">
+        Device Types
+      </h5>
+      <div class="card-body">
+        {% include 'inc/table.html' with table=devicetypes_table %}
       </div>
-      {% include 'inc/table.html' with table=devicetypes_table %}
       {% if perms.dcim.add_devicetype %}
-        <div class="panel-footer text-right noprint">
-          <a href="{% url 'dcim:devicetype_add' %}?manufacturer={{ object.pk }}" class="btn btn-xs btn-primary">
+        <div class="card-footer text-end noprint">
+          <a href="{% url 'dcim:devicetype_add' %}?manufacturer={{ object.pk }}" class="btn btn-sm btn-primary">
             <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add device type
           </a>
         </div>

+ 62 - 59
netbox/templates/dcim/poweroutlet.html

@@ -3,123 +3,126 @@
 {% load plugins %}
 
 {% block breadcrumbs %}
-  {{ block.super }}
-  <li><a href="{% url 'dcim:device_poweroutlets' pk=object.device.pk %}">Power Outlets</a></li>
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item"><a href="{% url 'dcim:device_poweroutlets' pk=object.device.pk %}">Power Outlets</a></li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
 {% block content %}
-    <div class="row">
+    <div class="row mb-3">
         <div class="col-md-6">
-            <div class="panel panel-default">
-                <div class="panel-heading">
-                    <strong>Power Outlet</strong>
+            <div class="card">
+                <h5 class="card-header">
+                    Power Outlet
+                </h5>
+                <div class="card-body">
+                    <table class="table table-hover attr-table">
+                        <tr>
+                            <th scope="row">Device</th>
+                            <td>
+                                <a href="{{ object.device.get_absolute_url }}">{{ object.device }}</a>
+                            </td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Name</th>
+                            <td>{{ object.name }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Label</th>
+                            <td>{{ object.label|placeholder }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Type</th>
+                            <td>{{ object.get_type_display }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Description</th>
+                            <td>{{ object.description|placeholder }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Power Port</th>
+                            <td>{{ object.power_port }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Feed Leg</th>
+                            <td>{{ object.get_feed_leg_display }}</td>
+                        </tr>
+                    </table>
                 </div>
-                <table class="table table-hover panel-body attr-table">
-                    <tr>
-                        <td>Device</td>
-                        <td>
-                            <a href="{{ object.device.get_absolute_url }}">{{ object.device }}</a>
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>Name</td>
-                        <td>{{ object.name }}</td>
-                    </tr>
-                    <tr>
-                        <td>Label</td>
-                        <td>{{ object.label|placeholder }}</td>
-                    </tr>
-                    <tr>
-                        <td>Type</td>
-                        <td>{{ object.get_type_display }}</td>
-                    </tr>
-                    <tr>
-                        <td>Description</td>
-                        <td>{{ object.description|placeholder }}</td>
-                    </tr>
-                    <tr>
-                        <td>Power Port</td>
-                        <td>{{ object.power_port }}</td>
-                    </tr>
-                    <tr>
-                        <td>Feed Leg</td>
-                        <td>{{ object.get_feed_leg_display }}</td>
-                    </tr>
-                </table>
             </div>
             {% include 'inc/custom_fields_panel.html' %}
             {% include 'extras/inc/tags_panel.html' with tags=object.tags.all %}
             {% plugin_left_page object %}
         </div>
         <div class="col-md-6">
-            <div class="panel panel-default">
-                <div class="panel-heading">
-                    <strong>Connection</strong>
-                </div>
+            <div class="card">
+                <h5 class="card-header">
+                    Connection
+                </h5>
+                <div class="card-body">
                 {% if object.mark_connected %}
-                    <div class="panel-body text-muted">
-                      <span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
+                    <div class="text-muted">
+                      <span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
                     </div>
                 {% elif object.cable %}
-                    <table class="table table-hover panel-body attr-table">
+                    <table class="table table-hover attr-table">
                         <tr>
-                            <td>Cable</td>
+                            <th scope="row">Cable</th>
                             <td>
                                 <a href="{{ object.cable.get_absolute_url }}">{{ object.cable }}</a>
-                                <a href="{% url 'dcim:poweroutlet_trace' pk=object.pk %}" class="btn btn-primary btn-xs" title="Trace">
+                                <a href="{% url 'dcim:poweroutlet_trace' pk=object.pk %}" class="btn btn-primary btn-sm lh-1" title="Trace">
                                     <i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i>
                                 </a>
                             </td>
                         </tr>
                         {% if object.connected_endpoint %}
                             <tr>
-                                <td>Device</td>
+                                <th scope="row">Device</th>
                                 <td>
                                     <a href="{{ object.connected_endpoint.device.get_absolute_url }}">{{ object.connected_endpoint.device }}</a>
                                 </td>
                             </tr>
                             <tr>
-                                <td>Name</td>
+                                <th scope="row">Name</th>
                                 <td>
                                     <a href="{{ object.connected_endpoint.get_absolute_url }}">{{ object.connected_endpoint.name }}</a>
                                 </td>
                             </tr>
                             <tr>
-                                <td>Type</td>
+                                <th scope="row">Type</th>
                                 <td>{{ object.connected_endpoint.get_type_display|placeholder }}</td>
                             </tr>
                             <tr>
-                                <td>Description</td>
+                                <th scope="row">Description</th>
                                 <td>{{ object.connected_endpoint.description|placeholder }}</td>
                             </tr>
                             <tr>
-                                <td>Path Status</td>
+                                <th scope="row">Path Status</th>
                                 <td>
                                     {% if object.path.is_active %}
-                                        <span class="label label-success">Reachable</span>
+                                        <span class="badge bg-success">Reachable</span>
                                     {% else %}
-                                        <span class="label label-danger">Not Reachable</span>
+                                        <span class="badge bg-danger">Not Reachable</span>
                                     {% endif %}
                                 </td>
                             </tr>
                         {% endif %}
                     </table>
                 {% else %}
-                    <div class="panel-body text-muted">
-                        Not connected
+                    <div class="text-muted">
+                        Not Connected
                         {% if perms.dcim.add_cable %}
-                            <a href="{% url 'dcim:poweroutlet_connect' termination_a_id=object.pk termination_b_type='power-port' %}?return_url={{ object.get_absolute_url }}" title="Connect" class="btn btn-primary btn-sm pull-right">
+                            <a href="{% url 'dcim:poweroutlet_connect' termination_a_id=object.pk termination_b_type='power-port' %}?return_url={{ object.get_absolute_url }}" title="Connect" class="btn btn-primary btn-sm float-end">
                                 <i class="mdi mdi-ethernet-cable" aria-hidden="true"></i> Connect
                             </a>
                         {% endif %}
                     </div>
                 {% endif %}
+                </div>
             </div>
             {% plugin_right_page object %}
         </div>
     </div>
-    <div class="row">
+    <div class="row mb-3">
         <div class="col-md-12">
             {% plugin_full_width_page object %}
         </div>

+ 69 - 62
netbox/templates/dcim/powerport.html

@@ -3,124 +3,131 @@
 {% load plugins %}
 
 {% block breadcrumbs %}
-  {{ block.super }}
-  <li><a href="{% url 'dcim:device_powerports' pk=object.device.pk %}">Power Ports</a></li>
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item"><a href="{% url 'dcim:device_powerports' pk=object.device.pk %}">Power Ports</a></li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
 {% block content %}
-    <div class="row">
+    <div class="row mb-3">
         <div class="col-md-6">
-            <div class="panel panel-default">
-                <div class="panel-heading">
-                    <strong>Power Port</strong>
+            <div class="card">
+                <h5 class="card-header">
+                    Power Port
+                </h5>
+                <div class="card-body">
+                    <table class="table table-hover attr-table">
+                        <tr>
+                            <th scope="row">Device</th>
+                            <td>
+                                <a href="{{ object.device.get_absolute_url }}">{{ object.device }}</a>
+                            </td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Name</th>
+                            <td>{{ object.name }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Label</th>
+                            <td>{{ object.label|placeholder }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Type</th>
+                            <td>{{ object.get_type_display }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Description</th>
+                            <td>{{ object.description|placeholder }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Maximum Draw</th>
+                            <td>{{ object.maximum_draw|placeholder }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Allocated Draw</th>
+                            <td>{{ object.allocated_draw|placeholder }}</td>
+                        </tr>
+                    </table>
                 </div>
-                <table class="table table-hover panel-body attr-table">
-                    <tr>
-                        <td>Device</td>
-                        <td>
-                            <a href="{{ object.device.get_absolute_url }}">{{ object.device }}</a>
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>Name</td>
-                        <td>{{ object.name }}</td>
-                    </tr>
-                    <tr>
-                        <td>Label</td>
-                        <td>{{ object.label|placeholder }}</td>
-                    </tr>
-                    <tr>
-                        <td>Type</td>
-                        <td>{{ object.get_type_display }}</td>
-                    </tr>
-                    <tr>
-                        <td>Description</td>
-                        <td>{{ object.description|placeholder }}</td>
-                    </tr>
-                    <tr>
-                        <td>Maximum Draw</td>
-                        <td>{{ object.maximum_draw|placeholder }}</td>
-                    </tr>
-                    <tr>
-                        <td>Allocated Draw</td>
-                        <td>{{ object.allocated_draw|placeholder }}</td>
-                    </tr>
-                </table>
             </div>
             {% include 'inc/custom_fields_panel.html' %}
             {% include 'extras/inc/tags_panel.html' with tags=object.tags.all %}
             {% plugin_left_page object %}
         </div>
         <div class="col-md-6">
-            <div class="panel panel-default">
-                <div class="panel-heading">
-                    <strong>Connection</strong>
-                </div>
+            <div class="card">
+                <h5 class="card-header">
+                    Connection
+                </h5>
+                <div class="card-body">
                 {% if object.mark_connected %}
-                    <div class="panel-body text-muted">
-                      <span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
+                    <div class="text-muted">
+                      <span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
                     </div>
                 {% elif object.cable %}
-                    <table class="table table-hover panel-body attr-table">
+                    <table class="table table-hover attr-table">
                         <tr>
-                            <td>Cable</td>
+                            <th scope="row">Cable</th>
                             <td>
                                 <a href="{{ object.cable.get_absolute_url }}">{{ object.cable }}</a>
-                                <a href="{% url 'dcim:powerport_trace' pk=object.pk %}" class="btn btn-primary btn-xs" title="Trace">
+                                <a href="{% url 'dcim:powerport_trace' pk=object.pk %}" class="btn btn-primary btn-sm lh-1" title="Trace">
                                     <i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i>
                                 </a>
                             </td>
                         </tr>
                         {% if object.connected_endpoint %}
                             <tr>
-                                <td>Device</td>
+                                <th scope="row">Device</th>
                                 <td>
                                     <a href="{{ object.connected_endpoint.device.get_absolute_url }}">{{ object.connected_endpoint.device }}</a>
                                 </td>
                             </tr>
                             <tr>
-                                <td>Name</td>
+                                <th scope="row">Name</th>
                                 <td>
                                     <a href="{{ object.connected_endpoint.get_absolute_url }}">{{ object.connected_endpoint.name }}</a>
                                 </td>
                             </tr>
                             <tr>
-                                <td>Type</td>
+                                <th scope="row">Type</th>
                                 <td>{{ object.connected_endpoint.get_type_display|placeholder }}</td>
                             </tr>
                             <tr>
-                                <td>Description</td>
+                                <th scope="row">Description</th>
                                 <td>{{ object.connected_endpoint.description|placeholder }}</td>
                             </tr>
                             <tr>
-                                <td>Path Status</td>
+                                <th scope="row">Path Status</th>
                                 <td>
                                     {% if object.path.is_active %}
-                                        <span class="label label-success">Reachable</span>
+                                        <span class="badge bg-success">Reachable</span>
                                     {% else %}
-                                        <span class="label label-danger">Not Reachable</span>
+                                        <span class="badge bg-danger">Not Reachable</span>
                                     {% endif %}
                                 </td>
                             </tr>
                         {% endif %}
                     </table>
                 {% else %}
-                    <div class="panel-body text-muted">
-                        Not connected
+                    <div class="text-muted">
+                        Not Connected
                         {% if perms.dcim.add_cable %}
-                            <span class="dropdown pull-right">
-                                <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                            <span class="dropdown float-end">
+                                <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                     <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> Connect
                                 </button>
-                                <ul class="dropdown-menu dropdown-menu-right">
-                                    <li><a href="{% url 'dcim:powerport_connect' termination_a_id=object.pk termination_b_type='power-outlet' %}?return_url={{ object.get_absolute_url }}">Power Outlet</a></li>
-                                    <li><a href="{% url 'dcim:powerport_connect' termination_a_id=object.pk termination_b_type='power-feed' %}?return_url={{ object.get_absolute_url }}">Power Feed</a></li>
+                                <ul class="dropdown-menu dropdown-menu-end">
+                                    <li>
+                                        <a class="dropdown-link" href="{% url 'dcim:powerport_connect' termination_a_id=object.pk termination_b_type='power-outlet' %}?return_url={{ object.get_absolute_url }}">Power Outlet</a>
+                                    </li>
+                                    <li>
+                                        <a class="dropdown-link" href="{% url 'dcim:powerport_connect' termination_a_id=object.pk termination_b_type='power-feed' %}?return_url={{ object.get_absolute_url }}">Power Feed</a>
+                                    </li>
                                 </ul>
                             </span>
                         {% endif %}
                     </div>
                 {% endif %}
+                </div>
             </div>
             {% plugin_right_page object %}
         </div>

+ 12 - 19
netbox/templates/dcim/virtualchassis_add_member.html

@@ -1,34 +1,27 @@
-{% extends 'base.html' %}
+{% extends 'layout.html' %}
 {% load form_helpers %}
 
+{% block title %}Add New Member to Virtual Chassis {{ virtual_chassis }}{% endblock %}
+
 {% block content %}
     <form action="" method="post" enctype="multipart/form-data" class="form form-horizontal">
         {% csrf_token %}
-        <div class="row">
-            <div class="col-md-6 col-md-offset-3">
-                <h3>{% block title %}Add New Member to Virtual Chassis {{ virtual_chassis }}{% endblock %}</h3>
-                {% if membership_form.non_field_errors %}
-                    <div class="panel panel-danger">
-                        <div class="panel-heading"><strong>Errors</strong></div>
-                        <div class="panel-body">
-                            {{ membership_form.non_field_errors }}
-                        </div>
-                    </div>
-                {% endif %}
-                <div class="panel panel-default">
-                    <div class="panel-heading"><strong>Add New Member</strong></div>
-                    <div class="table panel-body">
+        <div class="row mb-3">
+            <div class="col-md-6">
+                <div class="card">
+                    <h5 class="card-header">Add New Member</h5>
+                    <div class="card-body">
                         {% render_form member_select_form %}
                         {% render_form membership_form %}
                     </div>
                 </div>
             </div>
         </div>
-        <div class="row">
-            <div class="col-md-6 col-md-offset-3 text-right">
+        <div class="row mb-3">
+            <div class="col-md-6 text-end">
+                <a href="{{ return_url }}" class="btn btn-outline-danger">Cancel</a>
+                <button type="submit" name="_addanother" class="btn btn-outline-primary">Add Another</button>
                 <button type="submit" name="_save" class="btn btn-primary">Save</button>
-                <button type="submit" name="_addanother" class="btn btn-primary">Add Another</button>
-                <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
             </div>
         </div>
     </form>

+ 40 - 38
netbox/templates/extras/journalentry.html

@@ -3,52 +3,54 @@
 {% load static %}
 
 {% block breadcrumbs %}
-  <li><a href="{% url 'extras:journalentry_list' %}">Journal Entries</a></li>
-  <li><a href="{% url object.assigned_object|viewname:'journal' pk=object.assigned_object.pk %}">{{ object.assigned_object }}</a></li>
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item"><a href="{% url 'extras:journalentry_list' %}">Journal Entries</a></li>
+  <li class="breadcrumb-item"><a href="{% url object.assigned_object|viewname:'journal' pk=object.assigned_object.pk %}">{{ object.assigned_object }}</a></li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
 {% block content %}
-    <div class="row">
+    <div class="row mb-3">
         <div class="col-md-4">
-            <div class="panel panel-default">
-                <div class="panel-heading">
-                    <strong>Journal Entry</strong>
+            <div class="card">
+                <h5 class="card-header">
+                    Journal Entry
+                </h5>
+                <div class="card-body">
+                    <table class="table table-hover attr-table">
+                        <tr>
+                            <th scope="row">Object</th>
+                            <td>
+                                <a href="{{ object.assigned_object.get_absolute_url }}">{{ object.assigned_object }}</a>
+                            </td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Created</th>
+                            <td>
+                                {{ object.created }}
+                            </td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Created By</th>
+                            <td>
+                                {{ object.created_by }}
+                            </td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Kind</th>
+                            <td>
+                                <span class="badge bg-{{ object.get_kind_class }}">{{ object.get_kind_display }}</span>
+                            </td>
+                        </tr>
+                    </table>
                 </div>
-                <table class="table table-hover panel-body attr-table">
-                    <tr>
-                        <td>Object</td>
-                        <td>
-                            <a href="{{ object.assigned_object.get_absolute_url }}">{{ object.assigned_object }}</a>
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>Created</td>
-                        <td>
-                            {{ object.created }}
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>Created By</td>
-                        <td>
-                            {{ object.created_by }}
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>Kind</td>
-                        <td>
-                          <span class="label label-{{ object.get_kind_class }}">{{ object.get_kind_display }}</span>
-                        </td>
-                    </tr>
-                </table>
             </div>
         </div>
         <div class="col-md-8">
-            <div class="panel panel-default">
-                <div class="panel-heading">
-                    <strong>Comments</strong>
-                </div>
-                <div class="panel-body">
+            <div class="card">
+                <h5 class="card-header">
+                    Comments
+                </h5>
+                <div class="card-body">
                     {{ object.comments|render_markdown }}
                 </div>
             </div>

+ 103 - 91
netbox/templates/generic/object_bulk_import.html

@@ -1,22 +1,16 @@
-{% extends 'base.html' %}
+{% extends 'layout.html' %}
 {% load helpers %}
 {% load form_helpers %}
 
+{% block title %}{{ obj_type|bettertitle }} Bulk Import{% endblock %}
+
 {% block content %}
-{% block tabs %}{% endblock %}
     <div class="row">
         <div class="col-md-8 col-md-offset-2">
-            <h1>{% block title %}{{ obj_type|bettertitle }} Bulk Import{% endblock %}</h1>
-            {% if form.non_field_errors %}
-                <div class="panel panel-danger">
-                    <div class="panel-heading"><strong>Errors</strong></div>
-                    <div class="panel-body">
-                        {{ form.non_field_errors }}
-                    </div>
-                </div>
-            {% endif %}
-            <ul class="nav nav-tabs" role="tablist">
-                <li role="presentation" class="active"><a href="#csv" role="tab" data-toggle="tab">CSV</a></li>
+            <ul class="nav nav-tabs mb-3" role="tablist">
+                <li class="nav-item" role="presentation">
+                    <a href="#csv" class="nav-link active" role="tab" data-bs-toggle="tab">CSV</a>
+                </li>
             </ul>
             <div class="tab-content">
                 <div role="tabpanel" class="tab-pane active" id="csv">
@@ -24,93 +18,111 @@
                         {% csrf_token %}
                         {% render_form form %}
                         <div class="form-group">
-                            <div class="col-md-12 text-right">
-                                <button type="submit" class="btn btn-primary">Submit</button>
+                            <div class="col-md-12 text-end">
                                 {% if return_url %}
-                                    <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
+                                    <a href="{{ return_url }}" class="btn btn-outline-danger">Cancel</a>
                                 {% endif %}
+                                <button type="submit" class="btn btn-primary">Submit</button>
                             </div>
                         </div>
                     </form>
-                    <div class="clearfix"></div>
-                    <p></p>
                     {% if fields %}
-                        <div class="panel panel-default">
-                            <div class="panel-heading">
-                                <strong>CSV Field Options</strong>
-                            </div>
-                            <table class="table">
-                                <tr>
-                                    <th>Field</th>
-                                    <th>Required</th>
-                                    <th>Accessor</th>
-                                    <th>Description</th>
-                                </tr>
-                                {% for name, field in fields.items %}
-                                    <tr>
-                                        <td>
-                                            <code>{{ name }}</code>
-                                        </td>
-                                        <td>
-                                            {% if field.required %}
-                                                <i class="mdi mdi-check-bold text-success" title="Required"></i>
-                                            {% else %}
-                                                <span class="text-muted">&mdash;</span>
-                                            {% endif %}
-                                        </td>
-                                        <td>
-                                            {% if field.to_field_name %}
-                                                <code>{{ field.to_field_name }}</code>
-                                            {% else %}
-                                                <span class="text-muted">&mdash;</span>
-                                            {% endif %}
-                                        </td>
-                                        <td>
-                                            {% if field.STATIC_CHOICES %}
-                                                <button type="button" class="btn btn-link btn-xs pull-right" data-toggle="modal" data-target="#{{ name }}_choices">
-                                                    <i class="mdi mdi-help-circle"></i>
-                                                </button>
-                                                <div class="modal fade" id="{{ name }}_choices" tabindex="-1" role="dialog">
-                                                    <div class="modal-dialog" role="document">
-                                                        <div class="modal-content">
-                                                            <div class="modal-header">
-                                                                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-                                                                <h4 class="modal-title"><code>{{ name }}</code> Choices</h4>
+                    <div class="row my-3">
+                        <div class="col-md-12">
+                            <div class="card">
+                                <h5 class="card-header">
+                                    CSV Field Options
+                                </h5>
+                                <div class="card-body">
+                                    <table class="table">
+                                        <tr>
+                                            <th>Field</th>
+                                            <th>Required</th>
+                                            <th>Accessor</th>
+                                            <th>Description</th>
+                                        </tr>
+                                        {% for name, field in fields.items %}
+                                            <tr>
+                                                <td>
+                                                    <code>{{ name }}</code>
+                                                </td>
+                                                <td>
+                                                    {% if field.required %}
+                                                        <i class="mdi mdi-check-bold text-success" title="Required"></i>
+                                                    {% else %}
+                                                        <span class="text-muted">&mdash;</span>
+                                                    {% endif %}
+                                                </td>
+                                                <td>
+                                                    {% if field.to_field_name %}
+                                                        <code>{{ field.to_field_name }}</code>
+                                                    {% else %}
+                                                        <span class="text-muted">&mdash;</span>
+                                                    {% endif %}
+                                                </td>
+                                                <td>
+                                                    {% if field.STATIC_CHOICES %}
+                                                        <button type="button" class="btn btn-link btn-sm float-end" data-bs-toggle="modal" data-bs-target="#{{ name }}_choices">
+                                                            <i class="mdi mdi-help-circle"></i>
+                                                        </button>
+                                                        <div class="modal fade" id="{{ name }}_choices" tabindex="-1" role="dialog">
+                                                            <div class="modal-dialog" role="document">
+                                                                <div class="modal-content">
+                                                                    <div class="modal-header">
+                                                                        <h5 class="modal-title"><code>{{ name }}</code> Choices</h5>
+                                                                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                                                                    </div>
+                                                                    <div class="modal-body">
+                                                                        <table class="table table-striped">
+                                                                            <tr>
+                                                                                <th>Import Value</th>
+                                                                                <th>Label</th>
+                                                                            </tr>
+                                                                            {% for value, label in field.choices %}
+                                                                            {% if value %}
+                                                                            <tr>
+                                                                                <td>
+                                                                                    <samp>{{ value }}</samp>
+                                                                                </td>
+                                                                                <td>
+                                                                                    {{ label }}
+                                                                                </td>
+                                                                            </tr>
+                                                                            {% endif %}
+                                                                            {% endfor %}
+                                                                        </table>
+                                                                    </div>
+                                                                </div>
                                                             </div>
-                                                            <table class="table table-striped modal-body">
-                                                                <tr><th>Import Value</th><th>Label</th></tr>
-                                                                {% for value, label in field.choices %}
-                                                                    {% if value %}<tr><td><samp>{{ value }}</samp></td><td>{{ label }}</td></tr>{% endif %}
-                                                                {% endfor %}
-                                                            </table>
                                                         </div>
-                                                    </div>
-                                                </div>
-                                            {% endif %}
-                                            {% if field.help_text %}
-                                                {{ field.help_text }}<br />
-                                            {% elif field.label %}
-                                                {{ field.label }}<br />
-                                            {% endif %}
-                                            {% if field|widget_type == 'dateinput' %}
-                                                <small class="text-muted">Format: YYYY-MM-DD</small>
-                                            {% elif field|widget_type == 'checkboxinput' %}
-                                                <small class="text-muted">Specify "true" or "false"</small>
-                                            {% endif %}
-                                        </td>
-                                    </tr>
-                                {% endfor %}
-                            </table>
+                                                    {% endif %}
+                                                    {% if field.help_text %}
+                                                        {{ field.help_text }}<br />
+                                                    {% elif field.label %}
+                                                        {{ field.label }}<br />
+                                                    {% endif %}
+                                                    {% if field|widget_type == 'dateinput' %}
+                                                        <small class="text-muted">Format: YYYY-MM-DD</small>
+                                                    {% elif field|widget_type == 'checkboxinput' %}
+                                                        <small class="text-muted">Specify "true" or "false"</small>
+                                                    {% endif %}
+                                                </td>
+                                            </tr>
+                                        {% endfor %}
+                                    </table>
+                                </div>
+                            </div>
                         </div>
-                        <p class="small text-muted">
-                            <i class="mdi mdi-check-bold"></i> Required fields <strong>must</strong> be specified for all
-                            objects.
-                        </p>
-                        <p class="small text-muted">
-                            <i class="mdi mdi-information-outline"></i> Related objects may be referenced by any unique attribute.
-                            For example, <code>vrf.rd</code> would identify a VRF by its route distinguisher.
-                        </p>
-                    {% endif %}
+                    </div>
+                    <p class="small text-muted">
+                        <i class="mdi mdi-check-bold text-success"></i> Required fields <strong>must</strong> be specified for all
+                        objects.
+                    </p>
+                    <p class="small text-muted">
+                        <i class="mdi mdi-information-outline"></i> Related objects may be referenced by any unique attribute.
+                        For example, <code>vrf.rd</code> would identify a VRF by its route distinguisher.
+                    </p>
+                {% endif %}
                 </div>
             </div>
         </div>

+ 17 - 15
netbox/templates/generic/object_bulk_remove.html

@@ -1,36 +1,38 @@
-{% extends 'base.html' %}
+{% extends 'layout.html' %}
 {% load helpers %}
 
 {% block title %}Remove {{ table.rows|length }} {{ obj_type_plural|bettertitle }}?{% endblock %}
 
 {% block content %}
-    <div class="row">
-        <div class="col-md-8 col-md-offset-2">
-            <div class="panel panel-danger">
-                <div class="panel-heading"><strong>Confirm Bulk Removal</strong></div>
-                <div class="panel-body">
-                    <strong>Warning:</strong> The following operation will remove {{ table.rows|length }} {{ obj_type_plural }} from {{ parent_obj }}. Please carefully review the {{ obj_type_plural }} to be removed and confirm below.
-                </div>
+    <div class="row mb-3">
+        <div class="col-md-6 offset-md-3">
+            <div class="alert alert-danger" role="alert">
+                <h4 class="alert-heading">Confirm Bulk Removal</h4>
+                <p><strong>Warning:</strong> The following operation will remove {{ table.rows|length }} {{ obj_type_plural }} from {{ parent_obj }}.</p>
+                <hr />
+                <p class="mb-0">Please carefully review the {{ obj_type_plural }} to be removed and confirm below.</p>
             </div>
         </div>
     </div>
-    <div class="row">
-        <div class="col-md-8 col-md-offset-2">
-            <div class="panel panel-default">
-                {% include 'inc/table.html' %}
+    <div class="row mb-3">
+        <div class="col-md-12">
+            <div class="card">
+                <div class="card-body">
+                    {% include 'inc/table.html' %}
+                </div>
             </div>
         </div>
     </div>
-    <div class="row">
-        <div class="col-md-6 col-md-offset-3">
+    <div class="row mb-3">
+        <div class="col-md-6 offset-md-3">
             <form action="." method="post" class="form">
                 {% csrf_token %}
                 {% for field in form.hidden_fields %}
                     {{ field }}
                 {% endfor %}
                 <div class="text-center">
+                    <a href="{{ return_url }}" class="btn btn-outline-dark">Cancel</a>
                     <button type="submit" name="_confirm" class="btn btn-danger">Delete these {{ table.rows|length }} {{ obj_type_plural }}</button>
-                    <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
                 </div>
             </form>
         </div>

+ 33 - 38
netbox/templates/generic/object_bulk_rename.html

@@ -1,53 +1,48 @@
-{% extends 'base.html' %}
+{% extends 'layout.html' %}
 {% load helpers %}
 {% load form_helpers %}
 
+{% block title %}Renaming {{ selected_objects|length }} {{ obj_type_plural|bettertitle }}{% endblock %}
+
 {% block content %}
-    <h1>{% block title %}Renaming {{ selected_objects|length }} {{ obj_type_plural|bettertitle }}{% endblock %}</h1>
-    <div class="row">
+    <div class="row mb-3">
         <div class="col-md-7">
-            <table class="table">
-                <thead>
-                    <tr>
-                        <th>Current Name</th>
-                        <th>New Name</th>
-                    </tr>
-                </thead>
-                <tbody>
-                    {% for obj in selected_objects %}
-                        <tr{% if obj.new_name and obj.name != obj.new_name %} class="success"{% endif %}>
-                            <td>{{ obj.name }}</td>
-                            <td>{{ obj.new_name }}</td>
-                        </tr>
-                    {% endfor %}
-                </tbody>
-            </table>
+            <div class="card">
+                <div class="card-body">
+                    <table class="table">
+                        <thead>
+                            <tr>
+                                <th>Current Name</th>
+                                <th>New Name</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            {% for obj in selected_objects %}
+                                <tr{% if obj.new_name and obj.name != obj.new_name %} class="success"{% endif %}>
+                                    <td>{{ obj.name }}</td>
+                                    <td>{{ obj.new_name }}</td>
+                                </tr>
+                            {% endfor %}
+                        </tbody>
+                    </table>
+                </div>
+            </div>
         </div>
         <div class="col-md-5">
             <form action="" method="post" class="form form-horizontal">
                 {% csrf_token %}
-                {% if form.non_field_errors %}
-                    <div class="panel panel-danger">
-                        <div class="panel-heading"><strong>Errors</strong></div>
-                        <div class="panel-body">
-                            {{ form.non_field_errors }}
-                        </div>
-                    </div>
-                {% endif %}
-                <div class="panel panel-default">
-                    <div class="panel-heading"><strong>Rename</strong></div>
-                    <div class="panel-body">
+                <div class="card">
+                    <h5 class="card-header">Rename</h5>
+                    <div class="card-body">
                         {% render_form form %}
                     </div>
                 </div>
-                <div class="form-group text-right">
-                    <div class="col-md-12">
-                        <button type="submit" name="_preview" class="btn btn-primary">Preview</button>
-                        {% if '_preview' in request.POST and not form.errors %}
-                            <button type="submit" name="_apply" class="btn btn-primary">Apply</button>
-                        {% endif %}
-                        <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
-                    </div>
+                <div class="col-md-12 my-3 text-end">
+                    <a href="{{ return_url }}" class="btn btn-outline-danger">Cancel</a>
+                    <button type="submit" name="_preview" class="btn btn-primary">Preview</button>
+                    {% if '_preview' in request.POST and not form.errors %}
+                        <button type="submit" name="_apply" class="btn btn-primary">Apply</button>
+                    {% endif %}
                 </div>
             </form>
         </div>

+ 44 - 40
netbox/templates/ipam/rir.html

@@ -3,43 +3,45 @@
 {% load plugins %}
 
 {% block breadcrumbs %}
-  <li><a href="{% url 'ipam:rir_list' %}">RIRs</a></li>
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item"><a href="{% url 'ipam:rir_list' %}">RIRs</a></li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
 {% block content %}
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-6">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>RIR</strong>
+    <div class="card">
+      <h5 class="card-header">
+        RIR
+      </h5>
+      <div class="card-body">
+        <table class="table table-hover attr-table">
+          <tr>
+            <th scope="row">Name</th>
+            <td>{{ object.name }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Description</th>
+            <td>{{ object.description|placeholder }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Private</th>
+            <td>
+              {% if object.is_private %}
+                <i class="mdi mdi-check-bold text-success" title="Yes"></i>
+              {% else %}
+                <i class="mdi mdi-close-thick text-danger" title="No"></i>
+              {% endif %}
+            </td>
+          </tr>
+          <tr>
+            <th scope="row">Aggregates</th>
+            <td>
+              <a href="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}">{{ aggregates_table.rows|length }}</a>
+            </td>
+          </tr>
+        </table>
       </div>
-      <table class="table table-hover panel-body attr-table">
-        <tr>
-          <td>Name</td>
-          <td>{{ object.name }}</td>
-        </tr>
-        <tr>
-          <td>Description</td>
-          <td>{{ object.description|placeholder }}</td>
-        </tr>
-        <tr>
-          <td>Private</td>
-          <td>
-            {% if object.is_private %}
-              <i class="mdi mdi-check-bold text-success" title="Yes"></i>
-            {% else %}
-              <i class="mdi mdi-close-thick text-danger" title="No"></i>
-            {% endif %}
-          </td>
-        </tr>
-        <tr>
-          <td>Aggregates</td>
-          <td>
-            <a href="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}">{{ aggregates_table.rows|length }}</a>
-          </td>
-        </tr>
-      </table>
     </div>
     {% plugin_left_page object %}
 	</div>
@@ -48,17 +50,19 @@
     {% plugin_right_page object %}
   </div>
 </div>
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-12">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>Aggregates</strong>
+    <div class="card">
+      <h5 class="card-header">
+        Aggregates
+      </h5>
+      <div class="card-body">
+        {% include 'inc/table.html' with table=aggregates_table %}
       </div>
-      {% include 'inc/table.html' with table=aggregates_table %}
       {% if perms.ipam.add_aggregate %}
-        <div class="panel-footer text-right noprint">
-          <a href="{% url 'ipam:aggregate_add' %}?rir={{ object.pk }}" class="btn btn-xs btn-primary">
-            <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add aggregate
+        <div class="card-footer text-end noprint">
+          <a href="{% url 'ipam:aggregate_add' %}?rir={{ object.pk }}" class="btn btn-sm btn-primary">
+            <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Aggregate
           </a>
         </div>
       {% endif %}

+ 38 - 34
netbox/templates/ipam/role.html

@@ -3,37 +3,39 @@
 {% load plugins %}
 
 {% block breadcrumbs %}
-  <li><a href="{% url 'ipam:role_list' %}">Roles</a></li>
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item"><a href="{% url 'ipam:role_list' %}">Roles</a></li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
 {% block content %}
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-6">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>Role</strong>
+    <div class="card">
+      <h5 class="card-header">
+        Role
+      </h5>
+      <div class="card-body">
+        <table class="table table-hover attr-table">
+          <tr>
+            <th scope="row">Name</th>
+            <td>{{ object.name }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Description</th>
+            <td>{{ object.description|placeholder }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Weight</th>
+            <td>{{ object.weight }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Prefixes</th>
+            <td>
+              <a href="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}">{{ prefixes_table.rows|length }}</a>
+            </td>
+          </tr>
+        </table>
       </div>
-      <table class="table table-hover panel-body attr-table">
-        <tr>
-          <td>Name</td>
-          <td>{{ object.name }}</td>
-        </tr>
-        <tr>
-          <td>Description</td>
-          <td>{{ object.description|placeholder }}</td>
-        </tr>
-        <tr>
-          <td>Weight</td>
-          <td>{{ object.weight }}</td>
-        </tr>
-        <tr>
-          <td>Prefixes</td>
-          <td>
-            <a href="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}">{{ prefixes_table.rows|length }}</a>
-          </td>
-        </tr>
-      </table>
     </div>
     {% plugin_left_page object %}
 	</div>
@@ -42,17 +44,19 @@
     {% plugin_right_page object %}
   </div>
 </div>
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-12">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>Prefixes</strong>
+    <div class="card">
+      <h5 class="card-header">
+        Prefixes
+      </h5>
+      <div class="card-body">
+        {% include 'inc/table.html' with table=prefixes_table %}
       </div>
-      {% include 'inc/table.html' with table=prefixes_table %}
       {% if perms.ipam.add_prefix %}
-        <div class="panel-footer text-right noprint">
-          <a href="{% url 'ipam:prefix_add' %}?role={{ object.pk }}" class="btn btn-xs btn-primary">
-            <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add prefix
+        <div class="card-footer text-end noprint">
+          <a href="{% url 'ipam:prefix_add' %}?role={{ object.pk }}" class="btn btn-sm btn-primary">
+            <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Prefix
           </a>
         </div>
       {% endif %}

+ 51 - 43
netbox/templates/ipam/service.html

@@ -5,61 +5,69 @@
 {% load plugins %}
 
 {% block breadcrumbs %}
-  <li><a href="{% url 'ipam:service_list' %}">Services</a></li>
-  <li><a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a></li>
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item"><a href="{% url 'ipam:service_list' %}">Services</a></li>
+  <li class="breadcrumb-item"><a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a></li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
-{% block buttons %}
+{% block controls %}
+{% plugin_buttons object %}
+<div class="container mb-2 mx-0">
+  <div class="d-flex flex-wrap justify-content-end">
+  {% block extra_controls %}{% endblock %}
   {% if request.user|can_change:object %}
     {% edit_button object %}
   {% endif %}
   {% if request.user|can_delete:object %}
     {% delete_button object %}
   {% endif %}
+  </div>
+</div>
 {% endblock %}
 
 {% block content %}
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-6">
-        <div class="panel panel-default">
-            <div class="panel-heading">
-                <strong>Service</strong>
+        <div class="card">
+            <h5 class="card-header">
+                Service
+            </h5>
+            <div class="card-body">
+                <table class="table table-hover attr-table">
+                    <tr>
+                        <th scope="row">Name</th>
+                        <td>{{ object.name }}</td>
+                    </tr>
+                    <tr>
+                        <th scope="row">Parent</th>
+                        <td>
+                            <a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th scope="row">Protocol</th>
+                        <td>{{ object.get_protocol_display }}</td>
+                    </tr>
+                    <tr>
+                        <th scope="row">Ports</th>
+                        <td>{{ object.port_list }}</td>
+                    </tr>
+                    <tr>
+                        <th scope="row">IP Addresses</th>
+                        <td>
+                            {% for ipaddress in object.ipaddresses.all %}
+                                <a href="{{ ipaddress.get_absolute_url }}">{{ ipaddress }}</a><br />
+                            {% empty %}
+                                <span class="text-muted">None</span>
+                            {% endfor %}
+                        </td>
+                    </tr>
+                    <tr>
+                        <th scope="row">Description</th>
+                        <td>{{ object.description|placeholder }}</td>
+                    </tr>
+                </table>
             </div>
-            <table class="table table-hover panel-body attr-table">
-                <tr>
-                    <td>Name</td>
-                    <td>{{ object.name }}</td>
-                </tr>
-                <tr>
-                    <td>Parent</td>
-                    <td>
-                        <a href="{{ object.parent.get_absolute_url }}">{{ object.parent }}</a>
-                    </td>
-                </tr>
-                <tr>
-                    <td>Protocol</td>
-                    <td>{{ object.get_protocol_display }}</td>
-                </tr>
-                <tr>
-                    <td>Ports</td>
-                    <td>{{ object.port_list }}</td>
-                </tr>
-                <tr>
-                    <td>IP Addresses</td>
-                    <td>
-                        {% for ipaddress in object.ipaddresses.all %}
-                            <a href="{{ ipaddress.get_absolute_url }}">{{ ipaddress }}</a><br />
-                        {% empty %}
-                            <span class="text-muted">None</span>
-                        {% endfor %}
-                    </td>
-                </tr>
-                <tr>
-                    <td>Description</td>
-                    <td>{{ object.description|placeholder }}</td>
-                </tr>
-		    </table>
         </div>
         {% include 'inc/custom_fields_panel.html' %}
         {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='ipam:service_list' %}
@@ -69,7 +77,7 @@
         {% plugin_right_page object %}
     </div>
 </div>
-<div class="row">
+<div class="row mb-3">
     <div class="col-md-12">
         {% plugin_full_width_page object %}
     </div>

+ 25 - 26
netbox/templates/ipam/service_edit.html

@@ -2,37 +2,36 @@
 {% load form_helpers %}
 
 {% block form %}
-    <div class="card">
-        <h5 class="card-header">Service</h5>
-        <div class="card-body">
-            {% if obj.device %}
-                <div class="form-group">
-                    <label class="col-md-3 control-label required">Device</label>
-                    <div class="col-md-9">
-                        <p class="form-control-static">{{ obj.device }}</p>
-                    </div>
-                </div>
-            {% else %}
-                <div class="form-group">
-                    <label class="col-md-3 control-label required">Virtual Machine</label>
-                    <div class="col-md-9">
-                        <p class="form-control-static">{{ obj.virtual_machine }}</p>
-                    </div>
-                </div>
-            {% endif %}
-            {% render_field form.name %}
-            <div class="form-group form-inline">
-                <label class="col-md-3 control-label required">Port(s)</label>
-                <div class="col-md-9">
+    <div class="field-group">
+        <h4>Service</h4>
+        {% if obj.device %}
+            <div class="form-floating mb-3">
+                <input class="form-control" value="{{ obj.device }}" disabled />
+                <label class="form-label">Device</label>
+            </div>
+        {% else %}
+            <div class="form-floating mb-3">
+                <input class="form-control" value="{{ obj.virtual_machine }}" disabled />
+                <label class="form-label">Virtual Machine</label>
+            </div>
+        {% endif %}
+        {% render_field form.name %}
+        <div class="mb-3">
+            <label class="form-label">Port(s)</label>
+            <div class="row">
+                <div class="col-3">
                     {{ form.protocol }}
+                </div>
+                <div class="col-9 font-monospace">
                     {{ form.ports }}
-                    <span class="help-block">{{ form.ports.help_text }}</span>
                 </div>
+                <div class="form-text">{{ form.ports.help_text }}</div>
             </div>
-            {% render_field form.ipaddresses %}
-            {% render_field form.description %}
-            {% render_field form.tags %}
         </div>
+        
+        {% render_field form.ipaddresses %}
+        {% render_field form.description %}
+        {% render_field form.tags %}
     </div>
     {% if form.custom_fields %}
         <div class="card">

+ 10 - 10
netbox/templates/ipam/vlan/base.html

@@ -25,23 +25,23 @@
 
 {% block tabs %}
   <ul class="nav nav-tabs" style="margin-bottom: 20px">
-    <li role="presentation"{% if not active_tab %} class="active"{% endif %}>
-      <a href="{% url 'ipam:vlan' pk=object.pk %}">VLAN</a>
+    <li class="nav-item" role="presentation">
+      <a class="nav-link{% if not active_tab %} active{% endif %}" href="{% url 'ipam:vlan' pk=object.pk %}">VLAN</a>
     </li>
-    <li role="presentation"{% if active_tab == 'interfaces' %} class="active"{% endif %}>
-      <a href="{% url 'ipam:vlan_interfaces' pk=object.pk %}">Device Interfaces <span class="badge">{{ object.get_interfaces.count }}</span></a>
+    <li class="nav-item" role="presentation">
+      <a class="nav-link{% if active_tab == 'interfaces' %} active{% endif %}" href="{% url 'ipam:vlan_interfaces' pk=object.pk %}">Device Interfaces <span class="badge bg-primary">{{ object.get_interfaces.count }}</span></a>
     </li>
-    <li role="presentation"{% if active_tab == 'vminterfaces' %} class="active"{% endif %}>
-      <a href="{% url 'ipam:vlan_vminterfaces' pk=object.pk %}">VM Interfaces <span class="badge">{{ object.get_vminterfaces.count }}</span></a>
+    <li class="nav-item" role="presentation">
+      <a class="nav-link{% if active_tab == 'vminterfaces' %} active{% endif %}" href="{% url 'ipam:vlan_vminterfaces' pk=object.pk %}">VM Interfaces <span class="badge bg-primary">{{ object.get_vminterfaces.count }}</span></a>
     </li>
     {% if perms.extras.view_journalentry %}
-      <li role="presentation"{% if active_tab == 'journal' %} class="active"{% endif %}>
-        <a href="{% url 'ipam:vlan_journal' pk=object.pk %}">Journal</a>
+      <li class="nav-item" role="presentation">
+        <a class="nav-link{% if active_tab == 'journal' %} active{% endif %}" href="{% url 'ipam:vlan_journal' pk=object.pk %}">Journal</a>
       </li>
     {% endif %}
     {% if perms.extras.view_objectchange %}
-      <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
-        <a href="{% url 'ipam:vlan_changelog' pk=object.pk %}">Change Log</a>
+      <li class="nav-item" role="presentation">
+        <a class="nav-link{% if active_tab == 'changelog' %} active{% endif %}" href="{% url 'ipam:vlan_changelog' pk=object.pk %}">Change Log</a>
       </li>
     {% endif %}
   </ul>

+ 37 - 43
netbox/templates/ipam/vlan_edit.html

@@ -4,54 +4,48 @@
 {% load helpers %}
 
 {% block form %}
-    <div class="panel panel-default">
-        <div class="panel-heading"><strong>VLAN</strong></div>
-        <div class="panel-body">
-            {% render_field form.vid %}
-            {% render_field form.name %}
-            {% render_field form.status %}
-            {% render_field form.role %}
-            {% render_field form.description %}
-            {% render_field form.tags %}
-        </div>
+    <div class="field-group mb-3">
+        <h4>VLAN</h4>
+        {% render_field form.vid %}
+        {% render_field form.name %}
+        {% render_field form.status %}
+        {% render_field form.role %}
+        {% render_field form.description %}
+        {% render_field form.tags %}
     </div>
-    <div class="panel panel-default">
-        <div class="panel-heading"><strong>Tenancy</strong></div>
-        <div class="panel-body">
-            {% render_field form.tenant_group %}
-            {% render_field form.tenant %}
-        </div>
+    <div class="field-group mb-3">
+        <h4>Tenancy</h4>
+        {% render_field form.tenant_group %}
+        {% render_field form.tenant %}
     </div>
-    <div class="panel panel-default">
-        <div class="panel-heading">
-            <strong>Assignment</strong>
-        </div>
-        <div class="panel-body">
-            {% with site_tab_active=form.initial.site %}
-                <ul class="nav nav-tabs" role="tablist">
-                    <li role="presentation"{% if not site_tab_active %} class="active"{% endif %}><a href="#group" role="tab" data-toggle="tab">VLAN Group</a></li>
-                    <li role="presentation"{% if site_tab_active %} class="active"{% endif %}><a href="#site" role="tab" data-toggle="tab">Site</a></li>
-                </ul>
-                <div class="tab-content">
-                    <div class="tab-pane{% if not site_tab_active %} active{% endif %}" id="group">
-                        {% render_field form.scope_type %}
-                        {% render_field form.group %}
-                    </div>
-                    <div class="tab-pane{% if site_tab_active %} active{% endif %}" id="site">
-                        {% render_field form.region %}
-                        {% render_field form.sitegroup %}
-                        {% render_field form.site %}
-                    </div>
+    <div class="field-group mb-3">
+        <h4>Assignment</h4>
+        {% with site_tab_active=form.initial.site %}
+            <ul class="nav nav-tabs mb-3" role="tablist">
+                <li class="nav-item" role="presentation">
+                    <a class="nav-link{% if not site_tab_active %} active{% endif %}" href="#group" role="tab" data-bs-toggle="tab">VLAN Group</a>
+                </li>
+                <li class="nav-item" role="presentation">
+                    <a class="nav-link{% if site_tab_active %} active{% endif %}" href="#site" role="tab" data-bs-toggle="tab">Site</a>
+                </li>
+            </ul>
+            <div class="tab-content">
+                <div class="tab-pane{% if not site_tab_active %} active{% endif %}" id="group">
+                    {% render_field form.scope_type %}
+                    {% render_field form.group %}
                 </div>
-            {% endwith %}
-        </div>
+                <div class="tab-pane{% if site_tab_active %} active{% endif %}" id="site">
+                    {% render_field form.region %}
+                    {% render_field form.sitegroup %}
+                    {% render_field form.site %}
+                </div>
+            </div>
+        {% endwith %}
     </div>
     {% if form.custom_fields %}
-        <div class="panel panel-default">
-            <div class="panel-heading"><strong>Custom Fields</strong></div>
-            <div class="panel-body">
-                {% render_custom_fields form %}
-            </div>
+        <div class="field-group">
+            <h4>Custom Fields</h4>
+            {% render_custom_fields form %}
         </div>
     {% endif %}
 {% endblock %}

+ 43 - 39
netbox/templates/ipam/vlangroup.html

@@ -3,45 +3,47 @@
 {% load plugins %}
 
 {% block breadcrumbs %}
-  <li><a href="{% url 'ipam:vlangroup_list' %}">VLAN Groups</a></li>
+  <li class="breadcrumb-item"><a href="{% url 'ipam:vlangroup_list' %}">VLAN Groups</a></li>
   {% if object.scope %}
-    <li><a href="{{ object.scope.get_absolute_url }}">{{ object.scope }}</a></li>
+    <li class="breadcrumb-item"><a href="{{ object.scope.get_absolute_url }}">{{ object.scope }}</a></li>
   {% endif %}
-  <li>{{ object }}</li>
+  <li class="breadcrumb-item">{{ object }}</li>
 {% endblock %}
 
 {% block content %}
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-6">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>VLAN Group</strong>
+    <div class="card">
+      <h5 class="card-header">
+        VLAN Group
+      </h5>
+      <div class="card-body">
+        <table class="table table-hover attr-table">
+          <tr>
+            <th scope="row">Name</th>
+            <td>{{ object.name }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Description</th>
+            <td>{{ object.description|placeholder }}</td>
+          </tr>
+          <tr>
+            <th scope="row">Scope</th>
+            <td>
+            {% if object.scope %}
+              <a href="{{ object.scope.get_absolute_url }}">{{ object.scope }}</a>
+            {% else %}
+              <span class="text-muted">&mdash;</span>
+            {% endif %}
+          </tr>
+          <tr>
+            <th scope="row">VLANs</th>
+            <td>
+              <a href="{% url 'ipam:vlan_list' %}?group_id={{ object.pk }}">{{ vlans_count }}</a>
+            </td>
+          </tr>
+        </table>
       </div>
-      <table class="table table-hover panel-body attr-table">
-        <tr>
-          <td>Name</td>
-          <td>{{ object.name }}</td>
-        </tr>
-        <tr>
-          <td>Description</td>
-          <td>{{ object.description|placeholder }}</td>
-        </tr>
-        <tr>
-          <td>Scope</td>
-          <td>
-          {% if object.scope %}
-            <a href="{{ object.scope.get_absolute_url }}">{{ object.scope }}</a>
-          {% else %}
-            <span class="text-muted">&mdash;</span>
-          {% endif %}
-        </tr>
-        <tr>
-          <td>VLANs</td>
-          <td>
-            <a href="{% url 'ipam:vlan_list' %}?group_id={{ object.pk }}">{{ vlans_count }}</a>
-          </td>
-        </tr>
-      </table>
     </div>
     {% plugin_left_page object %}
 	</div>
@@ -50,16 +52,18 @@
     {% plugin_right_page object %}
   </div>
 </div>
-<div class="row">
+<div class="row mb-3">
 	<div class="col-md-12">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <strong>VLANs</strong>
+    <div class="card">
+      <h5 class="card-header">
+        VLANs
+      </h5>
+      <div class="card-body">
+        {% include 'inc/table.html' with table=vlans_table %}
       </div>
-      {% include 'inc/table.html' with table=vlans_table %}
       {% if perms.ipam.add_vlan %}
-        <div class="panel-footer text-right noprint">
-          <a href="{% url 'ipam:vlan_add' %}?group={{ object.pk }}" class="btn btn-xs btn-primary">
+        <div class="card-footer text-end noprint">
+          <a href="{% url 'ipam:vlan_add' %}?group={{ object.pk }}" class="btn btn-sm btn-primary">
             <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add VLAN
           </a>
         </div>

+ 0 - 12
netbox/templates/utilities/render_field.html

@@ -127,15 +127,3 @@
     {% endif %}
     
 {% endif %}
-
-{% comment %} <div class="invalid-feedback">
-{% if field.errors %}
-    <ul>
-        {% for error in field.errors %}
-            {# Embed an HTML comment indicating the error for extraction by tests #}
-            <!-- FORM-ERROR {{ field.name }}: {{ error }} -->
-            <li class="text-danger">{{ error }}</li>
-        {% endfor %}
-    </ul>
-{% endif %}
-</div> {% endcomment %}