= {
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",
diff --git a/apps/design-system/config/docs.ts b/apps/design-system/config/docs.ts
index 33903e95e2b..ab73703af78 100644
--- a/apps/design-system/config/docs.ts
+++ b/apps/design-system/config/docs.ts
@@ -202,6 +202,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/fragments/confirmation-modal',
items: [],
},
+ {
+ title: 'Status Codes',
+ href: '/docs/fragments/status-codes',
+ items: [],
+ },
],
},
{
diff --git a/apps/design-system/content/docs/fragments/status-codes.mdx b/apps/design-system/content/docs/fragments/status-codes.mdx
new file mode 100644
index 00000000000..e9f1402774d
--- /dev/null
+++ b/apps/design-system/content/docs/fragments/status-codes.mdx
@@ -0,0 +1,35 @@
+---
+title: Status Code
+description: Visually informative blocks for displaying HTTP status codes with method indicators.
+fragment: true
+---
+
+
+
+## Usage
+
+```tsx
+import { StatusCode } from 'ui-patterns'
+```
+
+```tsx
+
+```
+
+## 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 |
diff --git a/apps/design-system/registry/default/example/status-code-demo.tsx b/apps/design-system/registry/default/example/status-code-demo.tsx
new file mode 100644
index 00000000000..4f41585f901
--- /dev/null
+++ b/apps/design-system/registry/default/example/status-code-demo.tsx
@@ -0,0 +1,12 @@
+import { StatusCode } from 'ui-patterns'
+
+export default function StatusCodeDemo() {
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/apps/design-system/registry/examples.ts b/apps/design-system/registry/examples.ts
index 3a236c19096..821c5530446 100644
--- a/apps/design-system/registry/examples.ts
+++ b/apps/design-system/registry/examples.ts
@@ -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'],
+ },
]
diff --git a/apps/design-system/registry/fragments.ts b/apps/design-system/registry/fragments.ts
index 3a71fbcdb47..1a389e4679a 100644
--- a/apps/design-system/registry/fragments.ts
+++ b/apps/design-system/registry/fragments.ts
@@ -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',
+ },
]
diff --git a/apps/studio/components/interfaces/Auth/Overview/OverviewMetrics.tsx b/apps/studio/components/interfaces/Auth/Overview/OverviewMetrics.tsx
index d9619760498..a26ee94281e 100644
--- a/apps/studio/components/interfaces/Auth/Overview/OverviewMetrics.tsx
+++ b/apps/studio/components/interfaces/Auth/Overview/OverviewMetrics.tsx
@@ -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 (
-
-
-
- {row.method}
-
-
- {row.status_code}
-
-
-
- )
+ return
},
},
{
diff --git a/packages/ui-patterns/index.tsx b/packages/ui-patterns/index.tsx
index f7ffdde0b60..f0bcf7d138e 100644
--- a/packages/ui-patterns/index.tsx
+++ b/packages/ui-patterns/index.tsx
@@ -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'
diff --git a/packages/ui-patterns/src/StatusCode/index.tsx b/packages/ui-patterns/src/StatusCode/index.tsx
new file mode 100644
index 00000000000..54052bff441
--- /dev/null
+++ b/packages/ui-patterns/src/StatusCode/index.tsx
@@ -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 (
+
+
+ {method && (
+
+
+ {method}
+
+
+ )}
+
+
+ {statusCode}
+
+
+
+
+ )
+}