Skip to content

feat(chat): add progress bar renderer for markdown code blocks#836

Merged
PythonFZ merged 2 commits intomainfrom
feat/chat-progress-renderer
Jan 11, 2026
Merged

feat(chat): add progress bar renderer for markdown code blocks#836
PythonFZ merged 2 commits intomainfrom
feat/chat-progress-renderer

Conversation

@PythonFZ
Copy link
Copy Markdown
Member

@PythonFZ PythonFZ commented Jan 11, 2026

Add custom renderer for progress code blocks in chat messages. Users can now display progress bars using YAML-style syntax:

value: 50
max: 100
description: Loading...
color: success

Supports:

  • Determinate progress (LinearProgress) when value is provided
  • Indeterminate spinner (CircularProgress) when value is omitted
  • Customizable colors (primary, secondary, success, error, warning, info)
  • Display of value/max and percentage

Summary by CodeRabbit

  • New Features

    • Progress bars can now be embedded in chat messages with customizable colors, value ranges, and descriptions via Markdown code blocks.
  • Documentation

    • Added documentation covering progress bar syntax, parameters (value, min, max, description, color), and practical examples.
  • Tests

    • Added test coverage for chat progress bar functionality including determinate and indeterminate progress states.

✏️ Tip: You can customize this high-level summary in your review settings.

PythonFZ and others added 2 commits January 11, 2026 20:53
Add custom renderer for progress code blocks in chat messages.
Users can now display progress bars using YAML-style syntax:

```progress
value: 50
max: 100
description: Loading...
color: success
```

Supports:
- Determinate progress (LinearProgress) when value is provided
- Indeterminate spinner (CircularProgress) when value is omitted
- Customizable colors (primary, secondary, success, error, warning, info)
- Display of value/max and percentage

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document chat's markdown rendering capabilities (formatting, LaTeX, code blocks)
- Add progress bar code block syntax documentation with parameters
- Add test_chat_progress screenshot test for progress bar examples
- Add light/dark mode screenshots for progress bar feature

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 11, 2026

📝 Walkthrough

Walkthrough

The PR introduces progress indicator rendering support to the chat window. A new ProgressRenderer component parses and displays visual progress bars from Markdown code blocks labeled with the "progress" language identifier. Supporting types, utilities, documentation, and test coverage are added to enable this functionality across the chat interface.

Changes

Cohort / File(s) Change Summary
Progress Renderer Implementation
app/src/components/ChatWindow.tsx
Introduces ProgressRenderer component with supporting types (ProgressColor, ProgressConfig) and parseProgressConfig utility function. Extends Markdown code block handler to detect "progress" language and render ProgressRenderer instead of standard code blocks. Updates both normal and fullscreen rendering paths.
Documentation
docs/source/python-api.rst
Adds subsections documenting Markdown code blocks and progress bar syntax under Frame References, with example snippets and parameter descriptions (value, min, max, description, color).
Test Coverage
misc/test_screenshots.py
Adds test_chat_progress function to validate progress bar rendering with determinate and indeterminate states, capturing light and dark theme screenshots.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Progress bars now dance so bright,
In chat messages, a visual delight,
From zero to complete they stride,
With colors as the perfect guide!
Tracking tasks in Markdown's way,
Making progress come to play! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature addition: a progress bar renderer for markdown code blocks, which is the primary change across all files in the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @app/src/components/ChatWindow.tsx:
- Around line 131-134: The percentage calculation in ChatWindow.tsx can divide
by zero when config.max === config.min; update the computation of percentage
(the const percentage using config.value, config.min, config.max) to first
compute the denominator and only calculate ((config.value - config.min) / denom)
* 100 when denom > 0, otherwise set percentage to null (or a safe fallback like
0) so NaN/Infinity cannot propagate into the later Math.min/Math.max clamping on
line 148.
🧹 Nitpick comments (1)
app/src/components/ChatWindow.tsx (1)

526-561: Consider extracting the duplicated code block rendering logic.

The code component handler is duplicated nearly identically between fullscreen mode (lines 526-561) and normal mode (lines 801-836). This could be extracted to a shared function or custom component to improve maintainability.

♻️ Example extraction
// Define outside ChatWindow component
const createCodeComponent = (mode: "light" | "dark") => {
  return ({ node, className, children, ...props }: any) => {
    const match = /language-(\w+)/.exec(className || "");
    const language = match?.[1];
    const content = String(children).replace(/\n$/, "");

    if (language === "progress") {
      return <ProgressRenderer content={content} />;
    }

    return match ? (
      <SyntaxHighlighter
        style={mode === "dark" ? oneDark : oneLight}
        language={language}
        PreTag="div"
        {...props}
      >
        {content}
      </SyntaxHighlighter>
    ) : (
      <code className={className} {...props}>
        {children}
      </code>
    );
  };
};

Also applies to: 801-836

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 377cbba and f9fc560.

⛔ Files ignored due to path filters (2)
  • docs/source/_static/screenshots/darkmode/chat_progress.png is excluded by !**/*.png
  • docs/source/_static/screenshots/lightmode/chat_progress.png is excluded by !**/*.png
📒 Files selected for processing (3)
  • app/src/components/ChatWindow.tsx
  • docs/source/python-api.rst
  • misc/test_screenshots.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: You MUST NEVER @pytest.mark.xfail or similar - all tests must pass!
All default values (e.g., camera, particles) must be defined exclusively within the Pydantic model. Do not scatter fallback logic throughout the codebase.
Do not perform null checks combined with hardcoded literals for default values. Rely entirely on the schema to populate default values during initialization.
You can not use LUA scripts with Redis!
If sensible, implement collections.abc interfaces for your classes, such as MutableMapping or MutableSequence.
Use numpy style docstrings in Python code.
Docstrings must be concise and to the point.
Use type hints wherever possible in Python. Use list[int|float] | None instead of t.Optional[t.List[int|float]]!
Imports should always be at the top of the file in Python.

Files:

  • misc/test_screenshots.py
**/test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

When designing new tests, read the old tests first to understand the existing patterns. Use pytest.mark.parametrize to avoid code duplication. Tests should be very specific and test only one thing. Avoid complex test setups. Each test must be a function, not a method of a class!

Files:

  • misc/test_screenshots.py
🧬 Code graph analysis (1)
misc/test_screenshots.py (2)
tests/conftest.py (1)
  • server (419-425)
misc/conftest.py (7)
  • server (41-69)
  • page (73-87)
  • capture (91-120)
  • bmim_bf4 (124-132)
  • light (102-107)
  • toggle (116-118)
  • dark (109-114)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pytest (3.13, ubuntu-latest)
  • GitHub Check: pytest (3.11, ubuntu-latest)
  • GitHub Check: pytest (3.12, ubuntu-latest)
🔇 Additional comments (5)
docs/source/python-api.rst (1)

517-579: Documentation is well-structured and comprehensive.

The new sections clearly document the Markdown rendering capabilities and progress bar syntax. The parameters (value, min, max, description, color) match the TypeScript implementation, and the example code is syntactically correct. The cross-reference to progress_tracker for real-time updates is a helpful addition.

misc/test_screenshots.py (1)

764-797: Test follows established patterns and provides good coverage.

The test correctly demonstrates both determinate (with value: 75) and indeterminate (without value) progress bars. It follows the same structure as other screenshot tests in the file, using the standard fixtures and light/dark mode capture pattern.

app/src/components/ChatWindow.tsx (3)

58-72: Type definitions are well-structured.

The ProgressColor type correctly maps to MUI's supported color variants, and ProgressConfig properly models the expected configuration with optional value for indeterminate progress support.


74-126: Parsing logic is robust and handles edge cases well.

The function correctly uses indexOf(':') instead of split(':') to handle colons in description values. Number validation with Number.isNaN and color validation against a whitelist are properly implemented. Case-insensitive key matching (toLowerCase()) is a good UX choice.


136-175: ProgressRenderer component implementation looks good.

The component correctly handles both determinate (with value) and indeterminate (without value) progress states. The UI layout is clean with proper accessibility via semantic Typography components and appropriate color contrasts.

Comment on lines +131 to +134
const percentage =
config.value !== undefined
? ((config.value - config.min) / (config.max - config.min)) * 100
: null;
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 | 🟡 Minor

Potential division by zero when max === min.

If a user specifies max: 50 and min: 50, the percentage calculation will divide by zero, resulting in Infinity or NaN. While Math.min/Math.max clamping on line 148 handles Infinity, NaN would still propagate.

🔧 Suggested fix
 const percentage =
   config.value !== undefined
-    ? ((config.value - config.min) / (config.max - config.min)) * 100
+    ? config.max !== config.min
+      ? ((config.value - config.min) / (config.max - config.min)) * 100
+      : 100
     : null;
📝 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
const percentage =
config.value !== undefined
? ((config.value - config.min) / (config.max - config.min)) * 100
: null;
const percentage =
config.value !== undefined
? config.max !== config.min
? ((config.value - config.min) / (config.max - config.min)) * 100
: 100
: null;
🤖 Prompt for AI Agents
In @app/src/components/ChatWindow.tsx around lines 131 - 134, The percentage
calculation in ChatWindow.tsx can divide by zero when config.max === config.min;
update the computation of percentage (the const percentage using config.value,
config.min, config.max) to first compute the denominator and only calculate
((config.value - config.min) / denom) * 100 when denom > 0, otherwise set
percentage to null (or a safe fallback like 0) so NaN/Infinity cannot propagate
into the later Math.min/Math.max clamping on line 148.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Jan 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.93%. Comparing base (377cbba) to head (f9fc560).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #836      +/-   ##
==========================================
+ Coverage   79.92%   79.93%   +0.01%     
==========================================
  Files         161      161              
  Lines       19745    19745              
==========================================
+ Hits        15781    15783       +2     
+ Misses       3964     3962       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@PythonFZ PythonFZ merged commit 738edfa into main Jan 11, 2026
6 checks passed
@PythonFZ PythonFZ deleted the feat/chat-progress-renderer branch January 11, 2026 20:38
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.

2 participants