Просмотр исходного кода

Merge branch 'feature' into feature-object-filter

# Conflicts:
#	netbox/project-static/dist/netbox-dark.css
#	netbox/project-static/dist/netbox-light.css
#	netbox/project-static/styles/netbox.scss
#	netbox/project-static/styles/select.scss
thatmattlove 4 лет назад
Родитель
Сommit
06c730f4dc

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-dark.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-light.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 4 - 0
netbox/project-static/package.json

@@ -53,7 +53,11 @@
     "extends": "stylelint-config-twbs-bootstrap/scss",
     "extends": "stylelint-config-twbs-bootstrap/scss",
     "rules": {
     "rules": {
       "selector-max-class": 16,
       "selector-max-class": 16,
+      "selector-max-id": 4,
+      "selector-max-type": 16,
       "selector-max-compound-selectors": 16,
       "selector-max-compound-selectors": 16,
+      "declaration-no-important": null,
+      "selector-max-universal": 4,
       "selector-no-qualifying-type": [
       "selector-no-qualifying-type": [
         true,
         true,
         {
         {

+ 1 - 0
netbox/project-static/styles/bootstrap.scss

@@ -1,5 +1,6 @@
 // Import the rest of bootstrap.
 // Import the rest of bootstrap.
 @import '../node_modules/bootstrap/scss/utilities';
 @import '../node_modules/bootstrap/scss/utilities';
+@import './extensions';
 @import '../node_modules/bootstrap/scss/mixins';
 @import '../node_modules/bootstrap/scss/mixins';
 @import '../node_modules/bootstrap/scss/root';
 @import '../node_modules/bootstrap/scss/root';
 @import '../node_modules/bootstrap/scss/reboot';
 @import '../node_modules/bootstrap/scss/reboot';

+ 45 - 0
netbox/project-static/styles/extensions.scss

@@ -0,0 +1,45 @@
+// Bootstrap utility extensions.
+// See https://getbootstrap.com/docs/5.0/utilities/api/
+
+// Add responsive max-width classes for more granular controls over max-width.
+$max-width-extension: (
+  'max-width': (
+    property: max-width,
+    class: mw,
+    responsive: true,
+    values: (
+      20: 20%,
+      25: 25%,
+      33: 33%,
+      50: 50%,
+      66: 66%,
+      75: 75%,
+      80: 80%,
+      90: 90%,
+      100: 100%,
+    ),
+  ),
+);
+
+// Add more opacity classes.
+$opacity-extension: (
+  'opacity': (
+    property: opacity,
+    class: opacity,
+    values: (
+      0: 0,
+      10: 0.1,
+      20: 0.2,
+      25: 0.25,
+      33: 0.33,
+      50: 0.5,
+      66: 0.66,
+      75: 0.75,
+      80: 0.8,
+      90: 0.9,
+      100: 1,
+    ),
+  ),
+);
+
+$utilities: map-merge($utilities, $max-width-extension, $opacity-extension);

+ 76 - 26
netbox/project-static/styles/flatpickr-dark.scss

@@ -1,37 +1,59 @@
 // Dark Mode Styles for Flatpickr.
 // Dark Mode Styles for Flatpickr.
 
 
+$flatpickr-bg: $gray-800;
+$flatpickr-color: $body-color;
+$flatpickr-border-color: $gray-700;
+$flatpickr-title-color: $gray-300;
+$flatpickr-disabled-color: $gray-500;
+
 .flatpickr-calendar {
 .flatpickr-calendar {
-  background: $gray-700;
-  color: $body-color;
-  box-shadow: 1px 0 0 $gray-600, -1px 0 0 $gray-600, 0 1px 0 $gray-600, 0 -1px 0 $gray-600,
-    0 3px 13px rgb(0 0 0 / 8%);
+  color: $flatpickr-color;
+  background: $flatpickr-bg;
   border-radius: $border-radius;
   border-radius: $border-radius;
-  & span.flatpickr-weekday {
-    color: $gray-400;
-  }
+  box-shadow: 1px 0 0 $flatpickr-border-color, -1px 0 0 $flatpickr-border-color,
+    0 1px 0 $flatpickr-border-color, 0 -1px 0 $flatpickr-border-color, 0 3px 13px rgb(0 0 0 / 8%);
+
   &.arrowTop:before,
   &.arrowTop:before,
   &.arrowTop:after {
   &.arrowTop:after {
-    border-bottom-color: $gray-700;
+    border-bottom-color: $flatpickr-bg;
+  }
+
+  span.flatpickr-weekday {
+    color: $flatpickr-title-color;
+  }
+
+  .numInputWrapper {
+    span.arrowUp:after {
+      border-bottom-color: $input-color;
+    }
+    span.arrowDown:after {
+      border-top-color: $input-color;
+    }
   }
   }
+
   .flatpickr-months {
   .flatpickr-months {
-    & .flatpickr-month {
-      color: $body-color;
-      fill: $body-color;
+    .flatpickr-month {
+      color: $flatpickr-color;
+      fill: $flatpickr-color;
     }
     }
-    & .flatpickr-next-month,
-    & .flatpickr-prev-month {
-      color: $body-color;
-      fill: $body-color;
+
+    .flatpickr-next-month,
+    .flatpickr-prev-month {
+      color: $flatpickr-color;
+      fill: $flatpickr-color;
+      &:hover svg {
+        fill: $danger;
+      }
     }
     }
-    .flatpickr-current-month .flatpickr-monthDropdown-months {
-      background: $gray-700;
+
+    .flatpickr-current-month select {
+      background: $flatpickr-bg;
     }
     }
   }
   }
+
   .flatpickr-day {
   .flatpickr-day {
-    color: $body-color;
-    &.today {
-      border-color: $gray-200;
-    }
+    color: $flatpickr-color;
+
     &.selected,
     &.selected,
     &.startRange,
     &.startRange,
     &.endRange,
     &.endRange,
@@ -50,15 +72,17 @@
     &.selected.nextMonthDay,
     &.selected.nextMonthDay,
     &.startRange.nextMonthDay,
     &.startRange.nextMonthDay,
     &.endRange.nextMonthDay {
     &.endRange.nextMonthDay {
+      color: color-contrast($blue-300);
       background: $blue-300;
       background: $blue-300;
       border-color: $blue-300;
       border-color: $blue-300;
-      color: color-contrast($blue-300);
     }
     }
+
     &:hover {
     &:hover {
-      border-color: $gray-200;
-      background: $gray-200;
-      color: color-contrast($gray-200);
+      color: color-contrast($secondary);
+      background: $secondary;
+      border-color: $secondary;
     }
     }
+
     &.flatpickr-disabled,
     &.flatpickr-disabled,
     &.flatpickr-disabled:hover,
     &.flatpickr-disabled:hover,
     &.prevMonthDay,
     &.prevMonthDay,
@@ -66,7 +90,33 @@
     &.notAllowed,
     &.notAllowed,
     &.notAllowed.prevMonthDay,
     &.notAllowed.prevMonthDay,
     &.notAllowed.nextMonthDay {
     &.notAllowed.nextMonthDay {
-      color: $gray-500;
+      color: $flatpickr-disabled-color;
+
+      &:hover {
+        color: color-contrast($secondary);
+        background: $secondary;
+        border-color: $secondary;
+      }
+    }
+  }
+
+  .flatpickr-time {
+    input {
+      color: $input-color;
+      background: $flatpickr-bg;
+
+      &:hover,
+      &:active {
+        background: $flatpickr-bg;
+      }
     }
     }
+
+    .flatpickr-time-separator {
+      color: $flatpickr-disabled-color;
+    }
+  }
+
+  &.showTimeInput.hasTime .flatpickr-time {
+    border-top: 1px solid $flatpickr-border-color;
   }
   }
 }
 }

+ 130 - 436
netbox/project-static/styles/netbox.scss

@@ -1,117 +1,10 @@
 // Netbox-specific Styles and Overrides.
 // Netbox-specific Styles and Overrides.
 
 
 @use 'sass:map';
 @use 'sass:map';
-@import './sidenav.scss';
-
-:root {
-  --nbx-sidebar-bg: #{$gray-200};
-  --nbx-sidebar-scroll: #{$gray-500};
-  --nbx-sidebar-link-color: #{$gray-800};
-  --nbx-sidebar-link-hover-bg: #{$blue-100};
-  --nbx-sidebar-title-color: #{$text-muted};
-  --nbx-sidebar-shadow: inset 0px -25px 20px -25px rgba(0, 0, 0, 0.25);
-  --nbx-breadcrumb-bg: #{$light};
-  --nbx-body-bg: #{$white};
-  --nbx-body-color: #{$gray-800};
-  --nbx-pre-bg: #{$gray-100};
-  --nbx-pre-border-color: #{$gray-600};
-  --nbx-change-added: #{rgba($green, 0.4)};
-  --nbx-change-removed: #{rgba($red, 0.4)};
-  --nbx-cable-node-bg: #{$gray-100};
-  --nbx-cable-node-border-color: #{$gray-200};
-  --nbx-cable-termination-bg: #{$gray-200};
-  --nbx-cable-termination-border-color: #{$gray-300};
-  --nbx-search-filter-border-left-color: #{$gray-300};
-  --nbx-color-mode-toggle-color: #{$primary};
-  --nbx-sidenav-pin-color: #{$orange};
-  --nbx-sidenav-parent-color: #{$gray-900};
-
-  &[data-netbox-color-mode='dark'] {
-    --nbx-sidebar-bg: #{$gray-900};
-    --nbx-sidebar-scroll: #{$gray-700};
-    --nbx-sidebar-link-color: #{$gray-100};
-    --nbx-sidebar-link-hover-bg: #{rgba($blue-300, 0.15)};
-    --nbx-sidebar-title-color: #{$gray-600};
-    --nbx-sidebar-shadow: inset 0px -25px 20px -25px rgba(255, 255, 255, 0.05);
-    --nbx-breadcrumb-bg: #{$gray-800};
-    --nbx-body-bg: #{$darker};
-    --nbx-body-color: #{$gray-100};
-    --nbx-pre-bg: #{$gray-700};
-    --nbx-pre-border-color: #{$gray-600};
-    --nbx-change-added: #{rgba($green-300, 0.4)};
-    --nbx-change-removed: #{rgba($red-300, 0.4)};
-    --nbx-cable-node-bg: #{$gray-700};
-    --nbx-cable-node-border-color: #{$gray-600};
-    --nbx-cable-termination-bg: #{$gray-800};
-    --nbx-cable-termination-border-color: #{$gray-700};
-    --nbx-search-filter-border-left-color: #{$gray-600};
-    --nbx-color-mode-toggle-color: #{$yellow-300};
-    --nbx-sidenav-pin-color: #{$yellow};
-    --nbx-sidenav-parent-color: #{$gray-100};
-  }
-}
-
-* {
-  transition: background-color, color 0.1s ease-in-out;
-}
-
-.mw-25 {
-  max-width: 25% !important;
-}
-
-.mw-33 {
-  max-width: 33.33% !important;
-}
-
-.mw-50 {
-  max-width: 50% !important;
-}
-
-.mw-66 {
-  max-width: 66.66% !important;
-}
-
-.mw-75 {
-  max-width: 75% !important;
-}
-
-.text-xs {
-  font-size: $font-size-xs;
-  line-height: $line-height-sm;
-}
-
-.opacity-0 {
-  opacity: 0 !important;
-}
-.opacity-25 {
-  opacity: 0.25 !important;
-}
-.opacity-50 {
-  opacity: 0.5 !important;
-}
-.opacity-75 {
-  opacity: 0.75 !important;
-}
-.opacity-100 {
-  opacity: 1 !important;
-}
-
-// Force <small/> elements to make text smaller.
-small {
-  font-size: smaller !important;
-}
-
-// Automatically space out adjacent columns.
-.col:not(:last-child):not(:only-child) {
-  margin-bottom: $spacer;
-}
-
-// Ensure elements with data-href set show the correct cursor.
-// data-href is set on non non-anchor elements that need to redirect the user to a URL when
-// clicked, but where an anchor element does not suffice or is not supported.
-*[data-href] {
-  cursor: pointer;
-}
+@import './sidenav';
+@import './overrides';
+@import './utilities';
+@import './variables';
 
 
 @each $color, $value in $theme-colors {
 @each $color, $value in $theme-colors {
   // Override CSS values on each theme color.
   // Override CSS values on each theme color.
@@ -191,16 +84,16 @@ small {
   }
   }
 }
 }
 
 
-// Fix the hideous way Safari shows button anchor elements.
-a[type='button'] {
-  -webkit-appearance: unset !important;
-}
-
 // Ensure progress bars (utilization graph) in tables aren't too narrow to display the percentage.
 // Ensure progress bars (utilization graph) in tables aren't too narrow to display the percentage.
 table td > .progress {
 table td > .progress {
   min-width: 6rem;
   min-width: 6rem;
 }
 }
 
 
+// Automatically space out adjacent columns.
+.col:not(:last-child):not(:only-child) {
+  margin-bottom: $spacer;
+}
+
 .nav-mobile {
 .nav-mobile {
   display: none;
   display: none;
   flex-direction: column;
   flex-direction: column;
@@ -234,21 +127,23 @@ table td > .progress {
   overflow: hidden;
   overflow: hidden;
   border-bottom-right-radius: $card-border-radius;
   border-bottom-right-radius: $card-border-radius;
   border-bottom-left-radius: $card-border-radius;
   border-bottom-left-radius: $card-border-radius;
+
   thead th[scope='col'] {
   thead th[scope='col'] {
-    background-color: $table-flush-header-bg;
-    vertical-align: middle;
-    text-transform: uppercase;
     padding-top: map.get($spacers, 3);
     padding-top: map.get($spacers, 3);
     padding-bottom: map.get($spacers, 3);
     padding-bottom: map.get($spacers, 3);
-    border-bottom-color: $card-border-color;
+    text-transform: uppercase;
+    vertical-align: middle;
+    background-color: $table-flush-header-bg;
     border-top: 1px solid $card-border-color;
     border-top: 1px solid $card-border-color;
+    border-bottom-color: $card-border-color;
   }
   }
+
   th,
   th,
   td {
   td {
-    border-left: 0;
-    border-right: 0;
-    padding-left: map.get($spacers, 4) !important;
     padding-right: map.get($spacers, 4) !important;
     padding-right: map.get($spacers, 4) !important;
+    padding-left: map.get($spacers, 4) !important;
+    border-right: 0;
+    border-left: 0;
   }
   }
   tr[class] {
   tr[class] {
     border-color: $card-border-color !important;
     border-color: $card-border-color !important;
@@ -265,8 +160,8 @@ table td > .progress {
 .header-alert-container {
 .header-alert-container {
   // Center-align the alert(s).
   // Center-align the alert(s).
   display: flex;
   display: flex;
-  justify-content: center;
   align-items: center;
   align-items: center;
+  justify-content: center;
   // Apply the same spacing that's applied to the #content div's first child (.px-3).
   // Apply the same spacing that's applied to the #content div's first child (.px-3).
   padding: 0 $spacer;
   padding: 0 $spacer;
 
 
@@ -286,165 +181,106 @@ table td > .progress {
 }
 }
 
 
 span.profile-button .dropdown-menu {
 span.profile-button .dropdown-menu {
-  transition: opacity 0.2s ease-in-out;
-  display: block !important;
   right: 0;
   right: 0;
   left: auto;
   left: auto;
+  display: block !important;
   margin-top: 0.5rem;
   margin-top: 0.5rem;
   box-shadow: $box-shadow;
   box-shadow: $box-shadow;
+  transition: opacity 0.2s ease-in-out;
+
   &:not(.show) {
   &:not(.show) {
-    opacity: 0;
     pointer-events: none;
     pointer-events: none;
+    opacity: 0;
   }
   }
   &.show {
   &.show {
-    opacity: 1;
     pointer-events: auto;
     pointer-events: auto;
+    opacity: 1;
   }
   }
 }
 }
 
 
-div#advanced-search-content {
-  &.collapsing {
-    transition: height 0.1s ease-in-out;
-  }
-  div.card div.card-body div.col:not(:last-child) {
-    margin-right: 1rem;
-  }
+div#advanced-search-content div.card div.card-body div.col:not(:last-child) {
+  margin-right: 1rem;
 }
 }
 
 
-body {
-  background-color: var(--nbx-body-bg);
-  color: var(--nbx-body-color);
-  g#netbox-logo-1 {
-    fill: #9cc8f8;
-    stroke: #9cc8f8;
-  }
-
-  g#netbox-logo-2 {
-    fill: #1685fc;
-    stroke: #1685fc;
-  }
-
-  &[data-netbox-color-mode='light'] {
-    .btn.btn-primary,
-    .progress-bar.bg-primary,
-    .badge.bg-primary,
-    .nav.nav-pills .nav-item.nav-link.active,
-    .nav.nav-pills .nav-item .nav-link.active,
-    .nav.nav-pills .nav-item .show > .nav-link {
-      color: $gray-100;
+table {
+  a {
+    text-decoration: none;
+    &:hover {
+      text-decoration: underline;
     }
     }
   }
   }
-  &[data-netbox-color-mode='dark'] {
-    & {
-      .btn.btn-primary,
-      .progress-bar.bg-primary,
-      .badge.bg-primary,
-      .nav.nav-pills .nav-item.nav-link.active,
-      .nav.nav-pills .nav-item .nav-link.active,
-      .nav.nav-pills .nav-item .show > .nav-link {
-        color: $black;
-      }
-    }
-    .card table caption {
-      color: $gray-300;
+  &.table > :not(caption) > * > * {
+    padding-right: $table-cell-padding-x-sm !important;
+    padding-left: $table-cell-padding-x-sm !important;
+  }
+  td,
+  th {
+    font-size: $font-size-sm;
+    line-height: $line-height-sm;
+    vertical-align: middle;
+    &.min-width {
+      width: 1%;
     }
     }
-    .breadcrumb .breadcrumb-item > a {
-      color: $blue-200;
-      &:hover {
-        color: $blue-100;
-      }
+    .form-check-input {
+      // Ensure checkboxes aren't too small inside object tables.
+      margin-top: 0.125em;
+      font-size: $font-size-base;
     }
     }
 
 
-    .card,
-    .sidebar {
-      .text-muted {
-        color: $gray-400 !important;
-      }
-    }
-    .text-body[class] {
-      color: var(--nbx-body-color) !important;
-    }
-    g#netbox-logo-1 {
-      fill: $white;
-      stroke: $white;
+    .btn-sm {
+      line-height: $line-height-xs;
     }
     }
 
 
-    g#netbox-logo-2 {
-      fill: $gray-200;
-      stroke: $gray-200;
+    p {
+      // Remove spacing from paragraph elements within tables.
+      margin-bottom: 0;
     }
     }
   }
   }
-  & table,
-  &[data-netbox-color-mode] table {
-    a {
-      text-decoration: none;
-      &:hover {
-        text-decoration: underline;
-      }
-    }
-    &.table > :not(caption) > * > * {
-      padding-left: $table-cell-padding-x-sm !important;
-      padding-right: $table-cell-padding-x-sm !important;
-    }
-    td,
+
+  &.object-list {
     th {
     th {
-      font-size: $font-size-sm;
-      line-height: $line-height-sm;
-      vertical-align: middle;
-      &.min-width {
-        width: 1%;
-      }
-      & input.form-check-input {
-        // Ensure checkboxes aren't too small inside object tables.
-        font-size: $font-size-base;
-        margin-top: 0.125em;
-      }
-      & .btn-sm {
-        line-height: $line-height-xs;
-      }
+      font-size: $font-size-xs;
+      line-height: $line-height-xs;
+      vertical-align: bottom;
     }
     }
-    &.object-list {
-      th {
-        font-size: $font-size-xs;
-        line-height: $line-height-xs;
-        vertical-align: bottom;
-      }
-    }
-    &.attr-table {
-      th {
-        width: 25%;
-      }
+  }
+
+  &.attr-table {
+    th {
+      width: 25%;
     }
     }
   }
   }
 }
 }
 
 
 div.title-container {
 div.title-container {
   display: flex;
   display: flex;
-  justify-content: space-between;
   flex-wrap: wrap;
   flex-wrap: wrap;
+  justify-content: space-between;
 
 
-  div#content-title {
+  #content-title {
     display: flex;
     display: flex;
-    flex-direction: column;
     flex: 1 0 auto;
     flex: 1 0 auto;
+    flex-direction: column;
     padding-bottom: map.get($spacers, 2);
     padding-bottom: map.get($spacers, 2);
   }
   }
 }
 }
 
 
 nav.search {
 nav.search {
-  background-color: var(--nbx-body-bg);
   // Don't overtake dropdowns
   // Don't overtake dropdowns
   z-index: 999;
   z-index: 999;
   justify-content: center;
   justify-content: center;
+  background-color: var(--nbx-body-bg);
+
   form button.dropdown-toggle {
   form button.dropdown-toggle {
-    border-color: $input-border-color;
     font-weight: $input-group-addon-font-weight;
     font-weight: $input-group-addon-font-weight;
     line-height: $input-line-height;
     line-height: $input-line-height;
     color: $input-group-addon-color;
     color: $input-group-addon-color;
     background-color: $input-group-addon-bg;
     background-color: $input-group-addon-bg;
     border: $input-border-width solid $input-group-addon-border-color;
     border: $input-border-width solid $input-group-addon-border-color;
+    border-color: $input-border-color;
     @include border-radius($input-border-radius);
     @include border-radius($input-border-radius);
     border-left: 1px solid var(--nbx-search-filter-border-left-color);
     border-left: 1px solid var(--nbx-search-filter-border-left-color);
+
     &:focus {
     &:focus {
       box-shadow: unset !important;
       box-shadow: unset !important;
     }
     }
@@ -463,16 +299,16 @@ main.layout {
 
 
 main.login-container {
 main.login-container {
   display: flex;
   display: flex;
-  height: calc(100vh - 4rem);
-  width: 100%;
-  max-width: 100vw;
+  flex-direction: column;
   align-items: center;
   align-items: center;
   justify-content: center;
   justify-content: center;
-  flex-direction: column;
+  width: 100%;
+  max-width: 100vw;
+  height: calc(100vh - 4rem);
   padding-top: 40px;
   padding-top: 40px;
   padding-bottom: 40px;
   padding-bottom: 40px;
 
 
-  & + footer.footer button.color-mode-toggle {
+  + footer.footer button.color-mode-toggle {
     color: var(--nbx-color-mode-toggle-color);
     color: var(--nbx-color-mode-toggle-color);
   }
   }
 }
 }
@@ -500,24 +336,6 @@ footer.login-footer {
   }
   }
 }
 }
 
 
-h1 {
-  font-weight: $font-weight-bolder;
-}
-
-h2 {
-  font-weight: $font-weight-bold;
-}
-
-h3,
-h4 {
-  font-weight: $font-weight-medium;
-}
-
-h5,
-h6 {
-  font-weight: $font-weight-medium;
-}
-
 h1.accordion-item-title,
 h1.accordion-item-title,
 h2.accordion-item-title,
 h2.accordion-item-title,
 h3.accordion-item-title,
 h3.accordion-item-title,
@@ -525,54 +343,39 @@ h4.accordion-item-title,
 h5.accordion-item-title,
 h5.accordion-item-title,
 h6.accordion-item-title {
 h6.accordion-item-title {
   padding: 0.25rem 0.5rem;
   padding: 0.25rem 0.5rem;
+  font-size: $font-size-sm;
   font-weight: $font-weight-bold;
   font-weight: $font-weight-bold;
-  text-transform: uppercase;
   color: var(--nbx-sidebar-title-color);
   color: var(--nbx-sidebar-title-color);
-  font-size: $font-size-sm;
+  text-transform: uppercase;
 }
 }
 
 
 .form-login {
 .form-login {
   width: 100%;
   width: 100%;
   max-width: 330px;
   max-width: 330px;
   padding: 15px;
   padding: 15px;
-  & input:focus {
+
+  input:focus {
     z-index: 1;
     z-index: 1;
   }
   }
-}
-
-.form-login input[type='text'] {
-  margin-bottom: -1px;
-  border-bottom-left-radius: 0;
-  border-bottom-right-radius: 0;
-}
-
-.form-login input[type='password'] {
-  margin-bottom: 10px;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-
-.form-login .form-control {
-  position: relative;
-  box-sizing: border-box;
-  height: auto;
-  padding: 10px;
-  font-size: 16px;
-}
 
 
-li.dropdown-item.dropdown-item-btns {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
+  input[type='text'] {
+    margin-bottom: -1px;
+    border-bottom-right-radius: 0;
+    border-bottom-left-radius: 0;
+  }
+  input[type='password'] {
+    margin-bottom: 10px;
+    border-top-left-radius: 0;
+    border-top-right-radius: 0;
+  }
 
 
-.sidebar-sticky {
-  position: relative;
-  top: 0;
-  height: calc(100vh - 48px);
-  padding-top: 0.5rem;
-  overflow-x: hidden;
-  overflow-y: auto; // Scrollable contents if viewport is shorter than content.
+  .form-control {
+    position: relative;
+    box-sizing: border-box;
+    height: auto;
+    padding: 10px;
+    font-size: 16px;
+  }
 }
 }
 
 
 .navbar-brand {
 .navbar-brand {
@@ -586,9 +389,10 @@ nav.nav.nav-pills {
     padding: 0.25rem 0.5rem;
     padding: 0.25rem 0.5rem;
     font-size: $font-size-sm;
     font-size: $font-size-sm;
     border-radius: $border-radius;
     border-radius: $border-radius;
+
     &:hover {
     &:hover {
-      background-color: $accordion-button-active-bg;
       color: $accordion-button-active-color;
       color: $accordion-button-active-color;
+      background-color: $accordion-button-active-bg;
     }
     }
   }
   }
 }
 }
@@ -597,10 +401,10 @@ nav.nav.nav-pills {
 // that the footer is always at the bottom.
 // that the footer is always at the bottom.
 div.content-container {
 div.content-container {
   position: relative;
   position: relative;
-  min-height: 100vh;
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
   width: calc(100% - 4.5rem);
   width: calc(100% - 4.5rem);
+  min-height: 100vh;
   overflow-x: hidden;
   overflow-x: hidden;
   overflow-y: auto;
   overflow-y: auto;
 
 
@@ -623,146 +427,35 @@ div.content-container {
   }
   }
 }
 }
 
 
-.sidebar {
-  position: fixed;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 100; // Behind the navbar
-  border-right: 1px solid $border-color;
-  background-color: var(--nbx-sidebar-bg);
-  max-height: 100%;
-  width: 100%;
-
-  @include media-breakpoint-up(md) {
-    width: 100%;
-    max-width: $sidebar-width;
-  }
-
-  @include media-breakpoint-down(md) {
-    top: 8.125rem;
-    background-color: var(--nbx-body-bg);
-  }
-
-  div.accordion-item {
-    border: unset;
-    padding: 0 $spacer / 2;
-
-    // When an sidenav section is open, apply a shadow to provide a visual border.
-    &.is-open {
-      box-shadow: var(--nbx-sidebar-shadow);
-    }
-
-    & > a.accordion-button {
-      &:not(.collapsed) {
-        box-shadow: unset;
-      }
-      &.nav-link {
-        border-radius: $border-radius;
-        &:hover {
-          color: $accordion-button-active-color;
-          background-color: $accordion-button-active-bg;
-        }
-        &:focus {
-          border-color: unset;
-          box-shadow: unset;
-        }
-      }
-    }
-  }
-
-  .accordion-body {
-    max-height: calc(100vh - 24rem);
-    overflow-y: auto;
-    .nav-item {
-      .nav-link {
-        padding: 0.25rem 0.6rem;
-        font-size: $font-size-sm;
-        border-radius: $border-radius;
-        &:hover {
-          color: $accordion-button-active-color;
-          background-color: $accordion-button-active-bg;
-        }
-      }
-    }
-  }
-  // Ensure navigation accounts for the height of the header on mobile when nav is expanded.
-  &.collapse.show div.position-sticky {
-    @media (max-width: map.get($grid-breakpoints, 'md')) {
-      height: calc(100vh - 16.125rem);
-      overflow-y: auto;
-    }
-  }
-  div.position-sticky {
-    height: calc(100vh - #{$sidebar-bottom-height});
-  }
-  div.sidebar-bottom {
-    padding-left: 0.5rem;
-    padding-right: 0.5rem;
-    position: sticky;
-    height: $sidebar-bottom-height;
-    background-color: var(--nbx-sidebar-bg);
-
-    @include media-breakpoint-down(md) {
-      background-color: var(--nbx-body-bg);
-    }
-    .nav {
-      padding: 0 0.5rem;
-      justify-content: space-between;
-      margin: $spacer/2 0;
-
-      .nav-link {
-        padding: 0.5rem 0.25rem;
-      }
-    }
-  }
-  a.sidebar-logo {
-    display: flex;
-    flex-shrink: 1;
-    width: 100%;
-    height: 3rem;
-  }
-}
-
 .tooltip {
 .tooltip {
   pointer-events: none;
   pointer-events: none;
 }
 }
 
 
-.ws-nowrap {
-  white-space: nowrap !important;
-}
-
 .search-obj-selector {
 .search-obj-selector {
   @include media-breakpoint-down(lg) {
   @include media-breakpoint-down(lg) {
     // Limit the height and enable scrolling on mobile devices.
     // Limit the height and enable scrolling on mobile devices.
     max-height: 75vh;
     max-height: 75vh;
     overflow-y: auto;
     overflow-y: auto;
   }
   }
+
   .dropdown-item,
   .dropdown-item,
   .dropdown-header {
   .dropdown-header {
     font-size: $font-size-sm;
     font-size: $font-size-sm;
   }
   }
+
   .dropdown-header {
   .dropdown-header {
     text-transform: uppercase;
     text-transform: uppercase;
   }
   }
 }
 }
 
 
 span.color-label {
 span.color-label {
+  display: block;
   width: 5rem;
   width: 5rem;
   height: 1rem;
   height: 1rem;
-  display: block;
-  box-shadow: $box-shadow-sm;
-  border: 1px solid #303030;
-  border-radius: $border-radius;
   padding: $badge-padding-y $badge-padding-x;
   padding: $badge-padding-y $badge-padding-x;
-}
-
-pre {
+  border: 1px solid #303030;
   border-radius: $border-radius;
   border-radius: $border-radius;
-  border: 1px solid var(--nbx-pre-border-color);
-  background-color: var(--nbx-pre-bg);
-  padding: $spacer;
-  white-space: pre;
+  box-shadow: $box-shadow-sm;
 }
 }
 
 
 .btn {
 .btn {
@@ -771,11 +464,13 @@ pre {
 
 
 .card {
 .card {
   box-shadow: $box-shadow-sm;
   box-shadow: $box-shadow-sm;
+
   .card-header {
   .card-header {
+    padding: $card-cap-padding-x;
     color: $body-color;
     color: $body-color;
     border-bottom: none;
     border-bottom: none;
-    padding: $card-cap-padding-x;
   }
   }
+
   .card-header + .card-body {
   .card-header + .card-body {
     padding-top: 0;
     padding-top: 0;
   }
   }
@@ -847,9 +542,9 @@ pre {
   // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
   // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
   > .input-group > .form-control:-webkit-autofill {
   > .input-group > .form-control:-webkit-autofill {
     ~ label {
     ~ label {
+      z-index: 4;
       opacity: $form-floating-label-opacity;
       opacity: $form-floating-label-opacity;
       transform: $form-floating-label-transform;
       transform: $form-floating-label-transform;
-      z-index: 4;
     }
     }
   }
   }
 }
 }
@@ -866,10 +561,6 @@ textarea.form-control[name='data'] {
   font-family: $font-family-monospace;
   font-family: $font-family-monospace;
 }
 }
 
 
-table tr.vertical-align {
-  vertical-align: middle;
-}
-
 .card:not(:only-of-type) {
 .card:not(:only-of-type) {
   margin-bottom: $spacer;
   margin-bottom: $spacer;
 }
 }
@@ -879,9 +570,9 @@ table tr.vertical-align {
 }
 }
 
 
 nav.breadcrumb-container {
 nav.breadcrumb-container {
+  width: fit-content;
   padding: $badge-padding-y $badge-padding-x;
   padding: $badge-padding-y $badge-padding-x;
   font-size: $font-size-sm;
   font-size: $font-size-sm;
-  width: fit-content;
 
 
   ol.breadcrumb {
   ol.breadcrumb {
     margin-bottom: 0;
     margin-bottom: 0;
@@ -913,16 +604,17 @@ div.field-group:not(:first-of-type) {
 
 
 label.required {
 label.required {
   font-weight: $font-weight-bold;
   font-weight: $font-weight-bold;
+
   &:after {
   &:after {
+    position: absolute;
+    display: inline-block;
+    margin: 0 0 0 2px;
     font-family: 'Material Design Icons';
     font-family: 'Material Design Icons';
-    content: '\f06C4';
-    font-weight: normal;
     font-size: 8px;
     font-size: 8px;
     font-style: normal;
     font-style: normal;
-    margin: 0 0 0 2px;
+    font-weight: $font-weight-medium;
     text-decoration: none;
     text-decoration: none;
-    display: inline-block;
-    position: absolute;
+    content: '\f06C4';
   }
   }
 }
 }
 
 
@@ -966,11 +658,6 @@ div.bulk-buttons {
   }
   }
 }
 }
 
 
-i.bi-plus:before,
-span.bi-plus:before {
-  font-weight: $font-weight-bold !important;
-}
-
 table tbody {
 table tbody {
   @each $color, $value in $theme-colors {
   @each $color, $value in $theme-colors {
     tr.#{$color} {
     tr.#{$color} {
@@ -981,15 +668,18 @@ table tbody {
 }
 }
 
 
 pre.change-data {
 pre.change-data {
-  padding-left: 0;
   padding-right: 0;
   padding-right: 0;
-  & > span {
+  padding-left: 0;
+
+  > span {
     display: block;
     display: block;
-    padding-left: $spacer;
     padding-right: $spacer;
     padding-right: $spacer;
+    padding-left: $spacer;
+
     &.added {
     &.added {
       background-color: var(--nbx-change-added);
       background-color: var(--nbx-change-added);
     }
     }
+
     &.removed {
     &.removed {
       background-color: var(--nbx-change-removed);
       background-color: var(--nbx-change-removed);
     }
     }
@@ -998,9 +688,11 @@ pre.change-data {
 
 
 pre.change-diff {
 pre.change-diff {
   border-color: transparent;
   border-color: transparent;
+
   &.change-removed {
   &.change-removed {
     background-color: var(--nbx-change-removed);
     background-color: var(--nbx-change-removed);
   }
   }
+
   &.change-added {
   &.change-added {
     background-color: var(--nbx-change-added);
     background-color: var(--nbx-change-added);
   }
   }
@@ -1008,14 +700,15 @@ pre.change-diff {
 
 
 div.card-overlay {
 div.card-overlay {
   position: absolute;
   position: absolute;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   width: 100%;
   width: 100%;
   height: 100%;
   height: 100%;
   background-color: rgba($white, 0.75);
   background-color: rgba($white, 0.75);
   border-radius: $border-radius;
   border-radius: $border-radius;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  & > div.spinner-border {
+
+  > div.spinner-border {
     width: 6rem;
     width: 6rem;
     height: 6rem;
     height: 6rem;
     color: $secondary;
     color: $secondary;
@@ -1023,11 +716,12 @@ div.card-overlay {
 }
 }
 
 
 div.card > div.card-header > div.table-controls {
 div.card > div.card-header > div.table-controls {
-  max-width: 25%;
-  width: 100%;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
-  & .form-switch.form-check-inline {
+  width: 100%;
+  max-width: 25%;
+
+  .form-switch.form-check-inline {
     flex: 1 0 auto;
     flex: 1 0 auto;
     font-size: $font-size-sm;
     font-size: $font-size-sm;
   }
   }

+ 53 - 0
netbox/project-static/styles/overrides.scss

@@ -0,0 +1,53 @@
+// Overrides to native HTML elements (i.e., not bootstrap classes or custom components).
+
+* {
+  transition: background-color, color 0.1s ease-in-out;
+}
+
+body {
+  color: var(--nbx-body-color);
+  background-color: var(--nbx-body-bg);
+}
+
+pre {
+  padding: $spacer;
+  white-space: pre;
+  background-color: var(--nbx-pre-bg);
+  border: 1px solid var(--nbx-pre-border-color);
+  border-radius: $border-radius;
+}
+
+// Force <small/> elements to make text smaller.
+small {
+  font-size: smaller !important;
+}
+
+h1 {
+  font-weight: $font-weight-bolder;
+}
+
+h2 {
+  font-weight: $font-weight-bold;
+}
+
+h3,
+h4 {
+  font-weight: $font-weight-medium;
+}
+
+h5,
+h6 {
+  font-weight: $font-weight-medium;
+}
+
+// Fix the hideous way Safari shows button anchor elements.
+a[type='button'] {
+  -webkit-appearance: unset !important;
+}
+
+// Ensure elements with data-href set show the correct cursor.
+// data-href is set on non non-anchor elements that need to redirect the user to a URL when
+// clicked, but where an anchor element does not suffice or is not supported.
+*[data-href] {
+  cursor: pointer;
+}

+ 13 - 13
netbox/project-static/styles/select.scss

@@ -32,7 +32,7 @@ $spacing-s: $input-padding-x;
   }
   }
 }
 }
 
 
-@import './node_modules/slim-select/src/slim-select/slimselect.scss';
+@import './node_modules/slim-select/src/slim-select/slimselect';
 
 
 .ss-main {
 .ss-main {
   color: $form-select-color;
   color: $form-select-color;
@@ -50,6 +50,8 @@ $spacing-s: $input-padding-x;
   .ss-single-selected,
   .ss-single-selected,
   .ss-multi-selected {
   .ss-multi-selected {
     padding: $form-select-padding-y $input-padding-x $form-select-padding-y $form-select-padding-x;
     padding: $form-select-padding-y $input-padding-x $form-select-padding-y $form-select-padding-x;
+    background-color: $form-select-bg;
+    border: $form-select-border-width solid $input-border-color;
     &[disabled] {
     &[disabled] {
       color: $form-select-disabled-color;
       color: $form-select-disabled-color;
       background-color: $form-select-disabled-bg;
       background-color: $form-select-disabled-bg;
@@ -63,7 +65,6 @@ $spacing-s: $input-padding-x;
   }
   }
 
 
   .ss-single-selected {
   .ss-single-selected {
-    background-color: $form-select-bg;
     span.ss-arrow {
     span.ss-arrow {
       // Inherit the arrow color from the parent (see color selector).
       // Inherit the arrow color from the parent (see color selector).
       span.arrow-down,
       span.arrow-down,
@@ -83,17 +84,16 @@ $spacing-s: $input-padding-x;
 
 
   .ss-multi-selected {
   .ss-multi-selected {
     align-items: center;
     align-items: center;
-    padding-left: $input-padding-x;
     padding-right: $input-padding-x;
     padding-right: $input-padding-x;
-    background-color: $form-select-bg;
+    padding-left: $input-padding-x;
 
 
     .ss-values {
     .ss-values {
       .ss-disabled {
       .ss-disabled {
-        padding: 4px 0px;
+        padding: 4px 0;
       }
       }
       .ss-value {
       .ss-value {
-        border-radius: $badge-border-radius;
         color: var(--nbx-select-value-color);
         color: var(--nbx-select-value-color);
+        border-radius: $badge-border-radius;
 
 
         // Don't show the depth indicator outside of the menu.
         // Don't show the depth indicator outside of the menu.
         .depth {
         .depth {
@@ -111,18 +111,18 @@ $spacing-s: $input-padding-x;
     .ss-list {
     .ss-list {
       .ss-option {
       .ss-option {
         &.ss-option-selected {
         &.ss-option-selected {
-          background-color: var(--nbx-select-option-selected-bg);
           color: $body-color;
           color: $body-color;
+          background-color: var(--nbx-select-option-selected-bg);
         }
         }
 
 
         &:hover {
         &:hover {
-          background-color: var(--nbx-select-option-hover-bg);
           color: var(--nbx-select-option-hover-color);
           color: var(--nbx-select-option-hover-color);
+          background-color: var(--nbx-select-option-hover-bg);
         }
         }
 
 
         &:last-child {
         &:last-child {
-          border-bottom-left-radius: $form-select-border-radius;
           border-bottom-right-radius: $form-select-border-radius;
           border-bottom-right-radius: $form-select-border-radius;
+          border-bottom-left-radius: $form-select-border-radius;
         }
         }
 
 
         &.ss-disabled {
         &.ss-disabled {
@@ -138,6 +138,7 @@ $spacing-s: $input-padding-x;
           opacity: 0.3;
           opacity: 0.3;
         }
         }
       }
       }
+
       &::-webkit-scrollbar {
       &::-webkit-scrollbar {
         right: 0;
         right: 0;
         width: 4px;
         width: 4px;
@@ -156,9 +157,8 @@ $spacing-s: $input-padding-x;
         background-color: var(--nbx-sidebar-scroll);
         background-color: var(--nbx-sidebar-scroll);
       }
       }
     }
     }
-    border-bottom-left-radius: $form-select-border-radius;
     border-bottom-right-radius: $form-select-border-radius;
     border-bottom-right-radius: $form-select-border-radius;
-
+    border-bottom-left-radius: $form-select-border-radius;
     .ss-search {
     .ss-search {
       padding-right: $spacer * 0.5;
       padding-right: $spacer * 0.5;
 
 
@@ -167,9 +167,9 @@ $spacing-s: $input-padding-x;
       }
       }
 
 
       input[type='search'] {
       input[type='search'] {
-        background-color: $form-select-bg;
         color: $input-color;
         color: $input-color;
-        border: $form-select-border-width solid $form-select-border-color;
+        background-color: $form-select-bg;
+        border: $input-border-width solid $input-border-color;
         &:focus {
         &:focus {
           border-color: $form-select-focus-border-color;
           border-color: $form-select-focus-border-color;
           outline: 0;
           outline: 0;

+ 15 - 5
netbox/project-static/styles/sidenav.scss

@@ -169,6 +169,11 @@
     align-items: center;
     align-items: center;
     justify-content: space-between;
     justify-content: space-between;
     width: 100%;
     width: 100%;
+
+    &.no-buttons {
+      // When there are no buttons, don't extend to the full width of the sidenav.
+      padding-right: $spacer * 5;
+    }
   }
   }
 
 
   @include child-link() {
   @include child-link() {
@@ -407,12 +412,17 @@
   width: 6px;
   width: 6px;
   background-color: transparent;
   background-color: transparent;
 
 
-  .simplebar-scrollbar:before {
-    right: 0;
-    width: 3px;
-    background: var(--nbx-sidebar-scroll);
-    border-radius: $border-radius;
+  .simplebar-scrollbar {
+    transition: none;
+
+    &:before {
+      right: 0;
+      width: 3px;
+      background: var(--nbx-sidebar-scroll);
+      border-radius: $border-radius;
+    }
   }
   }
+
   &.simplebar-hover .simplebar-scrollbar:before {
   &.simplebar-hover .simplebar-scrollbar:before {
     width: 5px;
     width: 5px;
   }
   }

+ 25 - 0
netbox/project-static/styles/utilities.scss

@@ -0,0 +1,25 @@
+// Custom Utility classes.
+
+// Utility class for extra-small text.
+.text-xs {
+  font-size: $font-size-xs !important;
+  line-height: $line-height-sm !important;
+}
+
+// Add a border color that mimics the appearance of a form element.
+.border-input {
+  border: $input-border-width solid $input-border-color !important;
+}
+
+// Force no line wrapping.
+.ws-nowrap {
+  white-space: nowrap !important;
+}
+
+// Vertically align table rows/cells.
+table tr,
+table td {
+  .vertical-align {
+    vertical-align: middle;
+  }
+}

+ 51 - 0
netbox/project-static/styles/variables.scss

@@ -0,0 +1,51 @@
+// NetBox CSS Variables
+
+:root {
+  // Light Mode Variables.
+  --nbx-sidebar-bg: #{$gray-200};
+  --nbx-sidebar-scroll: #{$gray-500};
+  --nbx-sidebar-link-color: #{$gray-800};
+  --nbx-sidebar-link-hover-bg: #{$blue-100};
+  --nbx-sidebar-title-color: #{$text-muted};
+  --nbx-sidebar-shadow: inset 0px -25px 20px -25px rgba(0, 0, 0, 0.25);
+  --nbx-breadcrumb-bg: #{$light};
+  --nbx-body-bg: #{$white};
+  --nbx-body-color: #{$gray-800};
+  --nbx-pre-bg: #{$gray-100};
+  --nbx-pre-border-color: #{$gray-600};
+  --nbx-change-added: #{rgba($green, 0.4)};
+  --nbx-change-removed: #{rgba($red, 0.4)};
+  --nbx-cable-node-bg: #{$gray-100};
+  --nbx-cable-node-border-color: #{$gray-200};
+  --nbx-cable-termination-bg: #{$gray-200};
+  --nbx-cable-termination-border-color: #{$gray-300};
+  --nbx-search-filter-border-left-color: #{$gray-300};
+  --nbx-color-mode-toggle-color: #{$primary};
+  --nbx-sidenav-pin-color: #{$orange};
+  --nbx-sidenav-parent-color: #{$gray-900};
+
+  &[data-netbox-color-mode='dark'] {
+    // Dark Mode Variables.
+    --nbx-sidebar-bg: #{$gray-900};
+    --nbx-sidebar-scroll: #{$gray-700};
+    --nbx-sidebar-link-color: #{$gray-100};
+    --nbx-sidebar-link-hover-bg: #{rgba($blue-300, 0.15)};
+    --nbx-sidebar-title-color: #{$gray-600};
+    --nbx-sidebar-shadow: inset 0px -25px 20px -25px rgba(255, 255, 255, 0.05);
+    --nbx-breadcrumb-bg: #{$gray-800};
+    --nbx-body-bg: #{$darker};
+    --nbx-body-color: #{$gray-100};
+    --nbx-pre-bg: #{$gray-700};
+    --nbx-pre-border-color: #{$gray-600};
+    --nbx-change-added: #{rgba($green-300, 0.4)};
+    --nbx-change-removed: #{rgba($red-300, 0.4)};
+    --nbx-cable-node-bg: #{$gray-700};
+    --nbx-cable-node-border-color: #{$gray-600};
+    --nbx-cable-termination-bg: #{$gray-800};
+    --nbx-cable-termination-border-color: #{$gray-700};
+    --nbx-search-filter-border-left-color: #{$gray-600};
+    --nbx-color-mode-toggle-color: #{$yellow-300};
+    --nbx-sidenav-pin-color: #{$yellow};
+    --nbx-sidenav-parent-color: #{$gray-100};
+  }
+}

+ 1 - 1
netbox/templates/login.html

@@ -8,7 +8,7 @@
 
 
     {# Login banner #}
     {# Login banner #}
     {% if settings.BANNER_LOGIN %}
     {% if settings.BANNER_LOGIN %}
-      <div class="alert alert-secondary" role="alert">
+      <div class="alert alert-secondary mw-90 mw-md-75 mw-lg-80 mw-xl-75 mw-xxl-50" role="alert">
         {{ settings.BANNER_LOGIN|safe }}
         {{ settings.BANNER_LOGIN|safe }}
       </div>
       </div>
     {% endif %}
     {% endif %}

+ 3 - 3
netbox/templates/utilities/render_field.html

@@ -47,8 +47,8 @@
         <div class="col">
         <div class="col">
             <div class="input-group">
             <div class="input-group">
                 {{ field }}
                 {{ field }}
-                <button id="reslug" type="button" title="Regenerate Slug" class="btn btn-outline-dark">
-                    <i class="mdi mdi-undo-variant"></i>
+                <button id="reslug" type="button" title="Regenerate Slug" class="btn btn-outline-dark border-input">
+                    <i class="mdi mdi-reload"></i>
                 </button>
                 </button>
             </div>
             </div>
         </div>
         </div>
@@ -63,7 +63,7 @@
         <div class="col">
         <div class="col">
             <div class="input-group">
             <div class="input-group">
                 {{ field }}
                 {{ field }}
-                <button type="button" class="btn btn-outline-dark dropdown-toggle" data-bs-toggle="dropdown"></button>
+                <button type="button" class="btn btn-outline-dark border-input dropdown-toggle" data-bs-toggle="dropdown"></button>
                 <ul class="dropdown-menu dropdown-menu-end">
                 <ul class="dropdown-menu dropdown-menu-end">
                     <li><a href="#" target="{{ field.id_for_label }}" data="10000" class="set_speed dropdown-item">10 Mbps</a></li>
                     <li><a href="#" target="{{ field.id_for_label }}" data="10000" class="set_speed dropdown-item">10 Mbps</a></li>
                     <li><a href="#" target="{{ field.id_for_label }}" data="100000" class="set_speed dropdown-item">100 Mbps</a></li>
                     <li><a href="#" target="{{ field.id_for_label }}" data="100000" class="set_speed dropdown-item">100 Mbps</a></li>

+ 3 - 3
netbox/utilities/templates/navigation/nav_items.html

@@ -18,15 +18,15 @@
                                     <span class="nav-group-label">{{ group.label }}</span>
                                     <span class="nav-group-label">{{ group.label }}</span>
                                 </div>
                                 </div>
                             </li>
                             </li>
-                        
+
                         {% for item in group.items %}
                         {% for item in group.items %}
                             {# Each Item #}
                             {# Each Item #}
                             {% if request.user|has_perms:item.permissions %}
                             {% if request.user|has_perms:item.permissions %}
-                            <li class="nav-item">
+                            <li class="nav-item{% if not item.buttons %} no-buttons{% endif %}">
                                 <a href="{% url item.link %}" class="nav-link">
                                 <a href="{% url item.link %}" class="nav-link">
                                     <span class="sidenav-normal">{{ item.link_text }}</span>
                                     <span class="sidenav-normal">{{ item.link_text }}</span>
                                 </a>
                                 </a>
-                                
+
                                 {# Menu item buttons (if any) #}
                                 {# Menu item buttons (if any) #}
                                 {% if item.buttons %}
                                 {% if item.buttons %}
                                     <div class="btn-group px-2">
                                     <div class="btn-group px-2">

Некоторые файлы не были показаны из-за большого количества измененных файлов