Skip to content

Feat progress column api#715

Merged
Karanjot786 merged 7 commits into
Karanjot786:mainfrom
Komal2008:feat-progress-column-api
Jun 5, 2026
Merged

Feat progress column api#715
Karanjot786 merged 7 commits into
Karanjot786:mainfrom
Komal2008:feat-progress-column-api

Conversation

@Komal2008
Copy link
Copy Markdown
Contributor

@Komal2008 Komal2008 commented Jun 4, 2026

Description

Adds a composable ProgressColumn API for the Progress widget. This introduces built-in column definitions (BarColumn, TextColumn, TimeColumn, SpeedColumn, and PercentageColumn), template-based rendering, custom render callback support, and default column fallbacks while maintaining backward compatibility.

Related Issue

Closes #96

Which package(s)?

@termuijs/widgets

Type of Change

  • ✨ Feature (type:feature)
  • 🧪 Tests (type:testing)
  • ♻️ Refactor (type:refactor)

Checklist

  • ⭐ You starred the repo. The needs-star check blocks your merge otherwise.
  • Tests pass locally: bun vitest run
  • Build passes: bun run build
  • Typecheck passes: bun run typecheck
  • Your PR title follows type: short description.
  • Widget state mutators call markDirty() (if your change affects rendering).
  • No new any types without an inline comment explaining why.
  • No unrelated refactors bundled into this PR.

GSSoC 2026 Participation

  • You are a GSSoC 2026 contributor.
  • Your GSSoC profile: https://gssoc.girlscript.org/profile/2af89ea2-51ba-40f3-a887-93e5300bea0e

Screenshots

image

Notes for the Reviewer

Changes Included

  • Added ProgressColumn.ts with composable column definitions.

  • Added support for:

    • BarColumn
    • TextColumn
    • TimeColumn
    • SpeedColumn
    • PercentageColumn
  • Added template-based text rendering ({task.status} style templates).

  • Added custom render callback support for columns.

  • Added column resolution logic with default fallback columns.

  • Preserved existing Progress usage when no columns are provided.

  • Added unit tests for ProgressColumn definitions and Progress behavior.

  • Exported Progress and ProgressColumn APIs through the widgets package index.

Validation

  • Typecheck passes successfully.
  • ProgressColumn tests pass successfully.

Summary by CodeRabbit

  • New Features

    • Added a Progress widget for displaying and managing task lists with customizable columns.
    • New column types: Bar, Text (with template support), Time, Speed, Percentage.
    • Columns can be supplied or auto-derived; time/speed columns use per-column refresh throttling and configurable visible rows.
  • Tests

    • Added tests covering column factories, template rendering, refresh behavior, and default/fallback column handling.

@Komal2008 Komal2008 requested a review from Karanjot786 as a code owner June 4, 2026 15:00
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new Progress widget with a composable ProgressColumn API (Bar/Text/Percentage/Time/Speed), child-derived or prop-provided columns, per-column maxRefresh throttling, rendering and caching logic, tests, and barrel exports.

Changes

Progress Widget with Composable ProgressColumn API

Layer / File(s) Summary
Progress column types and factory functions
packages/widgets/src/feedback/ProgressColumn.ts, packages/widgets/src/feedback/ProgressColumn.test.ts
ProgressColumnDefinition discriminated union with kind ('bar' | 'text' | 'time' | 'speed' | 'percentage'), maxRefresh, template, and optional render. Factory functions (BarColumn, TextColumn, TimeColumn, SpeedColumn, PercentageColumn) return definitions; tests validate returned shapes and Progress column fallback behavior.
Column resolution from children or props
packages/widgets/src/feedback/Progress.ts
_resolveColumns(children) normalizes vnode-like children and maps known vnode type values to corresponding column factories using vnode.props.
Progress constructor, state, and API
packages/widgets/src/feedback/Progress.ts
Defines ProgressTask/ProgressProps, initializes internal _tasks and _columns (children → props.columns → defaults), and exposes tasks/columns getters with setTasks() to update tasks and mark the widget dirty.
Rendering loop and per-column throttling
packages/widgets/src/feedback/Progress.ts
_renderSelf() renders up to available height rows, preferring column.render(task) or using column.kind formatters (text template substitution, percentage, 10-segment bar, time/speed placeholders). Time/speed columns honor maxRefresh using _lastRefreshTimes and a per-(taskIndex-columnIndex) _columnCache.
Public API exports
packages/widgets/src/index.ts
Re-exports Progress and its types, the five column factories and column types (ProgressColumnDefinition, ProgressColumnProps), and re-exports MarqueeDirection/MarqueeOptions types.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

level:intermediate, quality:exceptional

Suggested reviewers

  • Karanjot786

Poem

🐰 I stitched columns neat, row by row,
Bars and text and timers that glow,
Cached little hops to save the screen,
Tasks march forward, tidy and keen,
Hooray — progress in a neat little show!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
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.
Title check ❓ Inconclusive The PR title 'Feat progress column api' is vague and doesn't follow the required 'type: short description' format specified in the template. Update the title to follow the format 'feat: add composable ProgressColumn API' or similar to clearly indicate the specific change being made.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and follows the template structure with all required sections completed, including a clear description, linked issue, package identification, type of change, checklist, and GSSoC participation details.
Linked Issues check ✅ Passed The PR successfully implements all acceptance criteria from issue #96: composable ProgressColumn API with BarColumn, TextColumn, TimeColumn, SpeedColumn, and PercentageColumn; template-based rendering; maxRefresh support; and backward compatibility.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the ProgressColumn API as specified in issue #96; no unrelated refactoring or out-of-scope modifications are present in the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added area:widgets @termuijs/widgets type:testing +10 pts. Tests. labels Jun 4, 2026
@Komal2008
Copy link
Copy Markdown
Contributor Author

Hi @Karanjot786 👋

I've completed the implementation for #96 and submitted the PR. Typecheck and tests are passing.

Could you please review it when you have time? Thanks!

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: 3

🤖 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 `@packages/widgets/src/feedback/Progress.ts`:
- Around line 133-146: Throttling currently skips adding a cell when (now - last
< intervalMs), causing columns to drop; replace the continue with logic that
preserves layout by appending a stable placeholder or the previously rendered
cell for that column: fetch a cached cell/value from a per-column cache (e.g.,
this._lastRenderedCells.get(columnIndex) or
this._lastRenderedValues.get(columnIndex)) and append that instead of skipping,
and ensure you update that cache whenever you render a fresh cell so subsequent
throttled frames can reuse it; reference symbols: refreshRate, column.kind,
columnIndex, this._lastRefreshTimes.
- Around line 44-53: Progress has unchecked "any" usages and assertion-heavy
vnode parsing and also mis-handles throttling spacing and Unicode fallback;
change _renderSelf signature and constructor to use Screen and Style types from
`@termuijs/core` instead of any (replace "screen: any" and "super(style as any)" /
"this.style as any" with the imported Screen and Style), replace the ad-hoc
casts in _resolveColumns/_renderSelf vnode handling with a proper type guard
that narrows items to a VNode-like shape (check typeof item === 'object' && item
!== null && 'type' in item and then assert a typed interface), fix the
throttling logic inside the column loop so skipped columns still append a
placeholder to parts (avoid using continue which shortens parts and breaks
parts.join(' ') spacing), and use caps.unicode with an ASCII fallback when
choosing bar characters (use caps.unicode ? '█' : fallbackChar and similarly for
empty/bar gaps) to ensure correct rendering across terminals.

In `@packages/widgets/src/feedback/ProgressColumn.test.ts`:
- Around line 53-68: Update the tests to render the Progress widget into a real
Screen instance: create a Screen (import from `@termuijs/core`), instantiate
Progress with the provided columns (BarColumn, TextColumn) and also with no args
for the default case, call progress.updateRect(...) to set its size/position,
then call progress.render(screen) and assert the screen's buffer/characters
contain the expected output for each case instead of only checking
progress.columns length; reference Progress, BarColumn, TextColumn,
progress.updateRect, and progress.render when locating where to change the
tests.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5d15f593-87fc-4525-9fdf-5e247f9c943c

📥 Commits

Reviewing files that changed from the base of the PR and between c36cc8c and 620e636.

📒 Files selected for processing (4)
  • packages/widgets/src/feedback/Progress.ts
  • packages/widgets/src/feedback/ProgressColumn.test.ts
  • packages/widgets/src/feedback/ProgressColumn.ts
  • packages/widgets/src/index.ts

Comment thread packages/widgets/src/feedback/Progress.ts
Comment thread packages/widgets/src/feedback/Progress.ts
Comment on lines +53 to +68
it('uses provided columns in Progress', () => {
const progress = new Progress({
columns: [
BarColumn(),
TextColumn(),
],
});

expect(progress.columns).toHaveLength(2);
});

it('falls back to default columns', () => {
const progress = new Progress();

expect(progress.columns.length).toBeGreaterThan(0);
});
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the test file and print the relevant section
ls -la packages/widgets/src/feedback/ProgressColumn.test.ts
sed -n '1,140p' packages/widgets/src/feedback/ProgressColumn.test.ts

# Check if the file imports/uses Screen and render/updateRect anywhere
rg -n "Screen|updateRect|render|render\(" packages/widgets/src/feedback/ProgressColumn.test.ts || true

# Find a known-good widget test pattern (Gauge) and inspect it briefly
GAUGE_FILE=$(fd -i -a -t f "Gauge.test\.ts" packages/widgets/src | head -n 1 || true)
echo "Gauge test file: $GAUGE_FILE"
if [ -n "$GAUGE_FILE" ]; then
  sed -n '1,220p' "$GAUGE_FILE"
  rg -n "Screen|updateRect|render|caps\.unicode" "$GAUGE_FILE" || true
fi

# List any other Progress-related tests for context
fd -i -a "ProgressColumn\.test\.ts" packages/widgets/src | cat
fd -i -a "Progress.*\.test\.ts" packages/widgets/src | head -n 50

Repository: Karanjot786/TermUI

Length of output: 5468


Render Progress with a real Screen in widget tests

packages/widgets/src/feedback/ProgressColumn.test.ts (lines 53-68) only checks progress.columns length, so it doesn’t validate any observable rendered output or widget render contract. Update these tests to instantiate a real Screen from @termuijs/core, call progress.updateRect(...), then progress.render(screen), and assert the rendered characters for both the provided columns case and the default columns fallback.

🤖 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 `@packages/widgets/src/feedback/ProgressColumn.test.ts` around lines 53 - 68,
Update the tests to render the Progress widget into a real Screen instance:
create a Screen (import from `@termuijs/core`), instantiate Progress with the
provided columns (BarColumn, TextColumn) and also with no args for the default
case, call progress.updateRect(...) to set its size/position, then call
progress.render(screen) and assert the screen's buffer/characters contain the
expected output for each case instead of only checking progress.columns length;
reference Progress, BarColumn, TextColumn, progress.updateRect, and
progress.render when locating where to change the tests.

@Karanjot786 Karanjot786 added gssoc:approved Approved PR. Earns +50 base points. quality:clean x 1.2 multiplier. Clean implementation. level:advanced +55 pts. Complex task. type:feature +10 pts. New feature. labels Jun 4, 2026
@Karanjot786
Copy link
Copy Markdown
Owner

Review: Throttled columns drop layout cells

In packages/widgets/src/feedback/Progress.ts around lines 133-146, the throttle logic uses continue when a frame is skipped. This drops cells and breaks column alignment.

Fix it by caching the last rendered value per column:

// add a cache map
private _lastRenderedCells = new Map<number, string>();

// in the render loop instead of continue:
if (now - last < intervalMs) {
    const cached = this._lastRenderedCells.get(columnIndex) ?? ' ';
    // render cached cell
} else {
    // render fresh cell and update cache
    this._lastRenderedCells.set(columnIndex, freshCell);
}

This keeps layout stable across throttled frames.

@Karanjot786 Karanjot786 force-pushed the feat-progress-column-api branch from 98298b7 to 1415d74 Compare June 4, 2026 17:04
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.

🧹 Nitpick comments (1)
packages/widgets/src/feedback/ProgressColumn.ts (1)

34-42: ⚡ Quick win

Use spread operator for consistency with other column factories.

TextColumn explicitly destructures template and maxRefresh, while BarColumn, TimeColumn, SpeedColumn, and PercentageColumn use the spread operator. Both approaches work correctly, but the inconsistency reduces maintainability.

♻️ Proposed refactor to match the pattern used by other factories
 export function TextColumn(
     props: TextColumnProps = {},
 ): ProgressColumnDefinition {
     return {
         kind: 'text',
-        template: props.template,
-        maxRefresh: props.maxRefresh,
+        ...props,
     };
 }
🤖 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 `@packages/widgets/src/feedback/ProgressColumn.ts` around lines 34 - 42, The
TextColumn factory currently returns an object that explicitly copies template
and maxRefresh; change it to use the same spread pattern as the other factories
by returning { kind: 'text', ...props } so it accepts any fields defined on
TextColumnProps and stays consistent with
BarColumn/TimeColumn/SpeedColumn/PercentageColumn; update the return in the
TextColumn function to spread props into the ProgressColumnDefinition (keeping
kind: 'text') so TextColumnProps and ProgressColumnDefinition usage remains
correct.
🤖 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.

Nitpick comments:
In `@packages/widgets/src/feedback/ProgressColumn.ts`:
- Around line 34-42: The TextColumn factory currently returns an object that
explicitly copies template and maxRefresh; change it to use the same spread
pattern as the other factories by returning { kind: 'text', ...props } so it
accepts any fields defined on TextColumnProps and stays consistent with
BarColumn/TimeColumn/SpeedColumn/PercentageColumn; update the return in the
TextColumn function to spread props into the ProgressColumnDefinition (keeping
kind: 'text') so TextColumnProps and ProgressColumnDefinition usage remains
correct.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0777b96a-9b81-4e7c-ad1c-decc4019c9a5

📥 Commits

Reviewing files that changed from the base of the PR and between 98298b7 and 1415d74.

📒 Files selected for processing (4)
  • packages/widgets/src/feedback/Progress.ts
  • packages/widgets/src/feedback/ProgressColumn.test.ts
  • packages/widgets/src/feedback/ProgressColumn.ts
  • packages/widgets/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/widgets/src/feedback/ProgressColumn.test.ts
  • packages/widgets/src/index.ts
  • packages/widgets/src/feedback/Progress.ts

@Karanjot786 Karanjot786 merged commit 9c0de64 into Karanjot786:main Jun 5, 2026
6 checks passed
@Karanjot786
Copy link
Copy Markdown
Owner

Thank you so much for your contribution, @Komal2008!

Your PR #715 added the ProgressColumn API to @termuijs/widgets. Developers can now show per-row progress bars inside DataGrid columns.

Keep contributing. We appreciate your work.

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

Labels

area:widgets @termuijs/widgets gssoc:approved Approved PR. Earns +50 base points. level:advanced +55 pts. Complex task. quality:clean x 1.2 multiplier. Clean implementation. type:feature +10 pts. New feature. type:testing +10 pts. Tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Refactor Progress to composable ProgressColumn API

2 participants