checkInTimeline.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import styled from '@emotion/styled';
  2. import DateTime from 'sentry/components/dateTime';
  3. import {Tooltip} from 'sentry/components/tooltip';
  4. import {CheckInStatus} from 'sentry/views/monitors/types';
  5. import {getColorsFromStatus} from 'sentry/views/monitors/utils';
  6. import {getAggregateStatus} from 'sentry/views/monitors/utils/getAggregateStatus';
  7. import {mergeBuckets} from 'sentry/views/monitors/utils/mergeBuckets';
  8. import {JobTickTooltip} from './jobTickTooltip';
  9. import type {MonitorBucketData, TimeWindowOptions} from './types';
  10. interface TimelineProps {
  11. end: Date;
  12. start: Date;
  13. timeWindowConfig: TimeWindowOptions;
  14. width: number;
  15. }
  16. export interface CheckInTimelineProps extends TimelineProps {
  17. bucketedData: MonitorBucketData;
  18. environment: string;
  19. }
  20. function getBucketedCheckInsPosition(
  21. timestamp: number,
  22. timelineStart: Date,
  23. msPerPixel: number
  24. ) {
  25. const elapsedSinceStart = new Date(timestamp).getTime() - timelineStart.getTime();
  26. return elapsedSinceStart / msPerPixel;
  27. }
  28. export function CheckInTimeline(props: CheckInTimelineProps) {
  29. const {bucketedData, start, end, timeWindowConfig, width, environment} = props;
  30. const elapsedMs = end.getTime() - start.getTime();
  31. const msPerPixel = elapsedMs / width;
  32. const jobTicks = mergeBuckets(bucketedData, environment);
  33. return (
  34. <TimelineContainer>
  35. {jobTicks.map(jobTick => {
  36. const {
  37. startTs,
  38. width: tickWidth,
  39. envMapping,
  40. roundedLeft,
  41. roundedRight,
  42. } = jobTick;
  43. const timestampMs = startTs * 1000;
  44. const left = getBucketedCheckInsPosition(timestampMs, start, msPerPixel);
  45. return (
  46. <JobTickTooltip
  47. jobTick={jobTick}
  48. timeWindowConfig={timeWindowConfig}
  49. skipWrapper
  50. key={startTs}
  51. >
  52. <JobTick
  53. style={{left, width: tickWidth}}
  54. status={getAggregateStatus(envMapping)}
  55. roundedLeft={roundedLeft}
  56. roundedRight={roundedRight}
  57. />
  58. </JobTickTooltip>
  59. );
  60. })}
  61. </TimelineContainer>
  62. );
  63. }
  64. export interface MockCheckInTimelineProps extends TimelineProps {
  65. mockTimestamps: Date[];
  66. }
  67. export function MockCheckInTimeline({
  68. mockTimestamps,
  69. start,
  70. end,
  71. timeWindowConfig,
  72. width,
  73. }: MockCheckInTimelineProps) {
  74. const elapsedMs = end.getTime() - start.getTime();
  75. const msPerPixel = elapsedMs / width;
  76. return (
  77. <TimelineContainer>
  78. {mockTimestamps.map(ts => {
  79. const timestampMs = ts.getTime();
  80. const left = getBucketedCheckInsPosition(timestampMs, start, msPerPixel);
  81. return (
  82. <Tooltip
  83. key={left}
  84. title={
  85. <DateTime date={timestampMs} format={timeWindowConfig.dateLabelFormat} />
  86. }
  87. skipWrapper
  88. >
  89. <JobTick
  90. style={{left}}
  91. status={CheckInStatus.IN_PROGRESS}
  92. roundedLeft
  93. roundedRight
  94. />
  95. </Tooltip>
  96. );
  97. })}
  98. </TimelineContainer>
  99. );
  100. }
  101. const TimelineContainer = styled('div')`
  102. position: relative;
  103. height: 100%;
  104. `;
  105. const JobTick = styled('div')<{
  106. roundedLeft: boolean;
  107. roundedRight: boolean;
  108. status: CheckInStatus;
  109. }>`
  110. position: absolute;
  111. top: calc(50% + 1px);
  112. transform: translateY(-50%);
  113. background: ${p => getColorsFromStatus(p.status, p.theme).tickColor};
  114. opacity: 0.7;
  115. width: 4px;
  116. height: 14px;
  117. ${p =>
  118. p.roundedLeft &&
  119. `
  120. border-top-left-radius: 2px;
  121. border-bottom-left-radius: 2px;
  122. `}
  123. ${p =>
  124. p.roundedRight &&
  125. `
  126. border-top-right-radius: 2px;
  127. border-bottom-right-radius: 2px;
  128. `}
  129. `;