Repository: netbox-community/netbox

Issue:
Show full 100% utilization bar in a different color from 99.9%
### NetBox version

v3.1.4

### Feature type

Change to existing functionality

### Proposed functionality

I propose when utilization is full, i.e. there is nothing free left, the utilization bar would not show the same red as it shows for 90% or 99.9%.  
Instead it could show a (slightly) different color, say brighter/darker red or purple.

### Use case

Make it easy for human operator to distinguish from the utilization bar whether utilization is totally full 100%, or not totally full <100%.

Currently the operator cannot just scan the list of utilization bars for whether something is 100% full or almost full because the bar has the same color and may display too similar bar length for 99%/99.9% and 100%.

100% is a slightly special case since there is nothing free left inside, so indicate that to the operator for spotting it easily.

### Database changes

None.

### External dependencies

None.


Discussion:
The `utilization_graph` tag used to render these graphs currently supports warning (yellow) and danger (red) thresholds; these default to 75 and 90, respectively. It should be simple to extend this to include a special style/color for 100 values, although we might also need to look into rounding (e.g. 99.99% not being the same as 100%).
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Please see our [contributing guide](https://github.com/netbox-community/netbox/blob/develop/CONTRIBUTING.md).

Resolving patch:
diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py
--- a/netbox/dcim/models/racks.py
+++ b/netbox/dcim/models/racks.py
@@ -412,7 +412,7 @@ def get_utilization(self):
                 available_units.remove(u)
 
         occupied_unit_count = self.u_height - len(available_units)
-        percentage = int(float(occupied_unit_count) / self.u_height * 100)
+        percentage = float(occupied_unit_count) / self.u_height * 100
 
         return percentage
 
diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py
--- a/netbox/ipam/models/ip.py
+++ b/netbox/ipam/models/ip.py
@@ -248,7 +248,7 @@ def get_utilization(self):
         """
         queryset = Prefix.objects.filter(prefix__net_contained_or_equal=str(self.prefix))
         child_prefixes = netaddr.IPSet([p.prefix for p in queryset])
-        utilization = int(float(child_prefixes.size) / self.prefix.size * 100)
+        utilization = float(child_prefixes.size) / self.prefix.size * 100
 
         return min(utilization, 100)
 
@@ -548,7 +548,7 @@ def get_utilization(self):
                 vrf=self.vrf
             )
             child_prefixes = netaddr.IPSet([p.prefix for p in queryset])
-            utilization = int(float(child_prefixes.size) / self.prefix.size * 100)
+            utilization = float(child_prefixes.size) / self.prefix.size * 100
         else:
             # Compile an IPSet to avoid counting duplicate IPs
             child_ips = netaddr.IPSet(
@@ -558,7 +558,7 @@ def get_utilization(self):
             prefix_size = self.prefix.size
             if self.prefix.version == 4 and self.prefix.prefixlen < 31 and not self.is_pool:
                 prefix_size -= 2
-            utilization = int(float(child_ips.size) / prefix_size * 100)
+            utilization = float(child_ips.size) / prefix_size * 100
 
         return min(utilization, 100)
 
diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py
--- a/netbox/utilities/templatetags/helpers.py
+++ b/netbox/utilities/templatetags/helpers.py
@@ -389,7 +389,9 @@ def utilization_graph(utilization, warning_threshold=75, danger_threshold=90):
     """
     Display a horizontal bar graph indicating a percentage of utilization.
     """
-    if danger_threshold and utilization >= danger_threshold:
+    if utilization == 100:
+        bar_class = 'bg-secondary'
+    elif danger_threshold and utilization >= danger_threshold:
         bar_class = 'bg-danger'
     elif warning_threshold and utilization >= warning_threshold:
         bar_class = 'bg-warning'


Test patch: