From 9384fbf90b9cc7ca80309fa906dab8982b5870bc Mon Sep 17 00:00:00 2001 From: Saxon Fletcher Date: Wed, 27 May 2026 13:29:32 +1000 Subject: [PATCH] bring back old charts --- .../ProjectHome/ProjectUsageSection.tsx | 153 +++++++++--------- 1 file changed, 77 insertions(+), 76 deletions(-) diff --git a/apps/studio/components/interfaces/ProjectHome/ProjectUsageSection.tsx b/apps/studio/components/interfaces/ProjectHome/ProjectUsageSection.tsx index 334e9bb4846..2690671c079 100644 --- a/apps/studio/components/interfaces/ProjectHome/ProjectUsageSection.tsx +++ b/apps/studio/components/interfaces/ProjectHome/ProjectUsageSection.tsx @@ -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 = { - 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 (
-
- {totalRequests.toLocaleString()} - Total Requests +
+
+ {totalRequests.toLocaleString()} + Total Requests +
+
+ + {successRate === 100 ? '100' : successRate.toFixed(1)}% + + Success Rate +
{ tooltipSide="left" />
- + {enabledServices.map((s) => (
- + {s.href ? ( { 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 = () => { {(s.total || 0).toLocaleString()}
+
+
+
+
+ Warn +
+ {(s.warn || 0).toLocaleString()} +
+
+
+
+ Err +
+ {(s.err || 0).toLocaleString()} +
+