Skip to content

fix: show status badges in overview when no quota data is available#489

Open
RaghavShubham wants to merge 2 commits into
robinebers:mainfrom
RaghavShubham:fix/status-badge-hidden-in-overview
Open

fix: show status badges in overview when no quota data is available#489
RaghavShubham wants to merge 2 commits into
robinebers:mainfrom
RaghavShubham:fix/status-badge-hidden-in-overview

Conversation

@RaghavShubham
Copy link
Copy Markdown

@RaghavShubham RaghavShubham commented May 22, 2026

Problem

When a plugin returns only a status badge — "No usage data" or "Rate limited" — and the card is rendered in overview/menu-bar scope, the badge was silently dropped, leaving the card visibly blank.

Root cause

ProviderCard filters lines by scope:

const filteredLines = scopeFilter === "all"
  ? lines
  : lines.filter(line => overviewLabels.has(line.label))

overviewLabels is built from skeletonLines with scope === "overview". For Claude that's only "Session" and "Weekly". The fallback badge has label "Status" — not in the set — so it gets filtered out.

After the first successful probe sets lastUpdatedAt, hasStaleData becomes true, but filteredLines stays empty. The {hasStaleData && …} block renders with no children → blank card.

This affects Enterprise accounts (API responds but contains no recognized quota fields), inference-only tokens, and any provider where the plugin falls back to a status-only badge.

Fix

src/components/provider-card.tsx — Badge-type lines are status indicators, not metric lines. They must always pass the scope filter:

// Badge lines are status indicators (e.g. "No usage data", "Rate limited") and must
// always be shown regardless of scope so the overview card is never silently blank.
const filteredLines = scopeFilter === "all"
  ? lines
  : lines.filter(line => line.type === "badge" || overviewLabels.has(line.label))

plugins/claude/plugin.js — Improve the fallback message so users can distinguish a working connection from an auth/network failure:

  • API connected, response has no recognized quota fields → "Connected — no quota data" (e.g. Enterprise plans)
  • Inference-only token / no API call made → "No usage data" (unchanged)

Tests

  • Added regression test in provider-card.test.tsx that reproduces the exact scenario: overview scope + lastUpdatedAt set + only a "Status" badge → badge must be visible.
  • Updated plugin.test.js to match the new "Connected — no quota data" text for the API-connected case, and added a complementary test for the inference-only path (must still show "No usage data" and must not call the HTTP API).

All 1087 tests pass.

Closes #440


Summary by cubic

Always show status badges in the overview and clarify Claude’s status when personal quota data isn’t available, including Enterprise org‑billing accounts.

  • Bug Fixes
    • ProviderCard always shows badge-type lines in overview so cards don’t render blank.
    • Claude plugin sets a clear status badge per scenario: 403 from usage API → "Enterprise — org-level billing"; API reachable but no recognized fields → "Connected — no quota data"; inference-only tokens → "No usage data" and skips HTTP calls.

Written for commit 4813319. Summary will update on new commits. Review in cubic

When a plugin returns only a "Status" badge (e.g. "No usage data" or
"Rate limited") and the card is rendered in overview scope, the badge
was silently filtered out because its label was not listed as an
overview-scoped line in plugin.json.  This left the card visibly
blank after the first successful probe set `lastUpdatedAt`, making
`hasStaleData` true while `filteredLines` remained empty.

Fix the scope filter in ProviderCard to always pass badge-type lines
through regardless of scope — they are status indicators, not metric
lines, and should always be visible.

Also improve the Claude plugin's fallback message when the usage API
responds successfully but returns no recognized quota fields (e.g.
Enterprise plans or future plan types): show "Connected — no quota
data" instead of the generic "No usage data" so users can distinguish
a working connection from an authentication or network failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 4 files

Re-trigger cubic

The personal usage endpoint (/api/oauth/usage) returns 403 for Enterprise
accounts because their billing is tracked at the organisation level, not
per-user.  Previously the plugin treated any 403 as a token-expired error,
which caused the JS probe to throw, the Rust runtime to emit an Error badge,
and the state management to set data=null.  On the first load this left the
provider card completely blank because hasStaleData was false and no
PluginError was prominently surfaced.

Fix: intercept 403 from the usage endpoint before the generic isAuthStatus
check and treat it as "no personal quota data" instead.  The probe no longer
throws, returns a "Status: Enterprise — org-level billing" badge, and the
card renders meaningful content on the first load.

A three-way fallback is now emitted when lines is empty:
  • 403 response                      → "Enterprise — org-level billing"
  • 200 but no recognized quota fields → "Connected — no quota data"
  • Inference-only / no API call       → "No usage data"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="plugins/claude/plugin.js">

<violation number="1" location="plugins/claude/plugin.js:632">
P2: Enterprise/org-billing status badge is not stable across probes because `orgBillingOnly` is function-local and lost when requests are throttled via the min-interval guard.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread plugins/claude/plugin.js
let lines = []
let rateLimited = false
let retryAfterSeconds = null
let orgBillingOnly = false // true when the API returned 403 (Enterprise org-level billing)
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot May 22, 2026

Choose a reason for hiding this comment

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

P2: Enterprise/org-billing status badge is not stable across probes because orgBillingOnly is function-local and lost when requests are throttled via the min-interval guard.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plugins/claude/plugin.js, line 632:

<comment>Enterprise/org-billing status badge is not stable across probes because `orgBillingOnly` is function-local and lost when requests are throttled via the min-interval guard.</comment>

<file context>
@@ -629,6 +629,7 @@
     let lines = []
     let rateLimited = false
     let retryAfterSeconds = null
+    let orgBillingOnly = false  // true when the API returned 403 (Enterprise org-level billing)
     if (canFetchLiveUsage) {
       if (nowMs < rateLimitedUntilMs) {
</file context>
Fix with Cubic

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Claude provider not displaying quota remaining

1 participant