mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 08:42:13 +02:00
Compare commits
25 Commits
postmortem
...
9.2.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91bf55dc20 | ||
|
|
d20a125742 | ||
|
|
d10bcd2edd | ||
|
|
0b32408bf2 | ||
|
|
269fbd3f24 | ||
|
|
2640ea8c10 | ||
|
|
f3180d3a83 | ||
|
|
7727fe835f | ||
|
|
00fbfbc08e | ||
|
|
44d1183066 | ||
|
|
0ccef797ab | ||
|
|
9914fb905f | ||
|
|
35ecc19ceb | ||
|
|
fa0362f739 | ||
|
|
8ea9084d9e | ||
|
|
eeb31a2250 | ||
|
|
b58c91dbab | ||
|
|
868bf4d3e1 | ||
|
|
a3fc20b393 | ||
|
|
c8dad04b5c | ||
|
|
ee7db393f8 | ||
|
|
e52da9fef2 | ||
|
|
9332df5648 | ||
|
|
120fc2ad71 | ||
|
|
1a7672748f |
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -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 -->
|
||||
@@ -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>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
<!-- End Detail Card Field Container -->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -10,4 +10,5 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
<!-- /Detail Card Container -->
|
||||
@@ -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>
|
||||
@@ -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;">
|
||||
@@ -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 -->
|
||||
@@ -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"> </div>
|
||||
</td>
|
||||
|
||||
@@ -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 -->
|
||||
@@ -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 -->
|
||||
@@ -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>
|
||||
|
||||
@@ -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> </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;">
|
||||
@@ -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 -->
|
||||
@@ -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 -->
|
||||
@@ -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 -->
|
||||
@@ -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>
|
||||
@@ -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 -->
|
||||
@@ -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 -->
|
||||
@@ -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 -->
|
||||
@@ -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 -->
|
||||
@@ -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"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- /Vertical Spacer -->
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
49
Copilot/package-lock.json
generated
49
Copilot/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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!,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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!,
|
||||
|
||||
Reference in New Issue
Block a user