Openstatus www.openstatus.dev

feat: page-components status report emails (#1786)

* feat: page-components status report emails

* fix: trpc router

authored by

Maximilian Kaske and committed by
GitHub
cabde919 1871de92

+49 -34
+20 -9
apps/server/src/routes/v1/maintenances/post.ts
··· 98 98 }); 99 99 } 100 100 101 - const _maintenance = await db.transaction(async (tx) => { 101 + const _newMaintenance = await db.transaction(async (tx) => { 102 102 const newMaintenance = await tx 103 103 .insert(maintenance) 104 104 .values({ ··· 129 129 return newMaintenance; 130 130 }); 131 131 132 - if (limits["status-subscribers"] && _maintenance.pageId) { 132 + if (limits["status-subscribers"] && _newMaintenance.pageId) { 133 133 const subscribers = await db 134 134 .select() 135 135 .from(pageSubscriber) 136 136 .where( 137 137 and( 138 - eq(pageSubscriber.pageId, _maintenance.pageId), 138 + eq(pageSubscriber.pageId, _newMaintenance.pageId), 139 139 isNotNull(pageSubscriber.acceptedAt), 140 140 ), 141 141 ) ··· 143 143 144 144 const _page = await db.query.page.findFirst({ 145 145 where: and( 146 - eq(page.id, _maintenance.pageId), 146 + eq(page.id, _newMaintenance.pageId), 147 147 eq(page.workspaceId, workspaceId), 148 148 ), 149 + }); 150 + 151 + const _maintenance = await db.query.maintenance.findFirst({ 152 + where: eq(maintenance.id, _newMaintenance.id), 149 153 with: { 150 - monitorsToPages: { 154 + maintenancesToPageComponents: { 151 155 with: { 152 - monitor: true, 156 + pageComponent: true, 153 157 }, 154 158 }, 155 159 }, 156 160 }); 161 + 162 + if (!_maintenance) { 163 + throw new OpenStatusApiError({ 164 + code: "INTERNAL_SERVER_ERROR", 165 + message: "Maintenance not found", 166 + }); 167 + } 157 168 158 169 const validSubscribers = subscribers.filter( 159 170 (s): s is typeof s & { token: string } => ··· 174 185 status: "maintenance", 175 186 message: _maintenance.message, 176 187 date: _maintenance.from.toISOString(), 177 - monitors: _page.monitorsToPages.map( 178 - (i) => i.monitor.externalName || i.monitor.name, 188 + pageComponents: _maintenance.maintenancesToPageComponents.map( 189 + (i) => i.pageComponent.name, 179 190 ), 180 191 }); 181 192 } 182 193 } 183 194 184 195 const data = MaintenanceSchema.parse({ 185 - ..._maintenance, 196 + ..._newMaintenance, 186 197 monitorIds: input.monitorIds, 187 198 }); 188 199
+4 -4
apps/server/src/routes/v1/statusReportUpdates/post.ts
··· 58 58 eq(statusReport.workspaceId, workspaceId), 59 59 ), 60 60 with: { 61 - monitorsToStatusReports: { 61 + statusReportsToPageComponents: { 62 62 with: { 63 - monitor: true, 63 + pageComponent: true, 64 64 }, 65 65 }, 66 66 }, ··· 134 134 status: _statusReportUpdate.status, 135 135 message: _statusReportUpdate.message, 136 136 date: _statusReportUpdate.date.toISOString(), 137 - monitors: _statusReport.monitorsToStatusReports.map( 138 - (i) => i.monitor.externalName || i.monitor.name, 137 + pageComponents: _statusReport.statusReportsToPageComponents.map( 138 + (i) => i.pageComponent.name, 139 139 ), 140 140 }); 141 141 }
+5 -2
apps/server/src/routes/v1/statusReports/post.ts
··· 179 179 monitorsToStatusReports: { 180 180 with: { monitor: true }, 181 181 }, 182 + statusReportsToPageComponents: { 183 + with: { pageComponent: true }, 184 + }, 182 185 }, 183 186 }); 184 187 ··· 208 211 status: _newStatusReportUpdate.status, 209 212 message: _newStatusReportUpdate.message, 210 213 date: _newStatusReportUpdate.date.toISOString(), 211 - monitors: _statusReport.monitorsToStatusReports.map( 212 - (i) => i.monitor.externalName || i.monitor.name, 214 + pageComponents: _statusReport.statusReportsToPageComponents.map( 215 + (i) => i.pageComponent.name, 213 216 ), 214 217 }); 215 218 }
+7 -6
apps/server/src/routes/v1/statusReports/update/post.ts
··· 86 86 .returning() 87 87 .get(); 88 88 89 - if (limits.notifications && _statusReport.pageId) { 89 + if (limits["status-subscribers"] && _statusReport.pageId) { 90 90 const _statusReportWithRelations = await db.query.statusReport.findFirst({ 91 91 where: eq(statusReport.id, Number(id)), 92 92 with: { 93 - monitorsToStatusReports: { 93 + statusReportsToPageComponents: { 94 94 with: { 95 - monitor: true, 95 + pageComponent: true, 96 96 }, 97 97 }, 98 98 page: true, ··· 129 129 status: _statusReportUpdate.status, 130 130 message: _statusReportUpdate.message, 131 131 date: _statusReportUpdate.date.toISOString(), 132 - monitors: _statusReportWithRelations.monitorsToStatusReports.map( 133 - (monitor) => monitor.monitor.externalName || monitor.monitor.name, 134 - ), 132 + pageComponents: 133 + _statusReportWithRelations.statusReportsToPageComponents.map( 134 + (i) => i.pageComponent.name, 135 + ), 135 136 }); 136 137 } 137 138 }
+9 -9
packages/api/src/router/email/index.ts
··· 32 32 with: { 33 33 statusReport: { 34 34 with: { 35 - monitorsToStatusReports: { 35 + statusReportsToPageComponents: { 36 36 with: { 37 - monitor: true, 37 + pageComponent: true, 38 38 }, 39 39 }, 40 40 page: { ··· 82 82 status: _statusReportUpdate.status, 83 83 message: _statusReportUpdate.message, 84 84 date: new Date(_statusReportUpdate.date).toISOString(), 85 - monitors: 86 - _statusReportUpdate.statusReport.monitorsToStatusReports.map( 87 - (i) => i.monitor.externalName || i.monitor.name, 85 + pageComponents: 86 + _statusReportUpdate.statusReport.statusReportsToPageComponents.map( 87 + (i) => i.pageComponent.name, 88 88 ), 89 89 }); 90 90 } ··· 101 101 eq(maintenance.workspaceId, opts.ctx.workspace.id), 102 102 ), 103 103 with: { 104 - maintenancesToMonitors: { 104 + maintenancesToPageComponents: { 105 105 with: { 106 - monitor: true, 106 + pageComponent: true, 107 107 }, 108 108 }, 109 109 page: { ··· 138 138 status: "maintenance", 139 139 message: _maintenance.message, 140 140 date: new Date(_maintenance.from).toISOString(), 141 - monitors: _maintenance.maintenancesToMonitors.map( 142 - (i) => i.monitor.externalName || i.monitor.name, 141 + pageComponents: _maintenance.maintenancesToPageComponents.map( 142 + (i) => i.pageComponent.name, 143 143 ), 144 144 }); 145 145 }
+4 -4
packages/emails/emails/status-report.tsx
··· 30 30 date: z.string(), 31 31 message: z.string(), 32 32 reportTitle: z.string(), 33 - monitors: z.array(z.string()), 33 + pageComponents: z.array(z.string()), 34 34 unsubscribeUrl: z.string().url().optional(), 35 35 }); 36 36 ··· 59 59 message, 60 60 reportTitle, 61 61 pageTitle, 62 - monitors, 62 + pageComponents, 63 63 unsubscribeUrl, 64 64 }: StatusReportProps) { 65 65 return ( ··· 105 105 </Column> 106 106 <Column style={{ textAlign: "right" }}> 107 107 <Text style={{ flexWrap: "wrap", wordWrap: "break-word" }}> 108 - {monitors.length > 0 ? monitors.join(", ") : "N/A"} 108 + {pageComponents.length > 0 ? pageComponents.join(", ") : "N/A"} 109 109 </Text> 110 110 </Column> 111 111 </Row> ··· 160 160 161 161 We'll post another update by **19:00 UTC** today or sooner if critical developments occur. We apologize for the inconvenience and appreciate your patience as we restore full cache functionality. 162 162 `, 163 - monitors: ["OpenStatus API", "OpenStatus Webhook"], 163 + pageComponents: ["OpenStatus API", "OpenStatus Webhook"], 164 164 unsubscribeUrl: 165 165 "https://status.openstatus.dev/unsubscribe/550e8400-e29b-41d4-a716-446655440000", 166 166 };