mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
fix: Fix inaccurate openapi docs for external alerts API (#1676)
# Summary This PR updates the external Alerts API specs so that the specs match the actual behavior of the API. I've also added a validator to an API which was missing any validation.
This commit is contained in:
parent
b8ab312a4c
commit
941bc23ef4
5 changed files with 264 additions and 123 deletions
5
.changeset/heavy-spies-move.md
Normal file
5
.changeset/heavy-spies-move.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@hyperdx/api": patch
|
||||
---
|
||||
|
||||
fix: Fix inaccurate openapi docs for external alerts API
|
||||
|
|
@ -47,10 +47,12 @@
|
|||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "High Error Rate"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "Error rate exceeds threshold"
|
||||
},
|
||||
"threshold": {
|
||||
|
|
@ -59,6 +61,16 @@
|
|||
},
|
||||
"interval": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"1d"
|
||||
],
|
||||
"example": "15m"
|
||||
},
|
||||
"thresholdType": {
|
||||
|
|
@ -73,19 +85,28 @@
|
|||
"type": "string",
|
||||
"enum": [
|
||||
"tile",
|
||||
"search"
|
||||
"saved_search"
|
||||
],
|
||||
"example": "tile"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"example": "inactive"
|
||||
"enum": [
|
||||
"OK",
|
||||
"ALERT",
|
||||
"INSUFFICIENT_DATA",
|
||||
"DISABLED"
|
||||
],
|
||||
"example": "ALERT"
|
||||
},
|
||||
"channel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"webhook"
|
||||
],
|
||||
"example": "webhook"
|
||||
},
|
||||
"webhookId": {
|
||||
|
|
@ -100,10 +121,12 @@
|
|||
},
|
||||
"tileId": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a901234"
|
||||
},
|
||||
"dashboard": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a567890"
|
||||
},
|
||||
"savedSearch": {
|
||||
|
|
@ -115,16 +138,32 @@
|
|||
"nullable": true
|
||||
},
|
||||
"silenced": {
|
||||
"type": "boolean",
|
||||
"nullable": true
|
||||
"type": "object",
|
||||
"nullable": true,
|
||||
"properties": {
|
||||
"by": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"until": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"format": "date-time",
|
||||
"example": "2023-01-01T00:00:00.000Z"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"format": "date-time",
|
||||
"example": "2023-01-01T00:00:00.000Z"
|
||||
}
|
||||
|
|
@ -142,25 +181,47 @@
|
|||
"properties": {
|
||||
"dashboardId": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a567890"
|
||||
},
|
||||
"tileId": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a901234"
|
||||
},
|
||||
"savedSearchId": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a345678"
|
||||
},
|
||||
"groupBy": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "ServiceName"
|
||||
},
|
||||
"threshold": {
|
||||
"type": "number",
|
||||
"example": 100
|
||||
},
|
||||
"interval": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"1d"
|
||||
],
|
||||
"example": "1h"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tile",
|
||||
"search"
|
||||
"saved_search"
|
||||
],
|
||||
"example": "tile"
|
||||
},
|
||||
|
|
@ -177,6 +238,9 @@
|
|||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"webhook"
|
||||
],
|
||||
"example": "webhook"
|
||||
},
|
||||
"webhookId": {
|
||||
|
|
@ -187,10 +251,12 @@
|
|||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "Test Alert"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "Test Alert Message"
|
||||
}
|
||||
}
|
||||
|
|
@ -198,14 +264,52 @@
|
|||
"UpdateAlertRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dashboardId": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a567890"
|
||||
},
|
||||
"tileId": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a901234"
|
||||
},
|
||||
"savedSearchId": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "65f5e4a3b9e77c001a345678"
|
||||
},
|
||||
"groupBy": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": "ServiceName"
|
||||
},
|
||||
"threshold": {
|
||||
"type": "number",
|
||||
"example": 500
|
||||
"example": 100
|
||||
},
|
||||
"interval": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"1d"
|
||||
],
|
||||
"example": "1h"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tile",
|
||||
"saved_search"
|
||||
],
|
||||
"example": "tile"
|
||||
},
|
||||
"thresholdType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
@ -214,27 +318,14 @@
|
|||
],
|
||||
"example": "above"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tile",
|
||||
"search"
|
||||
],
|
||||
"example": "tile"
|
||||
},
|
||||
"dashboardId": {
|
||||
"type": "string",
|
||||
"example": "65f5e4a3b9e77c001a567890"
|
||||
},
|
||||
"tileId": {
|
||||
"type": "string",
|
||||
"example": "65f5e4a3b9e77c001a901234"
|
||||
},
|
||||
"channel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"webhook"
|
||||
],
|
||||
"example": "webhook"
|
||||
},
|
||||
"webhookId": {
|
||||
|
|
@ -245,11 +336,13 @@
|
|||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "Updated Alert Name"
|
||||
"nullable": true,
|
||||
"example": "Test Alert"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "Updated message"
|
||||
"nullable": true,
|
||||
"example": "Test Alert Message"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -655,13 +748,11 @@
|
|||
"value": {
|
||||
"data": {
|
||||
"id": "65f5e4a3b9e77c001a123456",
|
||||
"name": "CPU Usage Alert",
|
||||
"message": "CPU usage is above 80%",
|
||||
"threshold": 80,
|
||||
"interval": "5m",
|
||||
"thresholdType": "above",
|
||||
"source": "tile",
|
||||
"state": "active",
|
||||
"state": "ALERT",
|
||||
"channel": {
|
||||
"type": "webhook",
|
||||
"webhookId": "65f5e4a3b9e77c001a789012"
|
||||
|
|
@ -868,13 +959,11 @@
|
|||
"data": [
|
||||
{
|
||||
"id": "65f5e4a3b9e77c001a123456",
|
||||
"name": "High Error Rate",
|
||||
"message": "Error rate exceeds threshold",
|
||||
"threshold": 100,
|
||||
"interval": "15m",
|
||||
"thresholdType": "above",
|
||||
"source": "tile",
|
||||
"state": "inactive",
|
||||
"state": "OK",
|
||||
"channel": {
|
||||
"type": "webhook",
|
||||
"webhookId": "65f5e4a3b9e77c001a789012"
|
||||
|
|
|
|||
|
|
@ -242,10 +242,10 @@ describe('External API Alerts', () => {
|
|||
message: 'This should fail validation',
|
||||
};
|
||||
|
||||
// API returns 500 for validation errors
|
||||
// API returns 400 for validation errors
|
||||
const response = await authRequest('post', ALERTS_BASE_URL)
|
||||
.send(invalidInput)
|
||||
.expect(500);
|
||||
.expect(400);
|
||||
|
||||
expect(response.body).toHaveProperty('message');
|
||||
|
||||
|
|
|
|||
|
|
@ -30,15 +30,18 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|||
* example: "65f5e4a3b9e77c001a123456"
|
||||
* name:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "High Error Rate"
|
||||
* message:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "Error rate exceeds threshold"
|
||||
* threshold:
|
||||
* type: number
|
||||
* example: 100
|
||||
* interval:
|
||||
* type: string
|
||||
* enum: [1m, 5m, 15m, 30m, 1h, 6h, 12h, 1d]
|
||||
* example: "15m"
|
||||
* thresholdType:
|
||||
* type: string
|
||||
|
|
@ -46,16 +49,18 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|||
* example: "above"
|
||||
* source:
|
||||
* type: string
|
||||
* enum: [tile, search]
|
||||
* enum: [tile, saved_search]
|
||||
* example: "tile"
|
||||
* state:
|
||||
* type: string
|
||||
* example: "inactive"
|
||||
* enum: [OK, ALERT, INSUFFICIENT_DATA, DISABLED]
|
||||
* example: "ALERT"
|
||||
* channel:
|
||||
* type: object
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* enum: [webhook]
|
||||
* example: "webhook"
|
||||
* webhookId:
|
||||
* type: string
|
||||
|
|
@ -65,9 +70,11 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|||
* example: "65f5e4a3b9e77c001a345678"
|
||||
* tileId:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a901234"
|
||||
* dashboard:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a567890"
|
||||
* savedSearch:
|
||||
* type: string
|
||||
|
|
@ -76,14 +83,26 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|||
* type: string
|
||||
* nullable: true
|
||||
* silenced:
|
||||
* type: boolean
|
||||
* type: object
|
||||
* nullable: true
|
||||
* properties:
|
||||
* by:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* at:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* until:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* createdAt:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* format: date-time
|
||||
* example: "2023-01-01T00:00:00.000Z"
|
||||
* updatedAt:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* format: date-time
|
||||
* example: "2023-01-01T00:00:00.000Z"
|
||||
*
|
||||
|
|
@ -98,19 +117,30 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|||
* properties:
|
||||
* dashboardId:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a567890"
|
||||
* tileId:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a901234"
|
||||
* savedSearchId:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a345678"
|
||||
* groupBy:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "ServiceName"
|
||||
* threshold:
|
||||
* type: number
|
||||
* example: 100
|
||||
* interval:
|
||||
* type: string
|
||||
* enum: [1m, 5m, 15m, 30m, 1h, 6h, 12h, 1d]
|
||||
* example: "1h"
|
||||
* source:
|
||||
* type: string
|
||||
* enum: [tile, search]
|
||||
* enum: [tile, saved_search]
|
||||
* example: "tile"
|
||||
* thresholdType:
|
||||
* type: string
|
||||
|
|
@ -121,55 +151,72 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* enum: [webhook]
|
||||
* example: "webhook"
|
||||
* webhookId:
|
||||
* type: string
|
||||
* example: "65f5e4a3b9e77c001a789012"
|
||||
* name:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "Test Alert"
|
||||
* message:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "Test Alert Message"
|
||||
*
|
||||
* UpdateAlertRequest:
|
||||
* type: object
|
||||
* properties:
|
||||
* dashboardId:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a567890"
|
||||
* tileId:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a901234"
|
||||
* savedSearchId:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "65f5e4a3b9e77c001a345678"
|
||||
* groupBy:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* example: "ServiceName"
|
||||
* threshold:
|
||||
* type: number
|
||||
* example: 500
|
||||
* example: 100
|
||||
* interval:
|
||||
* type: string
|
||||
* enum: [1m, 5m, 15m, 30m, 1h, 6h, 12h, 1d]
|
||||
* example: "1h"
|
||||
* source:
|
||||
* type: string
|
||||
* enum: [tile, saved_search]
|
||||
* example: "tile"
|
||||
* thresholdType:
|
||||
* type: string
|
||||
* enum: [above, below]
|
||||
* example: "above"
|
||||
* source:
|
||||
* type: string
|
||||
* enum: [tile, search]
|
||||
* example: "tile"
|
||||
* dashboardId:
|
||||
* type: string
|
||||
* example: "65f5e4a3b9e77c001a567890"
|
||||
* tileId:
|
||||
* type: string
|
||||
* example: "65f5e4a3b9e77c001a901234"
|
||||
* channel:
|
||||
* type: object
|
||||
* properties:
|
||||
* type:
|
||||
* type: string
|
||||
* enum: [webhook]
|
||||
* example: "webhook"
|
||||
* webhookId:
|
||||
* type: string
|
||||
* example: "65f5e4a3b9e77c001a789012"
|
||||
* name:
|
||||
* type: string
|
||||
* example: "Updated Alert Name"
|
||||
* nullable: true
|
||||
* example: "Test Alert"
|
||||
* message:
|
||||
* type: string
|
||||
* example: "Updated message"
|
||||
* nullable: true
|
||||
* example: "Test Alert Message"
|
||||
*
|
||||
* AlertResponse:
|
||||
* type: object
|
||||
|
|
@ -191,6 +238,7 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|||
*/
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /api/v2/alerts/{id}:
|
||||
|
|
@ -220,13 +268,11 @@ const router = express.Router();
|
|||
* value:
|
||||
* data:
|
||||
* id: "65f5e4a3b9e77c001a123456"
|
||||
* name: "CPU Usage Alert"
|
||||
* message: "CPU usage is above 80%"
|
||||
* threshold: 80
|
||||
* interval: "5m"
|
||||
* thresholdType: "above"
|
||||
* source: "tile"
|
||||
* state: "active"
|
||||
* state: "ALERT"
|
||||
* channel:
|
||||
* type: "webhook"
|
||||
* webhookId: "65f5e4a3b9e77c001a789012"
|
||||
|
|
@ -298,13 +344,11 @@ router.get(
|
|||
* value:
|
||||
* data:
|
||||
* - id: "65f5e4a3b9e77c001a123456"
|
||||
* name: "High Error Rate"
|
||||
* message: "Error rate exceeds threshold"
|
||||
* threshold: 100
|
||||
* interval: "15m"
|
||||
* thresholdType: "above"
|
||||
* source: "tile"
|
||||
* state: "inactive"
|
||||
* state: "OK"
|
||||
* channel:
|
||||
* type: "webhook"
|
||||
* webhookId: "65f5e4a3b9e77c001a789012"
|
||||
|
|
@ -388,23 +432,29 @@ router.get('/', async (req, res, next) => {
|
|||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
router.post('/', async (req, res, next) => {
|
||||
const teamId = req.user?.team;
|
||||
const userId = req.user?._id;
|
||||
if (teamId == null || userId == null) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
try {
|
||||
const alertInput = req.body;
|
||||
const createdAlert = await createAlert(teamId, alertInput, userId);
|
||||
router.post(
|
||||
'/',
|
||||
validateRequest({
|
||||
body: alertSchema,
|
||||
}),
|
||||
async (req, res, next) => {
|
||||
const teamId = req.user?.team;
|
||||
const userId = req.user?._id;
|
||||
if (teamId == null || userId == null) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
try {
|
||||
const alertInput = req.body;
|
||||
const createdAlert = await createAlert(teamId, alertInput, userId);
|
||||
|
||||
return res.json({
|
||||
data: translateAlertDocumentToExternalAlert(createdAlert),
|
||||
});
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
});
|
||||
return res.json({
|
||||
data: translateAlertDocumentToExternalAlert(createdAlert),
|
||||
});
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-nocheck TODO: Fix When Restoring Alerts
|
||||
import { FlattenMaps, LeanDocument } from 'mongoose';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AlertDocument } from '@/models/alert';
|
||||
|
|
@ -151,48 +152,6 @@ export const translateExternalChartToInternalChart = (
|
|||
};
|
||||
};
|
||||
|
||||
const translateChartDocumentToExternalChart = (
|
||||
chart: z.infer<typeof chartSchema>,
|
||||
): z.infer<typeof externalChartSchemaWithId> => {
|
||||
const { id, x, name, y, w, h, series, seriesReturnType } = chart;
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
asRatio: seriesReturnType === 'ratio',
|
||||
series: series.map(s => {
|
||||
const {
|
||||
type,
|
||||
table,
|
||||
aggFn,
|
||||
level,
|
||||
field,
|
||||
where,
|
||||
groupBy,
|
||||
sortOrder,
|
||||
content,
|
||||
numberFormat,
|
||||
} = s;
|
||||
|
||||
return {
|
||||
type,
|
||||
dataSource: table === 'metrics' ? 'metrics' : 'events',
|
||||
aggFn,
|
||||
level,
|
||||
field,
|
||||
where,
|
||||
groupBy,
|
||||
sortOrder,
|
||||
content,
|
||||
numberFormat,
|
||||
};
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
export type ExternalDashboard = {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
@ -220,12 +179,12 @@ export function translateDashboardDocumentToExternalDashboard(
|
|||
// Alert related types and transformations
|
||||
export type ExternalAlert = {
|
||||
id: string;
|
||||
name: string | null;
|
||||
message: string | null;
|
||||
name?: string | null;
|
||||
message?: string | null;
|
||||
threshold: number;
|
||||
interval: string;
|
||||
thresholdType: string;
|
||||
source: string;
|
||||
source?: string;
|
||||
state: string;
|
||||
channel: any;
|
||||
team: string;
|
||||
|
|
@ -233,16 +192,50 @@ export type ExternalAlert = {
|
|||
dashboard?: string;
|
||||
savedSearch?: string;
|
||||
groupBy?: string;
|
||||
silenced?: any;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
silenced?: {
|
||||
by?: string;
|
||||
at: string;
|
||||
until: string;
|
||||
};
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
};
|
||||
|
||||
type AlertDocumentObject =
|
||||
| AlertDocument
|
||||
| FlattenMaps<LeanDocument<AlertDocument>>;
|
||||
|
||||
function hasCreatedAt(
|
||||
alert: AlertDocumentObject,
|
||||
): alert is AlertDocument & { createdAt: Date } {
|
||||
return 'createdAt' in alert && alert.createdAt instanceof Date;
|
||||
}
|
||||
|
||||
function hasUpdatedAt(
|
||||
alert: AlertDocumentObject,
|
||||
): alert is AlertDocument & { updatedAt: Date } {
|
||||
return 'updatedAt' in alert && alert.updatedAt instanceof Date;
|
||||
}
|
||||
|
||||
function transformSilencedToExternalSilenced(
|
||||
silenced: AlertDocumentObject['silenced'],
|
||||
): ExternalAlert['silenced'] {
|
||||
return silenced
|
||||
? {
|
||||
by: silenced.by?.toString(),
|
||||
at: silenced.at.toISOString(),
|
||||
until: silenced.until.toISOString(),
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function translateAlertDocumentToExternalAlert(
|
||||
alert: AlertDocument,
|
||||
): ExternalAlert {
|
||||
// Convert to plain object if it's a Mongoose document
|
||||
const alertObj = alert.toJSON ? alert.toJSON() : { ...alert };
|
||||
const alertObj: AlertDocumentObject = alert.toJSON
|
||||
? alert.toJSON()
|
||||
: { ...alert };
|
||||
|
||||
// Copy all fields, renaming _id to id, ensuring ObjectId's are strings
|
||||
const result = {
|
||||
|
|
@ -260,9 +253,13 @@ export function translateAlertDocumentToExternalAlert(
|
|||
dashboard: alertObj.dashboard?.toString(),
|
||||
savedSearch: alertObj.savedSearch?.toString(),
|
||||
groupBy: alertObj.groupBy,
|
||||
silenced: alertObj.silenced,
|
||||
createdAt: alertObj.createdAt.toISOString(),
|
||||
updatedAt: alertObj.updatedAt.toISOString(),
|
||||
silenced: transformSilencedToExternalSilenced(alertObj.silenced),
|
||||
createdAt: hasCreatedAt(alertObj)
|
||||
? alertObj.createdAt.toISOString()
|
||||
: undefined,
|
||||
updatedAt: hasUpdatedAt(alertObj)
|
||||
? alertObj.updatedAt.toISOString()
|
||||
: undefined,
|
||||
};
|
||||
|
||||
return result;
|
||||
|
|
|
|||
Loading…
Reference in a new issue