Files
supabase/apps/studio/lib/constants/metrics.tsx
Danny White 73c9dbfa52 fix(studio): standardise custom icon weight (#48478)
## What kind of change does this PR introduce?

Bug fix and internal tooling update. Resolves FE-3472.

## What is the current behavior?

Custom Studio icons use inconsistent source stroke widths, and some
child-level styling prevents component props from overriding them. Mixed
custom and Lucide icon sets can therefore appear uneven.

## What is the new behavior?

Custom stroke icons use a root-level `stroke-width="1.5"`; fill-only
logos use `stroke="none"`. The build validates that contract and
regenerated components preserve existing exports and props.

Studio applies the same `1.5` weight across Reports categories and uses
one shared destination icon mapping in the replication selector,
destination rows and diagram.

| Before | After |
| --- | --- |
| <img width="418" height="516" alt="56398"
src="https://github.com/user-attachments/assets/6afa7042-e6be-40e7-9911-af2f61238c9d"
/> | <img width="390" height="550" alt="CleanShot 2026-07-30 at 17 12
37@2x"
src="https://github.com/user-attachments/assets/870f49cf-c8fa-40db-8be8-2eb5f264ff4a"
/> |
| <img width="510" height="734" alt="CleanShot 2026-07-30 at 17 19
28@2x"
src="https://github.com/user-attachments/assets/a5b2c088-dcd2-4907-976b-5820794d06e3"
/> | <img width="554" height="742" alt="CleanShot 2026-07-30 at 17 16
06@2x"
src="https://github.com/user-attachments/assets/ed3a77c4-5d94-4ca7-b9e4-1403b725a981"
/> |


## Testing

At 100% zoom, compare custom and Lucide icon weight in:

- Reports: **Add your first chart** and **Add block**
- Database > Replication: the destination selector, destination rows and
replication diagram
- Command menu (`⌘K`): **Search Database Tables**, **Search RLS
Policies**, **Search Edge Functions** and **Search Storage**
- Authentication > Users: right-click a user row and compare the
context-menu icons
- Database > Schema Visualizer: open a table node overflow menu
- A paused project: **Export your data > Download backups**

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added consistent destination icons across replication panels, rows,
and diagrams.
  * Updated instance health and metric icons for clearer identification.
* Standardized icon stroke weight and reduced default icon stroke
thickness.

* **Documentation**
* Clarified custom icon requirements, default properties, and validation
guidance.

* **Bug Fixes**
* Improved consistency of icon rendering across replication destinations
and reports.

* **Tests**
* Added coverage for icon SVG validation and replication destination
icon rendering.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 17:48:50 +10:00

420 lines
9.3 KiB
TypeScript

import { Auth, Realtime, Storage } from 'icons'
import { ActivityIcon, DatabaseIcon, HeartPulseIcon, ServerIcon } from 'lucide-react'
import { ReactNode } from 'react'
export type Metric = {
key: string
label: string
provider?: string
category?: MetricCategory
id?: string
}
type MetricCategory = {
label: string
icon: (className?: string) => ReactNode
key: string
}
export const InstanceHealthIcon = ({
className,
size = 16,
}: {
className?: string
size?: number
}) => <HeartPulseIcon size={size} strokeWidth={1.5} className={className} />
export const METRIC_CATEGORIES = {
API: {
label: 'All API usage',
icon: (className?: string) => (
<ActivityIcon size={16} strokeWidth={1.5} className={className} />
),
key: 'api',
},
API_DATABASE: {
label: 'Database API',
icon: (className?: string) => (
<DatabaseIcon size={16} strokeWidth={1.5} className={className} />
),
key: 'api_database',
},
API_AUTH: {
label: 'Authentication',
icon: (className?: string) => <Auth size={16} strokeWidth={1.5} className={className} />,
key: 'api_auth',
},
API_STORAGE: {
label: 'Storage',
icon: (className?: string) => <Storage size={16} strokeWidth={1.5} className={className} />,
key: 'api_storage',
},
API_REALTIME: {
label: 'Realtime',
icon: (className?: string) => <Realtime size={16} strokeWidth={1.5} className={className} />,
key: 'api_realtime',
},
INSTANCE: {
label: 'Instance health',
icon: (className?: string) => <InstanceHealthIcon className={className} />,
key: 'instance',
},
SUPAVISOR: {
label: 'Supavisor',
icon: (className?: string) => <ServerIcon size={16} strokeWidth={1.5} className={className} />,
key: 'supavisor',
},
}
// [Joshen] Eventually we can remove some charts here from DEPRECATED_REPORTS from Reports.constants.ts
export const METRICS: Metric[] = [
{
key: 'avg_cpu_usage',
label: 'Average CPU % Usage',
provider: 'infra-monitoring',
category: METRIC_CATEGORIES.INSTANCE,
},
{
key: 'max_cpu_usage',
label: 'Max CPU % Usage',
provider: 'infra-monitoring',
category: METRIC_CATEGORIES.INSTANCE,
},
{
key: 'disk_io_consumption',
label: 'Disk IO % Consumed',
provider: 'infra-monitoring',
category: METRIC_CATEGORIES.INSTANCE,
},
{
key: 'disk_io_budget',
label: 'Disk IO % Remaining',
provider: 'infra-monitoring',
category: METRIC_CATEGORIES.INSTANCE,
},
{
key: 'ram_usage',
label: 'Memory % Usage',
provider: 'infra-monitoring',
category: METRIC_CATEGORIES.INSTANCE,
},
{
key: 'total_realtime_egress',
label: 'Realtime Connection Egress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_realtime_requests',
label: 'Realtime Connection Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_REALTIME,
},
{
key: 'total_realtime_ingress',
label: 'Realtime Connection Ingress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_REALTIME,
},
/**
* API
*/
{
key: 'total_rest_ingress',
label: 'API Ingress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
{
key: 'total_rest_egress',
label: 'API Egress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
{
key: 'total_rest_requests',
label: 'API Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
{
key: 'total_rest_get_requests',
label: 'API GET Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
{
key: 'total_rest_post_requests',
label: 'API POST Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
{
key: 'total_rest_patch_requests',
label: 'API PATCH Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
{
key: 'total_rest_delete_requests',
label: 'API DELETE Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
{
key: 'total_rest_options_requests',
label: 'API OPTIONS Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_DATABASE,
},
/**
* Auth
*/
{
key: 'total_auth_billing_period_mau',
label: 'Auth Monthly Active User',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_billing_period_sso_mau',
label: 'Auth Monthly Active SSO User',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_ingress',
label: 'Auth Ingress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_egress',
label: 'Auth Egress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_requests',
label: 'Auth Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_get_requests',
label: 'Auth GET Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_post_requests',
label: 'Auth POST Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_patch_requests',
label: 'Auth PATCH Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_auth_options_requests',
label: 'Auth OPTIONS Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
/**
* Storage
*/
{
key: 'total_storage_ingress',
label: 'Storage Ingress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_egress',
label: 'Storage Egress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_image_render_count',
label: 'Storage Image Transformations',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_requests',
label: 'Storage Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_get_requests',
label: 'Storage GET Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_post_requests',
label: 'Storage POST Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_delete_requests',
label: 'Storage DELETE Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_options_requests',
label: 'Storage OPTIONS Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_auth_delete_requests',
label: 'Auth DELETE Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_AUTH,
},
{
key: 'total_egress',
label: 'All Egress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_get_requests',
label: 'All GET Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_cached_egress',
label: 'All Cached Egress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_storage_patch_requests',
label: 'Storage PATCH Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API_STORAGE,
},
{
key: 'total_requests',
label: 'All Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_patch_requests',
label: 'All PATCH Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_post_requests',
label: 'All POST Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_ingress',
label: 'All Ingress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_delete_requests',
label: 'All DELETE Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
{
key: 'total_options_requests',
label: 'All OPTIONS Requests',
provider: 'daily-stats',
category: METRIC_CATEGORIES.API,
},
/** Supavisor */
{
key: 'total_supavisor_egress_bytes',
label: 'Shared Pooler Egress',
provider: 'daily-stats',
category: METRIC_CATEGORIES.SUPAVISOR,
},
]
export const TIME_PERIODS_BILLING = [
{
key: 'currentBillingCycle',
label: 'Current billing cycle',
interval: '1d',
},
{
key: 'previousBillingCycle',
label: 'Previous billing cycle',
interval: '1d',
},
]
export const TIME_PERIODS_REPORTS = [
{
key: '7d',
label: 'Last 7 days',
interval: '1d',
},
{
key: '30d',
label: 'Last 30 days',
interval: '1d',
},
{
key: 'startMonth',
label: 'This month',
interval: '1d',
},
]
export const TIME_PERIODS_INFRA = [
{
key: '10m',
label: 'Last 10 minutes',
},
{
key: '30m',
label: 'Last 30 minutes',
},
{
key: '1h',
label: 'Last hour',
},
{
key: '3h',
label: 'Last 3 hours',
},
{
key: '1d',
label: 'Last 24 hours',
},
{
key: '7d',
label: 'Last 7 days',
},
]