Skip to content

Commit 265ca68

Browse files
update db report (supabase#36328)
* release charts to Teams and Enterprise * update db charts * clean up chart types and add disk_fs_used_system * show update data for Disk Size chart * remove feature flag release * update PostgREST connections tooltip * show percentage in tooltip only if value is not percentage itself * show percentage in tooltip only if value is not percentage itself * insert disk_fs_used_system * update db disk size chart * reorder admin connection
1 parent 669a96b commit 265ca68

File tree

6 files changed

+156
-79
lines changed

6 files changed

+156
-79
lines changed

apps/studio/components/ui/Charts/ComposedChart.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ import {
2828
} from './Charts.constants'
2929
import { CommonChartProps, Datum } from './Charts.types'
3030
import { numberFormatter, useChartSize } from './Charts.utils'
31-
import { calculateTotalChartAggregate, CustomLabel, CustomTooltip } from './ComposedChart.utils'
32-
import { MultiAttribute } from './ComposedChartHandler'
31+
import {
32+
calculateTotalChartAggregate,
33+
CustomLabel,
34+
CustomTooltip,
35+
type MultiAttribute,
36+
} from './ComposedChart.utils'
3337
import NoDataPlaceholder from './NoDataPlaceholder'
3438
import { ChartHighlight } from './useChartHighlight'
3539
import { formatBytes } from 'lib/helpers'
@@ -202,11 +206,10 @@ export default function ComposedChart({
202206
const isDiskSpaceChart = chartData?.some((att: any) =>
203207
att.name.toLowerCase().includes('disk_space_')
204208
)
205-
const isDBSizeChart = chartData?.some((att: any) =>
206-
att.name.toLowerCase().includes('pg_database_size')
207-
)
209+
const isDiskSizeChart = chartData?.some((att: any) => att.name.toLowerCase().includes('disk_fs_'))
208210
const isNetworkChart = chartData?.some((att: any) => att.name.toLowerCase().includes('network_'))
209-
const shouldFormatBytes = isRamChart || isDiskSpaceChart || isDBSizeChart || isNetworkChart
211+
const shouldFormatBytes = isRamChart || isDiskSpaceChart || isDiskSizeChart || isNetworkChart
212+
210213
//*
211214
// Set the y-axis domain
212215
// to the highest value in the chart data for percentage charts

apps/studio/components/ui/Charts/ComposedChart.utils.tsx

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,68 @@ import { useState } from 'react'
55
import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
66
import { CHART_COLORS, DateTimeFormats } from './Charts.constants'
77
import { numberFormatter } from './Charts.utils'
8-
import { MultiAttribute } from './ComposedChartHandler'
98
import { formatBytes } from 'lib/helpers'
109

10+
export interface ReportAttributes {
11+
id?: string
12+
label: string
13+
attributes?: (MultiAttribute | false)[]
14+
defaultChartStyle?: 'bar' | 'line' | 'stackedAreaLine'
15+
hide?: boolean
16+
hideChartType?: boolean
17+
format?: string
18+
className?: string
19+
showTooltip?: boolean
20+
showLegend?: boolean
21+
showTotal?: boolean
22+
showMaxValue?: boolean
23+
valuePrecision?: number
24+
docsUrl?: string
25+
syncId?: string
26+
showGrid?: boolean
27+
YAxisProps?: {
28+
width?: number
29+
tickFormatter?: (value: any) => string
30+
}
31+
hideHighlightedValue?: boolean
32+
}
33+
34+
type Provider = 'infra-monitoring' | 'daily-stats' | 'reference-line' | 'combine'
35+
36+
export type MultiAttribute = {
37+
attribute: string
38+
provider: Provider
39+
label?: string
40+
color?: string
41+
stackId?: string
42+
format?: string
43+
description?: string
44+
docsLink?: string
45+
isMaxValue?: boolean
46+
type?: 'line' | 'area-bar'
47+
omitFromTotal?: boolean
48+
tooltip?: string
49+
customValue?: number
50+
/**
51+
* Manipulate the value of the attribute before it is displayed on the chart.
52+
* @param value - The value of the attribute.
53+
* @returns The manipulated value.
54+
*/
55+
manipulateValue?: (value: number) => number
56+
/**
57+
* Create a virtual attribute by combining values from other attributes.
58+
* Expression should use attribute names and basic math operators (+, -, *, /).
59+
* Example: 'disk_fs_used - pg_database_size - disk_fs_used_wal'
60+
*/
61+
combine?: string
62+
id?: string
63+
value?: number
64+
isReferenceLine?: boolean
65+
strokeDasharray?: string
66+
className?: string
67+
hide?: boolean
68+
}
69+
1170
interface CustomIconProps {
1271
color: string
1372
}
@@ -78,9 +137,7 @@ const CustomTooltip = ({
78137
const isDiskSpaceChart = payload?.some((p: any) =>
79138
p.dataKey.toLowerCase().includes('disk_space_')
80139
)
81-
const isDBSizeChart = payload?.some((p: any) =>
82-
p.dataKey.toLowerCase().includes('pg_database_size')
83-
)
140+
const isDBSizeChart = payload?.some((p: any) => p.dataKey.toLowerCase().includes('disk_fs_'))
84141
const isNetworkChart = payload?.some((p: any) => p.dataKey.toLowerCase().includes('network_'))
85142
const shouldFormatBytes = isRamChart || isDiskSpaceChart || isDBSizeChart || isNetworkChart
86143

@@ -120,7 +177,7 @@ const CustomTooltip = ({
120177
{isPercentage ? '%' : ''}
121178

122179
{/* Show percentage if max value is set */}
123-
{!!maxValueData && !isMax && (
180+
{!!maxValueData && !isMax && !isPercentage && (
124181
<span className="text-[11px] text-foreground-light mb-0.5">({percentage}%)</span>
125182
)}
126183
</span>
@@ -154,6 +211,7 @@ const CustomTooltip = ({
154211
{isPercentage ? '%' : ''}
155212
</span>
156213
{maxValueAttribute &&
214+
!isPercentage &&
157215
!isNaN((total as number) / maxValueData?.value) &&
158216
isFinite((total as number) / maxValueData?.value) && (
159217
<span className="text-[11px] text-foreground-light mb-0.5">

apps/studio/components/ui/Charts/ComposedChartHandler.tsx

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,9 @@ import { useChartHighlight } from './useChartHighlight'
1616

1717
import type { ChartData } from './Charts.types'
1818
import type { UpdateDateRange } from 'pages/project/[ref]/reports/database'
19+
import { MultiAttribute } from './ComposedChart.utils'
1920

20-
type Provider = 'infra-monitoring' | 'daily-stats' | 'reference-line'
21-
22-
export type MultiAttribute = {
23-
attribute: string
24-
provider: Provider
25-
label?: string
26-
color?: string
27-
stackId?: string
28-
format?: 'percent' | 'number'
29-
description?: string
30-
docsLink?: string
31-
isMaxValue?: boolean
32-
type?: 'line' | 'area-bar'
33-
omitFromTotal?: boolean
34-
tooltip?: string
35-
customValue?: number
36-
id?: string
37-
value?: number
38-
isReferenceLine?: boolean
39-
strokeDasharray?: string
40-
className?: string
41-
}
42-
43-
interface ComposedChartHandlerProps {
21+
export interface ComposedChartHandlerProps {
4422
id?: string
4523
label: string
4624
attributes: MultiAttribute[]
@@ -189,6 +167,7 @@ const ComposedChartHandler = ({
189167
// Add regular attributes
190168
attributes.forEach((attr, index) => {
191169
if (!attr) return
170+
192171
// Handle custom value attributes (like disk size)
193172
if (attr.customValue !== undefined) {
194173
point[attr.attribute] = attr.customValue
@@ -200,7 +179,16 @@ const ComposedChartHandler = ({
200179

201180
const queryData = attributeQueries[index]?.data?.data
202181
const matchingPoint = queryData?.find((p: any) => p.period_start === timestamp)
203-
point[attr.attribute] = matchingPoint?.[attr.attribute] ?? 0
182+
let value = matchingPoint?.[attr.attribute] ?? 0
183+
184+
// Apply value manipulation if provided
185+
if (attr.manipulateValue && typeof attr.manipulateValue === 'function') {
186+
// Ensure value is a number before manipulation
187+
const numericValue = typeof value === 'number' ? value : Number(value) || 0
188+
value = attr.manipulateValue(numericValue)
189+
}
190+
191+
point[attr.attribute] = value
204192
})
205193

206194
// Add reference line values for each timestamp

apps/studio/data/reports/database-charts.ts

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { numberFormatter } from 'components/ui/Charts/Charts.utils'
22
import { formatBytes } from 'lib/helpers'
3-
import { Organization } from '../../types'
3+
import { Organization } from 'types'
44
import { Project } from '../projects/project-detail-query'
5+
import { ReportAttributes } from 'components/ui/Charts/ComposedChart.utils'
56

67
export const getReportAttributes = (isFreePlan: boolean) => [
78
{ id: 'ram_usage', label: 'Memory usage', hide: false },
@@ -26,7 +27,10 @@ export const getReportAttributes = (isFreePlan: boolean) => [
2627
},
2728
]
2829

29-
export const getReportAttributesV2 = (org: Organization, project: Project) => {
30+
export const getReportAttributesV2: (org: Organization, project: Project) => ReportAttributes[] = (
31+
org,
32+
project
33+
) => {
3034
const isFreePlan = org?.plan?.id === 'free'
3135
const computeSize = project?.infra_compute_size || 'medium'
3236
const isSpendCapEnabled =
@@ -46,7 +50,7 @@ export const getReportAttributesV2 = (org: Organization, project: Project) => {
4650
syncId: 'database-reports',
4751
valuePrecision: 2,
4852
YAxisProps: {
49-
width: 60,
53+
width: 75,
5054
tickFormatter: (value: any) => formatBytes(value, 2),
5155
},
5256
attributes: [
@@ -226,8 +230,8 @@ export const getReportAttributesV2 = (org: Organization, project: Project) => {
226230
],
227231
},
228232
{
229-
id: 'db-size',
230-
label: 'Database Size',
233+
id: 'disk-size',
234+
label: 'Disk Size',
231235
syncId: 'database-reports',
232236
valuePrecision: 2,
233237
hide: false,
@@ -243,19 +247,36 @@ export const getReportAttributesV2 = (org: Organization, project: Project) => {
243247
defaultChartStyle: 'line',
244248
docsUrl: 'https://supabase.com/docs/guides/platform/database-size',
245249
attributes: [
250+
{
251+
attribute: 'disk_fs_used_system',
252+
provider: 'infra-monitoring',
253+
format: 'bytes',
254+
label: 'System',
255+
tooltip: 'Reserved space for the system to ensure your database runs smoothly.',
256+
},
257+
{
258+
attribute: 'disk_fs_used_wal',
259+
provider: 'infra-monitoring',
260+
format: 'bytes',
261+
label: 'WAL',
262+
tooltip:
263+
'Disk usage by the write-ahead log. The usage depends on your WAL settings and the amount of data being written to the database.',
264+
},
265+
246266
{
247267
attribute: 'pg_database_size',
248268
provider: 'infra-monitoring',
269+
format: 'bytes',
249270
label: 'Database',
250-
tooltip: 'Total space on disk used by your database (tables, indexes, data, ...).',
271+
tooltip: 'Disk usage by your database (tables, indexes, data, ...).',
251272
},
252273
{
253-
attribute: 'max_pg_database_size',
254-
provider: 'reference-line',
255-
label: 'Disk size',
256-
value: (project?.volumeSizeGb || getRecommendedDbSize(computeSize)) * 1024 * 1024 * 1024,
257-
tooltip: 'Disk Size refers to the total space your project occupies on disk',
274+
attribute: 'disk_fs_size',
275+
provider: 'infra-monitoring',
258276
isMaxValue: true,
277+
format: 'bytes',
278+
label: 'Disk Size',
279+
tooltip: 'Disk Size refers to the total space your project occupies on disk',
259280
},
260281
!isFreePlan &&
261282
(isSpendCapEnabled
@@ -304,20 +325,21 @@ export const getReportAttributesV2 = (org: Organization, project: Project) => {
304325
showTotal: false,
305326
attributes: [
306327
{
307-
attribute: 'network_transmit_bytes',
328+
attribute: 'network_receive_bytes',
308329
provider: 'infra-monitoring',
309-
label: 'Transmit',
330+
label: 'Ingress',
331+
manipulateValue: (value: number) => value * -1,
310332
tooltip:
311-
'Data sent from your database to clients. High values may indicate large query results or numerous outgoing connections.',
312-
stackId: '2',
333+
'Data received by your database from clients. High values may indicate frequent queries, large data inserts, or many incoming connections.',
334+
stackId: '1',
313335
},
314336
{
315-
attribute: 'network_receive_bytes',
337+
attribute: 'network_transmit_bytes',
316338
provider: 'infra-monitoring',
317-
label: 'Receive',
339+
label: 'Egress',
318340
tooltip:
319-
'Data received by your database from clients. High values may indicate frequent queries, large data inserts, or many incoming connections.',
320-
stackId: '1',
341+
'Data sent from your database to clients. High values may indicate large query results or numerous outgoing connections.',
342+
stackId: '2',
321343
},
322344
],
323345
},
@@ -335,44 +357,49 @@ export const getReportAttributesV2 = (org: Organization, project: Project) => {
335357
{
336358
attribute: 'client_connections_postgres',
337359
provider: 'infra-monitoring',
338-
label: 'postgres',
339-
tooltip: 'Active connections',
360+
label: 'Postgres',
361+
tooltip:
362+
'Direct connections to the Postgres database from your application and external clients.',
340363
},
341364
{
342365
attribute: 'client_connections_authenticator',
343366
provider: 'infra-monitoring',
344-
label: 'postgrest',
345-
tooltip: 'Active connections',
367+
label: 'PostgREST',
368+
tooltip: 'Connections magaged by PostgREST to auto-generate RESTful API.',
346369
},
347370
{
348-
attribute: 'client_connections_supabase_auth_admin',
371+
attribute: 'client_connections_supabase_admin',
349372
provider: 'infra-monitoring',
350-
label: 'auth',
351-
tooltip: 'Active connections',
373+
label: 'Admin',
374+
tooltip:
375+
'Administrative connections used by various Supabase services for internal operations and maintenance tasks.',
352376
},
353377
{
354-
attribute: 'client_connections_supabase_storage_admin',
378+
attribute: 'client_connections_supabase_auth_admin',
355379
provider: 'infra-monitoring',
356-
label: 'storage',
357-
tooltip: 'Active connections',
380+
label: 'Auth',
381+
tooltip:
382+
'Administrative connections used by Supabase Auth service for user management and authentication operations.',
358383
},
359384
{
360-
attribute: 'client_connections_supabase_admin',
385+
attribute: 'client_connections_supabase_storage_admin',
361386
provider: 'infra-monitoring',
362-
label: 'supabase-admin',
363-
tooltip: 'Active connections',
387+
label: 'Storage',
388+
tooltip:
389+
'Administrative connections used by Supabase Storage service for file operations and bucket management.',
364390
},
365391
{
366392
attribute: 'client_connections_other',
367393
provider: 'infra-monitoring',
368-
label: 'other',
369-
tooltip: 'Active connections',
394+
label: 'Other',
395+
tooltip: "Miscellaneous database connections that don't fall into other categories.",
370396
},
371397
{
372398
attribute: 'max_db_connections',
373-
provider: 'infra-monitoring',
374-
label: 'Maximum connections allowed',
375-
tooltip: 'Maximum connections for instance size',
399+
provider: 'reference-line',
400+
label: 'Max connections',
401+
value: getConnectionLimits(computeSize).direct,
402+
tooltip: 'Max available connections for your current compute size',
376403
isMaxValue: true,
377404
},
378405
],

0 commit comments

Comments
 (0)