Skip to content

Commit 6bd557c

Browse files
Merge 64d928f into 5a3ccd9
2 parents 5a3ccd9 + 64d928f commit 6bd557c

File tree

6 files changed

+143
-62
lines changed

6 files changed

+143
-62
lines changed

debug_toolbar/panels/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ def content(self):
107107
def scripts(self):
108108
"""
109109
Scripts used by the HTML content of the panel when it's displayed.
110+
111+
When a panel is rendered on the frontend, the ``djdt.panel.render``
112+
JavaScript event will be dispatched. The scripts can listen for
113+
this event to support dynamic functionality.
110114
"""
111115
return []
112116

Lines changed: 72 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,75 @@
1-
const timingOffset = performance.timing.navigationStart,
2-
timingEnd = performance.timing.loadEventEnd,
3-
totalTime = timingEnd - timingOffset;
4-
function getLeft(stat) {
5-
return ((performance.timing[stat] - timingOffset) / totalTime) * 100.0;
6-
}
7-
function getCSSWidth(stat, endStat) {
8-
let width =
9-
((performance.timing[endStat] - performance.timing[stat]) / totalTime) *
10-
100.0;
11-
// Calculate relative percent (same as sql panel logic)
12-
width = (100.0 * width) / (100.0 - getLeft(stat));
13-
return width < 1 ? "2px" : width + "%";
14-
}
15-
function addRow(tbody, stat, endStat) {
16-
const row = document.createElement("tr");
17-
if (endStat) {
18-
// Render a start through end bar
19-
row.innerHTML =
20-
"<td>" +
21-
stat.replace("Start", "") +
22-
"</td>" +
23-
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
24-
"<td>" +
25-
(performance.timing[stat] - timingOffset) +
26-
" (+" +
27-
(performance.timing[endStat] - performance.timing[stat]) +
28-
")</td>";
29-
row.querySelector("rect").setAttribute(
30-
"width",
31-
getCSSWidth(stat, endStat)
32-
);
33-
} else {
34-
// Render a point in time
35-
row.innerHTML =
36-
"<td>" +
37-
stat +
38-
"</td>" +
39-
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
40-
"<td>" +
41-
(performance.timing[stat] - timingOffset) +
42-
"</td>";
43-
row.querySelector("rect").setAttribute("width", 2);
1+
import { $$ } from "./utils.js";
2+
3+
function insertBrowserTiming() {
4+
console.log(["inserted"]);
5+
const timingOffset = performance.timing.navigationStart,
6+
timingEnd = performance.timing.loadEventEnd,
7+
totalTime = timingEnd - timingOffset;
8+
function getLeft(stat) {
9+
return ((performance.timing[stat] - timingOffset) / totalTime) * 100.0;
10+
}
11+
function getCSSWidth(stat, endStat) {
12+
let width =
13+
((performance.timing[endStat] - performance.timing[stat]) /
14+
totalTime) *
15+
100.0;
16+
// Calculate relative percent (same as sql panel logic)
17+
width = (100.0 * width) / (100.0 - getLeft(stat));
18+
return width < 1 ? "2px" : width + "%";
19+
}
20+
function addRow(tbody, stat, endStat) {
21+
const row = document.createElement("tr");
22+
if (endStat) {
23+
// Render a start through end bar
24+
row.innerHTML =
25+
"<td>" +
26+
stat.replace("Start", "") +
27+
"</td>" +
28+
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
29+
"<td>" +
30+
(performance.timing[stat] - timingOffset) +
31+
" (+" +
32+
(performance.timing[endStat] - performance.timing[stat]) +
33+
")</td>";
34+
row.querySelector("rect").setAttribute(
35+
"width",
36+
getCSSWidth(stat, endStat)
37+
);
38+
} else {
39+
// Render a point in time
40+
row.innerHTML =
41+
"<td>" +
42+
stat +
43+
"</td>" +
44+
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
45+
"<td>" +
46+
(performance.timing[stat] - timingOffset) +
47+
"</td>";
48+
row.querySelector("rect").setAttribute("width", 2);
49+
}
50+
row.querySelector("rect").setAttribute("x", getLeft(stat));
51+
tbody.appendChild(row);
52+
}
53+
54+
const browserTiming = document.getElementById("djDebugBrowserTiming");
55+
// Determine if the browser timing section has already been rendered.
56+
if (browserTiming.classList.contains("djdt-hidden")) {
57+
const tbody = document.getElementById("djDebugBrowserTimingTableBody");
58+
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
59+
addRow(tbody, "domainLookupStart", "domainLookupEnd");
60+
addRow(tbody, "connectStart", "connectEnd");
61+
addRow(tbody, "requestStart", "responseEnd"); // There is no requestEnd
62+
addRow(tbody, "responseStart", "responseEnd");
63+
addRow(tbody, "domLoading", "domComplete"); // Spans the events below
64+
addRow(tbody, "domInteractive");
65+
addRow(tbody, "domContentLoadedEventStart", "domContentLoadedEventEnd");
66+
addRow(tbody, "loadEventStart", "loadEventEnd");
67+
browserTiming.classList.remove("djdt-hidden");
4468
}
45-
row.querySelector("rect").setAttribute("x", getLeft(stat));
46-
tbody.appendChild(row);
4769
}
4870

49-
const tbody = document.getElementById("djDebugBrowserTimingTableBody");
50-
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
51-
addRow(tbody, "domainLookupStart", "domainLookupEnd");
52-
addRow(tbody, "connectStart", "connectEnd");
53-
addRow(tbody, "requestStart", "responseEnd"); // There is no requestEnd
54-
addRow(tbody, "responseStart", "responseEnd");
55-
addRow(tbody, "domLoading", "domComplete"); // Spans the events below
56-
addRow(tbody, "domInteractive");
57-
addRow(tbody, "domContentLoadedEventStart", "domContentLoadedEventEnd");
58-
addRow(tbody, "loadEventStart", "loadEventEnd");
59-
document.getElementById("djDebugBrowserTiming").classList.remove("djdt-hidden");
71+
const djDebug = document.getElementById("djDebug");
72+
// Insert the browser timing now since it's possible for this
73+
// script to miss the initial panel load event.
74+
insertBrowserTiming();
75+
$$.onPanelRender(djDebug, "TimerPanel", insertBrowserTiming);

debug_toolbar/static/debug_toolbar/js/toolbar.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const djdt = {
2020
if (!this.className) {
2121
return;
2222
}
23-
const current = document.getElementById(this.className);
23+
const panelId = this.className;
24+
const current = document.getElementById(panelId);
2425
if ($$.visible(current)) {
2526
djdt.hide_panels();
2627
} else {
@@ -39,13 +40,24 @@ const djdt = {
3940
window.location
4041
);
4142
url.searchParams.append("store_id", store_id);
42-
url.searchParams.append("panel_id", this.className);
43+
url.searchParams.append("panel_id", panelId);
4344
ajax(url).then(function (data) {
4445
inner.previousElementSibling.remove(); // Remove AJAX loader
4546
inner.innerHTML = data.content;
4647
$$.executeScripts(data.scripts);
4748
$$.applyStyles(inner);
49+
djDebug.dispatchEvent(
50+
new CustomEvent("djdt.panel.render", {
51+
detail: { panelId: panelId },
52+
})
53+
);
4854
});
55+
} else {
56+
djDebug.dispatchEvent(
57+
new CustomEvent("djdt.panel.render", {
58+
detail: { panelId: panelId },
59+
})
60+
);
4961
}
5062
}
5163
}

debug_toolbar/static/debug_toolbar/js/utils.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ const $$ = {
77
}
88
});
99
},
10+
onPanelRender(root, panelId, fn) {
11+
/*
12+
This is a helper function to attach a handler for a `djdt.panel.render`
13+
event of a specific panel.
14+
15+
root: The container element that the listener should be attached to.
16+
panelId: The Id of the panel.
17+
fn: A function to execute when the event is triggered.
18+
*/
19+
root.addEventListener("djdt.panel.render", function (event) {
20+
if (event.detail.panelId === panelId) {
21+
fn.call(event);
22+
}
23+
});
24+
},
1025
show(element) {
1126
element.classList.remove("djdt-hidden");
1227
},

docs/changes.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ Next version
99
* Added ``PRETTIFY_SQL`` configuration option to support controlling
1010
SQL token grouping. By default it's set to True. When set to False,
1111
a performance improvement can be seen by the SQL panel.
12-
* Fixed issue with toolbar expecting URL paths to start with `/__debug__/`
13-
while the documentation indicates it's not required.
12+
* Added a JavaScript event when a panel loads of the format
13+
``djdt.panel.[PanelId]`` where PanelId is the ``panel_id`` property
14+
of the panel's Python class. Listening for this event corrects the bug
15+
in the Timer Panel in which it didn't insert the browser timings
16+
after switching requests in the History Panel.
17+
* Fixed issue with the toolbar expecting URL paths to start with
18+
``/__debug__/`` while the documentation indicates it's not required.
1419

1520
3.2 (2020-12-03)
1621
----------------

docs/panels.rst

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,9 @@ URL: https://github.com/danyi1212/django-windowsauth
184184

185185
Path: ``windows_auth.panels.LDAPPanel``
186186

187-
LDAP Operations performed during the request, including timing, request and response messages,
187+
LDAP Operations performed during the request, including timing, request and response messages,
188188
the entries received, write changes list, stack-tracing and error debugging.
189-
This panel also shows connection usage metrics when it is collected.
189+
This panel also shows connection usage metrics when it is collected.
190190
`Check out the docs <https://django-windowsauth.readthedocs.io/en/latest/howto/debug_toolbar.html>`_.
191191

192192
Line Profiler
@@ -402,3 +402,32 @@ common methods available.
402402
.. js:function:: djdt.show_toolbar
403403

404404
Shows the toolbar.
405+
406+
Events
407+
^^^^^^
408+
409+
.. js:attribute:: djdt.panel.render
410+
411+
This is an event raised when a panel is rendered. It has the property
412+
``detail.panelId`` which identifies which panel has been loaded. This
413+
event can be useful when creating custom scripts to process the HTML
414+
further.
415+
416+
An example of this for the ``CustomPanel`` would be:
417+
418+
.. code-block:: javascript
419+
420+
import { $$ } from "./utils.js";
421+
function addCustomMetrics() {
422+
// Logic to process/add custom metrics here.
423+
424+
// Be sure to cover the case of this function being called twice
425+
// due to file being loaded asynchronously.
426+
}
427+
const djDebug = document.getElementById("djDebug");
428+
$$.onPanelRender(djDebug, "CustomPanel", addCustomMetrics);
429+
// Since a panel's scripts are loaded asynchronously, it's possible that
430+
// the above statement would occur after the djdt.panel.render event has
431+
// been raised. To account for that, the rendering function should be
432+
// called here as well.
433+
addCustomMetrics();

0 commit comments

Comments
 (0)