Skip to content

fix(usage): correct chart clipping, expand truncated rows, add source mix - #7199

Merged
waleedlatif1 merged 10 commits into
stagingfrom
fix/usage-chart-polish
Aug 28, 2026
Merged

fix(usage): correct chart clipping, expand truncated rows, add source mix#7199
waleedlatif1 merged 10 commits into
stagingfrom
fix/usage-chart-polish

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Fixed the y-axis maximum being clipped at the container's left edge. The chart family used a fixed 26px gutter, which leaves 18px of drawable width once the label gap is taken out — four narrow glyphs. Both charts now derive it from the labels they draw, quantized to a step so three charts in a row still share an origin.
  • Fixed the vertical scrollbar that appeared when hovering near the bottom of a chart. A computed overflow-x promotes overflow-y to auto, and the tooltip's clamp ignored its own height.
  • Fixed the axis rules never rendering: hsl(var(--border)) is unparseable because the token is a hex, so SVG fell back to stroke: none.
  • Fixed the CSV export ignoring the workspace filter. The contract accepted it and the on-screen feed applied it, but the export route dropped it — an admin exporting a workspace-scoped feed downloaded the whole organization, under a truncation warning blaming the date range.
  • Fixed GLM rendering without a provider mark: the settings icon map held 11 of the registry's 24 providers. Completed, with a test that fails when the two drift. The server's parallel label map was the same duplicate and now reads the registry.
  • Other (N more) now expands in place. Fixed the drill-down name lookup this exposed, which was pinned to the top ten and refused to open for any row below it.
  • Added a source-mix radar beside the Sources list — the rows rank the sources, the web shows whether spend is concentrated or spread.
  • "Open logs" pointed at a workspace's run logs picked from an org-wide list; organization admin is not workspace membership, so it dead-ended for any workspace the admin had not joined. It now opens the org audit feed scoped to that workspace, and is hidden where that section is disabled.
  • Number fields no longer render the native stepper — ChipInput owns it, so no caller re-derives the vendor rules.
  • BYOK is withheld from the tab strip until the ledger carries BYOK rows.
  • ChartColumn was a uniform 0.86 downscale of its source art, rendering ~2px small beside every other settings nav icon.

Type of Change

  • Bug fix

Testing

Tested manually. Added rendered-geometry tests that assert against the real SVG across widths 280–1024 and 3–7 axes — both clipping bugs were invisible to a unit test of the helpers, since each came from a callsite combining correct helpers wrongly. Every new test verified to fail when its fix is reverted. bun run lint:check 26/26, bun run check:audits 37/37, check:migrations n/a (no migrations), type-check clean, 6659 app tests + 142 emcn tests passing.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

… mix

Two rendering defects on the organization usage panel, plus the follow-on
cleanup they surfaced.

The y-axis maximum was clipped at the container's left edge. The chart family
used a fixed 26px left gutter, which leaves 18px of drawable width once the
label gap is taken out — four narrow glyphs — so every tick from `7.3k` up lost
its first character. Both charts now derive the gutter from the labels they are
about to draw, through one shared `resolveChartPadding` so a bar and a line
chart still line up when stacked.

Hovering near the foot of the plot raised a vertical scrollbar over the chart.
The scroll container sets `overflow-x`, which promotes `overflow-y` to `auto`,
and the tooltip's vertical clamp was a fixed inset that ignored the box's real
height. The clamp now measures the tooltip, and the container pins `overflow-y`.

Also on the panel:

- The axis rules were invisible. `hsl(var(--border))` is unparseable — the token
  is a hex — so the presentation attribute was dropped and SVG's initial
  `stroke: none` applied.
- GLM rendered without a mark: the settings provider-icon map held 11 of the
  registry's 24 providers. Completed, with a test that fails when the two drift.
  The server's parallel label map was the same 11-entry duplicate and now reads
  the registry directly.
- `Other (N more)` opens the tail in place, raising the row limit to the API's
  ceiling. Fixed the drill-down name lookup this exposed, which was pinned to
  the top ten and so refused to open for any row below it.
- A radar chart of the source mix sits beside the Sources list. The rows rank
  the sources; they cannot show whether spend is concentrated or spread.
- "Open logs" pointed at `/workspace/<id>/logs` for a workspace picked from an
  organization-wide list. Organization admin is not workspace membership, so for
  any workspace the admin had not joined it was a one-way trip to an access
  denial. It now opens the organization's audit feed scoped to that workspace,
  which required threading the workspace filter the query builder already
  supported through the internal contract, route, hook, and URL state.
- BYOK is withheld from the tab strip until the ledger carries BYOK rows.
- The chip number field suppresses the native stepper, which painted browser
  chrome inside a flat chip surface. The component owns it, not its callers.
- `ChartColumn` was a uniform 0.86 downscale of its source art, so it rendered
  ~2px small beside every other icon in the settings nav.
…xport

Follow-up review of the previous commit, across the whole diff.

The CSV export ignored the workspace filter. The contract accepted it, the
on-screen feed applied it, and the export route dropped it on the floor — every
field of `AuditLogFilterParams` is optional, so omitting one still type-checks.
An admin exporting a workspace-scoped feed downloaded the whole organization,
under a truncation warning that blamed the date range. The route now forwards
the parsed query whole and refuses an out-of-organization id the way the list
route does, with tests for both.

The line chart's derived hover index was not clamped. The previous commit
replaced stored state with a derivation, but reproduced the clamp only for the
bar chart: `padding.left` follows the axis labels and `chartWidth` follows the
container, so a sidebar collapse mid-hover pushed the ratio past 1 and indexed
off the end — the dot, the rule and the tooltip all vanished until the cursor
moved.

Per-chart gutters de-aligned the logs dashboard, where three line charts sit in
one row. Deriving each from its own labels put their plot origins at 26, 27 and
32 where they had shared one. The gutter now rounds up to a step, which collapses
differences that small and leaves several pixels of slack instead of the
sub-pixel margin `Math.ceil` alone gave.

The radar chart, reviewed against its siblings:

- Its hover targets were triangles, whose far edge is the chord. Along its own
  spoke a triangle reaches only `reach·cos(π/n)` — at three axes, 50px against a
  74px radius — so the largest value's vertex, the one a reader aims at, sat
  outside every target. They are arc sectors now.
- The tooltip was positioned against the scroll container rather than the plot,
  so below the width floor it stayed nailed while the web slid under it. It now
  sits beside the hovered vertex through the family's own placer, instead of
  covering the densest part of the gradient.
- Captions below the centreline rode ~3px off the ring rather than the gap they
  were given, and captions beside the web were misaligned from their own vertex.
- Web opacities, stroke width, vertex radius, the per-theme fill relationship and
  the `screen` blend now match the bar and line charts rather than freelancing.
- Its rings read the shared grid fractions instead of dividing into even steps
  that agreed with the siblings only by coincidence.

Also: one `expanded` flag drove both lists in the workspace drill-down, so
opening either tail silently opened the other's; the Overview and tab lists
rendered an inert `Other` row while the same row two clicks away was a button;
the expand chevron knocked the value column out of alignment; row hover had
regressed to the chip surface where every other settings row uses the active
one; and the radar and the list beside it printed two different `Other (N more)`
counts under identical wording. The Overview's two readings of the source data
now share one section rather than drawing two half-width rules on one line.

Rendered-geometry tests cover the clipping and caption bugs against the real
SVG — a unit test of the helpers could not have caught either, since both came
from a callsite combining correct helpers wrongly.
Usage monitoring and Audit logs share their hosted and enterprise gates, so
reaching the usage panel proves both — but their self-hosted overrides are
separate flags. An install with usage monitoring on and audit logs off was
handed a drill-down action pointing at a section it had switched off.

The window is deliberately not carried across the link: the audit feed speaks in
rolling ranges and this panel in billing periods, so there is no honest mapping
for the current-period preset.
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 28, 2026 6:06am

Request Review

@greptile-apps

greptile-apps Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR expands the usage and audit-log interfaces while correcting chart geometry, export filtering, provider metadata, navigation, and numeric-input behavior.

  • Adds adaptive chart gutters, tooltip clamping, corrected SVG theme tokens, and a reusable radar chart.
  • Adds expandable usage-consumer rows and source-mix visualization.
  • Aligns audit-log list and CSV workspace filtering and hardens scoped audit presentation.
  • Consolidates provider metadata and updates settings navigation and input styling.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
apps/sim/ee/audit-logs/components/audit-logs.tsx Adds explicit workspace-scope states and gates audit-row presentation and export when the requested scope cannot be resolved.
apps/sim/ee/audit-logs/hooks/audit-logs.ts Makes audit query identity scope-aware so placeholder pages are retained only across filter changes within one organization/workspace scope.
apps/sim/app/api/audit-logs/export/route.ts Validates workspace membership and forwards the complete parsed audit filter set into CSV generation.
apps/sim/components/charts/chart-geometry.ts Adds adaptive, quantized y-axis padding derived from rendered label estimates.
apps/sim/components/charts/chart-tooltip.tsx Adds height-aware tooltip placement and aligns tooltip styling with current theme tokens.
apps/sim/ee/organization-usage/components/usage-source-mix.tsx Introduces the source-mix visualization used alongside ranked usage sources.
apps/sim/lib/billing/application/organization-usage/get-organization-usage-breakdown.ts Extends organization usage aggregation to support the new source and provider presentation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  U[Usage dashboard] --> C[Consumer breakdown]
  U --> S[Source ranking]
  S --> R[Source-mix radar]
  U --> E[Usage events]
  U --> A[Workspace-scoped audit feed]
  A --> F[Validated workspace filter]
  F --> L[Audit-log query]
  F --> X[CSV export]
Loading

Reviews (7): Last reviewed commit: "fix(audit-logs): stop Refresh issuing th..." | Re-trigger Greptile

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx Outdated
… feed

A workspace id in the URL that no longer resolves — deleted since, or never one
of ours — dropped the filter, so a request for one workspace's history was
answered with the whole organization's, under a URL that still claimed to be
scoped. The CSV export followed the same filter and would have carried the same
widening.

Every other deep-linked id in the app degrades to the unfiltered view, which is
right where the fallback shows less than was asked for. An audit feed is the one
place where widening is the dangerous direction, so it now stays closed and says
so, with the filter chip still rendered so the scope can be cleared.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed

You’re at about 95% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread apps/sim/ee/organization-usage/components/usage-monitoring.tsx Outdated
Comment thread apps/sim/components/charts/chart-tooltip.tsx Outdated
Comment thread apps/sim/ee/organization-usage/components/usage-consumers.tsx Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 28, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

…r row slot

Three findings from review.

A grid track minimum is a hard floor, so `minmax(320px, 1fr)` made the source
section wider than its column on a narrow viewport and overflowed instead of
collapsing. `min(320px, 100%)` caps the floor at the width actually available.

The tooltip height estimate used font sizes where it needed line boxes. The type
scale pairs no line-height with a size, so a line occupies the ambient 1.5 — a
10px date line is 15px, an 11px row is 16.5 — and the estimate came in ~1.5px
under the real box. Since it is what the clamp measures against and the chart
clips its overflow, an underestimate cuts the bottom off the box rather than
moving it up. Now derived from the line boxes, every part rounded up, with a test
that fails if any of the three constants drops below the rendered height.

The `Other` row drew its disclosure chevron bare at 14px while the rows above
reserved the 16px arrow or the 30px menu slot, pulling its figure out of the
column. It now centres in the same slot the rest of the list reserves.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed

You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx
Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx
…nswered

Disabling the query was not enough. An unresolved scope drops the filter, so its
query key equals the unscoped feed's, and a disabled query still serves whatever
is cached under its key — an admin reading the organization-wide feed who then
followed a stale scoped link kept those rows on screen, with Export still armed
against them because that gate reads the same list.

The rule now has a name and a seam: `presentableAuditEntries` returns nothing
unless the feed can answer the scope the URL asks for, and the export action
states that condition where it is read rather than inheriting it through an empty
list.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 28, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 39 files

You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx Outdated
…led lookup

Two more from review, both on the same surface.

The placeholder I added held previous pages across a workspace change, so
following a scoped link from the organization-wide feed painted the organization's
rows under a workspace-scoped URL until the scoped page arrived — with Export
armed against them. Gating presentation on `isPlaceholderData` would have fixed it
by throwing away the reason the placeholder exists, blanking the feed on every
keystroke again. The scope now leads the query key instead, ahead of the filters,
so "hold across a filter change, never across a scope change" is a prefix
comparison — the same shape the breakdown query already uses, and it retires the
hand-maintained key index.

A failed workspace lookup was reported as a workspace that is not part of the
organization. That is a wrong answer rather than a cautious one, and it offered
nothing to do about it. The two states are now distinct, the error one says so,
and Refresh retries the lookup alongside the feed so the control on screen can
actually clear the state it is showing.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 28, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 39 files

You’re at about 98% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx Outdated
Comment thread apps/sim/ee/audit-logs/hooks/audit-logs.test.tsx Outdated
…ic fields

The stepper was suppressed with a vendor-pseudo-element class string inside
`ChipInput`. Removing browser chrome with custom CSS is the wrong end of the
problem: the fields never wanted a stepper in the first place.

They are text fields with a numeric input mode now — the choice the retry
settings field already documents ("the native spinner is all that buys, and it
does not fit the field chrome"). No CSS, the numeric keypad is unchanged, and
`ChipModalField` gained an `inputMode` prop so a modal field can say the same
thing without asking for the stepper.

This also fixes a real defect in the credit-limit field. A number input reports
`''` for anything the browser considers invalid, so a typo arrived
indistinguishable from a cleared field and saved as "no limit"; as text it reaches
the `Number.isInteger` check and is refused. The usage-limit field's `min`
attribute went the same way — the minimum is enforced on commit, where it can
explain itself, rather than silently by the browser.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 28, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

…not fail

`refetch` ignores `enabled`, so refreshing the unscoped feed fired a workspace
lookup it has no use for and could fail a refresh that otherwise succeeded. It
now runs only when a scope asked for it.

The hook test claiming to cover an unresolved workspace scope passed `enabled:
false` with no workspace at all, so it asserted TanStack's disabled handling and
would have passed with the scope protection removed. The rule it named is derived
in the component and is covered there by `presentableAuditEntries`; a test that
cannot fail for its stated reason is worse than none.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 28, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 40 files

You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx
…to prevent

`refetch` ignores `enabled`, so pressing Refresh while the workspace scope was
unresolved or its lookup had failed fired the audit query anyway — and its filter
carries no workspace in that state, so the request was the organization-wide read
the gate exists to prevent. The result was never presented, but it was still
asked for.

Refresh now repeats the gate: the feed is refetched only while the scope is
answerable, and the lookup — the thing that has to succeed for a closed feed to
reopen — is retried whenever a scope asked for it.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 28, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 40 files

You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread apps/sim/ee/audit-logs/components/audit-logs.tsx
@waleedlatif1
waleedlatif1 merged commit 56abc6c into staging Aug 28, 2026
24 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/usage-chart-polish branch August 28, 2026 06:10
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