You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This plan covers the 6 acceptance criteria in #222: relabeling/format fixes to the
AI Credits dashboard's scorecards, table, and volume chart, plus a fetch-window
reduction — all feedback from Hadar Rottenberg (CEO) after the PR #179 production
deploy of gooddata.gooddollar.org.
Base branch:main @ current head — fresh PR, not a reopen of PR #179's branch (#179 is merged/closed).
Resolved (Thales, 2026-08-31): Fix 1 is relabel-only. "Total G$ Spent" → "Total Credits Bought in G$" with USD equivalent + subscription sub-line. "AI Credits Used" stays its own separate scorecard (different metric — credits consumed vs. credits purchased). The 3-scorecard layout itself is unchanged.
Reference files mapped
All 6 changes are scoped to one existing package, no new packages needed:
packages/ui/src/components/Scorecard.tsx and packages/ui/src/components/LineAreaChart.tsx — existing @goodwidget/ui primitives, imported not modified except where noted below.
packages/gooddata-widget/src/dashboards/aiCredits/generateDemoData.ts / mockState.ts — demo/QA fixture data; already has non-zero, growth-ramped streamed values, no upstream change needed for the fixes themselves, but Storybook fixtures must visibly reflect the new labels/sub-line/axis.
examples/storybook/src/stories/gooddata-widget/GoodDataWidgetQA.stories.tsx + examples/storybook/src/stories/helpers/goodDataWidgetStories.tsx — existing QA fixture stories, reused as-is (state matrix doesn't change, only what each state renders).
tests/widgets/gooddata-widget/states.spec.ts — existing Playwright spec asserting on scorecard-*/chart-*/daily-summary testIDs; extend assertions for the new sub-line and relabeled scorecard, per standing repo convention (Playwright spec + committed baseline screenshots for every widget-affecting change).
Existing @GoodDollar packages imported: @goodwidget/ui (Scorecard, LineAreaChart, BarChart, formatMetricValue, DataTableColumnDef) and @goodwidget/embed, both already wired via packages/gooddata-widget/package.json workspace deps — no new dependency needed.
New components — package placement assessment
Scorecard sub-line (fix: basics #2):Scorecard (packages/ui) currently renders label / value+prefix+suffix / optional trend row — no slot for a second descriptive line under the value. A "breakdown" caption (e.g. "out of X G$ in subscription (streaming)") is a generic KPI-card capability, not specific to AI Credits — add an optional subLabel?: string prop to Scorecard in packages/ui, rendered as a dim caption-sized line below the value row (reusing ScorecardTrendRow's spacing tier). This keeps the primitive reusable for the ~26 other Scorecard call sites rather than one-off wrapping it inside gooddata-widget.
flowRateToMonthly() ([BOUNTY] Migrate First-Wave UI Primitives To Tamagui-Native Wrappers #3): stays in packages/gooddata-widget/src/dashboards/aiCredits/analyticsConversions.ts, alongside flowRateToDaily — this file is already AI-Credits-specific unit-conversion logic, not a reusable primitive.
Streaming line visibility (Map GoodWalletV2 UI components to GoodWidget Tamagui primitives #4): no new component. LineAreaChart (packages/ui) already supports secondaryYAxis and AiCreditsDashboard.tsx already wires the "streamed" series to it. Demo fixture data (generateDemoData.ts) has realistic non-zero streamed values, so the dual-axis path itself isn't obviously broken — needs live-data verification (see below) before deciding between fixing the existing dual-axis config vs. the issue's stated fallback (split into two single-axis charts).
No new widget package, no new packages/ui chart type — everything is a targeted edit to existing files.
Required states, flows, and behaviors
Total Credits scorecard: relabel "Total G$ Spent" → "Total Credits Bought in G$", keep computing its primary value from weiToGd(gdOneTimeDepositsWei) + weiToGd(gdStreamedWei) as today, and add a USD-equivalent shown via weiToUsd(data.global.aiCreditsUsedWei). The "AI Credits Used" scorecard stays a separate, unchanged card (relabel-only per Thales — the 3-scorecard layout does not change).
Streaming/subscription sub-line: new subLabel on the first scorecard reading "out of X G$ in subscription (streaming)" where X = weiToGd(data.global.gdStreamedWei).
Flow-rate scorecard: relabel "G$ Flow Rate" → "Total Monthly Subscriptions", drop the suffix="/day", switch the value to flowRateToMonthly(data.global.gdTotalFlowRateWeiPerSecond) (new helper: BigInt(weiPerSecStr) * 2629746n, then reuse weiToGd's BigInt-safe reduction — mirrors flowRateToDaily's structure with SECONDS_PER_MONTH = 2629746n in place of SECONDS_PER_DAY).
G$ Volume chart streaming line: verify the existing secondaryYAxis dual-axis rendering against real (not just demo) data shape; if genuinely not visibly distinguishable (e.g. because live streamed amounts are much smaller than deposits even on their own axis), fall back to two single-axis LineAreaCharts — one for one-time deposits, one for streamed — per [Feature] AI Credits dashboard: display, labeling, and scale fixes #222's explicit fallback instruction.
Fetch window:ANALYTICS_DAYS_REQUESTED: 365 → 30 in connector.ts.
All 5 existing dashboard states (loading, live, demo, live-unavailable, empty) must continue to render correctly with the new labels/values — no new state is introduced.
Execution plan
Add SECONDS_PER_MONTH + flowRateToMonthly() to analyticsConversions.ts, following the existing flowRateToDaily pattern and its BigInt-safety comments.
Add optional subLabel?: string to Scorecard (packages/ui), rendered below the value row.
Investigate the G$ Volume chart's dual-axis rendering with realistic live-shaped data (demo generator or a captured live payload); fix or fall back to split charts per the required-behavior above.
Update connector.ts's ANALYTICS_DAYS_REQUESTED to 30.
Update Storybook QA fixtures / mock data (generateDemoData.ts, mockState.ts, goodDataWidgetStories.tsx) only if the new sub-line/relabeled values need different fixture shaping to demonstrate correctly — otherwise reuse as-is.
Extend tests/widgets/gooddata-widget/states.spec.ts with assertions for the new scorecard labels, sub-line, and (if changed) split-chart testIDs; regenerate and commit updated baseline screenshots under tests/widgets/gooddata-widget/test-results/ (standing repo convention — not optional).
Run typecheck/lint/build scoped to packages/gooddata-widget and packages/ui, plus the Playwright spec, before opening the PR. Commit one fix at a time, code + visual (Storybook/Playwright screenshot) verify before advancing to the next — same process as the feat(apps): AI Credits analytics data widget #179 rounds.
Acceptance criteria
First scorecard reads "Total Credits Bought in G$" with USD equivalent shown, "AI Credits Used" scorecard unchanged and still separate
Subscription/streaming portion shown as a sub-line under the first scorecard, computed via weiToGd(data.global.gdStreamedWei)
Flow-rate scorecard relabeled "Total Monthly Subscriptions", computed via new flowRateToMonthly(), no "/day" suffix
Streaming line is visibly distinguishable on the G$ Volume chart (dual-axis fix verified against realistic data, or split into two charts per the fallback)
Visually verify the G$ Volume chart's streaming line is actually legible at typical production data magnitudes, not just in the demo/ramped fixture data
Confirm flowRateToMonthly()'s 2629746 seconds-per-month constant and BigInt arithmetic match the rest of analyticsConversions.ts's precision conventions (4-decimal OUTPUT_PRECISION_DECIMALS reduction)
Confirm the new Scorecard.subLabel prop doesn't regress any other existing Scorecard call site's layout (it's additive/optional, but check other pages using variant="card")
Confirm Playwright baseline screenshots were regenerated and committed, not left stale
Confirm no unrelated widget/package was touched — this issue is scoped entirely to gooddata-widget's aiCredits dashboard plus one small packages/ui Scorecard addition
[DRAFT][PLAN] AI Credits dashboard: display, labeling, and scale fixes
Type: Task
Parent issue: #222
Plan for #222.
This plan covers the 6 acceptance criteria in #222: relabeling/format fixes to the
AI Credits dashboard's scorecards, table, and volume chart, plus a fetch-window
reduction — all feedback from Hadar Rottenberg (CEO) after the PR #179 production
deploy of
gooddata.gooddollar.org.Base branch:
main@ current head — fresh PR, not a reopen of PR #179's branch (#179 is merged/closed).Resolved (Thales, 2026-08-31): Fix 1 is relabel-only. "Total G$ Spent" → "Total Credits Bought in G$" with USD equivalent + subscription sub-line. "AI Credits Used" stays its own separate scorecard (different metric — credits consumed vs. credits purchased). The 3-scorecard layout itself is unchanged.
Reference files mapped
All 6 changes are scoped to one existing package, no new packages needed:
packages/gooddata-widget/src/dashboards/aiCredits/connector.ts—ANALYTICS_DAYS_REQUESTEDconstant (feat: route-based demo lab + Playwright setup for Copilot cloud agent #6).packages/gooddata-widget/src/dashboards/aiCredits/analyticsConversions.ts— wei→display conversions; addflowRateToMonthly()alongside the existingweiToGd/weiToUsd/flowRateToDaily([BOUNTY] Migrate First-Wave UI Primitives To Tamagui-Native Wrappers #3).packages/gooddata-widget/src/dashboards/aiCredits/AiCreditsDashboard.tsx— scorecard labels/values (Add iframe/webview bridge package and runnable Expo demo #1, fix: basics #2, [BOUNTY] Migrate First-Wave UI Primitives To Tamagui-Native Wrappers #3),LineAreaChartvolume chart config (Map GoodWalletV2 UI components to GoodWidget Tamagui primitives #4),TABLE_COLUMNSformatter for the AI Credits (USD) column (feat: route-based demo lab + Playwright setup for Copilot cloud agent #5).packages/ui/src/components/Scorecard.tsxandpackages/ui/src/components/LineAreaChart.tsx— existing@goodwidget/uiprimitives, imported not modified except where noted below.packages/gooddata-widget/src/dashboards/aiCredits/generateDemoData.ts/mockState.ts— demo/QA fixture data; already has non-zero, growth-ramped streamed values, no upstream change needed for the fixes themselves, but Storybook fixtures must visibly reflect the new labels/sub-line/axis.examples/storybook/src/stories/gooddata-widget/GoodDataWidgetQA.stories.tsx+examples/storybook/src/stories/helpers/goodDataWidgetStories.tsx— existing QA fixture stories, reused as-is (state matrix doesn't change, only what each state renders).tests/widgets/gooddata-widget/states.spec.ts— existing Playwright spec asserting onscorecard-*/chart-*/daily-summarytestIDs; extend assertions for the new sub-line and relabeled scorecard, per standing repo convention (Playwright spec + committed baseline screenshots for every widget-affecting change).Existing
@GoodDollarpackages imported:@goodwidget/ui(Scorecard, LineAreaChart, BarChart, formatMetricValue, DataTableColumnDef) and@goodwidget/embed, both already wired viapackages/gooddata-widget/package.jsonworkspace deps — no new dependency needed.New components — package placement assessment
Scorecard(packages/ui) currently renders label / value+prefix+suffix / optional trend row — no slot for a second descriptive line under the value. A "breakdown" caption (e.g. "out of X G$ in subscription (streaming)") is a generic KPI-card capability, not specific to AI Credits — add an optionalsubLabel?: stringprop toScorecardinpackages/ui, rendered as a dim caption-sized line below the value row (reusingScorecardTrendRow's spacing tier). This keeps the primitive reusable for the ~26 other Scorecard call sites rather than one-off wrapping it insidegooddata-widget.flowRateToMonthly()([BOUNTY] Migrate First-Wave UI Primitives To Tamagui-Native Wrappers #3): stays inpackages/gooddata-widget/src/dashboards/aiCredits/analyticsConversions.ts, alongsideflowRateToDaily— this file is already AI-Credits-specific unit-conversion logic, not a reusable primitive.LineAreaChart(packages/ui) already supportssecondaryYAxisandAiCreditsDashboard.tsxalready wires the "streamed" series to it. Demo fixture data (generateDemoData.ts) has realistic non-zero streamed values, so the dual-axis path itself isn't obviously broken — needs live-data verification (see below) before deciding between fixing the existing dual-axis config vs. the issue's stated fallback (split into two single-axis charts).packages/uichart type — everything is a targeted edit to existing files.Required states, flows, and behaviors
weiToGd(gdOneTimeDepositsWei) + weiToGd(gdStreamedWei)as today, and add a USD-equivalent shown viaweiToUsd(data.global.aiCreditsUsedWei). The "AI Credits Used" scorecard stays a separate, unchanged card (relabel-only per Thales — the 3-scorecard layout does not change).subLabelon the first scorecard reading "out of X G$ in subscription (streaming)" where X =weiToGd(data.global.gdStreamedWei).suffix="/day", switch the value toflowRateToMonthly(data.global.gdTotalFlowRateWeiPerSecond)(new helper:BigInt(weiPerSecStr) * 2629746n, then reuseweiToGd's BigInt-safe reduction — mirrorsflowRateToDaily's structure withSECONDS_PER_MONTH = 2629746nin place ofSECONDS_PER_DAY).secondaryYAxisdual-axis rendering against real (not just demo) data shape; if genuinely not visibly distinguishable (e.g. because live streamed amounts are much smaller than deposits even on their own axis), fall back to two single-axisLineAreaCharts — one for one-time deposits, one for streamed — per [Feature] AI Credits dashboard: display, labeling, and scale fixes #222's explicit fallback instruction.TABLE_COLUMNS'saiCreditsUsdformatter:.toFixed(2)→.toFixed(3).ANALYTICS_DAYS_REQUESTED:365→30inconnector.ts.All 5 existing dashboard states (loading, live, demo, live-unavailable, empty) must continue to render correctly with the new labels/values — no new state is introduced.
Execution plan
SECONDS_PER_MONTH+flowRateToMonthly()toanalyticsConversions.ts, following the existingflowRateToDailypattern and its BigInt-safety comments.subLabel?: stringtoScorecard(packages/ui), rendered below the value row.AiCreditsDashboard.tsx: scorecard labels/values/sub-line,flowRateToMonthlywiring,TABLE_COLUMNSformatter precision.connector.ts'sANALYTICS_DAYS_REQUESTEDto 30.generateDemoData.ts,mockState.ts,goodDataWidgetStories.tsx) only if the new sub-line/relabeled values need different fixture shaping to demonstrate correctly — otherwise reuse as-is.tests/widgets/gooddata-widget/states.spec.tswith assertions for the new scorecard labels, sub-line, and (if changed) split-chart testIDs; regenerate and commit updated baseline screenshots undertests/widgets/gooddata-widget/test-results/(standing repo convention — not optional).packages/gooddata-widgetandpackages/ui, plus the Playwright spec, before opening the PR. Commit one fix at a time, code + visual (Storybook/Playwright screenshot) verify before advancing to the next — same process as the feat(apps): AI Credits analytics data widget #179 rounds.Acceptance criteria
weiToGd(data.global.gdStreamedWei)flowRateToMonthly(), no "/day" suffixANALYTICS_DAYS_REQUESTED = 30)tests/widgets/gooddata-widget/states.spec.tsupdated and passing, with refreshed baseline screenshots committedHuman-reviewer checklist
flowRateToMonthly()'s2629746seconds-per-month constant and BigInt arithmetic match the rest ofanalyticsConversions.ts's precision conventions (4-decimalOUTPUT_PRECISION_DECIMALSreduction)Scorecard.subLabelprop doesn't regress any other existing Scorecard call site's layout (it's additive/optional, but check other pages usingvariant="card")gooddata-widget'saiCreditsdashboard plus one smallpackages/uiScorecard addition