feat(rate-limits): use 5m trend buckets and 24h/7d ranges

Overview API accepts bucket_minutes (5|60); rate-limit analysis uses
5-minute buckets and drops 15d/30d presets. Widen rank value column.
This commit is contained in:
ryan
2026-07-19 19:18:15 +08:00
parent 86d2d6b0ad
commit b56290d79d
10 changed files with 90 additions and 39 deletions
@@ -13,7 +13,8 @@ import type {
import {
formatOverviewRangeHint,
type OverviewRangeHours,
RATE_LIMIT_RANGE_OPTIONS,
type RateLimitRangeHours,
} from '../../access-logs/components/access-log-utils';
import { OverviewToolbar } from '../../access-logs/components/overview-toolbar';
import { RatePressureChart } from './rate-pressure-chart';
@@ -50,9 +51,9 @@ export function AnalysisTab({
data?: AccessLogOverview;
loading: boolean;
error: Error | null;
hours: OverviewRangeHours;
hours: RateLimitRangeHours;
hosts: string[];
onHoursChange: (hours: OverviewRangeHours) => void;
onHoursChange: (hours: RateLimitRangeHours) => void;
onHostsChange: (hosts: string[]) => void;
onRetry: () => void;
}) {
@@ -65,8 +66,9 @@ export function AnalysisTab({
<OverviewToolbar
hours={hours}
hosts={hosts}
onHoursChange={onHoursChange}
onHoursChange={(next) => onHoursChange(next as RateLimitRangeHours)}
onHostsChange={onHostsChange}
rangeOptions={RATE_LIMIT_RANGE_OPTIONS}
/>
{loading ? (
@@ -14,7 +14,7 @@ import {
type OverviewRangeHours,
} from '../../access-logs/components/access-log-utils';
const BUCKET_SECONDS = 3600;
const DEFAULT_BUCKET_SECONDS = 300;
const RPS_COLOR = '#38bdf8';
const VISITS_COLOR = '#a78bfa';
@@ -58,6 +58,11 @@ type RatePressureChartProps = {
};
export function RatePressureChart({ data, hours }: RatePressureChartProps) {
const bucketSeconds =
(data?.bucket_minutes && data.bucket_minutes > 0
? data.bucket_minutes
: 5) * 60 || DEFAULT_BUCKET_SECONDS;
const rangeLabel = useMemo(() => {
const end = data?.generated_at ? new Date(data.generated_at) : new Date();
const start = new Date(end.getTime() - hours * 3600 * 1000);
@@ -82,12 +87,12 @@ export function RatePressureChart({ data, hours }: RatePressureChartProps) {
const time = req?.bucket_started_at ?? visit?.bucket_started_at ?? '';
rawTimes.push(time);
labels.push(formatAxisTime(time, hours));
rpsValues.push((req?.value ?? 0) / BUCKET_SECONDS);
rpsValues.push((req?.value ?? 0) / bucketSeconds);
visitValues.push(visit?.value ?? 0);
}
return { labels, rpsValues, visitValues, rawTimes };
}, [data?.trends.requests, data?.trends.visits, hours]);
}, [bucketSeconds, data?.trends.requests, data?.trends.visits, hours]);
const option = useMemo<EChartsOption>(() => {
const rpsMax = calculateNiceAxisMax(chartModel.rpsValues);