Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- feat(ui): improve Request disclosures, body limits, history navigation, and table spacing.
- fix(ui): show short class names with full hover titles, standardize Timeline dots and bars on one blue token, and remove the redundant category legend.
- test: migrate JavaScript unit and mutation tests to Vitest with isolated workers, V8 coverage, per-test mutation analysis, and supported Node.js release ranges.
- feat(ui): expose captured trace totals and style clickable Log severity counters as filter pills alongside History status shortcuts.
2 changes: 1 addition & 1 deletion resources/assets/dist/css/debug.min.css

Large diffs are not rendered by default.

31 changes: 24 additions & 7 deletions resources/src/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -2032,7 +2032,7 @@
* -------------------------------------------------------------------
* Panel-specific helpers.
* -------------------------------------------------------------------
* "Since previous" navigation buttons in Log panel.
* Inter-message delta navigation buttons in the Log panel.
*/
.yii-debug-since-previous {
display: inline-flex;
Expand Down Expand Up @@ -2683,6 +2683,22 @@
color: var(--yii-debug-panel-muted);
}

.yii-debug-grid-summary-stat-warn {
--yii-debug-hue: var(--yii-debug-level-warning);
}

.yii-debug-grid-summary-stat-danger {
--yii-debug-hue: var(--yii-debug-level-error);
}

.yii-debug-grid-summary-stat-info {
--yii-debug-hue: var(--yii-debug-level-info);
}

.yii-debug-grid-summary-stat-trace {
--yii-debug-hue: var(--yii-debug-level-trace);
}

.yii-debug-grid-summary-stat-warn strong {
color: var(--yii-debug-warning);
}
Expand All @@ -2692,12 +2708,9 @@
}

/**
* Pill variant — the History status buckets are clickable filters
* (`<a>` elements) named by their vocabulary status class. Each bucket
* pill wears the tinted formula on its `--yii-debug-hue`. Inline spans
* (`<span class="yii-debug-grid-summary-stat-…">`) — used by panels
* like Log/DB for warning/error counts — are left alone and only get
* the colored `<strong>` from the rules above.
* Pill variant — History status buckets and Log level counters can be
* clickable filters (`<a>` elements). Each anchor wears the tinted formula
* for its `--yii-debug-hue`; inline summary spans remain plain metrics.
*/
.yii-debug-grid-summary-stat-2xx {
--yii-debug-hue: var(--yii-debug-status-2xx);
Expand All @@ -2716,6 +2729,10 @@
}

a:is(
.yii-debug-grid-summary-stat-danger,
.yii-debug-grid-summary-stat-warn,
.yii-debug-grid-summary-stat-info,
.yii-debug-grid-summary-stat-trace,
.yii-debug-grid-summary-stat-2xx,
.yii-debug-grid-summary-stat-3xx,
.yii-debug-grid-summary-stat-4xx,
Expand Down
22 changes: 21 additions & 1 deletion src/Panel/Log/LogCounts.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public function __construct(
* Number of messages at `LogLevel::INFO`.
*/
public int $info,
/**
* Number of messages at `LogLevel::TRACE`.
*/
public int $trace = 0,
) {}

/**
Expand All @@ -42,17 +46,25 @@ public static function fromRows(array $rows): self
$errors = 0;
$warnings = 0;
$info = 0;
$trace = 0;

foreach ($rows as $row) {
match ($row->level) {
LogLevel::ERROR => $errors++,
LogLevel::WARNING => $warnings++,
LogLevel::INFO => $info++,
LogLevel::TRACE => $trace++,
default => null,
};
}

return new self(count($rows), $errors, $warnings, $info);
return new self(
count($rows),
$errors,
$warnings,
$info,
$trace,
);
}

/**
Expand All @@ -71,6 +83,14 @@ public function hasInfo(): bool
return $this->info > 0;
}

/**
* Returns whether at least one `trace`-level message was captured.
*/
public function hasTrace(): bool
{
return $this->trace > 0;
}

/**
* Returns whether at least one `warning`-level message was captured.
*/
Expand Down
62 changes: 61 additions & 1 deletion tests/Panel/Log/LogCountsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,16 @@ public function testFromRowsAggregatesLevelsCorrectly(): void
$counts->info,
'One row is at info level.',
);
self::assertSame(
1,
$counts->trace,
'One row is at trace level.',
);
}

public function testFromRowsExposesHasFlagsForNonZeroCounts(): void
{
$counts = LogCounts::fromRows([self::row(LogLevel::ERROR)]);
$counts = LogCounts::fromRows([self::row(LogLevel::ERROR), self::row(LogLevel::TRACE)]);

self::assertTrue(
$counts->hasErrors(),
Expand All @@ -66,6 +71,41 @@ public function testFromRowsExposesHasFlagsForNonZeroCounts(): void
$counts->hasInfo(),
'No info entry was captured.',
);
self::assertTrue(
$counts->hasTrace(),
'A captured trace must raise the flag.',
);
}

public function testFromRowsIncludesUnknownLevelsOnlyInTotal(): void
{
$counts = LogCounts::fromRows([self::row(0x999)]);

self::assertSame(
1,
$counts->total,
'An unknown level must still contribute to the total.',
);
self::assertSame(
0,
$counts->errors,
'An unknown level must not count as an error.',
);
self::assertSame(
0,
$counts->warnings,
'An unknown level must not count as a warning.',
);
self::assertSame(
0,
$counts->info,
'An unknown level must not count as info.',
);
self::assertSame(
0,
$counts->trace,
'An unknown level must not count as trace.',
);
}

public function testFromRowsReturnsAllZeroCountsWhenNoRowsWereCaptured(): void
Expand All @@ -89,6 +129,26 @@ public function testFromRowsReturnsAllZeroCountsWhenNoRowsWereCaptured(): void
$counts->hasInfo(),
'Empty capture must report no info entries.',
);
self::assertFalse(
$counts->hasTrace(),
'Empty capture must report no trace entries.',
);
}

public function testTraceCountDefaultsToZeroForBackwardCompatibleConstruction(): void
{
$counts = new LogCounts(
total: 1,
errors: 0,
warnings: 0,
info: 1,
);

self::assertSame(
0,
$counts->trace,
'Existing construction without an explicit trace count must remain valid.',
);
}

private static function row(int $level): LogRow
Expand Down
Loading