Repository navigation
[BUG] Scan status chips show Succeeded and Partial without color on list pages #274
Description
Summary
Several pages color scan status chips with their own private copy of GetScanStatusColor. Four of these copies map success to Completed, a status that does not exist (ScanRunStatus is NotSet, Pending, Running, Succeeded, Partial, Failed), and they have no entry for Succeeded or Partial. On the Dashboard, Scan History, Observed Images and My Images pages, the two most common outcomes, a successful run and a partially successful run, therefore appear as grey default chips that look the same as unknown states. The seven copies have also drifted apart: the detail pages already handle Succeeded/Partial.
Area
docs/areas/web-ui.md, added in [Docs] Describe the current behavior by area #263- Security area: none
Current behavior
The scan status strings come from ScanRunStatus.ToString() (src/DockerUpdateGuard/UI/ApplicationViewService.cs: GetLatestObservedScanStatus / GetLatestRuntimeScanStatus around lines 1497-1528 return entity.Status.ToString() or "NotScanned"; scan history items use scanRun.Status.ToString(), around line 1436). Possible values are therefore Pending, Running, Succeeded, Partial, Failed, NotSet and NotScanned. Completed is never produced.
There are seven independent mappings:
| File | Maps Succeeded |
Maps Partial |
Maps dead Completed |
|---|---|---|---|
src/DockerUpdateGuard/Components/Pages/Dashboard.razor.cs:79 (chip at Dashboard.razor:237, recent scans) |
no | no | yes |
Components/Pages/ScanHistory.razor.cs:107 (chip at ScanHistory.razor:74) |
no | no | yes |
Components/Pages/ObservedImages.razor.cs:102 (chip at ObservedImages.razor:105) |
no | no | yes |
Components/Pages/MyImages.razor.cs:94 (chip at MyImages.razor:50) |
no | no | yes |
Components/Pages/ObservedImageDetail.razor.cs:71 |
yes | yes | yes |
Components/Pages/MyImageDetail.razor.cs:71 |
yes | yes | yes |
Components/Pages/RuntimeContainerDetail.razor.cs:116 |
yes | yes | yes |
The list-page variant:
// src/DockerUpdateGuard/Components/Pages/ScanHistory.razor.cs:107-117
return status.ToUpperInvariant() switch
{
"COMPLETED" => Color.Success,
"FAILED" => Color.Error,
"RUNNING" => Color.Info,
"PENDING" => Color.Warning,
_ => Color.Default,
};The existing tests pin the dead value: src/Tests/DockerUpdateGuard.Tests/MyImagesTests.cs:75-77 and MyImageDetailTests.cs:43-44 ([DataRow("Completed", Color.Success)]).
Reproduction: run any scheduled or manual scan that succeeds and open / or /scan-history. The Succeeded chip is grey (Color.Default). A vulnerability refresh where one image is Unavailable ends Partial, and its chip is grey as well. Open the observed image detail page of the same image, and the chip is green or orange.
Expected behavior
- Decision (product manager):
Succeededis shown in the success color andPartialin the warning color. - The other colors stay as they are:
Failed→ error,Running→ info,Pending→ warning. Anything else (NotSet,NotScanned, unknown) → default. Matching is case-insensitive andnull-safe. - Decision (product manager): there is one shared mapping, used by every scan status chip: Dashboard, Scan History, Observed Images, My Images, Observed Image detail, My Image detail and Runtime Container detail. The page-local copies are removed.
- The non-existent
Completedstatus is no longer mapped.
Acceptance criteria
- A single internal static helper, for example
ScanStatusDisplayFormatter.GetStatusColor(string? status)insrc/DockerUpdateGuard/UI/next toVulnerabilityDisplayFormatter, implements the mapping. - All seven pages use the shared helper, and no
GetScanStatusColormethod remains inComponents/Pages/*.razor.cs. - New
ScanStatusDisplayFormatterTests(MSTest[DataRow], naming perdocs/UNIT_TESTS.md, for exampleScanStatusDisplayFormatterGetStatusColorReturnsExpectedColor) cover:Succeeded→Color.SuccessPartial→Color.WarningFailed→Color.ErrorRunning→Color.InfoPending→Color.WarningNotSet,NotScanned,Completed, empty andnull→Color.Default- case-insensitivity
- A test proves that the mapping is complete for the enum: every
ScanRunStatusvalue exceptNotSetmaps to a non-default color (iterateEnum.GetValues<ScanRunStatus>()), so a future status cannot silently fall back to grey. - The obsolete
Completeddata rows inMyImagesTestsandMyImageDetailTestsare removed or moved to the new test class. Test data usingStatus = "Completed"inScanHistoryTests/ScanHistoryPersistentStateTestsis changed to a real status value. -
docs/areas/web-ui.mddescribes the scan status chip colors (for example in General or next to Pages and routes), and its Known gaps / open-question entry for this issue is removed. - Format, build, tests, analyzer gate and coverage gate pass (
.squad/stack.md).
Implementation notes
- Keep the helper
internal static, asVulnerabilityDisplayFormatteris. The test project already has access to internals. - Prefer comparing against
nameof(ScanRunStatus.Succeeded)etc., orEnum.TryParse<ScanRunStatus>(status, ignoreCase: true, …), instead of string literals, so a renamed enum member breaks the build rather than the colors. - The Docker Instances page shows the latest runtime scan status as plain text (
DockerInstances.razor:135), not as a chip. Leave it as it is unless it becomes a chip in this change. - Do not change the displayed text of the chips, only their color.
- This is purely presentational: no configuration, migration or service change.
Related
- [Docs] Describe the current behavior by area #263 (area documents)
- F-049 (P7) — Blazor UI tested only via reflection helpers; rendered components (incl. F-034 sink) untested #24 (Blazor UI tests via reflection): the new helper is testable directly, without reflection.
Generated by Claude Code
Activity