monitorCheckIns.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import React from 'react';
  2. import styled from '@emotion/styled';
  3. import {Button} from 'sentry/components/button';
  4. import {SectionHeading} from 'sentry/components/charts/styles';
  5. import DateTime from 'sentry/components/dateTime';
  6. import Duration from 'sentry/components/duration';
  7. import LoadingError from 'sentry/components/loadingError';
  8. import LoadingIndicator from 'sentry/components/loadingIndicator';
  9. import Pagination from 'sentry/components/pagination';
  10. import {PanelTable} from 'sentry/components/panels';
  11. import StatusIndicator from 'sentry/components/statusIndicator';
  12. import Text from 'sentry/components/text';
  13. import {Tooltip} from 'sentry/components/tooltip';
  14. import {IconDownload} from 'sentry/icons';
  15. import {t, tct} from 'sentry/locale';
  16. import {defined} from 'sentry/utils';
  17. import {useApiQuery} from 'sentry/utils/queryClient';
  18. import {useLocation} from 'sentry/utils/useLocation';
  19. import {
  20. CheckIn,
  21. CheckInStatus,
  22. Monitor,
  23. MonitorEnvironment,
  24. } from 'sentry/views/monitors/types';
  25. import {statusToText} from 'sentry/views/monitors/utils';
  26. type Props = {
  27. monitor: Monitor;
  28. monitorEnvs: MonitorEnvironment[];
  29. orgId: string;
  30. };
  31. const checkStatusToIndicatorStatus: Record<
  32. CheckInStatus,
  33. 'success' | 'error' | 'muted' | 'warning'
  34. > = {
  35. [CheckInStatus.OK]: 'success',
  36. [CheckInStatus.ERROR]: 'error',
  37. [CheckInStatus.IN_PROGRESS]: 'muted',
  38. [CheckInStatus.MISSED]: 'warning',
  39. [CheckInStatus.TIMEOUT]: 'error',
  40. };
  41. function MonitorCheckIns({monitor, monitorEnvs, orgId}: Props) {
  42. const location = useLocation();
  43. const queryKey = [
  44. `/organizations/${orgId}/monitors/${monitor.slug}/checkins/`,
  45. {
  46. query: {
  47. per_page: '10',
  48. environment: monitorEnvs.map(e => e.name),
  49. ...location.query,
  50. },
  51. },
  52. ] as const;
  53. const {
  54. data: checkInList,
  55. getResponseHeader,
  56. isLoading,
  57. isError,
  58. } = useApiQuery<CheckIn[]>(queryKey, {staleTime: 0});
  59. if (isLoading) {
  60. return <LoadingIndicator />;
  61. }
  62. if (isError) {
  63. return <LoadingError />;
  64. }
  65. const generateDownloadUrl = (checkin: CheckIn) =>
  66. `/api/0/organizations/${orgId}/monitors/${monitor.slug}/checkins/${checkin.id}/attachment/`;
  67. const emptyCell = <Text>{'\u2014'}</Text>;
  68. return (
  69. <React.Fragment>
  70. <SectionHeading>{t('Recent Check-Ins')}</SectionHeading>
  71. <PanelTable
  72. headers={[
  73. t('Status'),
  74. t('Started'),
  75. t('Duration'),
  76. t('Attachment'),
  77. t('Timestamp'),
  78. ]}
  79. >
  80. {checkInList.map(checkIn => (
  81. <React.Fragment key={checkIn.id}>
  82. <Status>
  83. <StatusIndicator
  84. status={checkStatusToIndicatorStatus[checkIn.status]}
  85. tooltipTitle={tct('Check In Status: [status]', {
  86. status: statusToText[checkIn.status],
  87. })}
  88. />
  89. <Text>{statusToText[checkIn.status]}</Text>
  90. </Status>
  91. {checkIn.status !== CheckInStatus.MISSED ? (
  92. <div>
  93. {monitor.config.timezone ? (
  94. <Tooltip
  95. title={
  96. <DateTime
  97. date={checkIn.dateCreated}
  98. forcedTimezone={monitor.config.timezone}
  99. timeZone
  100. timeOnly
  101. />
  102. }
  103. >
  104. {<DateTime date={checkIn.dateCreated} timeOnly />}
  105. </Tooltip>
  106. ) : (
  107. <DateTime date={checkIn.dateCreated} timeOnly />
  108. )}
  109. </div>
  110. ) : (
  111. emptyCell
  112. )}
  113. {defined(checkIn.duration) ? (
  114. <Duration seconds={checkIn.duration / 1000} />
  115. ) : (
  116. emptyCell
  117. )}
  118. {checkIn.attachmentId ? (
  119. <Button
  120. size="xs"
  121. icon={<IconDownload size="xs" />}
  122. href={generateDownloadUrl(checkIn)}
  123. >
  124. {t('Attachment')}
  125. </Button>
  126. ) : (
  127. emptyCell
  128. )}
  129. <Timestamp date={checkIn.dateCreated} />
  130. </React.Fragment>
  131. ))}
  132. </PanelTable>
  133. <Pagination pageLinks={getResponseHeader?.('Link')} />
  134. </React.Fragment>
  135. );
  136. }
  137. export default MonitorCheckIns;
  138. const Status = styled('div')`
  139. display: flex;
  140. align-items: center;
  141. `;
  142. const Timestamp = styled(DateTime)`
  143. color: ${p => p.theme.subText};
  144. `;