10000 [Workflow] List place or transition listeners in profiler · symfony/symfony@adcc652 · GitHub
[go: up one dir, main page]

Skip to content

Commit adcc652

Browse files
committed
[Workflow] List place or transition listeners in profiler
1 parent 7f58a4d commit adcc652

File tree

6 files changed

+438
-1
lines changed

6 files changed

+438
-1
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow_debug.php

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
])
2323
->args([
2424
tagged_iterator('workflow', 'name'),
25+
service('event_dispatcher'),
26+
service('debug.file_link_formatter'),
2527
])
2628
;
2729
};

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/workflow.html.twig

+209
B41A
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,102 @@
11
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
22

3+
{% block stylesheets %}
4+
{{ parent() }}
5+
<style>
6+
dialog {
7+
border: none;
8+
border-radius: 6px;
9+
box-shadow: var(--settings-modal-shadow);
10+
max-width: 94%;
11+
width: 1200px;
12+
}
13+
14+
dialog::backdrop {
15+
background: linear-gradient(
16+
45deg,
17+
rgb(18, 18, 20, 0.4),
18+
rgb(17, 17, 20, 0.8)
19+
);
20+
}
21+
22+
dialog[open] {
23+
animation: scale 0.3s ease normal;
24+
}
25+
26+
dialog[open]::backdrop {
27+
animation: backdrop 0.3s ease normal;
28+
}
29+
30+
dialog.hide {
31+
animation-direction: reverse;
32+
}
33+
34+
dialog h2 {
35+
margin-top: 0.2em
36+
}
37+
38+
dialog i.cancel {
39+
cursor: pointer;
40+
padding: 0 5px;
41+
float: right;
42+
}
43+
44+
dialog table {
45+
border: 1px solid #ccc;
46+
border-collapse: collapse;
47+
margin: 0 0 1em 0;
48+
margin-bottom: 1em;
49+
padding: 0;
50+
table-layout: fixed;
51+
}
52+
53+
dialog table tr {
54+
background-color: #f8f8f8;
55+
border: 1px solid #ddd;
56+
padding: .35em;
57+
}
58+
59+
dialog table th,
60+
dialog table td {
61+
padding: .625em;
62+
text-align: center;
63+
}
64+
65+
dialog table th {
66+
font-size: .85em;
67+
letter-spacing: .1em;
68+
text-transform: uppercase;
69+
}
70+
71+
dialog menu {
72+
padding: 0;
73+
margin: 0;
74+
display: flex;
75+
align-items: center;
76+
flex-direction: row;
77+
vertical-align: middle;
78+
justify-content: center;
79+
}
80+
81+
dialog menu small {
82+
margin-right: auto;
83+
}
84+
dialog menu small i {
85+
margin-right: 3px;
86+
}
87+
88+
@keyframes scale {
89+
from { transform: scale(0); }
90+
to { transform: scale(1); }
91+
}
92+
93+
@keyframes backdrop {
94+
from { opacity: 0; }
95+
to { opacity: 1; }
96+
}
97+
</style>
98+
{% endblock %}
9 10000 9+
3100
{% block toolbar %}
4101
{% if collector.callsCount > 0 %}
5102
{% set icon %}
@@ -40,6 +137,93 @@
40137
flowchart: { useMaxWidth: false },
41138
securityLevel: 'loose',
42139
});
140+
141+
{% for name, data in collector.workflows %}
142+
window.showNodeDetails{{ collector.hash(name) }} = function (node) {
143+
const map = {{ data.listeners|json_encode|raw }};
144+
showNodeDetails(node, map);
145+
};
146+
{% endfor %}
147+
148+
const showNodeDetails = function (node, map) {
149+
const dialog = document.getElementById('detailsDialog');
150+
151+
dialog.querySelector('tbody').innerHTML = '';
152+
for (const [eventName, listeners] of Object.entries(map[node])) {
153+
listeners.forEach(listener => {
154+
const row = document.createElement('tr');
155+
156+
const eventNameCode = document.createElement('code');
157+
eventNameCode.textContent = eventName;
158+
159+
const eventNameCell = document.createElement('td');
160+
eventNameCell.appendChild(eventNameCode);
161+
row.appendChild(eventNameCell);
162+
163+
const listenerDetailsCell = document.createElement('td');
164+
row.appendChild(listenerDetailsCell);
165+
166+
let listenerDetails;
167+
const listenerDetailsCode = document.createElement('code');
168+
listenerDetailsCode.textContent = listener.title;
169+
if (listener.file) {
170+
const link = document.createElement('a');
171+
link.href = listener.file;
172+
link.appendChild(listenerDetailsCode);
173+
listenerDetails = link;
174+
} else {
175+
listenerDetails = listenerDetailsCode;
176+
}
177+
listenerDetailsCell.appendChild(listenerDetails);
178+
179+
if (typeof listener.guardExpressions === 'object') {
180+
listenerDetailsCell.appendChild(document.createElement('br'));
181+
182+
const guardExpressionsWrapper = document.createElement('span');
183+
guardExpressionsWrapper.appendChild(document.createTextNode('guard expressions: '));
184+
185+
listener.guardExpressions.forEach((expression, index) => {
186+
if (index > 0) {
187+
guardExpressionsWrapper.appendChild(document.createTextNode(', '));
188+
}
189+
190+
const expressionCode = document.createElement('code');
191+
expressionCode.textContent = expression;
192+
guardExpressionsWrapper.appendChild(expressionCode);
193+
});
194+
195+
listenerDetailsCell.appendChild(guardExpressionsWrapper);
196+
}
197+
198+
dialog.querySelector('tbody').appendChild(row);
199+
});
200+
};
201+
202+
if (dialog.dataset.processed) {
203+
dialog.showModal();
204+
return;
205+
}
206+
207+
dialog.addEventListener('click', (e) => {
208+
const rect = dialog.getBoundingClientRect();
209+
210+
const inDialog =
211+
rect.top <= e.clientY &&
212+
e.clientY <= rect.top + rect.height &&
213+
rect.left <= e.clientX &&
214+
e.clientX <= rect.left + rect.width;
215+
216+
!inDialog && dialog.close();
217+
});
218+
219+
dialog.querySelectorAll('.cancel').forEach(elt => {
220+
elt.addEventListener('click', () => dialog.close());
221+
});
222+
223+
dialog.showModal();
224+
225+
dialog.dataset.processed = true;
226+
};
43227
// We do not load all mermaid diagrams at once, but only when the tab is opened
44228
// This is because mermaid diagrams are in a tab, and cannot be renderer with a
45229
// "good size" if they are not visible
@@ -71,6 +255,9 @@
71255
<h3>Definition</h3>
72256
<pre class="sf-mermaid">
73257
{{ data.dump|raw }}
258+
{% for nodeId, events in data.listeners %}
259+
click {{ nodeId }} showNodeDetails{{ collector.hash(name) }}
260+
{% endfor %}
74261
</pre>
75262

76263
<h3>Calls</h3>
@@ -128,4 +315,26 @@
128315
{% endfor %}
129316
</div>
130317
{% endif %}
318+
319+
<dialog id="detailsDialog">
320+
<h2>
321+
Event listeners
322+
<i class="cancel">×</i>
323+
</h2>
324+
325+
<table>
326+
<thead>
327+
<tr>
328+
<th>event</th>
329+
<th>listener</th>
330+
</tr>
331+
</thead>
332+
<tbody>
333+
</tbody>
334+
</table>
335+
<menu>
336+
<small><i>⌨</i> <kbd>esc</kbd></small>
337+
<button class="btn btn-sm cancel">Close</button>
338+
</menu>
339+
</dialog>
131340
{% endblock %}
Loading

0 commit comments

Comments
 (0)
0