Compare commits

...

25 Commits

Author SHA1 Message Date
Nawaz Dhandala
91bf55dc20 refactor: simplify logging for previous status duration and improve code formatting 2025-12-04 09:17:31 +00:00
Nawaz Dhandala
d20a125742 refactor: update previous status duration handling in notification template and logging 2025-12-04 09:14:41 +00:00
Nawaz Dhandala
d10bcd2edd refactor: enhance code readability by adding comments for previous status duration calculation 2025-12-04 08:59:04 +00:00
Nawaz Dhandala
0b32408bf2 refactor: update notification template and improve duration calculation logic 2025-12-04 08:58:42 +00:00
Nawaz Dhandala
269fbd3f24 feat: add dep-check script and remove tsconfig-paths from devDependencies 2025-12-04 08:51:40 +00:00
Nawaz Dhandala
2640ea8c10 refactor: streamline previous status duration calculation in notification 2025-12-03 23:21:07 +00:00
Nawaz Dhandala
f3180d3a83 feat: add previous status duration calculation to status change notification 2025-12-03 23:18:35 +00:00
Nawaz Dhandala
7727fe835f refactor: improve parameter destructuring for createIncidentStateChangedNotification method 2025-12-03 23:17:23 +00:00
Nawaz Dhandala
00fbfbc08e chore: bump version to 9.2.4 2025-12-03 23:08:21 +00:00
Nawaz Dhandala
44d1183066 feat: add monitor destination and request type details to notification templates and services 2025-12-03 23:08:04 +00:00
Nawaz Dhandala
0ccef797ab chore: bump version to 9.2.3 2025-12-03 22:44:46 +00:00
Nawaz Dhandala
9914fb905f fix: update background color for previous and current state/status badges to transparent 2025-12-03 22:43:03 +00:00
Nawaz Dhandala
35ecc19ceb fix: update background color for current state/status badge in notification templates 2025-12-03 22:37:01 +00:00
Nawaz Dhandala
fa0362f739 feat: update notification templates to include state transition details for alerts, incidents, monitors, and scheduled maintenance 2025-12-03 22:36:09 +00:00
Nawaz Dhandala
8ea9084d9e feat: enhance notification templates and logic to include previous state information for alerts, incidents, monitors, and scheduled maintenance 2025-12-03 22:25:45 +00:00
Simon Larsen
eeb31a2250 Merge pull request #2154 from OneUptime/email-improve
Email improve
2025-12-03 21:40:46 +00:00
Nawaz Dhandala
b58c91dbab fix: update version number to 9.2.2 2025-12-03 21:40:11 +00:00
Nawaz Dhandala
868bf4d3e1 fix: remove unnecessary empty row from DetailBoxEnd template for improved clarity 2025-12-03 21:37:20 +00:00
Nawaz Dhandala
a3fc20b393 fix: update incident and event title fields for improved clarity in email templates 2025-12-03 21:14:32 +00:00
Nawaz Dhandala
c8dad04b5c fix: add border-radius to logo images for improved aesthetics 2025-12-03 21:10:15 +00:00
Nawaz Dhandala
ee7db393f8 fix: update email templates to remove empty fields for improved clarity 2025-12-03 21:06:09 +00:00
Nawaz Dhandala
e52da9fef2 fix: remove emojis from email titles for consistency 2025-12-03 21:00:19 +00:00
Nawaz Dhandala
9332df5648 Refactor email templates for improved styling and structure
- Updated EmailTitle template to enhance title styling and added a title block comment.
- Adjusted spacing in End and Footer templates for better layout.
- Enhanced Footer template with new styling and added a powered by link.
- Modified InfoBlock template for improved text styling and added an info block comment.
- Refined Start template with new background color and added a top spacer.
- Updated Style template with new link and badge styles for better visual consistency.
- Enhanced SupportBlock template with a more engaging support message.
- Improved Thanks template with a more personalized closing message.
- Added TitleBlock comments for better organization.
- Updated UnsubscribeBlock for clearer subscription management options.
- Replaced VerticalSpace with a table-based spacer for consistent spacing.
- Enhanced SignupWelcomeEmail with improved messaging and button text.
- Updated SubscriberAnnouncementCreated template for better clarity and button integration.
- Refined SubscriberIncidentCreated template for improved incident details presentation.
- Enhanced SubscriberIncidentPostmortemCreated template for better postmortem details.
- Updated SubscriberIncidentStateChanged template for clearer incident state updates.
- Refined SubscriberScheduledMaintenanceEventCreated template for better event details.
- Introduced StatusBadge template for consistent incident status representation.
2025-12-03 20:40:46 +00:00
Nawaz Dhandala
120fc2ad71 fix: change field type for subscriber notification from Toggle to Checkbox 2025-12-03 19:35:49 +00:00
Nawaz Dhandala
1a7672748f fix: update title for status page visibility and add conditional display for subscriber notification 2025-12-03 19:35:07 +00:00
65 changed files with 958 additions and 351 deletions

View File

@@ -13,10 +13,8 @@
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=alertSeverity }}
{{> DetailBoxField title="Root Cause: " text="" }}
{{> DetailBoxField title="" text=rootCause }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=alertDescription }}
{{> DetailBoxField title="Root Cause: " text=rootCause }}
{{> DetailBoxField title="Description: " text=alertDescription }}
{{> DetailBoxEnd this }}

View File

@@ -13,10 +13,8 @@
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="Root Cause: " text="" }}
{{> DetailBoxField title="" text=rootCause }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=incidentDescription }}
{{> DetailBoxField title="Root Cause: " text=rootCause }}
{{> DetailBoxField title="Description: " text=incidentDescription }}
{{> DetailBoxEnd this }}

View File

@@ -13,8 +13,7 @@
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=alertSeverity }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=alertDescription }}
{{> DetailBoxField title="Description: " text=alertDescription }}
{{> DetailBoxEnd this }}

View File

@@ -14,11 +14,10 @@
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=alertSeverity }}
{{#if isPrivateNote}}
{{> DetailBoxField title="Private Note: " text="" }}
{{> DetailBoxField title="Private Note: " text=note }}
{{else}}
{{> DetailBoxField title="Public Note: " text="" }}
{{> DetailBoxField title="Public Note: " text=note }}
{{/if}}
{{> DetailBoxField title="" text=note }}
{{> DetailBoxEnd this }}

View File

@@ -13,16 +13,12 @@
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Alert Declared By: " text=declaredBy }}
{{> DetailBoxField title="Alert Declared At: " text="" }}
{{> DetailBoxField title="" text=declaredAt }}
{{> DetailBoxField title="Alert Declared At: " text=declaredAt }}
{{> DetailBoxField title="Severity: " text=alertSeverity }}
{{> DetailBoxField title="Root Cause: " text="" }}
{{> DetailBoxField title="" text=rootCause }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=alertDescription }}
{{> DetailBoxField title="Root Cause: " text=rootCause }}
{{> DetailBoxField title="Description: " text=alertDescription }}
{{#ifNotCond remediationNotes ""}}
{{> DetailBoxField title="Remediation Notes: " text="" }}
{{> DetailBoxField title="" text=remediationNotes }}
{{> DetailBoxField title="Remediation Notes: " text=remediationNotes }}
{{/ifNotCond}}
{{> DetailBoxEnd this }}

View File

@@ -4,19 +4,17 @@
{{> Logo this}}
{{> EmailTitle title=(concat "Alert: " alertTitle) }}
{{> InfoBlock info=(concat "Alert state changed to - " currentState)}}
{{> InfoBlock info="Alert state has changed"}}
{{> InfoBlock info="Here are the details: "}}
{{> DetailBoxStart this }}
{{> StateTransition this}}
{{> DetailBoxField title="Alert Title:" text=alertTitle }}
{{> DetailBoxField title="New State: " text=currentState }}
{{> DetailBoxField title="State changed at: " text="" }}
{{> DetailBoxField title="" text=stateChangedAt }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=alertSeverity }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=alertDescription }}
{{> DetailBoxField title="State changed at:" text=stateChangedAt }}
{{> DetailBoxField title="Resources Affected:" text=resourcesAffected }}
{{> DetailBoxField title="Severity:" text=alertSeverity }}
{{> DetailBoxField title="Description:" text=alertDescription }}
{{> DetailBoxEnd this }}

View File

@@ -2,15 +2,20 @@
{{> Logo this}}
{{> EmailTitle title="Forgot Password? We're here to help." }}
{{> EmailTitle title="Reset Your Password" }}
{{> InfoBlock info="Please click on the 'Reset your password' button below which will help you reset your password and once you're done, You're good to go!"}}
{{> InfoBlock info="We received a request to reset your password. Click the button below to create a new password for your account."}}
{{> ButtonBlock buttonUrl=tokenVerifyUrl buttonText="Reset your password"}}
{{> ButtonBlock buttonUrl=tokenVerifyUrl buttonText="Reset Password"}}
{{> InfoBlock info="You can also copy and paste this link:"}}
{{> VerticalSpace this}}
{{> InfoBlock info="Or copy and paste this link into your browser:"}}
{{> InfoBlock info=tokenVerifyUrl}}
{{> InfoBlock info="This password reset link expires in 24 hours."}}
{{> VerticalSpace this}}
{{> InfoBlock info="<strong>Note:</strong> This password reset link will expire in 24 hours. If you didn't request this reset, you can safely ignore this email."}}
{{> SupportBlock this }}

View File

@@ -13,8 +13,7 @@
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=incidentDescription }}
{{> DetailBoxField title="Description: " text=incidentDescription }}
{{> DetailBoxEnd this }}

View File

@@ -14,11 +14,10 @@
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{#if isPrivateNote}}
{{> DetailBoxField title="Private Note: " text="" }}
{{> DetailBoxField title="Private Note: " text=note }}
{{else}}
{{> DetailBoxField title="Public Note: " text="" }}
{{> DetailBoxField title="Public Note: " text=note }}
{{/if}}
{{> DetailBoxField title="" text=note }}
{{> DetailBoxEnd this }}

View File

@@ -13,16 +13,12 @@
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Incident Declared By: " text=declaredBy }}
{{> DetailBoxField title="Incident Declared At: " text="" }}
{{> DetailBoxField title="" text=declaredAt }}
{{> DetailBoxField title="Incident Declared At: " text=declaredAt }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="Root Cause: " text="" }}
{{> DetailBoxField title="" text=rootCause }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=incidentDescription }}
{{> DetailBoxField title="Root Cause: " text=rootCause }}
{{> DetailBoxField title="Description: " text=incidentDescription }}
{{#ifNotCond remediationNotes ""}}
{{> DetailBoxField title="Remediation Notes: " text="" }}
{{> DetailBoxField title="" text=remediationNotes }}
{{> DetailBoxField title="Remediation Notes: " text=remediationNotes }}
{{/ifNotCond}}
{{> DetailBoxEnd this }}

View File

@@ -4,19 +4,17 @@
{{> Logo this}}
{{> EmailTitle title=(concat "Incident: " incidentTitle) }}
{{> InfoBlock info=(concat "Incident state changed to - " currentState)}}
{{> InfoBlock info="Incident state has changed"}}
{{> InfoBlock info="Here are the details: "}}
{{> DetailBoxStart this }}
{{> StateTransition this}}
{{> DetailBoxField title="Incident Title:" text=incidentTitle }}
{{> DetailBoxField title="New State: " text=currentState }}
{{> DetailBoxField title="State changed at: " text="" }}
{{> DetailBoxField title="" text=stateChangedAt }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=incidentDescription }}
{{> DetailBoxField title="State changed at:" text=stateChangedAt }}
{{> DetailBoxField title="Resources Affected:" text=resourcesAffected }}
{{> DetailBoxField title="Severity:" text=incidentSeverity }}
{{> DetailBoxField title="Description:" text=incidentDescription }}
{{> DetailBoxEnd this }}

View File

@@ -2,28 +2,33 @@
{{> Logo this}}
{{> EmailTitle title=(concat "You have been invited to " projectName) }}
{{> EmailTitle title=(concat "👋 You're Invited to " projectName) }}
{{#ifCond isNewUser "true"}}
{{> InfoBlock info="Please sign up to a new account to accept this invitation"}}
{{> InfoBlock info="You've been invited to join a project on OneUptime. Create your account to get started."}}
{{> ButtonBlock buttonUrl=registerLink buttonText="Sign up to a new account"}}
{{> ButtonBlock buttonUrl=registerLink buttonText="Create Your Account"}}
{{> InfoBlock info="You can also copy and paste this link:"}}
{{> VerticalSpace this}}
{{> InfoBlock info="Or copy and paste this link into your browser:"}}
{{> InfoBlock info=registerLink}}
{{/ifCond}}
{{#ifCond isNewUser "false"}}
{{> InfoBlock info="Please sign in to your account to see all your invitations and manage them."}}
{{> InfoBlock info="You've been invited to join a project on OneUptime. Sign in to view and manage your invitations."}}
{{> ButtonBlock buttonUrl=signInLink buttonText="Sign in to OneUptime"}}
{{> ButtonBlock buttonUrl=signInLink buttonText="Sign In to OneUptime"}}
{{> InfoBlock info="You can also copy and paste this link:"}}
{{> VerticalSpace this}}
{{> InfoBlock info="Or copy and paste this link into your browser:"}}
{{> InfoBlock info=signInLink}}
{{/ifCond}}
{{> VerticalSpace this}}
{{> InfoBlock info="If you have not signed up to OneUptime so far. You'll be redirected to the account sign up page to sign up first."}}
{{> InfoBlock info="<em>If you don't have an account yet, you'll be redirected to create one first.</em>"}}
{{> SupportBlock this }}

View File

@@ -10,9 +10,15 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title="Monitor Name:" text=monitorName }}
{{#ifNotCond monitorDestination ""}}
{{#ifCond monitorType "API"}}
{{> DetailBoxField title="Monitor URL:" text=(concat requestType " " monitorDestination) }}
{{else}}
{{> DetailBoxField title="Monitor Destination:" text=monitorDestination }}
{{/ifCond}}
{{/ifNotCond}}
{{> DetailBoxField title="Current Status: " text=currentStatus }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=monitorDescription }}
{{> DetailBoxField title="Description: " text=monitorDescription }}
{{> DetailBoxEnd this }}

View File

@@ -10,9 +10,15 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title="Monitor Name:" text=monitorName }}
{{#ifNotCond monitorDestination ""}}
{{#ifCond monitorType "API"}}
{{> DetailBoxField title="Monitor URL:" text=(concat requestType " " monitorDestination) }}
{{else}}
{{> DetailBoxField title="Monitor Destination:" text=monitorDestination }}
{{/ifCond}}
{{/ifNotCond}}
{{> DetailBoxField title="Current Status: " text=currentStatus }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=monitorDescription }}
{{> DetailBoxField title="Description: " text=monitorDescription }}
{{> DetailBoxEnd this }}

View File

@@ -4,21 +4,28 @@
{{> Logo this}}
{{> EmailTitle title=(concat "Monitor: " monitorName) }}
{{> InfoBlock info=(concat "Monitor status changed to - " currentStatus)}}
{{> InfoBlock info="Monitor status has changed"}}
{{> InfoBlock info="Here are the details: "}}
{{> DetailBoxStart this }}
{{> DetailBoxField title="Monitor Name:" text=monitorName }}
{{> DetailBoxField title="New Status: " text=currentStatus }}
{{#ifNotCond rootCause ""}}
{{> DetailBoxField title="Root Cause: " text="" }}
{{> DetailBoxField title="" text=rootCause }}
{{> StatusTransition this}}
{{#ifNotCond previousStatusDurationText ""}}
{{> DetailBoxField title="Duration in Previous Status:" text=previousStatusDurationText }}
{{/ifNotCond}}
{{> DetailBoxField title="Status changed at: " text="" }}
{{> DetailBoxField title="" text=statusChangedAt }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=monitorDescription }}
{{> DetailBoxField title="Monitor Name:" text=monitorName }}
{{#ifNotCond monitorDestination ""}}
{{#ifCond monitorType "API"}}
{{> DetailBoxField title="Monitor URL:" text=(concat requestType " " monitorDestination) }}
{{else}}
{{> DetailBoxField title="Monitor Destination:" text=monitorDestination }}
{{/ifCond}}
{{/ifNotCond}}
{{#ifNotCond rootCause ""}}
{{> DetailBoxField title="Root Cause:" text=rootCause }}
{{/ifNotCond}}
{{> DetailBoxField title="Status changed at:" text=statusChangedAt }}
{{> DetailBoxField title="Description:" text=monitorDescription }}
{{> DetailBoxEnd this }}

View File

@@ -8,8 +8,14 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title="Monitor Name:" text=monitorName }}
{{> DetailBoxField title="Monitor Description: " text="" }}
{{> DetailBoxField title="" text=monitorDescription }}
{{#ifNotCond monitorDestination ""}}
{{#ifCond monitorType "API"}}
{{> DetailBoxField title="Monitor URL:" text=(concat requestType " " monitorDestination) }}
{{else}}
{{> DetailBoxField title="Monitor Destination:" text=monitorDestination }}
{{/ifCond}}
{{/ifNotCond}}
{{> DetailBoxField title="Monitor Description: " text=monitorDescription }}
{{> DetailBoxField title="Probe Status: " text=currentStatus }}
{{> DetailBoxEnd this }}

View File

@@ -1,3 +1,4 @@
<!-- Primary Action Button -->
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
@@ -8,26 +9,26 @@
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td class="st-Font st-Font--body"
style="border: 0; margin: 0; padding: 0; color: #000000; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
style="border: 0; margin: 0; padding: 0; color: #1a1a2e; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
<!-- Button & Modifier: fullWidth -->
<!-- Button & Modifier: fullWidth with gradient -->
<table class="st-Button st-Button--fullWidth" border="0" cellpadding="0" cellspacing="0"
width="100%">
<tbody>
<tr>
<td align="center" class="st-Button-area" height="38" valign="middle"
style="border: 0; margin: 0; padding: 0; background-color: #000000; border-radius: 5px; text-align: center;">
<td align="center" class="st-Button-area" height="48" valign="middle"
style="border: 0; margin: 0; padding: 0; background: linear-gradient(135deg, #1a1a2e 0%, #000000 100%); border-radius: 8px; text-align: center; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);">
<a class="st-Button-link"
style="border: 0; margin: 0; padding: 0; color: #ffffff; display: block; height: 38px; text-align: center; text-decoration: none;"
style="border: 0; margin: 0; padding: 0; color: #ffffff; display: block; height: 48px; text-align: center; text-decoration: none;"
href={{buttonUrl}}>
<span class="st-Button-internal"
style="border: 0; margin: 0; padding: 0; color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; font-weight: bold; height: 38px; line-height: 38px; mso-line-height-rule: exactly; text-decoration: none; vertical-align: middle; white-space: nowrap; width: 100%;">{{buttonText}}</span>
style="border: 0; margin: 0; padding: 0; color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 15px; font-weight: 600; height: 48px; line-height: 48px; mso-line-height-rule: exactly; text-decoration: none; vertical-align: middle; white-space: nowrap; width: 100%; letter-spacing: 0.3px;">{{buttonText}}</span>
</a>
</td>
</tr>
</tbody>
</table>
<!-- /Button & Modifier: fullWidth -->
<!-- /Button & Modifier: fullWidth with gradient -->
</td>
<td class="st-Spacer st-Spacer--gutter"
@@ -37,10 +38,11 @@
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="16"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
</tbody>
</table>
</table>
<!-- /Primary Action Button -->

View File

@@ -19,7 +19,7 @@
<a style="border: 0; margin: 0; padding: 0; text-decoration: none;" href={{homeURL}}>
<img alt="OneUptime" height="70" border="0"
style="height:70px; border: 0; margin: 0; padding: 0; color: #000000; display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; font-weight: normal;"
style="height:70px; border: 0; margin: 0; padding: 0; color: #000000; display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; font-weight: normal; border-radius: 10%;"
src="{{logoUrl}}">
</a>
</div>

View File

@@ -1,4 +1,4 @@
<!-- End Detail Card Field Container -->
</td>
</tr>
</tbody>
@@ -10,4 +10,5 @@
</td>
</tr>
</tbody>
</table>
</table>
<!-- /Detail Card Container -->

View File

@@ -1,7 +1,9 @@
<p style="Margin:0;font-size:16px;font-family:'inter','helvetica neue',helvetica,arial,sans-serif;line-height:30px;color:#424761">
<!-- Detail Card Field -->
<div class="st-DetailCard-field" style="padding: 10px 0; border-bottom: 1px solid #e2e8f0;">
{{#if title}}
<strong>{{{title}}} </strong>{{{text}}} </span>
{{else}}
{{{text}}}
<p class="st-DetailCard-label" style="Margin:0 0 4px 0;font-size:11px;font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;line-height:16px;color:#64748b;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;">{{{title}}}</p>
{{/if}}
</p>
{{#if text}}
<p class="st-DetailCard-value" style="Margin:0;font-size:15px;font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;line-height:24px;color:#1e293b;font-weight:500;">{{{text}}}</p>
{{/if}}
</div>

View File

@@ -1,19 +1,20 @@
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="500" style="min-width: 500px;margin: 10px 50px;">
<!-- Detail Card Container -->
<table class="st-Copy st-Width st-Width--mobile st-DetailCard" border="0" cellpadding="0" cellspacing="0"
width="472" style="min-width: 472px; margin: 16px 64px; border-radius: 12px; overflow: hidden;">
<tbody>
<tr style="border-collapse:collapse">
<td width="720" align="center" valign="top" style="padding:0;Margin:0"></td>
<td width="100%" align="center" valign="top" style="padding:0;Margin:0"></td>
</tr>
<tr style="border-collapse:collapse">
<td align="left"
style="padding:0;Margin:0;padding-top:0px;padding-left:40px;padding-right:40px;padding-bottom:30px;background-color:#f7f8fa;border-radius: 5px">
style="padding:0;Margin:0;padding-top:0px;padding-left:0;padding-right:0;padding-bottom:0;background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);border-radius: 12px; border: 1px solid #e2e8f0; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);">
<table cellpadding="0" cellspacing="0" width="100%"
style="border-collapse:collapse;border-spacing:0px">
<tbody>
<tr style="border-collapse:collapse">
<td width="720" align="center" valign="top" style="padding:0;Margin:0">
<td width="100%" align="center" valign="top" style="padding:0;Margin:0">
<table cellpadding="0" cellspacing="0" width="100%" role="presentation"
style="border-collapse:collapse;border-spacing:0px">
<tbody>
<tr style="border-collapse:collapse">
<td align="left" style="padding:0;Margin:0;padding-top:30px">
<td align="left" style="padding:24px 28px 0 28px;Margin:0;">

View File

@@ -1,3 +1,4 @@
<!-- Email Title Block -->
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
@@ -7,10 +8,10 @@
width="64">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td class="st-Font st-Font--body"
style="color: #000000 !important; border:0;margin:0;padding:0; font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Ubuntu,sans-serif;font-size:16px;line-height:24px">
<td class="st-Font st-Font--title"
style="color: #1a1a2e !important; border:0;margin:0;padding:0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;font-size:24px;line-height:32px;font-weight:700;">
<h3>{{title}}</h3>
<h2 style="margin: 0; padding: 0; font-size: 24px; line-height: 32px; font-weight: 700; color: #1a1a2e;">{{title}}</h2>
</td>
<td class="st-Spacer st-Spacer--gutter"
@@ -20,10 +21,11 @@
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="16"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
</tbody>
</table>
</table>
<!-- /Email Title Block -->

View File

@@ -7,7 +7,7 @@
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--emailEnd" height="64"
<td class="st-Spacer st-Spacer--emailEnd" height="48"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler">&nbsp;</div>
</td>

View File

@@ -1,8 +1,9 @@
<!-- Footer Block -->
<table class="st-Footer st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
<tr>
<td class="st-Spacer st-Spacer--divider" colspan="3" height="20"
<td class="st-Spacer st-Spacer--divider" colspan="3" height="24"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
@@ -13,7 +14,7 @@
width="64">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td bgcolor="#fdfdfd" colspan="2" height="1"
<td bgcolor="#e5e7eb" colspan="2" height="1"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
@@ -24,7 +25,7 @@
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--divider" colspan="3" height="31"
<td class="st-Spacer st-Spacer--divider" colspan="3" height="24"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
@@ -36,10 +37,10 @@
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td class="st-Font st-Font--caption"
style="border: 0; margin: 0;padding: 0; color: #8898aa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; line-height: 16px;">
style="border: 0; margin: 0;padding: 0; color: #6b7280; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 13px; line-height: 18px; text-align: center;">
<span class="st-Delink st-Delink--footer"
style="border: 0; margin: 0; padding: 0; color: #8898aa; text-decoration: none;">
© {{year}} OneUptime
style="border: 0; margin: 0; padding: 0; color: #6b7280; text-decoration: none;">
© {{year}} OneUptime · Powered by <a href="https://oneuptime.com" style="color: #1a1a2e; text-decoration: none; font-weight: 500;">OneUptime</a>
</span>
</td>
<td class="st-Spacer st-Spacer--gutter"
@@ -49,10 +50,11 @@
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--emailEnd" colspan="3" height="64"
<td class="st-Spacer st-Spacer--emailEnd" colspan="3" height="48"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
</tbody>
</table>
</table>
<!-- /Footer Block -->

View File

@@ -1,4 +1,4 @@
<!-- Info Block -->
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
@@ -9,7 +9,7 @@
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td class="st-Font st-Font--body"
style="border: 0; margin: 0; padding: 0; color: #000000 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
style="border: 0; margin: 0; padding: 0; color: #374151 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 15px; line-height: 26px;">
{{{info}}}
</td>
<td class="st-Spacer st-Spacer--gutter"
@@ -19,12 +19,11 @@
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="14"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
</tbody>
</table>
<!-- /Info Block -->

View File

@@ -18,7 +18,7 @@
<a style="border: 0; margin: 0; padding: 0; text-decoration: none;" href={{homeURL}}>
<img height="70" width="70" alt="OneUptime" border="0"
style="height:70px; width:70px; border: 0; margin: 0; padding: 0; color: #000000; display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; font-weight: normal;"
style="height:70px; width:70px; border: 0; margin: 0; padding: 0; color: #000000; display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; font-weight: normal; border-radius: 10%;"
src="https://res.cloudinary.com/deityhub/image/upload/v1637736803/1png.png">
</a>
</div>

View File

@@ -5,21 +5,33 @@
{{> Header}}
<body class="st-Email" bgcolor="f7f7f7"
<body class="st-Email" bgcolor="f3f4f6"
style="border: 0; margin: 0; padding: 0; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; min-width: 100%; width: 100%;"
override="fix">
<!-- Background -->
<table class="st-Background" bgcolor="f7f7f7" border="0" cellpadding="0" cellspacing="0" width="100%"
<table class="st-Background" bgcolor="f3f4f6" border="0" cellpadding="0" cellspacing="0" width="100%"
style="border: 0; margin: 0; padding: 0;">
<tbody>
<tr>
<td style="border: 0; margin: 0; padding: 0;">
<!-- Top Spacer -->
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600" style="min-width: 600px;">
<tbody>
<tr>
<td height="32" style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px;">
<div>&nbsp;</div>
</td>
</tr>
</tbody>
</table>
<!-- /Top Spacer -->
<!-- Wrapper -->
<table class="st-Wrapper" align="center" bgcolor="ffffff" border="0" cellpadding="0" cellspacing="0"
width="600"
style="border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; margin: 0 auto; min-width: 600px;">
style="border-radius: 12px; margin: 0 auto; min-width: 600px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03); border-top: 4px solid #1a1a2e;">
<tbody>
<tr>
<td style="border: 0; margin: 0; padding: 0;">

View File

@@ -0,0 +1,29 @@
<!-- State Transition Block - Inline version for DetailBox -->
<div class="st-DetailCard-field" style="padding: 16px 0; border-bottom: 1px solid #e2e8f0;">
<p class="st-DetailCard-label" style="Margin:0 0 12px 0;font-size:11px;font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;line-height:16px;color:#64748b;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;">STATE CHANGE</p>
<table cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse;">
<tbody>
<tr>
{{#if previousState}}
<!-- Previous State Badge -->
<td align="center" valign="middle" style="padding: 0;">
<span style="display: inline-block; padding: 6px 14px; border-radius: 6px; font-size: 13px; font-weight: 600; background-color: transparent; color: {{previousStateColor}}; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{previousState}}
</span>
</td>
<!-- Arrow -->
<td align="center" valign="middle" style="padding: 0 12px;">
<span style="font-size: 20px; color: #94a3b8; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">→</span>
</td>
{{/if}}
<!-- Current State Badge -->
<td align="center" valign="middle" style="padding: 0;">
<span style="display: inline-block; padding: 6px 14px; border-radius: 6px; font-size: 13px; font-weight: 600; background-color: transparent; color: {{currentStateColor}}; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{currentState}}
</span>
</td>
</tr>
</tbody>
</table>
</div>
<!-- /State Transition Block -->

View File

@@ -0,0 +1,58 @@
<!-- Status Badge - Used for incident states, severity levels, etc. -->
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
<tr>
<td class="st-Spacer st-Spacer--gutter"
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
width="64">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td style="border: 0; margin: 0; padding: 0;">
{{#ifCond badgeType "critical"}}
<span class="st-Badge st-Badge--critical" style="display: inline-block; padding: 6px 14px; border-radius: 9999px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; background-color: #fef2f2; color: #dc2626; border: 1px solid #fecaca; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{badgeText}}
</span>
{{/ifCond}}
{{#ifCond badgeType "warning"}}
<span class="st-Badge st-Badge--warning" style="display: inline-block; padding: 6px 14px; border-radius: 9999px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; background-color: #fffbeb; color: #d97706; border: 1px solid #fde68a; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{badgeText}}
</span>
{{/ifCond}}
{{#ifCond badgeType "success"}}
<span class="st-Badge st-Badge--success" style="display: inline-block; padding: 6px 14px; border-radius: 9999px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; background-color: #f0fdf4; color: #16a34a; border: 1px solid #bbf7d0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{badgeText}}
</span>
{{/ifCond}}
{{#ifCond badgeType "info"}}
<span class="st-Badge st-Badge--info" style="display: inline-block; padding: 6px 14px; border-radius: 9999px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; background-color: #eff6ff; color: #2563eb; border: 1px solid #bfdbfe; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{badgeText}}
</span>
{{/ifCond}}
{{#ifCond badgeType "neutral"}}
<span class="st-Badge st-Badge--neutral" style="display: inline-block; padding: 6px 14px; border-radius: 9999px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; background-color: #f3f4f6; color: #4b5563; border: 1px solid #d1d5db; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{badgeText}}
</span>
{{/ifCond}}
</td>
<td class="st-Spacer st-Spacer--gutter"
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
width="64">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
</tbody>
</table>
<!-- /Status Badge -->

View File

@@ -0,0 +1,29 @@
<!-- Status Transition Block - Inline version for DetailBox -->
<div class="st-DetailCard-field" style="padding: 16px 0; border-bottom: 1px solid #e2e8f0;">
<p class="st-DetailCard-label" style="Margin:0 0 12px 0;font-size:11px;font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;line-height:16px;color:#64748b;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;">STATUS CHANGE</p>
<table cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse;">
<tbody>
<tr>
{{#if previousStatus}}
<!-- Previous Status Badge -->
<td align="center" valign="middle" style="padding: 0;">
<span style="display: inline-block; padding: 6px 14px; border-radius: 6px; font-size: 13px; font-weight: 600; background-color: transparent; color: {{previousStatusColor}}; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{previousStatus}}
</span>
</td>
<!-- Arrow -->
<td align="center" valign="middle" style="padding: 0 12px;">
<span style="font-size: 20px; color: #94a3b8; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">→</span>
</td>
{{/if}}
<!-- Current Status Badge -->
<td align="center" valign="middle" style="padding: 0;">
<span style="display: inline-block; padding: 6px 14px; border-radius: 6px; font-size: 13px; font-weight: 600; background-color: transparent; color: {{currentStatusColor}}; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;">
{{currentStatus}}
</span>
</td>
</tr>
</tbody>
</table>
</div>
<!-- /Status Transition Block -->

View File

@@ -52,7 +52,7 @@
**/
span.st-Delink a {
color: #000000 !important;
color: #1a1a2e !important;
text-decoration: none !important;
}
@@ -66,7 +66,7 @@
/** Modifier: title */
span.st-Delink.st-Delink--title a {
color: #000000 !important;
color: #1a1a2e !important;
text-decoration: none !important;
}
@@ -74,14 +74,111 @@
/** Modifier: footer */
span.st-Delink.st-Delink--footer a {
color: #8898aa !important;
color: #6b7280 !important;
text-decoration: none !important;
}
/** */
.ii a[href] {
color: #000000;
color: #1a1a2e;
}
/**
* # Links
* - Styled links with modern colors
**/
a.st-Link {
color: #1a1a2e !important;
text-decoration: none !important;
transition: color 0.2s ease !important;
}
a.st-Link:hover {
color: #000000 !important;
text-decoration: underline !important;
}
/**
* # Status Badges
* - Colored badges for incident/alert states
**/
.st-Badge {
display: inline-block !important;
padding: 4px 12px !important;
border-radius: 9999px !important;
font-size: 12px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
}
.st-Badge--critical {
background-color: #fef2f2 !important;
color: #dc2626 !important;
border: 1px solid #fecaca !important;
}
.st-Badge--warning {
background-color: #fffbeb !important;
color: #d97706 !important;
border: 1px solid #fde68a !important;
}
.st-Badge--success {
background-color: #f0fdf4 !important;
color: #16a34a !important;
border: 1px solid #bbf7d0 !important;
}
.st-Badge--info {
background-color: #f3f4f6 !important;
color: #1a1a2e !important;
border: 1px solid #d1d5db !important;
}
.st-Badge--neutral {
background-color: #f3f4f6 !important;
color: #4b5563 !important;
border: 1px solid #d1d5db !important;
}
/**
* # Detail Cards
* - Modern card styling for detail boxes
**/
.st-DetailCard {
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%) !important;
border: 1px solid #e2e8f0 !important;
border-radius: 12px !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
}
.st-DetailCard-field {
padding: 12px 0 !important;
border-bottom: 1px solid #e2e8f0 !important;
}
.st-DetailCard-field:last-child {
border-bottom: none !important;
}
.st-DetailCard-label {
color: #64748b !important;
font-size: 12px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
margin-bottom: 4px !important;
}
.st-DetailCard-value {
color: #1e293b !important;
font-size: 15px !important;
font-weight: 500 !important;
}
/**
@@ -107,7 +204,7 @@
/** Modifier: gutter */
body[override] td.st-Spacer.st-Spacer--gutter {
width: 32px !important;
width: 24px !important;
}
/** */
@@ -134,8 +231,8 @@
body[override] td.st-Font.st-Font--title,
body[override] td.st-Font.st-Font--title span,
body[override] td.st-Font.st-Font--title a {
font-size: 28px !important;
line-height: 36px !important;
font-size: 26px !important;
line-height: 34px !important;
}
/** */
@@ -144,8 +241,8 @@
body[override] td.st-Font.st-Font--header,
body[override] td.st-Font.st-Font--header span,
body[override] td.st-Font.st-Font--header a {
font-size: 24px !important;
line-height: 32px !important;
font-size: 22px !important;
line-height: 30px !important;
}
/** */
@@ -154,8 +251,8 @@
body[override] td.st-Font.st-Font--body,
body[override] td.st-Font.st-Font--body span,
body[override] td.st-Font.st-Font--body a {
font-size: 18px !important;
line-height: 28px !important;
font-size: 16px !important;
line-height: 26px !important;
}
/** */
@@ -164,8 +261,8 @@
body[override] td.st-Font.st-Font--caption,
body[override] td.st-Font.st-Font--caption span,
body[override] td.st-Font.st-Font--caption a {
font-size: 14px !important;
line-height: 20px !important;
font-size: 13px !important;
line-height: 19px !important;
}
/** */
@@ -185,7 +282,7 @@
body[override] table.st-Divider td.st-Spacer.st-Spacer--gutter,
body[override] tr.st-Divider td.st-Spacer.st-Spacer--gutter {
background-color: #000000;
background-color: #1a1a2e;
}
/**
@@ -212,10 +309,23 @@
body[override] table.st-Button td.st-Button-area,
body[override] table.st-Button td.st-Button-area a.st-Button-link,
body[override] table.st-Button td.st-Button-area span.st-Button-internal {
height: 44px !important;
line-height: 44px !important;
font-size: 18px !important;
height: 48px !important;
line-height: 48px !important;
font-size: 16px !important;
vertical-align: middle !important;
}
/**
* # Detail Cards - Mobile
**/
body[override] .st-DetailCard {
border-radius: 8px !important;
}
body[override] .st-Badge {
font-size: 11px !important;
padding: 3px 10px !important;
}
}
</style>

View File

@@ -1,3 +1,4 @@
{{> InfoBlock info="If you need help. Please do not hesitate to contact OneUptime support team at support@oneuptime.com."}}
<!-- Support Block -->
{{> InfoBlock info="Need help? Contact our support team at <a href='mailto:support@oneuptime.com' style='color: #1a1a2e; text-decoration: none; font-weight: 500;'>support@oneuptime.com</a>"}}
{{> Thanks }}
<!-- /Support Block -->

View File

@@ -1,2 +1,3 @@
{{> InfoBlock info="Thanks, have a great day."}}
{{> InfoBlock info="OneUptime Team."}}
<!-- Thanks Block -->
{{> InfoBlock info="<span style='color: #374151;'>Best regards,</span><br><strong style='color: #1a1a2e;'>The OneUptime Team</strong>"}}
<!-- /Thanks Block -->

View File

@@ -1,4 +1,4 @@
<!-- Title Block -->
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
@@ -9,8 +9,8 @@ width="600" style="min-width: 600px;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td class="st-Font st-Font--body"
style="border: 0; margin: 0; padding: 0; color: #000000 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
<strong>{{{title}}}</strong>
style="border: 0; margin: 0; padding: 0; color: #1a1a2e !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 15px; line-height: 26px;">
<strong style="color: #1a1a2e; font-weight: 600;">{{{title}}}</strong>
</td>
<td class="st-Spacer st-Spacer--gutter"
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
@@ -19,11 +19,11 @@ width="600" style="min-width: 600px;">
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="14"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
</tbody>
</table>
<!-- /Title Block -->

View File

@@ -1,3 +1,4 @@
<!-- Unsubscribe Block -->
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
@@ -7,10 +8,10 @@
width="64">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
<td class="st-Font st-Font--body"
style="border: 0; margin: 0; padding: 0; color: #000000 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; line-height: 20px;">
<td class="st-Font st-Font--caption"
style="border: 0; margin: 0; padding: 0; color: #6b7280 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 13px; line-height: 20px;">
If you wish to change preferences or unsubscribe, please click <a href="{{unsubscribeUrl}}">here.</a>
<span style="color: #6b7280;">Want to change your notification preferences?</span> <a href="{{unsubscribeUrl}}" style="color: #1a1a2e; text-decoration: none; font-weight: 500;">Manage subscription</a>
</td>
<td class="st-Spacer st-Spacer--gutter"
@@ -20,10 +21,11 @@
</td>
</tr>
<tr>
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="14"
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler"></div>
</td>
</tr>
</tbody>
</table>
</table>
<!-- /Unsubscribe Block -->

View File

@@ -1,3 +1,12 @@
<div style="margin-top: 10px; margin-bottom: 10px">
</div>
<!-- Vertical Spacer -->
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
width="600" style="min-width: 600px;">
<tbody>
<tr>
<td height="20" style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
<div class="st-Spacer st-Spacer--filler">&nbsp;</div>
</td>
</tr>
</tbody>
</table>
<!-- /Vertical Spacer -->

View File

@@ -10,8 +10,7 @@
{{> DetailBoxField title="Probe Name:" text=probeName }}
{{> DetailBoxField title="Probe Description:" text=probeDescription }}
{{> DetailBoxField title="Probe Status:" text=probeStatus }}
{{> DetailBoxField title="Status Since:" text="" }}
{{> DetailBoxField title="" text=lastAlive }}
{{> DetailBoxField title="Status Since:" text=lastAlive }}
{{> DetailBoxField title="Project Name: " text=projectName }}
{{> DetailBoxEnd this }}

View File

@@ -11,8 +11,7 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title="Scheduled Maintenance Title:" text=scheduledMaintenanceTitle }}
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=scheduledMaintenanceDescription }}
{{> DetailBoxField title="Description: " text=scheduledMaintenanceDescription }}
{{> DetailBoxEnd this }}

View File

@@ -12,11 +12,10 @@
{{> DetailBoxField title="Scheduled Maintenance Title:" text=scheduledMaintenanceTitle }}
{{> DetailBoxField title="Current State: " text=currentState }}
{{#if isPrivateNote}}
{{> DetailBoxField title="Private Note: " text="" }}
{{> DetailBoxField title="Private Note: " text=note }}
{{else}}
{{> DetailBoxField title="Public Note: " text="" }}
{{> DetailBoxField title="Public Note: " text=note }}
{{/if}}
{{> DetailBoxField title="" text=note }}
{{> DetailBoxEnd this }}

View File

@@ -11,8 +11,7 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title="Scheduled Maintenance Title:" text=scheduledMaintenanceTitle }}
{{> DetailBoxField title="Current State: " text=currentState }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=scheduledMaintenanceDescription }}
{{> DetailBoxField title="Description: " text=scheduledMaintenanceDescription }}
{{> DetailBoxEnd this }}

View File

@@ -4,17 +4,15 @@
{{> Logo this}}
{{> EmailTitle title=(concat "Scheduled Maintenance: " scheduledMaintenanceTitle) }}
{{> InfoBlock info=(concat "Scheduled Maintenance status changed to - " currentState)}}
{{> InfoBlock info="Scheduled Maintenance state has changed"}}
{{> InfoBlock info="Here are the details: "}}
{{> DetailBoxStart this }}
{{> StateTransition this}}
{{> DetailBoxField title="Scheduled Maintenance Title:" text=scheduledMaintenanceTitle }}
{{> DetailBoxField title="New State: " text=currentState }}
{{> DetailBoxField title="State changed at: " text="" }}
{{> DetailBoxField title="" text=stateChangedAt }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=scheduledMaintenanceDescription }}
{{> DetailBoxField title="State changed at:" text=stateChangedAt }}
{{> DetailBoxField title="Description:" text=scheduledMaintenanceDescription }}
{{> DetailBoxEnd this }}

View File

@@ -1,14 +1,20 @@
{{> Start this}}
{{> Logo this}}
{{> EmailTitle title="Welcome to OneUptime. Please verify your email." }}
{{> InfoBlock info="Thank you for signing up. Next step would be to verify your email account. Can you please click on 'Verify Email' button which will help us to get your email verified. "}}
{{> ButtonBlock buttonUrl=tokenVerifyUrl buttonText="Verify Email"}}
{{> EmailTitle title="🎉 Welcome to OneUptime!" }}
{{> InfoBlock info="You can also copy and paste this link:"}}
{{> InfoBlock info="Thank you for signing up! To get started, please verify your email address by clicking the button below."}}
{{> ButtonBlock buttonUrl=tokenVerifyUrl buttonText="Verify Email Address"}}
{{> VerticalSpace this}}
{{> InfoBlock info="Or copy and paste this link into your browser:"}}
{{> InfoBlock info=tokenVerifyUrl}}
{{> VerticalSpace this}}
{{> SupportBlock this }}
{{> Footer this}}

View File

@@ -10,8 +10,7 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title="Status Page Name:" text=statusPageName }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=statusPageDescription }}
{{> DetailBoxField title="Description: " text=statusPageDescription }}
{{> DetailBoxEnd this }}

View File

@@ -6,8 +6,7 @@
{{> InfoBlock info=(concat "A new announcement has been created for : " statusPageName) }}
{{> DetailBoxStart this }}
{{> DetailBoxField title=announcementTitle text="" }}
{{> DetailBoxField title="" text=announcementDescription }}
{{> DetailBoxField title=announcementTitle text=announcementDescription }}
{{> DetailBoxEnd this }}

View File

@@ -10,8 +10,7 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title="Status Page Name:" text=statusPageName }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=statusPageDescription }}
{{> DetailBoxField title="Description: " text=statusPageDescription }}
{{> DetailBoxEnd this }}

View File

@@ -1,26 +1,32 @@
{{> Start this}}
{{> CustomLogo this}}
{{> EmailTitle title=(concat "Announcement: " announcementTitle) }}
{{> InfoBlock info=(concat "A new announcement has been created for : " statusPageName) }}
{{> EmailTitle title=(concat "📢 Announcement: " announcementTitle) }}
{{> InfoBlock info=(concat "A new announcement has been posted for " statusPageName ".") }}
{{> DetailBoxStart this }}
{{> DetailBoxField title=announcementTitle text="" }}
{{> DetailBoxField title="" text=announcementDescription }}
{{> DetailBoxField title="Announcement" text=announcementTitle }}
{{#if announcementDescription}}
{{> DetailBoxField title="Details" text=announcementDescription }}
{{/if}}
{{> DetailBoxEnd this }}
{{> InfoBlock info=(concat subscriberEmailNotificationFooterText "") }}
{{#if detailsUrl}}
{{> InfoBlock info=(concat "Find further information here: " detailsUrl)}}
{{> ButtonBlock buttonUrl=detailsUrl buttonText="View Announcement"}}
{{else}}
{{> InfoBlock info=(concat "Find further information here: " statusPageUrl)}}
{{> ButtonBlock buttonUrl=statusPageUrl buttonText="View Status Page"}}
{{/if}}
{{> VerticalSpace this}}
{{#if subscriberEmailNotificationFooterText}}
{{> InfoBlock info=subscriberEmailNotificationFooterText }}
{{/if}}
{{> UnsubscribeBlock this}}
{{> VerticalSpace this}}
{{> Footer this}}
{{> End this}}

View File

@@ -1,35 +1,34 @@
{{> Start this}}
{{> CustomLogo this}}
{{> EmailTitle title=(concat "Incident: " incidentTitle) }}
{{> InfoBlock info="A new incident has been created. Here are the details: "}}
{{> EmailTitle title=(concat "New Incident: " incidentTitle) }}
{{> InfoBlock info="A new incident has been reported that may affect the services you're subscribed to."}}
{{> DetailBoxStart this }}
{{> DetailBoxField title=incidentTitle text="" }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="Description: " text="" }}
{{> DetailBoxField title="" text=incidentDescription }}
{{> DetailBoxField title="Incident" text=incidentTitle }}
{{> DetailBoxField title="Severity" text=incidentSeverity }}
{{> DetailBoxField title="Affected Resources" text=resourcesAffected }}
{{#if incidentDescription}}
{{> DetailBoxField title="Description" text=incidentDescription }}
{{/if}}
{{> DetailBoxEnd this }}
{{> InfoBlock info=(concat subscriberEmailNotificationFooterText "") }}
{{#if detailsUrl}}
{{> InfoBlock info=(concat "Find further information here: " detailsUrl)}}
{{> ButtonBlock buttonUrl=detailsUrl buttonText="View Incident Details"}}
{{else}}
{{> InfoBlock info=(concat "Find further information here: " statusPageUrl)}}
{{> ButtonBlock buttonUrl=statusPageUrl buttonText="View Status Page"}}
{{/if}}
{{> UnsubscribeBlock this}}
{{> VerticalSpace this}}
{{#if subscriberEmailNotificationFooterText}}
{{> InfoBlock info=subscriberEmailNotificationFooterText }}
{{/if}}
{{> UnsubscribeBlock this}}
{{> Footer this}}
{{> End this}}

View File

@@ -6,11 +6,10 @@
{{> InfoBlock info="A new note has been added to the incident. Here are the details: "}}
{{> DetailBoxStart this }}
{{> DetailBoxField title=incidentTitle text="" }}
{{> DetailBoxField title="Incident Title: " text=incidentTitle }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="Note: " text="" }}
{{> DetailBoxField title="" text=note }}
{{> DetailBoxField title="Note: " text=note }}
{{> DetailBoxEnd this }}

View File

@@ -1,35 +1,34 @@
{{> Start this}}
{{> CustomLogo this}}
{{> EmailTitle title=(concat "Postmortem Published: " incidentTitle) }}
{{> InfoBlock info="A postmortem has been published for an incident. Here are the details: "}}
{{> InfoBlock info="A postmortem report has been published for an incident that affected services you're subscribed to."}}
{{> DetailBoxStart this }}
{{> DetailBoxField title=incidentTitle text="" }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="Postmortem: " text="" }}
{{> DetailBoxField title="" text=postmortemNote }}
{{> DetailBoxField title="Incident" text=incidentTitle }}
{{> DetailBoxField title="Severity" text=incidentSeverity }}
{{> DetailBoxField title="Affected Resources" text=resourcesAffected }}
{{#if postmortemNote}}
{{> DetailBoxField title="Postmortem Summary" text=postmortemNote }}
{{/if}}
{{> DetailBoxEnd this }}
{{> InfoBlock info=(concat subscriberEmailNotificationFooterText "") }}
{{#if detailsUrl}}
{{> InfoBlock info=(concat "Find further information here: " detailsUrl)}}
{{> ButtonBlock buttonUrl=detailsUrl buttonText="Read Full Postmortem"}}
{{else}}
{{> InfoBlock info=(concat "Find further information here: " statusPageUrl)}}
{{> ButtonBlock buttonUrl=statusPageUrl buttonText="View Status Page"}}
{{/if}}
{{> UnsubscribeBlock this}}
{{> VerticalSpace this}}
{{#if subscriberEmailNotificationFooterText}}
{{> InfoBlock info=subscriberEmailNotificationFooterText }}
{{/if}}
{{> UnsubscribeBlock this}}
{{> Footer this}}
{{> End this}}

View File

@@ -1,26 +1,32 @@
{{> Start this}}
{{> CustomLogo this}}
{{> EmailTitle title=emailTitle }}
{{> InfoBlock info="Incident state has changed. Here are the details: "}}
{{> InfoBlock info="The status of an incident affecting services you're subscribed to has been updated."}}
{{> DetailBoxStart this }}
{{> DetailBoxField title=incidentTitle text="" }}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Severity: " text=incidentSeverity }}
{{> DetailBoxField title="State: " text=incidentState }}
{{> DetailBoxField title="Incident" text=incidentTitle }}
{{> DetailBoxField title="Current State" text=incidentState }}
{{> DetailBoxField title="Severity" text=incidentSeverity }}
{{> DetailBoxField title="Affected Resources" text=resourcesAffected }}
{{> DetailBoxEnd this }}
{{> InfoBlock info=(concat subscriberEmailNotificationFooterText "") }}
{{#if detailsUrl}}
{{> InfoBlock info=(concat "Find further information here: " detailsUrl)}}
{{> ButtonBlock buttonUrl=detailsUrl buttonText="View Incident Details"}}
{{else}}
{{> InfoBlock info=(concat "Find further information here: " statusPageUrl)}}
{{> ButtonBlock buttonUrl=statusPageUrl buttonText="View Status Page"}}
{{/if}}
{{> VerticalSpace this}}
{{#if subscriberEmailNotificationFooterText}}
{{> InfoBlock info=subscriberEmailNotificationFooterText }}
{{/if}}
{{> UnsubscribeBlock this}}
{{> VerticalSpace this}}
{{> Footer this}}
{{> End this}}

View File

@@ -1,36 +1,37 @@
{{> Start this}}
{{> CustomLogo this}}
{{> EmailTitle title=(concat "Scheduled Maintenance Event: " eventTitle) }}
{{> InfoBlock info="Here are more details for this scheduled event: "}}
{{> EmailTitle title=(concat "Scheduled Maintenance: " eventTitle) }}
{{> InfoBlock info="A scheduled maintenance event has been announced for services you're subscribed to."}}
{{> DetailBoxStart this }}
{{> DetailBoxField title=eventTitle text="" }}
{{> DetailBoxField title="Event Status: " text="Scheduled" }}
{{> DetailBoxField title="Maintenance Event" text=eventTitle }}
{{> DetailBoxField title="Status" text="Scheduled" }}
{{> DetailBoxField title="Scheduled Time" text=scheduledAt }}
{{#if resourcesAffected}}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{> DetailBoxField title="Affected Resources" text=resourcesAffected }}
{{/if}}
{{#if eventDescription}}
{{> DetailBoxField title="Description" text=eventDescription }}
{{/if}}
{{> DetailBoxField title="Event Scheduled At: " text="" }}
{{> DetailBoxField title="" text=scheduledAt }}
{{> DetailBoxField title="Event Description: " text="" }}
{{> DetailBoxField title="" text=eventDescription }}
{{> DetailBoxEnd this }}
{{> InfoBlock info=(concat subscriberEmailNotificationFooterText "") }}
{{#if detailsUrl}}
{{> InfoBlock info=(concat "Find further information here: " detailsUrl)}}
{{> ButtonBlock buttonUrl=detailsUrl buttonText="View Maintenance Details"}}
{{else}}
{{> InfoBlock info=(concat "Find further information here: " statusPageUrl)}}
{{> ButtonBlock buttonUrl=statusPageUrl buttonText="View Status Page"}}
{{/if}}
{{> VerticalSpace this}}
{{#if subscriberEmailNotificationFooterText}}
{{> InfoBlock info=subscriberEmailNotificationFooterText }}
{{/if}}
{{> UnsubscribeBlock this}}
{{> VerticalSpace this}}
{{> Footer this}}
{{> End this}}

View File

@@ -9,13 +9,12 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title=eventTitle text="" }}
{{> DetailBoxField title="Event Title: " text=eventTitle }}
{{> DetailBoxField title="Event Description: " text=eventDescription }}
{{#if resourcesAffected}}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}
{{/if}}
{{> DetailBoxField title="Note: " text="" }}
{{> DetailBoxField title="" text=note }}
{{> DetailBoxField title="Note: " text=note }}
{{> DetailBoxEnd this }}

View File

@@ -10,7 +10,7 @@
{{> DetailBoxStart this }}
{{> DetailBoxField title=eventTitle text="" }}
{{> DetailBoxField title="Event Title: " text=eventTitle }}
{{> DetailBoxField title="Event State: " text=eventState }}
{{#if resourcesAffected}}
{{> DetailBoxField title="Resources Affected: " text=resourcesAffected }}

View File

@@ -26,6 +26,8 @@ import { JSONObject } from "../../Types/JSON";
import MonitorType, {
MonitorTypeHelper,
} from "../../Types/Monitor/MonitorType";
import MonitorSteps from "../../Types/Monitor/MonitorSteps";
import MonitorStep from "../../Types/Monitor/MonitorStep";
import ObjectID from "../../Types/ObjectID";
import PositiveNumber from "../../Types/PositiveNumber";
import Typeof from "../../Types/Typeof";
@@ -71,11 +73,61 @@ import { createWhatsAppMessageFromTemplate } from "../Utils/WhatsAppTemplateUtil
import { WhatsAppMessagePayload } from "../../Types/WhatsApp/WhatsAppMessage";
import MetricService from "./MetricService";
export interface MonitorDestinationInfo {
monitorDestination: string;
requestType: string;
monitorType: string;
}
export class Service extends DatabaseService<Model> {
public constructor() {
super(Model);
}
public getMonitorDestinationInfo(monitor: Model): MonitorDestinationInfo {
let monitorDestination: string = "";
let requestType: string = "";
const monitorType: MonitorType | undefined = monitor.monitorType;
if (monitor.monitorSteps) {
const monitorSteps: MonitorSteps = monitor.monitorSteps;
const stepsArray: Array<MonitorStep> =
monitorSteps.data?.monitorStepsInstanceArray || [];
if (stepsArray.length > 0) {
const firstStep: MonitorStep | undefined = stepsArray[0];
// Get monitor destination
if (firstStep?.data?.monitorDestination) {
monitorDestination =
firstStep.data.monitorDestination.toString() || "";
}
// Get request type for API monitors
if (monitorType === MonitorType.API && firstStep?.data?.requestType) {
requestType = firstStep.data.requestType;
}
// For port monitors, append port to destination
if (
monitorType === MonitorType.Port &&
firstStep?.data?.monitorDestinationPort
) {
const port: string = firstStep.data.monitorDestinationPort.toString();
if (monitorDestination && port) {
monitorDestination = `${monitorDestination}:${port}`;
}
}
}
}
return {
monitorDestination,
requestType,
monitorType: monitorType || "",
};
}
public async refreshMonitorCurrentStatus(monitorId: ObjectID): Promise<void> {
const monitor: Model | null = await this.findOneById({
id: monitorId,
@@ -1135,6 +1187,8 @@ ${createdItem.description?.trim() || "No description provided."}
name: true,
},
description: true,
monitorType: true,
monitorSteps: true,
},
props: {
isRoot: true,
@@ -1172,6 +1226,10 @@ ${createdItem.description?.trim() || "No description provided."}
? "Disabled"
: "Enabled";
// Get monitor destination info using the helper function
const destinationInfo: MonitorDestinationInfo =
this.getMonitorDestinationInfo(monitor);
const vars: Dictionary<string> = {
title: title,
monitorName: monitor.name!,
@@ -1184,6 +1242,9 @@ ${createdItem.description?.trim() || "No description provided."}
monitorViewLink: (
await this.getMonitorLinkInDashboard(monitor.projectId!, monitor.id!)
).toString(),
monitorDestination: destinationInfo.monitorDestination,
requestType: destinationInfo.requestType,
monitorType: destinationInfo.monitorType,
};
if (doesResourceHasOwners === true) {
@@ -1259,6 +1320,8 @@ ${createdItem.description?.trim() || "No description provided."}
name: true,
},
description: true,
monitorType: true,
monitorSteps: true,
},
props: {
isRoot: true,
@@ -1292,6 +1355,10 @@ ${createdItem.description?.trim() || "No description provided."}
? "Disconnected"
: "Connected";
// Get monitor destination info using the helper function
const destinationInfo: MonitorDestinationInfo =
this.getMonitorDestinationInfo(monitor);
const vars: Dictionary<string> = {
title: `Probes for monitor ${monitor.name} is ${status}.`,
monitorName: monitor.name!,
@@ -1304,6 +1371,9 @@ ${createdItem.description?.trim() || "No description provided."}
monitorViewLink: (
await this.getMonitorLinkInDashboard(monitor.projectId!, monitor.id!)
).toString(),
monitorDestination: destinationInfo.monitorDestination,
requestType: destinationInfo.requestType,
monitorType: destinationInfo.monitorType,
};
if (doesResourceHasOwners === true) {

View File

@@ -41,12 +41,22 @@ export default class PushNotificationUtil {
incidentTitle: string;
projectName: string;
newState: string;
previousState?: string;
incidentViewLink: string;
}): PushNotificationMessage {
const { incidentTitle, projectName, newState, incidentViewLink } = params;
const {
incidentTitle,
projectName,
newState,
previousState,
incidentViewLink,
} = params;
const stateChangeText: string = previousState
? `Incident state changed from ${previousState} to ${newState}`
: `Incident state changed to ${newState}`;
return PushNotificationUtil.applyDefaults({
title: `Incident Updated: ${incidentTitle}`,
body: `Incident state changed to ${newState} in ${projectName}. Click to view details.`,
body: `${stateChangeText} in ${projectName}. Click to view details.`,
clickAction: incidentViewLink,
url: incidentViewLink,
tag: "incident-state-changed",
@@ -56,6 +66,7 @@ export default class PushNotificationUtil {
incidentTitle: incidentTitle,
projectName: projectName,
newState: newState,
previousState: previousState,
url: incidentViewLink,
},
});
@@ -113,12 +124,22 @@ export default class PushNotificationUtil {
monitorName: string;
projectName: string;
newStatus: string;
previousStatus?: string;
monitorViewLink: string;
}): PushNotificationMessage {
const { monitorName, projectName, newStatus, monitorViewLink } = params;
const {
monitorName,
projectName,
newStatus,
previousStatus,
monitorViewLink,
} = params;
const statusChangeText: string = previousStatus
? `Monitor status changed from ${previousStatus} to ${newStatus}`
: `Monitor status changed to ${newStatus}`;
return PushNotificationUtil.applyDefaults({
title: `Monitor ${newStatus}: ${monitorName}`,
body: `Monitor status changed to ${newStatus} in ${projectName}. Click to view details.`,
body: `${statusChangeText} in ${projectName}. Click to view details.`,
clickAction: monitorViewLink,
url: monitorViewLink,
tag: "monitor-status-changed",
@@ -128,6 +149,7 @@ export default class PushNotificationUtil {
monitorName: monitorName,
projectName: projectName,
newStatus: newStatus,
previousStatus: previousStatus,
url: monitorViewLink,
},
});

View File

@@ -19,7 +19,6 @@
"devDependencies": {
"@types/node": "^17.0.45",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.6.3"
},
"engines": {
@@ -301,19 +300,6 @@
"node": ">=0.3.1"
}
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -321,26 +307,6 @@
"dev": true,
"license": "ISC"
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
@@ -385,21 +351,6 @@
}
}
},
"node_modules/tsconfig-paths": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"json5": "^2.2.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",

View File

@@ -9,6 +9,7 @@
"scripts": {
"build": "tsc",
"compile": "tsc",
"dep-check": "npm install -g depcheck && depcheck ./ --skip-missing=true",
"dev": "ts-node --transpile-only -r tsconfig-paths/register src/Index.ts",
"start": "node --enable-source-maps ./build/dist/Index.js",
"clear-modules": "rm -rf node_modules && rm -f package-lock.json && npm install"
@@ -21,7 +22,6 @@
},
"devDependencies": {
"@types/node": "^17.0.45",
"tsconfig-paths": "^4.2.0",
"ts-node": "^10.9.2",
"typescript": "^5.6.3"
},

View File

@@ -63,8 +63,7 @@ const POSTMORTEM_FORM_FIELDS: Fields<Incident> = [
title: "Postmortem Published At",
fieldType: FormFieldSchemaType.DateTime,
required: false,
description:
"Set the posted-on timestamp subscribers will see. ",
description: "Set the posted-on timestamp subscribers will see. ",
placeholder: "Select date and time",
getDefaultValue: () => {
return OneUptimeDate.getCurrentDate();
@@ -86,7 +85,7 @@ const POSTMORTEM_FORM_FIELDS: Fields<Incident> = [
notifySubscribersOnPostmortemPublished: true,
},
title: "Notify Subscribers",
fieldType: FormFieldSchemaType.Toggle,
fieldType: FormFieldSchemaType.Checkbox,
required: false,
description: "Notify subscribers when this postmortem is published.",
defaultValue: true,
@@ -259,7 +258,7 @@ const IncidentPostmortem: FunctionComponent<
field: {
showPostmortemOnStatusPage: true,
},
title: "Visible on Status Page?",
title: "Postmortem visible on Status Page?",
fieldType: FieldType.Boolean,
},
{
@@ -268,6 +267,9 @@ const IncidentPostmortem: FunctionComponent<
},
title: "Notify Subscribers",
fieldType: FieldType.Boolean,
showIf: (item: Incident): boolean => {
return Boolean(item.showPostmortemOnStatusPage);
},
},
{
field: {

View File

@@ -1 +1 @@
9.2.1
9.2.4

View File

@@ -12,6 +12,7 @@ import Text from "Common/Types/Text";
import { EVERY_MINUTE } from "Common/Utils/CronTime";
import AlertService from "Common/Server/Services/AlertService";
import AlertStateTimelineService from "Common/Server/Services/AlertStateTimelineService";
import AlertStateService from "Common/Server/Services/AlertStateService";
import ProjectService from "Common/Server/Services/ProjectService";
import UserNotificationSettingService from "Common/Server/Services/UserNotificationSettingService";
import PushNotificationUtil from "Common/Server/Utils/PushNotificationUtil";
@@ -24,6 +25,8 @@ import AlertFeedService from "Common/Server/Services/AlertFeedService";
import { AlertFeedEventType } from "Common/Models/DatabaseModels/AlertFeed";
import { Blue500 } from "Common/Types/BrandColors";
import UserService from "Common/Server/Services/UserService";
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
import QueryHelper from "Common/Server/Types/Database/QueryHelper";
import { createWhatsAppMessageFromTemplate } from "Common/Server/Utils/WhatsAppTemplateUtil";
import { WhatsAppMessagePayload } from "Common/Types/WhatsApp/WhatsAppMessage";
@@ -45,13 +48,16 @@ RunCron(
select: {
_id: true,
createdAt: true,
startsAt: true,
projectId: true,
project: {
name: true,
},
alertId: true,
alertStateId: true,
alertState: {
name: true,
color: true,
},
},
});
@@ -116,6 +122,41 @@ RunCron(
},
});
// Fetch the previous state timeline entry
let previousState: AlertState | null = null;
if (alertStateTimeline.alertId && alertStateTimeline.startsAt) {
const previousTimeline: AlertStateTimeline | null =
await AlertStateTimelineService.findOneBy({
query: {
alertId: alertStateTimeline.alertId,
startsAt: QueryHelper.lessThan(alertStateTimeline.startsAt),
},
sort: {
startsAt: SortOrder.Descending,
},
props: {
isRoot: true,
},
select: {
alertStateId: true,
},
});
if (previousTimeline?.alertStateId) {
previousState = await AlertStateService.findOneById({
id: previousTimeline.alertStateId,
props: {
isRoot: true,
},
select: {
name: true,
color: true,
},
});
}
}
// now find owners.
let doesResourceHasOwners: boolean = true;
@@ -145,6 +186,9 @@ RunCron(
alertTitle: alert.title!,
projectName: alertStateTimeline.project!.name!,
currentState: alertState!.name!,
currentStateColor: alertState!.color?.toString() || "#000000",
previousState: previousState?.name || "",
previousStateColor: previousState?.color?.toString() || "#6b7280",
alertDescription: await Markdown.convertToHTML(
alert.description! || "",
MarkdownContentType.Email,
@@ -177,7 +221,7 @@ RunCron(
};
const sms: SMSMessage = {
message: `This is a message from OneUptime. Alert ${alertIdentifier} - state changed to ${alertState!
message: `This is a message from OneUptime. Alert ${alertIdentifier} - state changed${previousState ? ` from ${previousState.name}` : ""} to ${alertState!
.name!}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard.`,
};
@@ -186,7 +230,7 @@ RunCron(
{
sayMessage: `This is a message from OneUptime. Alert ${
alertIdentifier
} state changed to ${alertState!
} state changed${previousState ? ` from ${previousState.name}` : ""} to ${alertState!
.name!}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard. Good bye.`,
},
],
@@ -195,7 +239,7 @@ RunCron(
const pushMessage: PushNotificationMessage =
PushNotificationUtil.createGenericNotification({
title: `Alert State Changed: ${alert.title}`,
body: `Alert state changed to ${alertState!.name!} in ${alertStateTimeline.project!.name!}. Click to view details.`,
body: `Alert state changed${previousState ? ` from ${previousState.name}` : ""} to ${alertState!.name!} in ${alertStateTimeline.project!.name!}. Click to view details.`,
clickAction: (
await AlertService.getAlertLinkInDashboard(
alertStateTimeline.projectId!,

View File

@@ -11,6 +11,7 @@ import PushNotificationMessage from "Common/Types/PushNotification/PushNotificat
import { EVERY_MINUTE } from "Common/Utils/CronTime";
import IncidentService from "Common/Server/Services/IncidentService";
import IncidentStateTimelineService from "Common/Server/Services/IncidentStateTimelineService";
import IncidentStateService from "Common/Server/Services/IncidentStateService";
import ProjectService from "Common/Server/Services/ProjectService";
import UserNotificationSettingService from "Common/Server/Services/UserNotificationSettingService";
import PushNotificationUtil from "Common/Server/Utils/PushNotificationUtil";
@@ -24,6 +25,8 @@ import IncidentFeedService from "Common/Server/Services/IncidentFeedService";
import { IncidentFeedEventType } from "Common/Models/DatabaseModels/IncidentFeed";
import { Blue500 } from "Common/Types/BrandColors";
import UserService from "Common/Server/Services/UserService";
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
import QueryHelper from "Common/Server/Types/Database/QueryHelper";
import { createWhatsAppMessageFromTemplate } from "Common/Server/Utils/WhatsAppTemplateUtil";
import { WhatsAppMessagePayload } from "Common/Types/WhatsApp/WhatsAppMessage";
@@ -45,14 +48,17 @@ RunCron(
select: {
_id: true,
createdAt: true,
startsAt: true,
projectId: true,
project: {
name: true,
},
incidentId: true,
incidentStateId: true,
incidentState: {
name: true,
isResolvedState: true,
color: true,
},
},
});
@@ -120,6 +126,41 @@ RunCron(
},
});
// Fetch the previous state timeline entry
let previousState: IncidentState | null = null;
if (incidentStateTimeline.incidentId && incidentStateTimeline.startsAt) {
const previousTimeline: IncidentStateTimeline | null =
await IncidentStateTimelineService.findOneBy({
query: {
incidentId: incidentStateTimeline.incidentId,
startsAt: QueryHelper.lessThan(incidentStateTimeline.startsAt),
},
sort: {
startsAt: SortOrder.Descending,
},
props: {
isRoot: true,
},
select: {
incidentStateId: true,
},
});
if (previousTimeline?.incidentStateId) {
previousState = await IncidentStateService.findOneById({
id: previousTimeline.incidentStateId,
props: {
isRoot: true,
},
select: {
name: true,
color: true,
},
});
}
}
// now find owners.
let doesResourceHasOwners: boolean = true;
@@ -151,6 +192,9 @@ RunCron(
incidentTitle: incident.title!,
projectName: incidentStateTimeline.project!.name!,
currentState: incidentState!.name!,
currentStateColor: incidentState!.color?.toString() || "#000000",
previousState: previousState?.name || "",
previousStateColor: previousState?.color?.toString() || "#6b7280",
incidentDescription: await Markdown.convertToHTML(
incident.description! || "",
MarkdownContentType.Email,
@@ -196,7 +240,7 @@ RunCron(
};
const sms: SMSMessage = {
message: `This is a message from OneUptime. Incident ${incidentIdentifier} - state changed to ${incidentState!
message: `This is a message from OneUptime. Incident ${incidentIdentifier} - state changed${previousState ? ` from ${previousState.name}` : ""} to ${incidentState!
.name!}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard.`,
};
@@ -205,19 +249,33 @@ RunCron(
{
sayMessage: `This is a message from OneUptime. Incident ${
incidentIdentifier
} state changed to ${incidentState!
} state changed${previousState ? ` from ${previousState.name}` : ""} to ${incidentState!
.name!}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard. Good bye.`,
},
],
};
const pushNotificationParams: {
incidentTitle: string;
projectName: string;
newState: string;
previousState?: string;
incidentViewLink: string;
} = {
incidentTitle: incident.title!,
projectName: incidentStateTimeline.project!.name!,
newState: incidentState!.name!,
incidentViewLink: vars["incidentViewLink"] || "",
};
if (previousState?.name) {
pushNotificationParams.previousState = previousState.name;
}
const pushMessage: PushNotificationMessage =
PushNotificationUtil.createIncidentStateChangedNotification({
incidentTitle: incident.title!,
projectName: incidentStateTimeline.project!.name!,
newState: incidentState!.name!,
incidentViewLink: vars["incidentViewLink"] || "",
});
PushNotificationUtil.createIncidentStateChangedNotification(
pushNotificationParams,
);
const eventType: NotificationSettingEventType =
NotificationSettingEventType.SEND_INCIDENT_STATE_CHANGED_OWNER_NOTIFICATION;

View File

@@ -7,7 +7,9 @@ import NotificationSettingEventType from "Common/Types/NotificationSetting/Notif
import { SMSMessage } from "Common/Types/SMS/SMS";
import PushNotificationMessage from "Common/Types/PushNotification/PushNotificationMessage";
import { EVERY_MINUTE } from "Common/Utils/CronTime";
import MonitorService from "Common/Server/Services/MonitorService";
import MonitorService, {
MonitorDestinationInfo,
} from "Common/Server/Services/MonitorService";
import ProjectService from "Common/Server/Services/ProjectService";
import UserNotificationSettingService from "Common/Server/Services/UserNotificationSettingService";
import PushNotificationUtil from "Common/Server/Utils/PushNotificationUtil";
@@ -40,6 +42,8 @@ RunCron(
currentMonitorStatus: {
name: true,
},
monitorType: true,
monitorSteps: true,
},
});
@@ -71,6 +75,10 @@ RunCron(
continue;
}
// Get monitor destination info using the helper function
const destinationInfo: MonitorDestinationInfo =
MonitorService.getMonitorDestinationInfo(monitor);
const vars: Dictionary<string> = {
monitorName: monitor.name!,
projectName: monitor.project!.name!,
@@ -85,6 +93,9 @@ RunCron(
monitor.id!,
)
).toString(),
monitorDestination: destinationInfo.monitorDestination,
requestType: destinationInfo.requestType,
monitorType: destinationInfo.monitorType,
};
if (doesResourceHasOwners === true) {

View File

@@ -10,7 +10,9 @@ import PushNotificationMessage from "Common/Types/PushNotification/PushNotificat
import { EVERY_MINUTE } from "Common/Utils/CronTime";
import MonitorOwnerTeamService from "Common/Server/Services/MonitorOwnerTeamService";
import MonitorOwnerUserService from "Common/Server/Services/MonitorOwnerUserService";
import MonitorService from "Common/Server/Services/MonitorService";
import MonitorService, {
MonitorDestinationInfo,
} from "Common/Server/Services/MonitorService";
import TeamMemberService from "Common/Server/Services/TeamMemberService";
import UserNotificationSettingService from "Common/Server/Services/UserNotificationSettingService";
import PushNotificationUtil from "Common/Server/Utils/PushNotificationUtil";
@@ -143,6 +145,8 @@ RunCron(
currentMonitorStatus: {
name: true,
},
monitorType: true,
monitorSteps: true,
},
});
@@ -150,6 +154,10 @@ RunCron(
continue;
}
// Get monitor destination info using the helper function
const destinationInfo: MonitorDestinationInfo =
MonitorService.getMonitorDestinationInfo(monitor);
const vars: Dictionary<string> = {
monitorName: monitor.name!,
projectName: monitor.project!.name!,
@@ -164,6 +172,9 @@ RunCron(
monitor.id!,
)
).toString(),
monitorDestination: destinationInfo.monitorDestination,
requestType: destinationInfo.requestType,
monitorType: destinationInfo.monitorType,
};
for (const user of users) {

View File

@@ -8,8 +8,11 @@ import NotificationSettingEventType from "Common/Types/NotificationSetting/Notif
import { SMSMessage } from "Common/Types/SMS/SMS";
import PushNotificationMessage from "Common/Types/PushNotification/PushNotificationMessage";
import { EVERY_MINUTE } from "Common/Utils/CronTime";
import MonitorService from "Common/Server/Services/MonitorService";
import MonitorService, {
MonitorDestinationInfo,
} from "Common/Server/Services/MonitorService";
import MonitorStatusTimelineService from "Common/Server/Services/MonitorStatusTimelineService";
import MonitorStatusService from "Common/Server/Services/MonitorStatusService";
import ProjectService from "Common/Server/Services/ProjectService";
import UserNotificationSettingService from "Common/Server/Services/UserNotificationSettingService";
import PushNotificationUtil from "Common/Server/Utils/PushNotificationUtil";
@@ -20,6 +23,9 @@ import MonitorStatus from "Common/Models/DatabaseModels/MonitorStatus";
import MonitorStatusTimeline from "Common/Models/DatabaseModels/MonitorStatusTimeline";
import User from "Common/Models/DatabaseModels/User";
import { WhatsAppMessagePayload } from "Common/Types/WhatsApp/WhatsAppMessage";
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
import QueryHelper from "Common/Server/Types/Database/QueryHelper";
import logger from "Common/Server/Utils/Logger";
RunCron(
"MonitorOwner:SendStatusChangeEmail",
@@ -39,6 +45,9 @@ RunCron(
_id: true,
projectId: true,
createdAt: true,
startsAt: true,
monitorId: true,
monitorStatusId: true,
project: {
name: true,
},
@@ -46,9 +55,12 @@ RunCron(
_id: true,
name: true,
description: true,
monitorType: true,
monitorSteps: true,
},
monitorStatus: {
name: true,
color: true,
},
rootCause: true,
},
@@ -68,6 +80,75 @@ RunCron(
},
});
// Fetch the previous status timeline entry
let previousStatus: MonitorStatus | null = null;
let previousStatusDuration: string = "";
if (monitorStatusTimeline.monitorId && monitorStatusTimeline.startsAt) {
const previousTimeline: MonitorStatusTimeline | null =
await MonitorStatusTimelineService.findOneBy({
query: {
monitorId: monitorStatusTimeline.monitorId,
startsAt: QueryHelper.lessThan(monitorStatusTimeline.startsAt),
},
sort: {
startsAt: SortOrder.Descending,
},
props: {
isRoot: true,
},
select: {
monitorStatusId: true,
startsAt: true,
createdAt: true,
},
});
if (previousTimeline?.monitorStatusId) {
previousStatus = await MonitorStatusService.findOneById({
id: previousTimeline.monitorStatusId,
props: {
isRoot: true,
},
select: {
name: true,
color: true,
},
});
/*
* Calculate how long the monitor was in the previous status
* Use startsAt if available, otherwise fall back to createdAt
*/
const previousStartTime: Date | undefined =
previousTimeline.startsAt || previousTimeline.createdAt;
const currentStartTime: Date | undefined =
monitorStatusTimeline.startsAt || monitorStatusTimeline.createdAt;
if (previousStartTime && currentStartTime) {
logger.debug(
`Calculating duration between ${previousStartTime.toISOString()} and ${currentStartTime.toISOString()}`,
);
const durationInSeconds: number =
OneUptimeDate.getDifferenceInSeconds(
currentStartTime,
previousStartTime,
);
previousStatusDuration =
OneUptimeDate.convertSecondsToDaysHoursMinutesAndSeconds(
durationInSeconds,
);
logger.debug(`Previous status duration: ${previousStatusDuration}`);
}
}
}
// Get monitor destination info using the helper function
const destinationInfo: MonitorDestinationInfo =
MonitorService.getMonitorDestinationInfo(monitor);
// now find owners.
let doesResourceHasOwners: boolean = true;
@@ -88,10 +169,18 @@ RunCron(
}
for (const user of owners) {
// Build the "Was X for Y" string
const previousStatusDurationText: string =
previousStatus?.name && previousStatusDuration
? `Was ${previousStatus.name} for ${previousStatusDuration}`
: "";
const vars: Dictionary<string> = {
monitorName: monitor.name!,
projectName: monitorStatusTimeline.project!.name!,
currentStatus: monitorStatus!.name!,
currentStatusColor: monitorStatus!.color?.toString() || "#000000",
previousStatusDurationText: previousStatusDurationText,
monitorDescription: await Markdown.convertToHTML(
monitor.description! || "",
MarkdownContentType.Email,
@@ -112,6 +201,9 @@ RunCron(
monitorStatusTimeline.rootCause || "",
MarkdownContentType.Email,
)) || "",
monitorDestination: destinationInfo.monitorDestination,
requestType: destinationInfo.requestType,
monitorType: destinationInfo.monitorType,
};
if (doesResourceHasOwners === true) {
@@ -129,7 +221,7 @@ RunCron(
const sms: SMSMessage = {
message: `This is a message from OneUptime. ${
monitor.name || "Monitor"
} status changed to ${monitorStatus!
} status changed${previousStatus ? ` from ${previousStatus.name}` : ""} to ${monitorStatus!
.name!}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard.`,
};
@@ -138,19 +230,33 @@ RunCron(
{
sayMessage: `This is a message from OneUptime. ${
monitor.name || "Monitor"
} status changed to ${monitorStatus!
} status changed${previousStatus ? ` from ${previousStatus.name}` : ""} to ${monitorStatus!
.name!}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard. Good bye.`,
},
],
};
const pushNotificationParams: {
monitorName: string;
projectName: string;
newStatus: string;
previousStatus?: string;
monitorViewLink: string;
} = {
monitorName: monitor.name || "Monitor",
projectName: monitorStatusTimeline.project!.name!,
newStatus: monitorStatus!.name!,
monitorViewLink: vars["monitorViewLink"] || "",
};
if (previousStatus?.name) {
pushNotificationParams.previousStatus = previousStatus.name;
}
const pushMessage: PushNotificationMessage =
PushNotificationUtil.createMonitorStatusChangedNotification({
monitorName: monitor.name || "Monitor",
projectName: monitorStatusTimeline.project!.name!,
newStatus: monitorStatus!.name!,
monitorViewLink: vars["monitorViewLink"] || "",
});
PushNotificationUtil.createMonitorStatusChangedNotification(
pushNotificationParams,
);
const eventType: NotificationSettingEventType =
NotificationSettingEventType.SEND_MONITOR_STATUS_CHANGED_OWNER_NOTIFICATION;

View File

@@ -12,6 +12,7 @@ import { EVERY_MINUTE } from "Common/Utils/CronTime";
import ProjectService from "Common/Server/Services/ProjectService";
import ScheduledMaintenanceService from "Common/Server/Services/ScheduledMaintenanceService";
import ScheduledMaintenanceStateTimelineService from "Common/Server/Services/ScheduledMaintenanceStateTimelineService";
import ScheduledMaintenanceStateService from "Common/Server/Services/ScheduledMaintenanceStateService";
import UserNotificationSettingService from "Common/Server/Services/UserNotificationSettingService";
import PushNotificationUtil from "Common/Server/Utils/PushNotificationUtil";
import Markdown, { MarkdownContentType } from "Common/Server/Types/Markdown";
@@ -24,6 +25,8 @@ import { ScheduledMaintenanceFeedEventType } from "Common/Models/DatabaseModels/
import { Blue500 } from "Common/Types/BrandColors";
import ObjectID from "Common/Types/ObjectID";
import UserService from "Common/Server/Services/UserService";
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
import QueryHelper from "Common/Server/Types/Database/QueryHelper";
import { createWhatsAppMessageFromTemplate } from "Common/Server/Utils/WhatsAppTemplateUtil";
import { WhatsAppMessagePayload } from "Common/Types/WhatsApp/WhatsAppMessage";
@@ -50,6 +53,7 @@ RunCron(
project: {
name: true,
},
scheduledMaintenanceId: true,
scheduledMaintenance: {
_id: true,
title: true,
@@ -57,8 +61,10 @@ RunCron(
projectId: true,
scheduledMaintenanceNumber: true,
},
scheduledMaintenanceStateId: true,
scheduledMaintenanceState: {
name: true,
color: true,
},
},
});
@@ -81,6 +87,47 @@ RunCron(
},
});
// Fetch the previous state timeline entry
let previousState: ScheduledMaintenanceState | null = null;
if (
scheduledMaintenanceStateTimeline.scheduledMaintenanceId &&
scheduledMaintenanceStateTimeline.startsAt
) {
const previousTimeline: ScheduledMaintenanceStateTimeline | null =
await ScheduledMaintenanceStateTimelineService.findOneBy({
query: {
scheduledMaintenanceId:
scheduledMaintenanceStateTimeline.scheduledMaintenanceId,
startsAt: QueryHelper.lessThan(
scheduledMaintenanceStateTimeline.startsAt,
),
},
sort: {
startsAt: SortOrder.Descending,
},
props: {
isRoot: true,
},
select: {
scheduledMaintenanceStateId: true,
},
});
if (previousTimeline?.scheduledMaintenanceStateId) {
previousState = await ScheduledMaintenanceStateService.findOneById({
id: previousTimeline.scheduledMaintenanceStateId,
props: {
isRoot: true,
},
select: {
name: true,
color: true,
},
});
}
}
// now find owners.
let doesResourceHasOwners: boolean = true;
@@ -107,6 +154,10 @@ RunCron(
scheduledMaintenanceTitle: scheduledMaintenance.title!,
projectName: scheduledMaintenanceStateTimeline.project!.name!,
currentState: scheduledMaintenanceState!.name!,
currentStateColor:
scheduledMaintenanceState!.color?.toString() || "#000000",
previousState: previousState?.name || "",
previousStateColor: previousState?.color?.toString() || "#6b7280",
scheduledMaintenanceDescription: await Markdown.convertToHTML(
scheduledMaintenance.description! || "",
MarkdownContentType.Email,
@@ -139,7 +190,7 @@ RunCron(
const sms: SMSMessage = {
message: `This is a message from OneUptime. Scheduled maintenance event - ${
scheduledMaintenance.title
}, state changed to ${scheduledMaintenanceState!
}, state changed${previousState ? ` from ${previousState.name}` : ""} to ${scheduledMaintenanceState!
.name!}. To view this event, go to OneUptime Dashboard. To unsubscribe from this notification go to User Settings in OneUptime Dashboard.`,
};
@@ -148,7 +199,7 @@ RunCron(
{
sayMessage: `This is a message from OneUptime. Scheduled maintenance event ${
scheduledMaintenance.title
} state changed to ${scheduledMaintenanceState!
} state changed${previousState ? ` from ${previousState.name}` : ""} to ${scheduledMaintenanceState!
.name!}. To view this event, go to OneUptime Dashboard. To unsubscribe from this notification go to User Settings in OneUptime Dashboard. Good bye.`,
},
],
@@ -157,7 +208,7 @@ RunCron(
const pushMessage: PushNotificationMessage =
PushNotificationUtil.createGenericNotification({
title: "Scheduled Maintenance State Changed",
body: `Scheduled maintenance ${scheduledMaintenance.title} state changed to ${scheduledMaintenanceState!.name!}. Click to view details.`,
body: `Scheduled maintenance ${scheduledMaintenance.title} state changed${previousState ? ` from ${previousState.name}` : ""} to ${scheduledMaintenanceState!.name!}. Click to view details.`,
clickAction: (
await ScheduledMaintenanceService.getScheduledMaintenanceLinkInDashboard(
scheduledMaintenance.projectId!,