Skip to content

fix(gooddata-widget): AI Credits dashboard display, labeling, and scale fixes - #227

Open
goodbounties-nanoclaw-agent[bot] wants to merge 12 commits into
mainfrom
feat/ai-credits-dashboard-fixes-222
Open

fix(gooddata-widget): AI Credits dashboard display, labeling, and scale fixes#227
goodbounties-nanoclaw-agent[bot] wants to merge 12 commits into
mainfrom
feat/ai-credits-dashboard-fixes-222

Conversation

@goodbounties-nanoclaw-agent

Copy link
Copy Markdown
Contributor

Closes #222. Implements the plan from #224.

Fixes

  1. Total scorecard rename + USD equivalent (8ac9e4b) — "AI Credits Used" → "Total Credits Bought in G$", now shows the USD equivalent via weiToUsd(data.global.aiCreditsUsedWei).
  2. Subscription sub-line (3653fb7) — adds "out of X G$ in subscription (streaming)" under the total scorecard via weiToGd(data.global.gdStreamedWei).
  3. Flow-rate scorecard rename (7d1bb8e) — "G$ Flow Rate" (per-day) → "Total Monthly Subscriptions", backed by a new flowRateToMonthly() conversion helper instead of the old daily rate.
  4. G$ Volume chart streamed-line legibility (150ddd0) — investigated by pulling real production data from the live AntSeed Worker (/v1/analytics) and tracing LineAreaChart's dual-axis scaling code directly. The secondaryYAxis mechanism has computed each axis independently since the original feat(apps): AI Credits analytics data widget #179 PR and already renders both series legibly, including at the ~40x deposit-vs-streamed magnitude disparity seen in real production data — no functional bug found, so no code change was needed here. Added a new RealisticVolume Storybook QA fixture shaped after that real data plus a Playwright regression test asserting both axis labels stay visible, so this is guarded going forward instead of only being covered by the smooth demo/live ramp fixture.
  5. Daily table USD precision (713da80) — "AI Credits (USD)" column: .toFixed(2).toFixed(3).
  6. Analytics fetch window (00f1ae9) — ANALYTICS_DAYS_REQUESTED: 365 → 30 in connector.ts.

The same commit (150ddd0) also retrofits tests/widgets/gooddata-widget/states.spec.ts with text assertions covering fixes #1-#3's renamed labels/sub-line (previously verified only visually, not by the committed spec) and refreshes all baseline screenshots for the new copy, per repo convention.

Out of scope, flagging rather than fixing here

While tracing the flow-rate conversion, found generateDemoData.ts's demo-mode flow rate is computed as Math.floor(streamedGd / SECONDS_PER_DAY), which floors to 0 for any realistic demo streamedGd value — so demo mode's gdTotalFlowRateWeiPerSecond is always "0". Not one of #222's 6 acceptance criteria and not touched by this PR; flagging so it can be tracked as its own fix rather than silently left in place.

Verified

Each fix above was committed individually and visually verified via Storybook + Playwright before moving to the next, per the process used for the #179 rounds. Full pipeline (pnpm build, scoped lint, npx playwright test tests/widgets/gooddata-widget/states.spec.ts) passes.

Note on commit signatures: commits on this branch show as unsigned (neither the Git Data API nor the Contents API produce GPG/SSH-signed commits in this environment — confirmed empirically). This repo's ruleset requires signed commits on main. Squash-merging this PR is safe (GitHub signs the resulting squash commit itself, independent of source-branch signatures) — please don't rebase-merge, which would carry the unsigned commits onto main directly.

Co-Authored-By: Claude noreply@anthropic.com

Adds an optional subLabel? prop rendered as a dim caption line below the
value row, reusing the trend row's spacing tier. Needed by the AI Credits
dashboard's "Total Credits Bought in G$" scorecard to show a
streaming/subscription breakdown line (#222), but kept generic in
packages/ui since it's a reusable KPI-card capability, not AI-Credits
specific.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…om 365 to 30 days

A full year of daily points was an unnecessary perf hit for a dashboard
that only visualizes the trailing month. Per #222 (fix 6).

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…ts (USD) column

.toFixed(2) rounded most rows' sub-cent daily AI Credit usage to $0.00.
Per #222 (fix 5).

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…monthly total

Replaces flowRateToDaily with flowRateToMonthly (plain multiplication by
2629746 seconds/month, mirroring the existing BigInt-safe reduction) and
relabels "G$ Flow Rate" -> "Total Monthly Subscriptions", dropping the
"/day" suffix that read as a daily rate. Per #222 (fix 3).

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…USD equivalent

Relabels the first AI Credits scorecard from "Total G$ Spent" to "Total
Credits Bought in G$" and appends the USD-equivalent value (already
computed for the separate "AI Credits Used" card) as a suffix, per CEO
feedback after the PR #179 production deploy (#222, fix 1).

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…ine on total scorecard

Adds a "out of X G$ in subscription (streaming)" caption under the
first scorecard's value, using the already-computed streamed total, so
the breakdown between one-time and recurring credit purchases is
visible at a glance (#222, fix 2).

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…ility + cover scorecard label fixes

Fix #4 investigation: the G$ Volume chart's secondaryYAxis mechanism (in
LineAreaChart, present since #179) already computes each axis's scale
independently from only its own series' values, so a large magnitude gap
between one-time deposits and streamed G$ doesn't flatten the streamed line.
Confirmed this against a fixture shaped after real production data pulled
from the live AntSeed Worker (sparse deposit spikes up to ~40x the streamed
band) — both lines render clearly distinguishable on their own axes. No
LineAreaChart or dashboard code change was needed; the deliverable is the
new "RealisticVolume" QA fixture plus a Playwright assertion so this stays
covered going forward instead of relying on the smooth demo/live ramp.

Also retrofits the live-state spec with text assertions for fixes #1-#3's
renamed scorecard labels and sub-line, which had been verified visually but
not covered by the Playwright spec, and refreshes all baseline screenshots
to reflect the new label copy.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the GoodData widget’s AI Credits dashboard to improve labeling, value presentation, and scale/legibility under realistic production-like data, and tightens the default analytics fetch window.

Changes:

  • Renames/retunes dashboard scorecards (adds USD equivalent + subscription sub-line; switches flow-rate to monthly subscriptions via a new conversion).
  • Improves daily table USD precision (3 decimals) and reduces analytics fetch window to 30 days.
  • Adds a production-shaped Storybook fixture plus a Playwright regression test targeting dual-axis volume-chart legibility.

Reviewed changes

Copilot reviewed 7 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/widgets/gooddata-widget/states.spec.ts Adds assertions for updated scorecard copy and a new “realistic volume” chart regression check.
packages/ui/src/components/Scorecard.tsx Adds subLabel support to render a caption line under the value row.
packages/gooddata-widget/src/dashboards/aiCredits/connector.ts Reduces default analytics history window from 365 days to 30 days.
packages/gooddata-widget/src/dashboards/aiCredits/analyticsConversions.ts Introduces flowRateToMonthly() conversion using average seconds per month.
packages/gooddata-widget/src/dashboards/aiCredits/AiCreditsDashboard.tsx Applies updated scorecard labels/values, monthly conversion, and 3-decimal USD formatting.
examples/storybook/src/stories/helpers/goodDataWidgetStories.tsx Adds a realistic 30-day analytics fixture and story wrapper for QA/regression coverage.
examples/storybook/src/stories/gooddata-widget/GoodDataWidgetQA.stories.tsx Exposes the new “RealisticVolume” QA story.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +127 to +136
global: {
gdOneTimeDepositsWei: String(
REALISTIC_VOLUME_DAILY.reduce((sum, day) => sum + BigInt(day.gdOneTimeDepositsWei), 0n),
),
gdStreamedWei: REALISTIC_VOLUME_DAILY[REALISTIC_VOLUME_DAILY.length - 1].gdStreamedWei,
aiCreditsUsedWei: String(
REALISTIC_VOLUME_DAILY.reduce((sum, day) => sum + BigInt(day.aiCreditsUsedWei), 0n),
),
gdTotalFlowRateWeiPerSecond: REALISTIC_VOLUME_DAILY[REALISTIC_VOLUME_DAILY.length - 1].gdTotalFlowRateWeiPerSecond,
updatedAt: `${REALISTIC_VOLUME_DAILY[REALISTIC_VOLUME_DAILY.length - 1].date}T23:59:59.999Z`,
Comment on lines +108 to +111
// The rotated axis title can wrap onto two lines (each its own text node), so
// match the distinctive word rather than the full label string.
await expect(volumeChart.getByText('Deposits', { exact: false }).first()).toBeVisible()
await expect(volumeChart.getByText('Streamed', { exact: false }).first()).toBeVisible()
…rd for flow rate, flag USD-deposit gap

Total Monthly Subscriptions showed G$0.00 in the live preview because the
flow-rate scorecard read global.gdTotalFlowRateWeiPerSecond directly, which
mirrors the Worker's most recent daily record even when that record is
today's still-accumulating, missing:true snapshot — right after a day
boundary this reads as 0 until the new day's first streaming event lands.
Reuse dailyRecords (already filtered to exclude missing:true records for the
chart/table) so the scorecard reads the same latest-complete-day value.

Also fixes Scorecard 1's USD line incorrectly reusing aiCreditsUsedWei (a
different metric, "AI credits consumed") instead of the USD equivalent of
the deposited/bought G$ total. The Worker's schema exposes no G$/USD
exchange rate to compute that client-side, so per explicit request the USD
line stays (not removed) but now reads as a labeled data-source-gap
placeholder pending a rate field from the data team.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…oss from wei-space truncation

generateDemoData's per-day flow rate divided streamedGd (a plain integer,
200-800) by SECONDS_PER_DAY before scaling to wei, which always floors to
exactly 0 for that range. Do the division after scaling to wei so the
fractional per-second rate survives instead of being truncated away first.

This is a separate root cause from the live-data flow-rate bug fixed
separately (that one reads a stale/missing daily record; this one is pure
integer-division precision loss) — fixing one does not fix the other.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…m and scope dual-axis test to svg

RealisticVolume fixture's global.gdStreamedWei used only the last day's
value instead of summing the window, breaking the "out of X G$ in
subscription" figure for that fixture (Copilot review on #227).

The dual-axis Playwright test matched "Deposits"/"Streamed" text anywhere in
the chart container, which could pass via the legend (rendered as a sibling
YStack outside the chart's <svg>) even if the axis titles themselves were
broken. Scope the lookup to the chart's own <svg> so the test actually
guards axis-title legibility, which is its stated purpose.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…r bugfix round

Regenerated after fixing the flow-rate/USD-line bugs and the two
Copilot-flagged test/fixture issues.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…rate for deposited-total USD line

Per Thales's call: replace the "(USD rate pending)" placeholder with an
actual estimate, computed as totalGdSpent * TEMP_GD_USD_RATE (0.00013),
until the Worker exposes a live rate. Kept clearly marked as temporary in
a code comment so it's easy to find and swap out — Thales is following up
with Mike/Hadar on a real rate field.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
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.

[Feature] AI Credits dashboard: display, labeling, and scale fixes

1 participant