Skip to content

feat(credits-admin): render daily-refills and 30-day usage panels#368

Merged
fbac merged 1 commit into
otr-devfrom
fbac/credits-admin-render-usage-panels
Jul 14, 2026
Merged

feat(credits-admin): render daily-refills and 30-day usage panels#368
fbac merged 1 commit into
otr-devfrom
fbac/credits-admin-render-usage-panels

Conversation

@fbac

@fbac fbac commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

The account view already fetched dailyRefills (daily_refill ledger rows) and usageDaily (30-day bucketed consumption) and shipped them in the JSON, but the client rendered neither — two dead queries per page load.

  • Wire up a Daily refills table and an inline bar sparkline for usage (CSP-safe, CSS-only, no external lib), each with an empty state.
  • Pin both with page tests.

Part of a 5-PR credits-admin audit sweep. Touches admin-page.ts — merge after the collapse-balance PR (or rebase).

Test Plan

  • pnpm vitest run tests/credits-admin/ → 53/53 (TDD red→green)
  • Rendered browser JS syntax-checked via node --check
  • typecheck / eslint / prettier --check clean

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Note

Add daily refills table and 30-day usage sparkline to credits admin page

  • Adds a 'Daily refills' card rendering j.dailyRefills into a #refills-table in admin-page.ts, with an empty-state hint row when no data is present.
  • Adds a 'Usage (last 30 days)' card rendering j.usageDaily as a bar sparkline in #usage-spark, scaling bar heights relative to max usage (minimum 2%) with tooltips showing bucket start and credit amounts.
  • Adds tests in admin-page.test.ts asserting the HTML contains both new panel elements and their associated script references.

Macroscope summarized 272e60c.

The account view already fetched dailyRefills (daily_refill ledger rows) and
usageDaily (30-day bucketed consumption) and shipped them in the JSON, but the
client rendered neither — two dead queries per page load. Wire them up: a
Daily refills table and an inline bar sparkline for usage (CSP-safe, CSS-only,
no external lib), each with an empty state. Pin both with page tests.
@fbac fbac requested a review from a team as a code owner July 14, 2026 10:23
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@fbac, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e4de0988-9777-4708-8bc2-2bc7d1411d42

📥 Commits

Reviewing files that changed from the base of the PR and between 7b11e05 and 272e60c.

📒 Files selected for processing (2)
  • src/api/v2/credits-admin/handlers/admin-page.ts
  • tests/credits-admin/admin-page.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fbac/credits-admin-render-usage-panels

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.

@claude

claude Bot commented Jul 14, 2026

Copy link
Copy Markdown

Claude finished @fbac's task —— View job


PR Review: Daily Refills & Usage Panels

  • Read repository conventions (CLAUDE.md)
  • Review handler implementation (admin-page.ts)
  • Review test coverage (admin-page.test.ts)
  • Analyze code quality, bugs, performance, security
  • Post comprehensive review feedback

Summary

This PR successfully wires up UI rendering for dailyRefills and usageDaily data that was already being fetched. The implementation is clean, follows existing patterns, and includes appropriate test coverage. The code is CSP-safe (CSS-only sparkline, no external libs) as advertised.

✅ Strengths

  1. Zero breaking changes — Only adds rendering logic, doesn't touch request/response contracts or money flows
  2. CSP-compliant — Bar chart is pure CSS with inline styles, avoiding script-based charting libs
  3. Proper empty states — Both panels handle zero-data gracefully with hint text
  4. Good test coverage — Tests verify both UI elements exist and that the JS consumes the data
  5. XSS protection — Uses esc() helper consistently for user-controlled data (dates, numbers)
  6. Accessibility — Sparkline bars include title attributes for tooltips

Code Quality

Positive observations

admin-page.ts:267-273 — Daily refills rendering:

var refills = j.dailyRefills || [];
var ft = document.querySelector("#refills-table tbody");
ft.innerHTML = refills.length
  ? refills.map(function (r) {
      return "<tr><td>" + fmtDate(r.createdAt) + "</td><td>" + esc(r.delta) + "</td><td>" + esc(r.note || "") + "</td></tr>";
    }).join("")
  : '<tr><td colspan="3" class="hint">No daily refills.</td></tr>';

✅ Proper empty state, safe HTML escaping, good fallback for r.note

admin-page.ts:275-290 — Usage sparkline:

var maxUsage = usage.reduce(function (m, u) {
  var c = Number(u.consumed);
  return c > m ? c : m;
}, 0);
// ... then normalizes heights as percentages

✅ Auto-scales bars relative to max usage, ensures minimum 2% height for visibility

🔍 Issues & Suggestions

Minor: Potential rendering bug with zero usage

admin-page.ts:286

var h = maxUsage > 0 ? Math.max(2, Math.round((c / maxUsage) * 100)) : 2;

Issue: When maxUsage === 0 (all usage buckets are zero), bars still render at 2% height, which visually suggests usage occurred. This contradicts the sparkline showing "No usage" for an empty array.

Suggestion: If all buckets are zero, fall back to the empty state:

if (!usage.length || maxUsage === 0) {
  spark.innerHTML = '<span class="hint">No usage in the last 30 days.</span>';
  return; // or use else
}

Minor: Data type consistency

admin-page.ts:281

var c = Number(u.consumed);

The backend serializes consumed as a string (u.consumed.toString() in account-view-get.ts:114), so this coercion is necessary. However, it's fragile if the backend schema changes.

Suggestion: Add a comment explaining why the string→number coercion is needed:

// Backend sends BigInt as string; convert for math
var c = Number(u.consumed);

Nit: Magic number for bar height

admin-page.ts:286

Math.max(2, Math.round((c / maxUsage) * 100))

The minimum 2 (percent) is hardcoded in multiple places (line 286, 287 fallback).

Optional: Extract to a const for clarity:

var MIN_BAR_HEIGHT_PCT = 2;
var h = maxUsage > 0 ? Math.max(MIN_BAR_HEIGHT_PCT, ...) : MIN_BAR_HEIGHT_PCT;

Test Coverage

tests/credits-admin/admin-page.test.ts:32-42

Both new UI elements are tested:

  • Checks id="refills-table" exists
  • Checks id="usage-spark" exists
  • Verifies JS references dailyRefills and usageDaily data

Suggestion: Consider adding a future integration test (out of scope for this PR) that actually loads account data and verifies the panels populate correctly. Current tests only check the HTML shell contains the elements.

Performance

No concerns

  • Rendering is client-side on page load (acceptable for admin tool)
  • Dataset sizes are capped (REFILL_LIMIT=20, USAGE_WINDOW_DAYS=30)
  • CSS-only bars avoid heavy charting libs

Security

No concerns

  • All dynamic data is escaped via esc() helper (admin-page.ts:193-196)
  • CSP header enforces script-src 'nonce-${nonce}' (line 14)
  • No new API endpoints or authentication changes

CLAUDE.md Compliance

Passes all checklist items

  • Request schema changes? → N/A (no schema changes)
  • Credits/balances touched? → No, only renders existing data (read-only)

This PR is display-only — it consumes data already fetched by account-view-get.ts without touching ledger operations or request contracts.

Final Recommendation

✅ Approve with optional minor refinements

The PR is production-ready as-is. The zero-usage edge case is cosmetic and may never occur in practice (accounts with 30 days of history likely have some usage). If you want to harden it, apply the maxUsage === 0 check.


Merge order note: Author mentions merging after "collapse-balance PR". Ensure that dependency is satisfied before merging to avoid conflicts in admin-page.ts.


@macroscopeapp

macroscopeapp Bot commented Jul 14, 2026

Copy link
Copy Markdown

Approvability

Verdict: Needs human review

These changes add display panels for daily refills and usage data in the credits admin page. While the changes are purely UI rendering with no backend impact, they touch files in a credits-related directory and are owned by xmtplabs/engineering, warranting review by the designated owners.

You can customize Macroscope's approvability policy. Learn more.

@fbac fbac merged commit fe31b8c into otr-dev Jul 14, 2026
10 checks passed
@fbac fbac deleted the fbac/credits-admin-render-usage-panels branch July 14, 2026 10:56
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.

1 participant