feat(design-system): status code component (#42064)

## 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?

Formalising our status code component that was introduced in the new
charts + update auth overview page.


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

* **New Features**
* Added a StatusCode UI component to display HTTP methods and status
codes with color-coded indicators.
* Added a demo showcasing multiple StatusCode examples and alignment
variants.

* **Documentation**
* Added a documentation fragment and sidebar entry for Status Codes with
a preview of the demo.

* **Refactor**
* Updated an Auth Overview view to use the new StatusCode component for
consistent status rendering.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
kemal.earth authored and GitHub committed 2026-03-12 10:57:46 +00:00
1 parent 5b6a1c9858
commit 2c48910673
9 files changed
+213 -45

No files matched your search

+22
View File
@@ -71,6 +71,17 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"StatusCode": {
name: "StatusCode",
type: "components:fragment",
registryDependencies: undefined,
component: React.lazy(() => import("@/../../packages/ui-patterns/src/StatusCode")),
source: "",
files: ["registry/default//StatusCode/index.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"accordion-demo": {
name: "accordion-demo",
type: "components:example",
@@ -2931,6 +2942,17 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"status-code-demo": {
name: "status-code-demo",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/status-code-demo")),
source: "",
files: ["registry/default/example/status-code-demo.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"chart-bar-interactive": {
name: "chart-bar-interactive",
type: "components:block",
+5
View File
@@ -202,6 +202,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/fragments/confirmation-modal',
items: [],
},
{
title: 'Status Codes',
href: '/docs/fragments/status-codes',
items: [],
},
],
},
{
@@ -0,0 +1,35 @@
---
title: Status Code
description: Visually informative blocks for displaying HTTP status codes with method indicators.
fragment: true
---
<ComponentPreview name="status-code-demo" peekCode wide />
## Usage
```tsx
import { StatusCode } from 'ui-patterns'
```
```tsx
<StatusCode method="GET" statusCode="200" />
```
## API Reference
| Prop | Type | Default | Description |
| ------------ | --------------------------------- | -------- | ---------------------------------------------------------------------------- |
| `statusCode` | `number \| string \| undefined` | — | The HTTP status code to display. Drives the color coding (see below). |
| `method` | `string` | — | Optional HTTP method label (e.g. `GET`, `POST`). Rendered as a pill prefix. |
| `className` | `string` | — | Additional CSS classes applied to the root element. |
### Color coding
The status code pill color is determined automatically from the `statusCode` value:
| Value | Color |
| ---------------------------------- | ---------- |
| `1xx`, `2xx`, `3xx`, `'info'`, `'success'`, `undefined` | Neutral |
| `4xx`, `'warning'`, `'redirect'` | Warning |
| `5xx`, `'error'` | Destructive |
@@ -0,0 +1,12 @@
import { StatusCode } from 'ui-patterns'
export default function StatusCodeDemo() {
return (
<div className="flex flex-col gap-2">
<StatusCode method="GET" statusCode="200" />
<StatusCode method="POST" statusCode="404" />
<StatusCode method="DELETE" statusCode="500" />
<StatusCode method="PUT" statusCode="100" />
</div>
)
}
+5
View File
@@ -1593,4 +1593,9 @@ export const examples: Registry = [
registryDependencies: ['mermaid'],
files: ['example/mermaid-basic.tsx'],
},
{
name: 'status-code-demo',
type: 'components:example',
files: ['example/status-code-demo.tsx'],
},
]
+6
View File
@@ -37,4 +37,10 @@ export const fragments: Registry = [
files: ['/PageSection/index.tsx'],
optionalPath: '/PageSection',
},
{
name: 'StatusCode',
type: 'components:fragment',
files: ['/StatusCode/index.tsx'],
optionalPath: '/StatusCode',
},
]
@@ -1,13 +1,28 @@
import { useQuery } from '@tanstack/react-query'
import { useParams } from 'common'
import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import AlertError from 'components/ui/AlertError'
import { getStatusColor } from 'components/ui/DataTable/DataTable.utils'
import { Service } from 'data/graphql/graphql'
import dayjs from 'dayjs'
import { ChevronRight, ExternalLink, Telescope, BarChart2, Bot } from 'lucide-react'
import { BarChart2, Bot, ChevronRight, ExternalLink, Telescope } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useParams } from 'common'
import { getStatusLevel } from 'components/interfaces/UnifiedLogs/UnifiedLogs.utils'
import AlertError from 'components/ui/AlertError'
import { cn, Tooltip, TooltipContent, TooltipTrigger, Button } from 'ui'
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state'
import { AiIconAnimation, Button, cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
import { StatusCode } from 'ui-patterns'
import {
Chart,
ChartActions,
ChartCard,
ChartContent,
ChartEmptyState,
ChartHeader,
ChartLoadingState,
ChartMetric,
ChartTitle,
} from 'ui-patterns/Chart'
import {
PageSection,
PageSectionContent,
@@ -15,17 +30,8 @@ import {
PageSectionSummary,
PageSectionTitle,
} from 'ui-patterns/PageSection'
import {
Chart,
ChartCard,
ChartHeader,
ChartActions,
ChartMetric,
ChartTitle,
ChartContent,
ChartEmptyState,
ChartLoadingState,
} from 'ui-patterns/Chart'
import { ErrorCodeTooltip } from '../../Settings/Logs/ErrorCodeTooltip'
import {
AuthErrorCodeRow,
fetchTopAuthErrorCodes,
@@ -40,13 +46,6 @@ import {
getAuthSuccessRates,
getMetricValues,
} from './OverviewUsage.constants'
import { getStatusColor } from 'components/ui/DataTable/DataTable.utils'
import { ErrorCodeTooltip } from '../../Settings/Logs/ErrorCodeTooltip'
import { Service } from 'data/graphql/graphql'
import { AiIconAnimation } from 'ui'
import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state'
const StatCard = ({
title,
@@ -317,27 +316,7 @@ export const OverviewMetrics = ({ metrics, isLoading, error }: OverviewMetricsPr
header: 'Request',
className: 'w-auto !pr-0',
render: (row) => {
const level = getStatusLevel(row.status_code)
const colors = getStatusColor(level)
return (
<div className="flex items-center gap-2">
<span className="flex-shrink-0 flex items-center text-xs font-mono">
<span className="select-text py-0.5 px-2 text-center rounded-l rounded-r-none bg-surface-75 text-foreground-light border border-r-0">
{row.method}
</span>
<span
className={cn(
'py-0.5 px-2 border rounded-l-0 rounded-r tabular-nums',
colors.text,
colors.bg,
colors.border
)}
>
{row.status_code}
</span>
</span>
</div>
)
return <StatusCode method={row.method} statusCode={row.status_code} />
},
},
{
+1
View File
@@ -24,5 +24,6 @@ export * from './src/PopupFrame'
export * from './src/PromoToast'
export * from './src/Row'
export * from './src/ShimmeringLoader'
export * from './src/StatusCode'
export * from './src/TimestampInfo'
export * from './src/Toc'
@@ -0,0 +1,103 @@
'use client'
import { cn } from 'ui'
export interface StatusCodeProps {
method?: string
statusCode: number | string | undefined
className?: string
}
export function getStatusColor(
value?: number | string,
method?: string
): Record<'text' | 'bg' | 'border', string> {
if (!method && value !== undefined) {
const statusNum = Number(value)
const isValidHttpStatus = !isNaN(statusNum) && statusNum >= 100 && statusNum < 600
if (!isValidHttpStatus) {
return {
text: 'text-foreground-lighter',
bg: 'bg-surface-200',
border: '',
}
}
}
const normalized =
typeof value === 'number'
? value < 100
? String(value)
: String(Math.floor(value / 100))
: typeof value === 'string' && /^\d+$/.test(value) && value.length >= 3
? String(Math.floor(Number(value) / 100))
: value
switch (normalized) {
case '1':
case '2':
case '3':
case 'info':
case 'success':
case undefined:
return {
text: 'text-foreground-lighter',
bg: 'bg-surface-200',
border: '',
}
case '4':
case 'warning':
case 'redirect':
return {
text: 'text-warning',
bg: 'bg-warning-300',
border: 'border-warning-500/50',
}
case '5':
case 'error':
return {
text: 'text-destructive',
bg: 'bg-destructive-300',
border: 'border-destructive-500/50',
}
default:
return {
text: 'text-foreground-lighter',
bg: 'bg-surface-200',
border: '',
}
}
}
export const StatusCode = ({ method, statusCode, className }: StatusCodeProps) => {
const colors = getStatusColor(statusCode, method)
return (
<div className={cn('flex items-center gap-2', className)}>
<span className="flex-shrink-0 flex text-xs font-mono items-start justify-start">
{method && (
<span className="flex items-center justify-end">
<span className="select-text py-0.5 px-2 text-right rounded-l rounded-r-none bg-surface-75 text-foreground-light border border-r-0 w-auto">
{method}
</span>
</span>
)}
<span className="flex items-center justify-start">
<span
className={cn(
'py-0.5 px-2 border rounded-l-0 rounded-r tabular-nums text-left w-auto',
!method && 'rounded-l',
colors.text,
colors.bg,
colors.border
)}
>
{statusCode}
</span>
</span>
</span>
</div>
)
}