mirror of
https://github.com/supabase/supabase.git
synced 2026-05-08 01:40:13 -04:00
bf16d7f613
## Problem The Report Blocks section (custom dashboards) has four visual and UX bugs: tooltip content overflows its container, Y-axis labels with 5+ digits get clipped (e.g. `10000` renders as `0000`), action buttons become unreachable when a block title is long, and scrolling inside a scrollable block also scrolls the parent page. ## Fix - Remove the fixed `w-[200px]` class from `ChartTooltipContent` in `ChartBlock` so tooltips auto-size to their content instead of overflowing. - Compute a dynamic Y-axis width in `ChartBlock` based on the string length of the maximum data value, replacing the `undefined` default that caused clipping. - Add `min-w-0` to the label container and `shrink-0` to the actions container in `ReportBlockContainer` so the truncation works correctly and action buttons are never pushed off-screen. - Add `overscroll-contain` to the scrollable SQL code and results table divs in `QueryBlock` to stop scroll events from propagating to the page. ## How to test - Navigate to a custom Report with multiple blocks - Hover over a chart bar on a block with a long metric name. The tooltip should be fully visible with no text overflow. - Find or create a block whose Y-axis values exceed 9999 (e.g. disk IOPS). The full number should appear on the Y-axis without any leading digits being clipped. - Use a block on a read replica so the label appends "of replica", making it long. The chart-type toggle, log scale toggle, and remove buttons should all remain visible and clickable. - Add a SQL snippet block that returns a large table of results. Scroll within the results table. The page should not scroll while the inner table is scrolling. ## Before <img width="1166" height="680" alt="CleanShot 2026-04-07 at 15 36 45@2x" src="https://github.com/user-attachments/assets/8e7bd3c9-8319-47c9-b2d9-b194d2803809" /> ## After <img width="1166" height="680" alt="CleanShot 2026-04-07 at 15 36 15@2x" src="https://github.com/user-attachments/assets/6ca5873a-cd09-4001-9cd0-932c12b6536e" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Style** * More consistent Y-axis sizing with dynamic widths for better label fit. * Improved Y-axis number formatting (K/M suffixes, sensible decimals) for clearer tick labels. * Simplified, more flexible chart tooltips (min-width applied; removed fixed widths). * Tighter report header layout so labels truncate predictably and actions keep their size. * Added overscroll containment to query results and SQL view to reduce unwanted scrolling. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
63 lines
2.0 KiB
TypeScript
63 lines
2.0 KiB
TypeScript
import { ChartConfig } from '@/components/interfaces/SQLEditor/UtilityPanel/ChartConfig'
|
|
|
|
export const checkHasNonPositiveValues = (data: Record<string, unknown>[], key: string): boolean =>
|
|
data.some((row) => (row[key] as number) <= 0)
|
|
|
|
export const formatYAxisTick = (value: number): string => {
|
|
if (Math.abs(value) >= 1_000_000) {
|
|
const n = value / 1_000_000
|
|
return `${Number.isInteger(n) ? n : n.toFixed(1)}M`
|
|
}
|
|
if (Math.abs(value) >= 1_000) {
|
|
const n = value / 1_000
|
|
return `${Number.isInteger(n) ? n : n.toFixed(1)}K`
|
|
}
|
|
if (value !== 0 && Math.abs(value) < 1) {
|
|
return parseFloat(value.toFixed(2)).toString()
|
|
}
|
|
if (!Number.isInteger(value)) {
|
|
return parseFloat(value.toFixed(1)).toString()
|
|
}
|
|
return String(value)
|
|
}
|
|
|
|
export const computeYAxisWidth = (
|
|
data: Record<string, unknown>[],
|
|
key: string,
|
|
{
|
|
isLogScale = false,
|
|
isPercentage = false,
|
|
}: { isLogScale?: boolean; isPercentage?: boolean } = {}
|
|
): number => {
|
|
if (isLogScale) return 52
|
|
if (isPercentage) return Math.max(36, (3 + 1) * 8) // max tick is "100"
|
|
const maxMagnitude =
|
|
data.length > 0 ? Math.max(...data.map((d) => Math.abs(Number(d[key]) || 0))) : 0
|
|
return Math.max(36, (formatYAxisTick(maxMagnitude).length + 1) * 8)
|
|
}
|
|
|
|
export const formatLogTick = (value: number): string => {
|
|
if (value >= 1_000_000)
|
|
return `${(value / 1_000_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}M`
|
|
if (value >= 1_000)
|
|
return `${(value / 1_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}k`
|
|
return value.toLocaleString()
|
|
}
|
|
|
|
export const getCumulativeResults = (results: { rows: any[] }, config: ChartConfig) => {
|
|
if (!results?.rows?.length) {
|
|
return []
|
|
}
|
|
|
|
const cumulativeResults = results.rows.reduce((acc, row) => {
|
|
const prev = acc[acc.length - 1] || {}
|
|
const next = {
|
|
...row,
|
|
[config.yKey]: (prev[config.yKey] || 0) + row[config.yKey],
|
|
}
|
|
return [...acc, next]
|
|
}, [])
|
|
|
|
return cumulativeResults
|
|
}
|