mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 18:05:11 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? UI refinements for Explorer query surfaces. ## What is the current behavior? - The assistant chat textarea uses a tighter radius than the Run SQL / Create a notebook cards on Explorer home. - Chart results sit unevenly in the results pane because axis gutters stack on card padding, and long Y labels can clip. - Selecting SQL in the editor changes the primary Run button to Run selected, which is easy to trigger by accident. - The Prettify SQL icon in notebook query cells uses Lucide's default size, so it doesn't match other toolbar actions. ## What is the new behavior? - Assistant chat form uses `rounded-lg` so it matches the home action cards everywhere the form is used. - Query result charts collapse unused axis space, add a little padding when labels are on, and size the Y axis from formatted ticks so longer labels fit. - Run is a default split button that always executes the full query. Run selected is a secondary menu item, disabled until SQL is selected. - Notebook cell Prettify SQL icons use `size={16}` and `strokeWidth={2}` like the rest of the Explorer toolbar. ## Additional context Cmd+Enter in the editor still runs the current selection when there is one. ## Test plan - [ ] Open Explorer home and confirm the assistant chat radius matches the Run SQL and Create a notebook cards. - [ ] Run a query, switch to chart view, and check spacing with labels off and on, including large Y values. - [ ] With no selection, click Run and confirm the full query runs. Open the split menu and confirm Run selected is disabled. - [ ] Select SQL, click Run, and confirm the full query still runs. Use Run selected from the menu to run only the selection. - [ ] In a notebook query cell, confirm Prettify SQL matches the size and stroke of nearby toolbar icons. Made with [Cursor](https://cursor.com) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a split Run control in the query editor, with separate actions for running all content or only selected text. - Added support for customizing chart X-axis display settings. - Improved chart Y-axis sizing, scaling, and tick formatting for clearer results. - **Bug Fixes** - The “Run selected” action is unavailable when no text is selected. - **Style** - Updated toolbar icon sizing and added rounded corners to the assistant chat input. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
139 lines
4.1 KiB
TypeScript
139 lines
4.1 KiB
TypeScript
import { useMemo } from 'react'
|
|
import { cn, type ChartConfig as ChartSeriesConfig } from 'ui'
|
|
import { Chart, ChartBar, ChartCard, ChartContent, ChartLine } from 'ui-patterns/Chart'
|
|
|
|
import { type QueryResult } from '../types'
|
|
import NoDataPlaceholder from '@/components/ui/Charts/NoDataPlaceholder'
|
|
import {
|
|
computeYAxisWidth,
|
|
formatLogTick,
|
|
formatYAxisTick,
|
|
getCumulativeResults,
|
|
} from '@/components/ui/QueryBlock/QueryBlock.utils'
|
|
import { type ChartConfig } from '@/data/content/notebooks/notebook-schema'
|
|
|
|
interface QueryResultChartProps {
|
|
chart?: ChartConfig
|
|
result?: QueryResult
|
|
}
|
|
|
|
const Y_SERIES_COLORS = [
|
|
'hsl(var(--brand-default))',
|
|
'hsl(var(--chart-blue))',
|
|
'hsl(var(--chart-3))',
|
|
]
|
|
|
|
const toChartValue = (value: unknown): string | number => {
|
|
if (typeof value === 'number' || typeof value === 'string') return value
|
|
if (value === null || value === undefined) return ''
|
|
return String(value)
|
|
}
|
|
|
|
export const QueryResultChart = ({ chart, result }: QueryResultChartProps) => {
|
|
const { type, x_column, y_series = [], cumulative, show_labels, scale } = chart ?? {}
|
|
|
|
const hasConfig = !!x_column && y_series.length > 0
|
|
// Logarithmic scale only makes sense for a single series — DisplaySettingsButton
|
|
// resets `scale` to linear once a second Y column is added
|
|
const effectiveScale = y_series.length > 1 ? 'linear' : scale
|
|
|
|
const chartConfig: ChartSeriesConfig = useMemo(
|
|
() =>
|
|
y_series.reduce((acc, key, index) => {
|
|
acc[key] = { label: key, color: Y_SERIES_COLORS[index] }
|
|
return acc
|
|
}, {} as ChartSeriesConfig),
|
|
[y_series]
|
|
)
|
|
|
|
const chartRows = useMemo(() => {
|
|
const xKey = x_column ?? ''
|
|
return (result?.rows ?? []).map((row) => {
|
|
const chartRow: Record<string, string | number> = { [xKey]: toChartValue(row[xKey]) }
|
|
y_series.forEach((yKey) => {
|
|
chartRow[yKey] = toChartValue(row[yKey])
|
|
})
|
|
return chartRow
|
|
})
|
|
}, [result, x_column, y_series])
|
|
|
|
const cumulativeResults = useMemo(
|
|
() => getCumulativeResults({ rows: chartRows }, { yKey: y_series }),
|
|
[chartRows, y_series]
|
|
)
|
|
const resultToRender = cumulative ? cumulativeResults : chartRows
|
|
|
|
const yAxisWidth = Math.max(
|
|
36,
|
|
...y_series.map((key) =>
|
|
computeYAxisWidth(resultToRender, key, { isLogScale: effectiveScale === 'log' })
|
|
)
|
|
)
|
|
|
|
const yAxisProps = {
|
|
...(show_labels ? { width: yAxisWidth } : {}),
|
|
scale: effectiveScale === 'log' ? 'log' : 'auto',
|
|
domain: effectiveScale === 'log' ? ([1, 'auto'] as const) : undefined,
|
|
tickFormatter: effectiveScale === 'log' ? formatLogTick : formatYAxisTick,
|
|
}
|
|
|
|
if (!result || (result?.rows && result.rows.length === 0)) {
|
|
return (
|
|
<NoDataPlaceholder
|
|
isFullHeight
|
|
className="border-0"
|
|
size="normal"
|
|
message="No results"
|
|
description="Your query returned no rows"
|
|
/>
|
|
)
|
|
}
|
|
|
|
if (!hasConfig) {
|
|
return (
|
|
<NoDataPlaceholder
|
|
isFullHeight
|
|
className="border-0"
|
|
size="normal"
|
|
message="Configure your chart"
|
|
description="Select your X and Y axis in the display settings"
|
|
/>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Chart className="flex flex-grow min-h-0">
|
|
<ChartCard className="flex flex-grow rounded-none border-0 min-h-0">
|
|
<ChartContent className={cn('min-h-0 h-full w-full', show_labels && 'pl-2 pb-2')}>
|
|
{type === 'bar' && (
|
|
<ChartBar
|
|
isFullHeight
|
|
xKey={x_column}
|
|
dataKey={y_series[0]}
|
|
dataKeys={y_series}
|
|
config={chartConfig}
|
|
showXAxis={show_labels}
|
|
showYAxis={show_labels}
|
|
data={resultToRender}
|
|
YAxisProps={yAxisProps}
|
|
/>
|
|
)}
|
|
{type === 'line' && (
|
|
<ChartLine
|
|
isFullHeight
|
|
xKey={x_column}
|
|
dataKey={y_series[0]}
|
|
dataKeys={y_series}
|
|
config={chartConfig}
|
|
showXAxis={show_labels}
|
|
showYAxis={show_labels}
|
|
data={resultToRender}
|
|
YAxisProps={yAxisProps}
|
|
/>
|
|
)}
|
|
</ChartContent>
|
|
</ChartCard>
|
|
</Chart>
|
|
)
|
|
}
|