Merge ticket/022-edit-existing-metric-declarations

This commit is contained in:
Hugh Kaznowski
2026-09-05 19:41:59 +01:00
5 changed files with 467 additions and 21 deletions
+27
View File
@@ -205,6 +205,28 @@ async function postJson<T>(path: string, body: unknown): Promise<T> {
return res.json() as Promise<T>
}
// Same error handling as `postJson` (throws `ApiError` with the parsed message) but for a PUT — used where updating in place, rather than creating, is the operation.
async function putJson<T>(path: string, body: unknown): Promise<T> {
const res = await fetch(path, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
if (!res.ok) {
let message = `${path} failed: ${res.status}`
try {
const errorBody = (await res.json()) as Partial<ApiErrorBody>
if (errorBody && typeof errorBody.error === 'string') {
message = errorBody.error
}
} catch {
// response body wasn't JSON; fall back to the generic message
}
throw new ApiError(message)
}
return res.json() as Promise<T>
}
async function sendJson<T>(path: string, method: string, body?: unknown): Promise<T> {
const res = await fetch(path, {
method,
@@ -275,6 +297,11 @@ export function declareMetric(request: MetricDeclaration): Promise<MetricDeclara
return postJson('/api/metrics', request)
}
// Updates the metric declaration named `existingName` in place (`existingName` may differ from `request.name` to rename it), rather than declaring a second metric or failing on a duplicate-name conflict.
export function updateMetric(existingName: string, request: MetricDeclaration): Promise<MetricDeclaration> {
return putJson(`/api/metrics/${encodeURIComponent(existingName)}`, request)
}
export function fetchMetricBucketValues(
name: string,
params: {