feat(api): add CloudWatch alarms and metric charts to the cloud explorer
CI / checks (pull_request) Successful in 27m29s
CI / checks (pull_request) Successful in 27m29s
This commit is contained in:
@@ -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'])
|
||||
})
|
||||
@@ -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+$/, '')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user