serviceIncidents.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import ConfigStore from 'sentry/stores/configStore';
  2. import type {SentryServiceIncident, SentryServiceStatus} from 'sentry/types/system';
  3. type IncidentImpact = SentryServiceStatus['indicator'];
  4. /**
  5. * This is a partial typing of the statuspage API [0]
  6. *
  7. * [0]: https://doers.statuspage.io/api/v2/incidents/
  8. */
  9. type StatuspageIncident = {
  10. created_at: string;
  11. id: string;
  12. impact: IncidentImpact;
  13. name: string;
  14. shortlink: string;
  15. status: string;
  16. components?: Array<any>;
  17. incident_updates?: Array<any>;
  18. };
  19. function getIncidentsFromIncidentResponse(statuspageIncidents: StatuspageIncident[]): {
  20. incidents: SentryServiceIncident[];
  21. indicator: IncidentImpact;
  22. } {
  23. if (statuspageIncidents === null || statuspageIncidents.length === 0) {
  24. return {incidents: [], indicator: 'none'};
  25. }
  26. let isMajor = false;
  27. const incidents: SentryServiceIncident[] = [];
  28. statuspageIncidents.forEach(item => {
  29. if (!isMajor && item.impact === 'major') {
  30. isMajor = true;
  31. }
  32. incidents.push({
  33. id: item.id,
  34. name: item.name,
  35. createdAt: item.created_at,
  36. updates:
  37. item.incident_updates?.map(update => ({
  38. body: update.body,
  39. status: update.status,
  40. updatedAt: update.updated_at,
  41. })) ?? [],
  42. affectedComponents:
  43. item.components?.map(componentUpdate => ({
  44. name: componentUpdate.name,
  45. status: componentUpdate.status,
  46. updatedAt: componentUpdate.updated_at,
  47. })) ?? [],
  48. url: item.shortlink,
  49. status: item.status,
  50. });
  51. });
  52. return {incidents, indicator: isMajor ? 'major' : 'minor'};
  53. }
  54. export async function loadIncidents(): Promise<SentryServiceStatus | null> {
  55. const cfg = ConfigStore.get('statuspage');
  56. let response: Response | undefined = undefined;
  57. if (!cfg || !cfg.id) {
  58. return null;
  59. }
  60. try {
  61. response = await fetch(
  62. `https://${cfg.id}.${cfg.api_host}/api/v2/incidents/unresolved.json`
  63. );
  64. } catch (err) {
  65. // No point in capturing this as we can't make statuspage come back.
  66. return null;
  67. }
  68. if (!response.ok) {
  69. // Sometimes statuspage responds with a 500
  70. return null;
  71. }
  72. const data = await response.json();
  73. const {incidents, indicator} = getIncidentsFromIncidentResponse(data.incidents);
  74. return {
  75. incidents,
  76. indicator,
  77. url: data.page.url,
  78. };
  79. }