Merge branch 'monitor-alert'

This commit is contained in:
Simon Larsen 2024-10-08 20:26:12 +01:00
commit bc714759bc
No known key found for this signature in database
GPG Key ID: 96C5DCA24769DBCA
12 changed files with 200 additions and 16 deletions

View File

@ -282,6 +282,38 @@ export class Service extends DatabaseService<UserNotificationSetting> {
});
}
const alertCreatedNotificationEvent: PositiveNumber = await this.countBy(
{
query: {
userId,
projectId,
eventType:
NotificationSettingEventType.SEND_ALERT_CREATED_OWNER_NOTIFICATION,
},
props: {
isRoot: true,
},
},
);
if (alertCreatedNotificationEvent.toNumber() === 0) {
const item: UserNotificationSetting = new UserNotificationSetting();
item.userId = userId;
item.projectId = projectId;
item.eventType =
NotificationSettingEventType.SEND_ALERT_CREATED_OWNER_NOTIFICATION;
item.alertByEmail = true;
await this.create({
data: item,
props: {
isRoot: true,
},
});
}
// check monitor state changed notification
const monitorStateChangedNotificationEvent: PositiveNumber =
await this.countBy({
@ -404,6 +436,38 @@ export class Service extends DatabaseService<UserNotificationSetting> {
},
});
}
// check alert state changed notification
const alertStateChangedNotificationEvent: PositiveNumber =
await this.countBy({
query: {
userId,
projectId,
eventType:
NotificationSettingEventType.SEND_ALERT_STATE_CHANGED_OWNER_NOTIFICATION,
},
props: {
isRoot: true,
},
});
if (alertStateChangedNotificationEvent.toNumber() === 0) {
const item: UserNotificationSetting = new UserNotificationSetting();
item.userId = userId;
item.projectId = projectId;
item.eventType =
NotificationSettingEventType.SEND_ALERT_STATE_CHANGED_OWNER_NOTIFICATION;
item.alertByEmail = true;
await this.create({
data: item,
props: {
isRoot: true,
},
});
}
}
protected override async onBeforeCreate(

View File

@ -5,6 +5,13 @@ enum NotificationSettingEventType {
SEND_INCIDENT_STATE_CHANGED_OWNER_NOTIFICATION = "Send incident state changed notification when I am the owner of the incident",
SEND_INCIDENT_OWNER_ADDED_NOTIFICATION = "Send notification when I am added as a owner to the incident",
// Alerts
SEND_ALERT_CREATED_OWNER_NOTIFICATION = "Send alert created notification when I am the owner of the alert",
SEND_ALERT_NOTE_POSTED_OWNER_NOTIFICATION = "Send alert note posted notification when I am the owner of the alert",
SEND_ALERT_STATE_CHANGED_OWNER_NOTIFICATION = "Send alert state changed notification when I am the owner of the alert",
SEND_ALERT_OWNER_ADDED_NOTIFICATION = "Send notification when I am added as a owner to the alert",
// Monitors
SEND_MONITOR_OWNER_ADDED_NOTIFICATION = "Send notification when I am added as a owner to the monitor",
SEND_MONITOR_CREATED_OWNER_NOTIFICATION = "Send monitor created notification when I am the owner of the monitor",

View File

@ -40,10 +40,27 @@ const HeaderAlert: (props: ComponentProps) => ReactElement = (
break;
}
let bgColor: string = "bg-gray";
switch (props.alertType) {
case HeaderAlertType.SUCCESS:
bgColor = "bg-green";
break;
case HeaderAlertType.ERROR:
bgColor = "bg-red";
break;
case HeaderAlertType.WARNING:
bgColor = "bg-yellow";
break;
case HeaderAlertType.INFO:
bgColor = "bg-indigo";
break;
}
const getElement: GetReactElementFunction = (): ReactElement => {
return (
<div
className={`cursor-pointer hover:bg-gray-100 p-1 h-7 pl-2 pr-2 -mt-2 -ml-5 mr-1 rounded-full ${props.className}`}
className={`cursor-pointer ${bgColor}-50 hover:${bgColor}-200 mr-2 ml-2 p-1 h-7 pl-2 pr-2 rounded-full ${props.className}`}
onClick={() => {
props.onClick && props.onClick();
}}

View File

@ -26,17 +26,21 @@ const HeaderAlertGroup: (props: ComponentProps) => ReactElement = (
return <></>;
}
// const className: string = "rounded-lg m-3 h-10 pr-0 pl-0 flex border-2 border-gray-200";
const className: string = "rounded-lg m-3 mt-5 h-10 pr-0 pl-0 flex"
return (
<div className="rounded-lg m-3 h-10 pr-0 pl-0 flex border-2 border-gray-200">
<div className={className}>
{children.map((child: ReactElement | false, index: number) => {
const isLastElement: boolean = index === props.children.length - 1;
// const isLastElement: boolean = index === props.children.length - 1;
return (
<div key={index} className="p-3 flex">
<div key={index} className="flex">
{child}
{!isLastElement && (
{/* {!isLastElement && (
<div className="border-r-2 border-gray-200"></div>
)}
)} */}
</div>
);
})}

View File

@ -221,8 +221,8 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
hasAcceptedInvitation: false,
}}
alertType={HeaderAlertType.INFO}
singularName=""
pluralName=""
singularName="Invitation"
pluralName="Invitations"
tooltip="Looks like you have pending project invitations. Please click here to review and accept them."
requestOptions={{
isMultiTenantRequest: true,
@ -242,8 +242,8 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
},
}}
refreshToggle={activeIncidentToggleRefresh}
singularName=""
pluralName=""
singularName="Incident"
pluralName="Incidents"
tooltip="View all active incidents"
requestOptions={{
isMultiTenantRequest: true,
@ -263,8 +263,8 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
},
}}
refreshToggle={activeAlertToggleRefresh}
singularName=""
pluralName=""
singularName="Alert"
pluralName="Alerts"
tooltip="View all active alerts"
onClick={() => {
Navigation.navigate(RouteMap[PageMap.ALERTS]!);

View File

@ -132,6 +132,22 @@ const Settings: FunctionComponent<PageComponentProps> = (): ReactElement => {
return (
<Fragment>
<div>
{getModelTable({
eventOptions: [
NotificationSettingEventType.SEND_ALERT_NOTE_POSTED_OWNER_NOTIFICATION,
NotificationSettingEventType.SEND_ALERT_OWNER_ADDED_NOTIFICATION,
NotificationSettingEventType.SEND_ALERT_CREATED_OWNER_NOTIFICATION,
NotificationSettingEventType.SEND_ALERT_STATE_CHANGED_OWNER_NOTIFICATION,
],
title: "Alert Notifications",
description:
"Here are the list of notification methods we will use when an event happens on an alert.",
})}
</div>
<div>
{getModelTable({
eventOptions: [
@ -146,6 +162,20 @@ const Settings: FunctionComponent<PageComponentProps> = (): ReactElement => {
})}
</div>
<div>
{getModelTable({
eventOptions: [
NotificationSettingEventType.SEND_INCIDENT_NOTE_POSTED_OWNER_NOTIFICATION,
NotificationSettingEventType.SEND_INCIDENT_OWNER_ADDED_NOTIFICATION,
NotificationSettingEventType.SEND_INCIDENT_CREATED_OWNER_NOTIFICATION,
NotificationSettingEventType.SEND_INCIDENT_STATE_CHANGED_OWNER_NOTIFICATION,
],
title: "Alert Notifications",
description:
"Here are the list of notification methods we will use when an event happens on an incident.",
})}
</div>
<div>
{getModelTable({
eventOptions: [

View File

@ -36,6 +36,7 @@ import DeleteOldTelemetryTable from "./DeleteOldTelelmetryTable";
import MoveTelemetryServiceTokenToTelemetryIngestionKey from "./MoveTelemetryServiceTokenToTelemetryIngestionKey";
import AddDefaultCopilotActionTypes from "./AddDefaultCopilotActionTypes";
import AddDefaultAlertSeverityAndStateToExistingProjects from "./AddDefaultAlertSeverityAndStateToExistingProjects";
import RefreshDefaultUserNotificationSetting from "./RefreshUserNotificationSetting";
// This is the order in which the migrations will be run. Add new migrations to the end of the array.
@ -77,6 +78,7 @@ const DataMigrations: Array<DataMigrationBase> = [
new MoveTelemetryServiceTokenToTelemetryIngestionKey(),
new AddDefaultCopilotActionTypes(),
new AddDefaultAlertSeverityAndStateToExistingProjects(),
new RefreshDefaultUserNotificationSetting()
];
export default DataMigrations;

View File

@ -0,0 +1,60 @@
import DataMigrationBase from "./DataMigrationBase";
import LIMIT_MAX from "Common/Types/Database/LimitMax";
import TeamMemberService from "Common/Server/Services/TeamMemberService";
import UserNotificationSettingService from "Common/Server/Services/UserNotificationSettingService";
import UserService from "Common/Server/Services/UserService";
import TeamMember from "Common/Models/DatabaseModels/TeamMember";
import User from "Common/Models/DatabaseModels/User";
export default class RefreshDefaultUserNotificationSetting extends DataMigrationBase {
public constructor() {
super("RefreshDefaultUserNotificationSetting");
}
public override async migrate(): Promise<void> {
// get all the users with email isVerified true.
const users: Array<User> = await UserService.findBy({
query: {
isEmailVerified: true,
},
select: {
email: true,
},
skip: 0,
limit: LIMIT_MAX,
props: {
isRoot: true,
},
});
for (const user of users) {
// then get all the projects the user belongs to.
const teamMembers: Array<TeamMember> = await TeamMemberService.findBy({
query: {
userId: user.id!,
hasAcceptedInvitation: true,
},
select: {
projectId: true,
},
limit: LIMIT_MAX,
skip: 0,
props: {
isRoot: true,
},
});
for (const teamMember of teamMembers) {
await UserNotificationSettingService.addDefaultNotificationSettingsForUser(
user.id!,
teamMember.projectId!,
);
}
}
}
public override async rollback(): Promise<void> {
return;
}
}

View File

@ -173,7 +173,7 @@ RunCron(
smsMessage: sms,
callRequestMessage: callMessage,
eventType:
NotificationSettingEventType.SEND_INCIDENT_CREATED_OWNER_NOTIFICATION,
NotificationSettingEventType.SEND_ALERT_CREATED_OWNER_NOTIFICATION,
});
} catch (e) {
logger.error("Error in sending alert created resource notification");

View File

@ -166,7 +166,7 @@ RunCron(
smsMessage: sms,
callRequestMessage: callMessage,
eventType:
NotificationSettingEventType.SEND_INCIDENT_NOTE_POSTED_OWNER_NOTIFICATION,
NotificationSettingEventType.SEND_ALERT_NOTE_POSTED_OWNER_NOTIFICATION,
});
}
}

View File

@ -201,7 +201,7 @@ RunCron(
smsMessage: sms,
callRequestMessage: callMessage,
eventType:
NotificationSettingEventType.SEND_INCIDENT_OWNER_ADDED_NOTIFICATION,
NotificationSettingEventType.SEND_ALERT_OWNER_ADDED_NOTIFICATION,
});
}
}

View File

@ -186,7 +186,7 @@ RunCron(
smsMessage: sms,
callRequestMessage: callMessage,
eventType:
NotificationSettingEventType.SEND_INCIDENT_STATE_CHANGED_OWNER_NOTIFICATION,
NotificationSettingEventType.SEND_ALERT_STATE_CHANGED_OWNER_NOTIFICATION,
});
}
}