bring back old charts

This commit is contained in:
Saxon Fletcher committed 2026-05-27 13:29:32 +10:00
1 parent 87408ed9d9
commit 9384fbf90b
1 file changed
+77 -76
@@ -7,26 +7,26 @@ import { Card, CardContent, CardHeader, CardTitle, Loading } from 'ui'
import { Row } from 'ui-patterns'
import { LogsBarChart } from 'ui-patterns/LogsBarChart'
import { normalizeChartBuckets } from './ChartDataTransform.utils'
import type { LogsBarChartDatum } from './ProjectUsage.metrics'
import {
computeSuccessAndNonSuccessRates,
sumErrors,
sumTotal,
sumWarnings,
} from './ProjectUsage.metrics'
import { useServiceHealthMetrics } from '@/components/interfaces/Observability/useServiceHealthMetrics'
import NoDataPlaceholder from '@/components/ui/Charts/NoDataPlaceholder'
import { ChartIntervalDropdown } from '@/components/ui/Logs/ChartIntervalDropdown'
import { CHART_INTERVALS } from '@/components/ui/Logs/logs.utils'
import { UsageApiCounts, useProjectLogStatsQuery } from '@/data/analytics/project-log-stats-query'
import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
import { useFillTimeseriesSorted } from '@/hooks/analytics/useFillTimeseriesSorted'
import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
type LogsBarChartDatum = {
timestamp: string
error_count: number
ok_count: number
warning_count: number
}
type ChartIntervalKey = '1hr' | '1day' | '7day'
type ServiceKey = 'db' | 'auth' | 'storage' | 'realtime'
type ServiceKey = 'db' | 'functions' | 'auth' | 'storage' | 'realtime'
type ServiceEntry = {
key: ServiceKey
@@ -39,6 +39,8 @@ type ServiceEntry = {
type ServiceComputed = ServiceEntry & {
data: LogsBarChartDatum[]
total: number
warn: number
err: number
isLoading: boolean
error: unknown | null
}
@@ -70,34 +72,11 @@ export const ProjectUsageSection = () => {
return { datetimeFormat: format }
}, [selectedInterval])
// Use V1 data fetching
const { data: logStatsData, isPending: isLoading } = useProjectLogStatsQuery({
projectRef,
interval,
})
// Calculate date range for gap filling
const startDateLocal = dayjs().subtract(
selectedInterval.startValue,
selectedInterval.startUnit as dayjs.ManipulateType
)
const endDateLocal = dayjs()
// Fill gaps in timeseries data
const { data: filledCharts } = useFillTimeseriesSorted({
data: logStatsData?.result ?? [],
timestampKey: 'timestamp',
valueKey: [
'total_auth_requests',
'total_rest_requests',
'total_storage_requests',
'total_realtime_requests',
],
defaultValue: 0,
startDate: startDateLocal.toISOString(),
endDate: endDateLocal.toISOString(),
minPointsToFill: 5,
})
const {
services: healthServices,
isLoading: isHealthLoading,
endDate,
} = useServiceHealthMetrics(projectRef as string, interval, 0)
const serviceBase: ServiceEntry[] = useMemo(
() => [
@@ -108,6 +87,12 @@ export const ProjectUsageSection = () => {
route: '/logs/postgres-logs',
enabled: true,
},
{
key: 'functions',
title: 'Functions requests',
route: '/logs/edge-functions-logs',
enabled: true,
},
{
key: 'auth',
title: 'Auth requests',
@@ -135,51 +120,35 @@ export const ProjectUsageSection = () => {
const services: ServiceComputed[] = useMemo(
() =>
serviceBase.map((s) => {
// Map service keys to V1 data field names
const dataKeyMap: Record<ServiceKey, keyof UsageApiCounts> = {
db: 'total_rest_requests',
auth: 'total_auth_requests',
storage: 'total_storage_requests',
realtime: 'total_realtime_requests',
}
const dataKey = dataKeyMap[s.key]
// Transform V1 data to LogsBarChart format
// Since V1 doesn't have error/warning breakdown, we show everything as "ok"
const transformedData: LogsBarChartDatum[] = (filledCharts || []).map((item) => ({
timestamp: item.timestamp,
error_count: 0,
warning_count: 0,
ok_count: Number(item[dataKey]) || 0,
}))
// Calculate total from filled data
const total = transformedData.reduce((sum, item) => sum + item.ok_count, 0)
const healthData = healthServices[s.key]
const data = normalizeChartBuckets(healthData.eventChartData, interval, new Date(endDate))
const total = sumTotal(data)
const warn = sumWarnings(data)
const err = sumErrors(data)
return {
...s,
data: transformedData,
data,
total,
isLoading,
error: null,
warn,
err,
isLoading: healthData.isLoading,
error: healthData.error,
}
}),
[serviceBase, filledCharts, isLoading]
[serviceBase, healthServices, interval, endDate]
)
const isLoading = isHealthLoading
const handleBarClick =
(logRoute: string, serviceKey: ServiceKey) => (datum: LogsBarChartDatum) => {
if (!datum?.timestamp) return
const datumTimestamp = dayjs(datum.timestamp).toISOString()
const start = dayjs(datumTimestamp).subtract(1, 'minute').toISOString()
const end = dayjs(datumTimestamp).add(1, 'minute').toISOString()
const queryParams = new URLSearchParams({
iso_timestamp_start: start,
iso_timestamp_end: end,
})
const unit = interval === '1hr' ? 'minute' : interval === '1day' ? 'hour' : 'day'
const start = dayjs(datum.timestamp).toISOString()
const end = dayjs(datum.timestamp).add(1, unit).toISOString()
const queryParams = new URLSearchParams({ its: start, ite: end })
router.push(`/project/${projectRef}${logRoute}?${queryParams.toString()}`)
@@ -200,13 +169,28 @@ export const ProjectUsageSection = () => {
const enabledServices = services.filter((s) => s.enabled)
const totalRequests = enabledServices.reduce((sum, s) => sum + (s.total || 0), 0)
const totalErrors = enabledServices.reduce((sum, s) => sum + (s.err || 0), 0)
const totalWarnings = enabledServices.reduce((sum, s) => sum + (s.warn || 0), 0)
const { successRate } = computeSuccessAndNonSuccessRates(
totalRequests,
totalWarnings,
totalErrors
)
return (
<div className="space-y-6">
<div className="flex flex-row justify-between items-center gap-x-2">
<div className="flex items-start gap-2 heading-section text-foreground-light">
<span className="text-foreground">{totalRequests.toLocaleString()}</span>
<span>Total Requests</span>
<div className="flex flex-col md:flex-row md:items-center md:gap-6">
<div className="flex items-start gap-2 heading-section text-foreground-light">
<span className="text-foreground">{totalRequests.toLocaleString()}</span>
<span>Total Requests</span>
</div>
<div className="flex items-start gap-2 heading-section text-foreground-light">
<span className="text-foreground">
{successRate === 100 ? '100' : successRate.toFixed(1)}%
</span>
<span>Success Rate</span>
</div>
</div>
<ChartIntervalDropdown
value={interval}
@@ -216,13 +200,13 @@ export const ProjectUsageSection = () => {
tooltipSide="left"
/>
</div>
<Row maxColumns={4} minWidth={280}>
<Row maxColumns={3} minWidth={280}>
{enabledServices.map((s) => (
<Card key={s.key} className="mb-0 md:mb-0 h-full flex flex-col h-64">
<CardHeader className="flex flex-row items-end justify-between gap-2 space-y-0 pb-0 border-b-0">
<div className="flex items-center gap-2">
<div className="flex flex-col">
<CardTitle className="text-xs font-mono uppercase text-foreground-light">
<CardTitle className="text-foreground-light">
{s.href ? (
<Link
href={s.href}
@@ -233,6 +217,7 @@ export const ProjectUsageSection = () => {
properties: {
service_type: s.key,
total_requests: s.total || 0,
error_count: s.err || 0,
},
groups: {
project: projectRef,
@@ -251,6 +236,22 @@ export const ProjectUsageSection = () => {
<span className="text-foreground text-xl">{(s.total || 0).toLocaleString()}</span>
</div>
</div>
<div className="flex items-end gap-4 text-foreground-light">
<div className="flex flex-col items-end">
<div className="flex items-center gap-2">
<div className="w-1.5 h-1.5 bg-warning rounded-full" />
<span className="heading-meta">Warn</span>
</div>
<span className="text-foreground text-xl">{(s.warn || 0).toLocaleString()}</span>
</div>
<div className="flex flex-col items-end">
<div className="flex items-center gap-2">
<div className="w-1.5 h-1.5 bg-destructive rounded-full" />
<span className="heading-meta">Err</span>
</div>
<span className="text-foreground text-xl">{(s.err || 0).toLocaleString()}</span>
</div>
</div>
</CardHeader>
<CardContent className="p-card flex-1 h-full overflow-hidden">
<Loading isFullHeight active={isLoading}>