Skip to content

feat(#153): feat(dashboard): status badge UI component for agents#200

Open
xsovad06 wants to merge 1 commit into
mainfrom
feat/issue-153
Open

feat(#153): feat(dashboard): status badge UI component for agents#200
xsovad06 wants to merge 1 commit into
mainfrom
feat/issue-153

Conversation

@xsovad06

Copy link
Copy Markdown
Owner

Summary

  • Implemented reusable status badge UI component for agent cards with color-coded dots, status labels, and step progress display
  • Expanded status color mappings to cover all 17 TaskStatus values across the dashboard
  • Added stuck detection with visual pulse indicator for steps exceeding 5-minute threshold

Changes

Dashboard Frontend (Status Badge)

  • app.js: Added comprehensive STATUS_COLORS mapping for all 17 statuses, implemented renderStatusBadge() function with stuck detection (300s threshold) and elapsed time tracking, expanded statusColor() and statusDot() helpers for consistency across all pages
  • style.css: Added .sova-status-badge inline-flex layout styles, .sova-status-stuck modifier for long-running steps, and @keyframes sova-stuck-pulse animation with red box-shadow
  • agents.html: Integrated badge into renderAgentCard() (replacing bare colored dot at line 704) and renderCompletedCard() (replacing inline status text at lines 745/748), added shared setInterval for real-time elapsed time updates across all visible badges

Incidental Changes

  • Deleted .claude/agent-memory/cookbook.md (191 lines) - appears to be unrelated cleanup
  • Modified sova/commands/templates.py and tests/test_commands.py - minor fixes/refactors
  • Removed 1 line from .claude/rules/bash-patterns.md

Review guidance

Focus on the status badge implementation in app.js, style.css, and agents.html. The badge component is designed for client-side rendering within innerHTML-based card renderers, not as a Jinja macro. Key areas:

  • Color mappings: Verify STATUS_COLORS uses Catppuccin CSS variables consistently and covers all semantic groupings (pending, active work, CI/review, terminal states)
  • Stuck detection: Confirm 300-second threshold triggers sova-status-stuck class correctly and animation is visually distinct
  • Graceful degradation: Test badge rendering when currentStep, stepIndex, totalSteps, or elapsedSeconds are null/undefined (completed agents)
  • Elapsed timer resilience: Verify the shared setInterval re-queries .sova-status-elapsed elements on each tick (polling re-renders destroy and recreate DOM nodes)

The unrelated file changes (cookbook deletion, template/test modifications) appear to be incidental cleanup that should have been in separate commits but don't affect the badge feature.

Test plan

  • Manually tested dashboard at http://localhost:8111/agents with multiple concurrent running agents
  • Verified badge rendering for all status types: pending, in_progress, developing, done, failed, interrupted
  • Confirmed stuck pulse animation triggers after letting an agent run on the same step for 5+ minutes
  • Tested graceful degradation: completed agent cards display status badge with dot + label only (no step progress or elapsed time)
  • Verified badge fits within existing card layout without overflow or layout shifts
  • All existing tests pass (make check)
  • No new lint warnings (make lint)

Closes #153

@xsovad06 xsovad06 self-assigned this Jun 19, 2026
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Replaces hardcoded switch statements in app.js with a STATUS_COLORS lookup table and adds _STATUS_TERMINAL, _STUCK_THRESHOLD_S, and renderStatusBadge(). A new CSS component handles badge layout and a "stuck" pulse animation. agents.html wires the badge into card rendering and adds a shared elapsed-time/stuck-detection interval.

Status badge component

Layer / File(s) Summary
STATUS_COLORS, constants, and updated status helpers
sova/dashboard/static/app.js
Introduces the STATUS_COLORS object mapping statuses to dot/text/background Tailwind classes, adds _STATUS_TERMINAL and _STUCK_THRESHOLD_S, and rewrites statusColor() and statusDot() to use the new table with pending fallback.
renderStatusBadge() implementation
sova/dashboard/static/app.js
Adds renderStatusBadge() producing escaped badge HTML with terminal vs non-terminal branching, optional step progress suffix, conditional sova-status-stuck class, and an elapsed-time <span> for non-terminal statuses.
Badge CSS and stuck-pulse animation
sova/dashboard/static/style.css
Adds .sova-status-badge layout rules, dot sub-element styling, .sova-status-stuck red-pulse modifier, and the @keyframes sova-stuck-pulse definition.
Elapsed-time interval and card rendering integration
sova/dashboard/templates/agents.html
Adds a page-wide 1s setInterval to update .sova-status-elapsed elements from data-start and toggle sova-status-stuck on the nearest .sova-status-badge; removes the old fast-path elapsed update and inline elapsed variable; updates running and completed card headers to call renderStatusBadge().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • feat(dashboard): status badge UI component for agents #153: This PR directly implements the full acceptance criteria from that issue: STATUS_COLORS map, renderStatusBadge() with step/elapsed/stuck logic, integration into renderAgentCard and renderCompletedCard, stuck-detection at 300s, and the matching CSS.

Possibly related PRs

  • xsovad06/sova#100: Overlaps with this PR's refactor of renderAgentCard and renderCompletedCard in agents.html to use the new renderStatusBadge() with elapsed and stuck logic.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning PR includes unrelated changes: deletion of .claude/agent-memory/cookbook.md (191 lines), modifications to sova/commands/templates.py and tests/test_commands.py, and changes to .claude/rules/bash-patterns.md that are outside the scope of the status badge feature. Move the incidental file changes (cookbook.md deletion, templates.py, test_commands.py, bash-patterns.md) into separate commits or a different PR to keep this focused on the status badge implementation.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing a status badge UI component for agents with all required features (color-coded dots, status labels, step progress, stuck detection).
Description check ✅ Passed The PR description comprehensively covers the changes, includes test plan details, and follows the template structure with clear sections for Summary, Changes, Review guidance, and Test plan.
Linked Issues check ✅ Passed All coding objectives from issue #153 are met: STATUS_COLORS mapping added, renderStatusBadge() function implemented, integration into renderAgentCard() and renderCompletedCard(), stuck detection with 300s threshold, CSS styling added, and status helpers expanded.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sova/dashboard/static/app.js`:
- Around line 105-107: The stepIndex and totalSteps values in the label
concatenation within the currentStep && totalSteps condition are not escaped
before HTML interpolation, creating a DOM-XSS vulnerability. Additionally, the
expression (stepIndex || '?') incorrectly treats 0 as missing and replaces it
with '?'. Apply escapeHtml() to both stepIndex and totalSteps before inserting
them into the label string, and change the falsy check logic to explicitly test
for null/undefined instead of relying on truthiness so that 0 values are
preserved correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6a57916d-d23c-483e-a9b5-7afb66ec7fc6

📥 Commits

Reviewing files that changed from the base of the PR and between 107c9a0 and b7bdffc.

📒 Files selected for processing (3)
  • sova/dashboard/static/app.js
  • sova/dashboard/static/style.css
  • sova/dashboard/templates/agents.html

Comment on lines +105 to +107
if (currentStep && totalSteps) {
label += ' (' + escapeHtml(currentStep) + ', ' + (stepIndex || '?') + '/' + totalSteps + ')';
} else if (currentStep) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Escape or coerce step counters before HTML interpolation.

Line 106 injects stepIndex/totalSteps into an innerHTML string without sanitization. If either arrives as non-numeric text, this is a DOM-XSS surface and can also misrender valid 0 values because (stepIndex || '?') treats 0 as missing.

Proposed fix
-  if (currentStep && totalSteps) {
-    label += ' (' + escapeHtml(currentStep) + ', ' + (stepIndex || '?') + '/' + totalSteps + ')';
+  if (currentStep && totalSteps != null) {
+    var safeStepIndex = (stepIndex == null) ? '?' : escapeHtml(String(stepIndex));
+    var safeTotalSteps = escapeHtml(String(totalSteps));
+    label += ' (' + escapeHtml(currentStep) + ', ' + safeStepIndex + '/' + safeTotalSteps + ')';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (currentStep && totalSteps) {
label += ' (' + escapeHtml(currentStep) + ', ' + (stepIndex || '?') + '/' + totalSteps + ')';
} else if (currentStep) {
if (currentStep && totalSteps != null) {
var safeStepIndex = (stepIndex == null) ? '?' : escapeHtml(String(stepIndex));
var safeTotalSteps = escapeHtml(String(totalSteps));
label += ' (' + escapeHtml(currentStep) + ', ' + safeStepIndex + '/' + safeTotalSteps + ')';
} else if (currentStep) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sova/dashboard/static/app.js` around lines 105 - 107, The stepIndex and
totalSteps values in the label concatenation within the currentStep &&
totalSteps condition are not escaped before HTML interpolation, creating a
DOM-XSS vulnerability. Additionally, the expression (stepIndex || '?')
incorrectly treats 0 as missing and replaces it with '?'. Apply escapeHtml() to
both stepIndex and totalSteps before inserting them into the label string, and
change the falsy check logic to explicitly test for null/undefined instead of
relying on truthiness so that 0 values are preserved correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(dashboard): status badge UI component for agents

1 participant