Skip to content

Commit e51768a

Browse files
committed
feat: feat: Add colorization based on health level for panels and toolbar
1 parent 2321b88 commit e51768a

File tree

8 files changed

+88
-5
lines changed

8 files changed

+88
-5
lines changed

debug_toolbar/panels/__init__.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.utils.functional import classproperty
44

55
from debug_toolbar import settings as dt_settings
6-
from debug_toolbar.utils import get_name_from_obj
6+
from debug_toolbar.utils import ToolbarHealthLevel, get_name_from_obj
77

88

99
class Panel:
@@ -129,6 +129,19 @@ def scripts(self):
129129
"""
130130
return []
131131

132+
@property
133+
def health_level(self):
134+
"""
135+
Returns the health level of the panel as a `ToolbarHealthLevel` enum value.
136+
137+
This property is used by the toolbar to determine the overall health status of each panel.
138+
The default implementation returns `ToolbarHealthLevel.NONE`, indicating no issues.
139+
140+
Subclasses should override this property to provide custom health logic, returning
141+
`ToolbarHealthLevel.WARNING` or `ToolbarHealthLevel.ERROR` as appropriate based on panel-specific conditions.
142+
"""
143+
return ToolbarHealthLevel.NONE
144+
132145
# Panel early initialization
133146

134147
@classmethod

debug_toolbar/panels/alerts.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.utils.translation import gettext_lazy as _
44

55
from debug_toolbar.panels import Panel
6-
from debug_toolbar.utils import is_processable_html_response
6+
from debug_toolbar.utils import ToolbarHealthLevel, is_processable_html_response
77

88

99
class FormParser(HTMLParser):
@@ -92,6 +92,16 @@ def nav_subtitle(self):
9292
else:
9393
return ""
9494

95+
@property
96+
def health_level(self):
97+
"""
98+
Return the health level of the panel based on the alerts.
99+
"""
100+
if not self.alerts:
101+
return ToolbarHealthLevel.NONE
102+
103+
return ToolbarHealthLevel.CRITICAL
104+
95105
def add_alert(self, alert):
96106
self.alerts.append(alert)
97107

debug_toolbar/panels/sql/panel.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
is_select_query,
2020
reformat_sql,
2121
)
22-
from debug_toolbar.utils import render_stacktrace
22+
from debug_toolbar.utils import ToolbarHealthLevel, render_stacktrace
2323

2424

2525
def get_isolation_level_display(vendor, level):
@@ -186,6 +186,18 @@ def title(self):
186186
count,
187187
) % {"count": count}
188188

189+
@property
190+
def health_level(self):
191+
""" """
192+
stats = self.get_stats()
193+
slow_queries = len([1 for q in stats.get("queries", []) if q.get("is_slow")])
194+
if slow_queries > 10:
195+
return ToolbarHealthLevel.CRITICAL
196+
elif slow_queries > 0:
197+
return ToolbarHealthLevel.WARNING
198+
199+
return super().health_level
200+
189201
template = "debug_toolbar/panels/sql.html"
190202

191203
@classmethod

debug_toolbar/static/debug_toolbar/css/toolbar.css

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434
--djdt-button-border-color: var(--djdt-table-border-color);
3535
--djdt-pre-border-color: var(--djdt-table-border-color);
3636
--djdt-raw-border-color: var(--djdt-table-border-color);
37+
38+
--djdt-health-bg-1: #4b3f1b;
39+
--djdt-health-color-1: #ffe761;
40+
--djdt-health-bc-1: #ffcc00;
41+
--djdt-health-bg-2: #5a2327;
42+
--djdt-health-color-2: #ffb3b3;
43+
--djdt-health-bc-2: #ff0000;
3744
}
3845

3946
#djDebug[data-theme="dark"] {
@@ -56,6 +63,13 @@
5663
--djdt-button-border-color: var(--djdt-table-border-color);
5764
--djdt-pre-border-color: var(--djdt-table-border-color);
5865
--djdt-raw-border-color: var(--djdt-table-border-color);
66+
67+
--djdt-health-bg-1: #4b3f1b;
68+
--djdt-health-color-1: #ffe761;
69+
--djdt-health-bc-1: #ffcc00;
70+
--djdt-health-bg-2: #5a2327;
71+
--djdt-health-color-2: #ffb3b3;
72+
--djdt-health-bc-2: #ff0000;
5973
}
6074

6175
/* Debug Toolbar CSS Reset, adapted from Eric Meyer's CSS Reset */
@@ -377,6 +391,25 @@
377391
animation: spin 2s linear infinite;
378392
}
379393

394+
/* Panel and Toolbar hidden button health states */
395+
#djDebug .djdt-health-1 {
396+
background: var(--djdt-health-bg-1) !important;
397+
color: var(--djdt-health-color-1) !important;
398+
}
399+
400+
#djDebug .djdt-health-2 {
401+
background: var(--djdt-health-bg-2) !important;
402+
color: var(--djdt-health-color-2) !important;
403+
}
404+
405+
#djDebug .djdt-toolbarhandle-health-1 {
406+
border-color: var(--djdt-health-bc-1) !important;
407+
}
408+
409+
#djDebug .djdt-toolbarhandle-health-2 {
410+
border-color: var(--djdt-health-bc-2) !important;
411+
}
412+
380413
@keyframes spin {
381414
0% {
382415
transform: rotate(0deg);

debug_toolbar/templates/debug_toolbar/base.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
</ul>
3232
</div>
3333
<div class="djdt-hidden" id="djDebugToolbarHandle">
34-
<div title="{% translate 'Show toolbar' %}" id="djShowToolBarButton">
34+
<div title="{% translate 'Show toolbar' %}" id="djShowToolBarButton" class="{% if toolbar.health_level %} djdt-toolbarhandle-health-{{ toolbar.health_level }}{% endif %}">
3535
<span id="djShowToolBarD">D</span><span id="djShowToolBarJ">J</span>DT
3636
</div>
3737
</div>

debug_toolbar/templates/debug_toolbar/includes/panel_button.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{% load i18n %}
22

3-
<li id="djdt-{{ panel.panel_id }}" class="djDebugPanelButton">
3+
<li id="djdt-{{ panel.panel_id }}" class="djDebugPanelButton{% if panel.health_level %} djdt-health-{{ panel.health_level }}{% endif %}">
44
<input type="checkbox" data-cookie="djdt{{ panel.panel_id }}" {% if panel.enabled %}checked title="{% translate "Disable for next and successive requests" %}"{% else %}title="{% translate "Enable for next and successive requests" %}"{% endif %}>
55
{% if panel.has_content and panel.enabled %}
66
<a href="#" title="{{ panel.title }}" class="{{ panel.panel_id }}">

debug_toolbar/toolbar.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ def csp_nonce(self):
7272
"""
7373
return getattr(self.request, "csp_nonce", None)
7474

75+
@property
76+
def health_level(self):
77+
"""
78+
Return the maximum health level across all panels.
79+
This is used to color the toolbar hidden button.
80+
"""
81+
return max(panel.health_level for panel in self.panels)
82+
7583
def get_panel_by_id(self, panel_id):
7684
"""
7785
Get the panel with the given id, which is the class name by default.

debug_toolbar/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import sys
77
import warnings
88
from collections.abc import Sequence
9+
from enum import IntEnum
910
from pprint import PrettyPrinter, pformat
1011
from typing import Any
1112

@@ -401,3 +402,9 @@ def is_processable_html_response(response):
401402
and content_encoding == ""
402403
and content_type in _HTML_TYPES
403404
)
405+
406+
407+
class ToolbarHealthLevel(IntEnum):
408+
NONE = 0
409+
WARNING = 1
410+
CRITICAL = 2

0 commit comments

Comments
 (0)