feat(api): add CloudWatch alarms and metric charts to the cloud explorer
CI / checks (pull_request) Successful in 27m29s

This commit is contained in:
Zakaria
2026-10-24 22:48:41 -04:00
parent f4b3e45f3d
commit 6dd33b8f65
26 changed files with 1551 additions and 1 deletions
@@ -0,0 +1,12 @@
import {expect, test} from 'vitest'
import {formatValue, niceTicks} from './metricChart'
test('picks about five round ticks that include zero', () => {
expect(niceTicks(0, 7)).toEqual([0, 2, 4, 6, 8])
expect(niceTicks(0, 100)).toEqual([0, 25, 50, 75, 100])
expect(niceTicks(-3, 3)).toEqual([-4, -2, 0, 2, 4])
})
test('formats values compactly from a thousand up', () => {
expect([formatValue(7), formatValue(0.25), formatValue(1500), formatValue(2_000_000), formatValue(12.5)]).toEqual(['7', '0.25', '1.5K', '2M', '12.5'])
})
+34
View File
@@ -0,0 +1,34 @@
/** Time ranges offered above CloudWatch charts. */
export const RANGES = [{label: '1 hour', minutes: 60}, {label: '3 hours', minutes: 180}, {label: '24 hours', minutes: 1440}, {label: '7 days', minutes: 10080}]
/** About five round ticks covering [min, max], always including zero when the range does. */
export function niceTicks(min: number, max: number, count = 5): number[] {
const span = max - min
const raw = span / (count - 1)
const magnitude = 10 ** Math.floor(Math.log10(raw))
const step = [1, 2, 2.5, 5, 10].map((factor) => factor * magnitude).find((candidate) => candidate >= raw) ?? 10 * magnitude
const start = Math.floor(min / step) * step
const end = Math.ceil(max / step) * step
const ticks: number[] = []
for (let value = start; value <= end + step / 2; value += step) ticks.push(Number(value.toPrecision(12)))
return ticks
}
export function timeTicks(start: number, end: number, count: number): number[] {
if (end <= start) return [start]
const step = (end - start) / count
return Array.from({length: count + 1}, (_, index) => start + index * step)
}
export function formatValue(value: number): string {
const abs = Math.abs(value)
if (abs >= 1e9) return `${trim(value / 1e9)}B`
if (abs >= 1e6) return `${trim(value / 1e6)}M`
if (abs >= 1e3) return `${trim(value / 1e3)}K`
return trim(value)
}
function trim(value: number): string {
return Number.isInteger(value) ? String(value) : value.toFixed(Math.abs(value) < 10 ? 2 : 1).replace(/\.?0+$/, '')
}