Skip to content

Commit

Permalink
Merge pull request #4886 from sfadschm/4.2
Browse files Browse the repository at this point in the history
[Debug] [4.2] Structure debug toolbar timeline with collapsible elements.
  • Loading branch information
lonnieezell authored Jun 28, 2021
2 parents f887865 + a988368 commit 6d752f4
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 11 deletions.
102 changes: 92 additions & 10 deletions system/Debug/Toolbar.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,47 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques
* @return string
*/
protected function renderTimeline(array $collectors, float $startTime, int $segmentCount, int $segmentDuration, array &$styles): string
{
$rows = $this->collectTimelineData($collectors);
$output = '';
$styleCount = 0;

// Use recursive render function
return $this->renderTimelineRecursive($rows, $startTime, $segmentCount, $segmentDuration, $styles, $styleCount);
}

/**
* Recursively renders timeline elements and their children.
*
* @param array $rows
* @param float $startTime
* @param int $segmentCount
* @param int $segmentDuration
* @param array $styles
* @param int $styleCount
* @param int $level
* @param bool $isChild
*
* @return string
*/
protected function renderTimelineRecursive(array $rows, float $startTime, int $segmentCount, int $segmentDuration, array &$styles, int &$styleCount, int $level = 0, bool $isChild = false): string
{
$displayTime = $segmentCount * $segmentDuration;
$rows = $this->collectTimelineData($collectors);
$output = '';
$styleCount = 0;

$output = '';

foreach ($rows as $row) {
$output .= '<tr>';
$output .= "<td>{$row['name']}</td>";
$output .= "<td>{$row['component']}</td>";
$output .= "<td class='debug-bar-alignRight'>" . number_format($row['duration'] * 1000, 2) . ' ms</td>';
$hasChildren = isset($row['children']) && !empty($row['children']);
$open = $row['name'] === 'Controller';

if ($hasChildren) {
$output .= '<tr class="timeline-parent' . ($open ? ' timeline-parent-open' : '') . '" id="timeline-' . $styleCount . '_parent" onclick="ciDebugBar.toggleChildRows(\'timeline-' . $styleCount . '\');">';
} else {
$output .= '<tr>';
}
$output .= '<td class="' . ($isChild ? 'debug-bar-width30' : '') . '" style="--level: ' . $level . ';">' . ($hasChildren ? '<nav></nav>' : '') . $row['name'] . '</td>';
$output .= '<td class="' . ($isChild ? 'debug-bar-width10' : '') . '">' . $row['component'] . '</td>';
$output .= '<td class="' . ($isChild ? 'debug-bar-width10 ' : '') . 'debug-bar-alignRight">' . number_format($row['duration'] * 1000, 2) . ' ms</td>';
$output .= "<td class='debug-bar-noverflow' colspan='{$segmentCount}'>";

$offset = ((((float) $row['start'] - $startTime) * 1000) / $displayTime) * 100;
Expand All @@ -217,6 +247,19 @@ protected function renderTimeline(array $collectors, float $startTime, int $segm
$output .= '</tr>';

$styleCount++;

// Add children if any
if ($hasChildren) {
$output .= '<tr class="child-row" id="timeline-' . ($styleCount - 1) . '_children" style="' . ($open ? '' : 'display: none;') . '">';
$output .= '<td colspan="' . ($segmentCount + 3) . '" class="child-container">';
$output .= '<table class="timeline">';
$output .= '<tbody>';
$output .= $this->renderTimelineRecursive($row['children'], $startTime, $segmentCount, $segmentDuration, $styles, $styleCount, $level + 1, true);
$output .= '</tbody>';
$output .= '</table>';
$output .= '</td>';
$output .= '</tr>';
}
}

return $output;
Expand Down Expand Up @@ -246,15 +289,54 @@ protected function collectTimelineData($collectors): array

// Sort it
$sortArray = [
array_column($data, 'start'), SORT_NUMERIC, SORT_ASC,
array_column($data, 'duration'), SORT_NUMERIC, SORT_DESC,
&$data
array_column($data, 'start'), SORT_NUMERIC, SORT_ASC,
array_column($data, 'duration'), SORT_NUMERIC, SORT_DESC,
&$data,
];
array_multisort(...$sortArray);

// Add end time to each element
array_walk($data, static function(&$row) {
$row['end'] = $row['start'] + $row['duration'];
});

// Group it
$data = $this->structureTimelineData($data);

return $data;
}

/**
* Arranges the already sorted timeline data into a parent => child structure.
*
* @param array $elements
*
* @return array
*/
protected function structureTimelineData(array $elements): array
{
// We define ourselves as the first element of the array
$element = array_shift($elements);

// If we have children behind us, collect and attach them to us
while (!empty($elements) && $elements[array_key_first($elements)]['end'] <= $element['end']) {
$element['children'][] = array_shift($elements);
}

// Make sure our children know whether they have children, too
if (isset($element['children'])) {
$element['children'] = $this->structureTimelineData($element['children']);
}

// If we have no younger siblings, we can return
if (empty($elements)) {
return [$element];
}

// Make sure our younger siblings know their relatives, too
return array_merge([$element], $this->structureTimelineData($elements));
}

//--------------------------------------------------------------------

/**
Expand Down
25 changes: 24 additions & 1 deletion system/Debug/Toolbar/Views/toolbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,22 @@
#debug-bar .timeline {
margin-left: 0;
width: 100%; }
#debug-bar .timeline tr.timeline-parent {
cursor: pointer; }
#debug-bar .timeline tr.timeline-parent td:first-child nav {
background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent;
background-position: 0 25%;
display: inline-block;
height: 15px;
width: 15px;
margin-right: 3px;
vertical-align: middle; }
#debug-bar .timeline tr.timeline-parent.timeline-parent-open td:first-child nav {
background-position: 0 75%; }
#debug-bar .timeline tr.timeline-parent.timeline-parent-open {
background-color: #DFDFDF; }
#debug-bar .timeline tr.child-row:hover {
background: transparent; }
#debug-bar .timeline th {
border-left: 1px solid;
font-size: 12px;
Expand All @@ -200,7 +216,14 @@
padding: 5px;
position: relative; }
#debug-bar .timeline td:first-child {
border-left: 0; }
border-left: 0;
max-width: none; }
#debug-bar .timeline td.child-container {
padding: 0px; }
#debug-bar .timeline td.child-container .timeline{
margin: 0px; }
#debug-bar .timeline td.child-container td:first-child:not(.child-container){
padding-left: calc(5px + 10px * var(--level)); }
#debug-bar .timeline .timer {
border-radius: 4px;
-moz-border-radius: 4px;
Expand Down
20 changes: 20 additions & 0 deletions system/Debug/Toolbar/Views/toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,26 @@ var ciDebugBar = {
}
},

/**
* Toggle display of timeline child elements
*
* @param obj
*/
toggleChildRows : function (obj) {
if (typeof obj == 'string')
{
par = document.getElementById(obj + '_parent')
obj = document.getElementById(obj + '_children');
}

if (par && obj)
{
obj.style.display = obj.style.display == 'none' ? '' : 'none';
par.classList.toggle('timeline-parent-open');
}
},


//--------------------------------------------------------------------

/**
Expand Down

0 comments on commit 6d752f4

Please sign in to comment.