diff --git a/src/pages/ethereum/execution/gas-profiler/HomePage.tsx b/src/pages/ethereum/execution/gas-profiler/HomePage.tsx index f912ec2a8..d818937a5 100644 --- a/src/pages/ethereum/execution/gas-profiler/HomePage.tsx +++ b/src/pages/ethereum/execution/gas-profiler/HomePage.tsx @@ -25,12 +25,18 @@ import { } from '@/components/Charts/MultiLine'; import { BarChart } from '@/components/Charts/Bar'; import { - fctOpcodeOpsHourlyServiceListOptions, - fctOpcodeOpsDailyServiceListOptions, - fctOpcodeGasByOpcodeHourlyServiceListOptions, - fctOpcodeGasByOpcodeDailyServiceListOptions, -} from '@/api/@tanstack/react-query.gen'; -import type { FctOpcodeOpsHourly, FctOpcodeOpsDaily } from '@/api/types.gen'; + fctOpcodeOpsHourlyServiceList, + fctOpcodeOpsDailyServiceList, + fctOpcodeGasByOpcodeHourlyServiceList, + fctOpcodeGasByOpcodeDailyServiceList, +} from '@/api/sdk.gen'; +import type { + FctOpcodeOpsHourly, + FctOpcodeOpsDaily, + FctOpcodeGasByOpcodeHourly, + FctOpcodeGasByOpcodeDaily, +} from '@/api/types.gen'; +import { fetchAllPages } from '@/utils/api-pagination'; import { useRecentBlocks } from './hooks/useRecentBlocks'; import { useGasProfilerBounds } from './hooks/useGasProfilerBounds'; import { GasProfilerSkeleton, OpcodeAnalysis } from './components'; @@ -216,70 +222,111 @@ export function HomePage(): JSX.Element { return now - config.days * 24 * 60 * 60; }, [config.days]); - // Opcode Ops Per Second Queries (real data) + // Opcode Ops Per Second Queries (real data) - with pagination const opcodeOpsHourlyQuery = useQuery({ - ...fctOpcodeOpsHourlyServiceListOptions({ - query: { - hour_start_date_time_gte: startTimestamp, - order_by: 'hour_start_date_time asc', - page_size: config.pageSize, - }, - }), + queryKey: ['gas-profiler', 'opcode-ops-hourly', startTimestamp, config.pageSize], + queryFn: ({ signal }) => + fetchAllPages( + fctOpcodeOpsHourlyServiceList, + { + query: { + hour_start_date_time_gte: startTimestamp, + order_by: 'hour_start_date_time asc', + page_size: config.pageSize, + }, + }, + 'fct_opcode_ops_hourly', + signal + ), enabled: !isDaily, }); const opcodeOpsDailyQuery = useQuery({ - ...fctOpcodeOpsDailyServiceListOptions({ - query: { - day_start_date_like: '20%', - order_by: 'day_start_date desc', - page_size: config.pageSize, - }, - }), + queryKey: ['gas-profiler', 'opcode-ops-daily', config.pageSize], + queryFn: ({ signal }) => + fetchAllPages( + fctOpcodeOpsDailyServiceList, + { + query: { + day_start_date_like: '20%', + order_by: 'day_start_date desc', + page_size: config.pageSize, + }, + }, + 'fct_opcode_ops_daily', + signal + ), enabled: isDaily, }); - // Top Opcodes by Gas Queries (real data) + // Top Opcodes by Gas Queries (real data) - with pagination const opcodeGasHourlyQuery = useQuery({ - ...fctOpcodeGasByOpcodeHourlyServiceListOptions({ - query: { - hour_start_date_time_gte: startTimestamp, - order_by: 'total_gas desc', - page_size: 1000, // Get all opcodes for aggregation - }, - }), + queryKey: ['gas-profiler', 'opcode-gas-hourly', startTimestamp], + queryFn: ({ signal }) => + fetchAllPages( + fctOpcodeGasByOpcodeHourlyServiceList, + { + query: { + hour_start_date_time_gte: startTimestamp, + order_by: 'total_gas desc', + page_size: 10000, + }, + }, + 'fct_opcode_gas_by_opcode_hourly', + signal + ), enabled: !isDaily, }); const opcodeGasDailyQuery = useQuery({ - ...fctOpcodeGasByOpcodeDailyServiceListOptions({ - query: { - day_start_date_like: '20%', - order_by: 'total_gas desc', - page_size: 1000, // Get all opcodes for aggregation - }, - }), + queryKey: ['gas-profiler', 'opcode-gas-daily'], + queryFn: ({ signal }) => + fetchAllPages( + fctOpcodeGasByOpcodeDailyServiceList, + { + query: { + day_start_date_like: '20%', + order_by: 'total_gas desc', + page_size: 10000, + }, + }, + 'fct_opcode_gas_by_opcode_daily', + signal + ), enabled: isDaily, }); - // Opcode ops records - const opcodeOpsRecords = useMemo( - () => - isDaily - ? [...(opcodeOpsDailyQuery.data?.fct_opcode_ops_daily ?? [])].reverse() - : opcodeOpsHourlyQuery.data?.fct_opcode_ops_hourly, - [isDaily, opcodeOpsDailyQuery.data, opcodeOpsHourlyQuery.data] - ); + // Opcode ops records (fetchAllPages returns array directly) + // Filter by time period for daily data + const opcodeOpsRecords = useMemo(() => { + if (isDaily) { + const allRecords = [...(opcodeOpsDailyQuery.data ?? [])].reverse(); + if (config.days === null) return allRecords; // 'all' - no filtering + // Filter to last N days + const cutoffDate = new Date(); + cutoffDate.setDate(cutoffDate.getDate() - config.days); + const cutoffStr = cutoffDate.toISOString().split('T')[0]; // YYYY-MM-DD + return allRecords.filter(r => (r.day_start_date ?? '') >= cutoffStr); + } + return opcodeOpsHourlyQuery.data; + }, [isDaily, opcodeOpsDailyQuery.data, opcodeOpsHourlyQuery.data, config.days]); - // Aggregate opcodes for OpcodeAnalysis component + // Aggregate opcodes for OpcodeAnalysis component (fetchAllPages returns array directly) + // Filter by time period for daily data const opcodeStats = useMemo(() => { - const records = isDaily - ? opcodeGasDailyQuery.data?.fct_opcode_gas_by_opcode_daily - : opcodeGasHourlyQuery.data?.fct_opcode_gas_by_opcode_hourly; + let records = isDaily ? opcodeGasDailyQuery.data : opcodeGasHourlyQuery.data; if (!records?.length) return []; - // Aggregate gas by opcode across all time periods + // Filter daily records by time period + if (isDaily && config.days !== null) { + const cutoffDate = new Date(); + cutoffDate.setDate(cutoffDate.getDate() - config.days); + const cutoffStr = cutoffDate.toISOString().split('T')[0]; + records = records.filter(r => ((r as FctOpcodeGasByOpcodeDaily).day_start_date ?? '') >= cutoffStr); + } + + // Aggregate gas by opcode across the filtered time period const opcodeMap = new Map(); for (const r of records) { if (!r.opcode) continue; @@ -298,16 +345,23 @@ export function HomePage(): JSX.Element { count: data.totalCount, })) .sort((a, b) => b.totalGas - a.totalGas); - }, [isDaily, opcodeGasDailyQuery.data, opcodeGasHourlyQuery.data]); + }, [isDaily, opcodeGasDailyQuery.data, opcodeGasHourlyQuery.data, config.days]); // Aggregate gas by category across the time period (top 8 + Other for bar chart) + // Filter by time period for daily data const gasByCategoryData = useMemo(() => { - const records = isDaily - ? opcodeGasDailyQuery.data?.fct_opcode_gas_by_opcode_daily - : opcodeGasHourlyQuery.data?.fct_opcode_gas_by_opcode_hourly; + let records = isDaily ? opcodeGasDailyQuery.data : opcodeGasHourlyQuery.data; if (!records?.length) return { labels: [], data: [], total: 0 }; + // Filter daily records by time period + if (isDaily && config.days !== null) { + const cutoffDate = new Date(); + cutoffDate.setDate(cutoffDate.getDate() - config.days); + const cutoffStr = cutoffDate.toISOString().split('T')[0]; + records = records.filter(r => ((r as FctOpcodeGasByOpcodeDaily).day_start_date ?? '') >= cutoffStr); + } + // Aggregate gas by category const categoryMap = new Map(); for (const r of records) { @@ -338,7 +392,7 @@ export function HomePage(): JSX.Element { })), total, }; - }, [isDaily, opcodeGasDailyQuery.data, opcodeGasHourlyQuery.data]); + }, [isDaily, opcodeGasDailyQuery.data, opcodeGasHourlyQuery.data, config.days]); // Navigate to older/newer blocks const handleLoadOlderBlocks = useCallback(() => { diff --git a/src/pages/ethereum/execution/gas-profiler/constants.ts b/src/pages/ethereum/execution/gas-profiler/constants.ts index b8630da7f..1751936bd 100644 --- a/src/pages/ethereum/execution/gas-profiler/constants.ts +++ b/src/pages/ethereum/execution/gas-profiler/constants.ts @@ -1,16 +1,18 @@ import type { SeriesData } from '@/components/Charts/MultiLine'; /** Available time period options for chart display */ -export type TimePeriod = '7d' | '30d' | '90d' | '180d' | '1y' | '2y' | 'all'; +export type TimePeriod = '24h' | '72h' | '7d' | '30d' | '90d' | '180d' | '1y' | '2y' | 'all'; /** Configuration for each time range option */ export const TIME_RANGE_CONFIG = { - '7d': { days: 7, dataType: 'hourly' as const, pageSize: 168 }, - '30d': { days: 30, dataType: 'hourly' as const, pageSize: 720 }, - '90d': { days: 90, dataType: 'hourly' as const, pageSize: 2160 }, - '180d': { days: 180, dataType: 'daily' as const, pageSize: 180 }, - '1y': { days: 365, dataType: 'daily' as const, pageSize: 365 }, - '2y': { days: 730, dataType: 'daily' as const, pageSize: 730 }, + '24h': { days: 1, dataType: 'hourly' as const, pageSize: 10000 }, + '72h': { days: 3, dataType: 'hourly' as const, pageSize: 10000 }, + '7d': { days: 7, dataType: 'daily' as const, pageSize: 10000 }, + '30d': { days: 30, dataType: 'daily' as const, pageSize: 10000 }, + '90d': { days: 90, dataType: 'daily' as const, pageSize: 10000 }, + '180d': { days: 180, dataType: 'daily' as const, pageSize: 10000 }, + '1y': { days: 365, dataType: 'daily' as const, pageSize: 10000 }, + '2y': { days: 730, dataType: 'daily' as const, pageSize: 10000 }, all: { days: null, dataType: 'daily' as const, pageSize: 10000 }, } as const; @@ -22,6 +24,9 @@ export interface ChartConfig { /** Time period selector options for UI rendering */ export const TIME_PERIOD_OPTIONS = [ + // TODO: Enable when hourly data is current + // { value: '24h' as const, label: '24h' }, + // { value: '72h' as const, label: '72h' }, { value: '7d' as const, label: '7d' }, { value: '30d' as const, label: '30d' }, // TODO: Enable when data is available