fix(notifications): route Rocket.Chat links by monitor type

Build title_link from the monitor type (hardware -> infrastructure,
pagespeed -> pagespeed, uptime types -> uptime) and omit it when
clientHost is not configured, instead of always linking to the
infrastructure page.
This commit is contained in:
Marcos Paulo Diniz committed 2026-08-13 11:56:28 -03:00
1 parent 8d1fd61bb4
commit d4eaad6170
2 files changed
+52 -2

No files matched your search

@@ -1,4 +1,5 @@
const SERVICE_NAME = "RocketChatProvider";
import { supportsUptimeDetails, type MonitorType } from "@/domain/monitors/monitor.type.js";
import type { Notification, NotificationMessage } from "@/domain/notifications/notification.type.js";
import { NotificationProvider } from "@/domain/notifications/providers/INotificationProvider.js";
import { getTestMessage } from "@/domain/notifications/providers/utils.js";
@@ -84,6 +85,7 @@ export class RocketChatProvider extends NotificationProvider {
}
private buildPayload(message: NotificationMessage): RocketChatPayload {
const monitorUrl = this.monitorUrl(message);
const fields: RocketChatField[] = [
{ title: "Monitor", value: message.monitor.name, short: true },
{ title: "Type", value: message.monitor.type, short: true },
@@ -123,7 +125,7 @@ export class RocketChatProvider extends NotificationProvider {
{
color: this.severityColor(message.severity),
title: message.content.title,
title_link: `${message.clientHost}/infrastructure/${message.monitor.id}`,
...(monitorUrl ? { title_link: monitorUrl } : {}),
fields,
ts: message.content.timestamp.toISOString(),
},
@@ -131,6 +133,27 @@ export class RocketChatProvider extends NotificationProvider {
};
}
private monitorUrl(message: NotificationMessage): string | undefined {
const clientHost = message.clientHost?.trim();
if (!clientHost || clientHost === "Host not defined") {
return undefined;
}
if (message.monitor.type === "hardware") {
return `${clientHost}/infrastructure/${message.monitor.id}`;
}
if (message.monitor.type === "pagespeed") {
return `${clientHost}/pagespeed/${message.monitor.id}`;
}
if (supportsUptimeDetails(message.monitor.type as MonitorType)) {
return `${clientHost}/uptime/${message.monitor.id}`;
}
return undefined;
}
private severityColor(severity: NotificationMessage["severity"]): string {
switch (severity) {
case "critical":
@@ -1,4 +1,5 @@
import { describe, expect, it, jest } from "@jest/globals";
import type { MonitorType } from "../../../../src/domain/monitors/monitor.type.ts";
import type { NotificationSeverity } from "../../../../src/domain/notifications/notification.type.ts";
import { createMockLogger } from "../../../helpers/createMockLogger.ts";
import { makeMessage, makeMessageWithIncident, makeMessageWithThresholds, makeNotification } from "../../../helpers/notificationMessage.ts";
@@ -102,7 +103,7 @@ describe("RocketChatProvider", () => {
{
color: "#FF0000",
title: "Monitor Down: Test Monitor",
title_link: "https://app.example.com/infrastructure/mon-1",
title_link: "https://app.example.com/uptime/mon-1",
fields: [
{ title: "Monitor", value: "Test Monitor", short: true },
{ title: "Type", value: "http", short: true },
@@ -128,6 +129,32 @@ describe("RocketChatProvider", () => {
expect(payload).not.toHaveProperty("channel");
});
it.each([
["http", "https://app.example.com/uptime/mon-1"],
["ping", "https://app.example.com/uptime/mon-1"],
["pagespeed", "https://app.example.com/pagespeed/mon-1"],
["hardware", "https://app.example.com/infrastructure/mon-1"],
])("links %s monitors to %s", async (type, expectedLink) => {
const { provider } = createProvider();
await provider.sendMessage(
makeNotification({ type: "rocket_chat" }),
makeMessage({ monitor: { id: "mon-1", name: "Test Monitor", url: "https://example.com", type: type as MonitorType, status: "down" } })
);
const payload = mockGotPost.mock.calls[0][1].json;
expect(payload.attachments[0].title_link).toBe(expectedLink);
});
it.each([["Host not defined"], [""], [" "]])("omits title_link when clientHost is %j", async (clientHost) => {
const { provider } = createProvider();
await provider.sendMessage(makeNotification({ type: "rocket_chat" }), makeMessage({ clientHost }));
const payload = mockGotPost.mock.calls[0][1].json;
expect(payload.attachments[0]).not.toHaveProperty("title_link");
});
it.each([
["critical", "#FF0000"],
["warning", "#FFA500"],