jobTickTooltip.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import DateTime from 'sentry/components/dateTime';
  4. import Text from 'sentry/components/text';
  5. import type {TooltipProps} from 'sentry/components/tooltip';
  6. import {Tooltip} from 'sentry/components/tooltip';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import type {
  10. JobTickData,
  11. TimeWindowOptions,
  12. } from 'sentry/views/monitors/components/overviewTimeline/types';
  13. import type {CheckInStatus} from 'sentry/views/monitors/types';
  14. import {statusToText, tickStyle} from 'sentry/views/monitors/utils';
  15. interface Props extends Omit<TooltipProps, 'title'> {
  16. jobTick: JobTickData;
  17. timeWindowConfig: TimeWindowOptions;
  18. }
  19. export function JobTickTooltip({jobTick, timeWindowConfig, children, ...props}: Props) {
  20. const {startTs, endTs, envMapping} = jobTick;
  21. const {dateLabelFormat} = timeWindowConfig;
  22. const capturedEnvs = Object.keys(envMapping);
  23. const representsSingleJob =
  24. capturedEnvs.length === 1 &&
  25. Object.values(envMapping[capturedEnvs[0]]).reduce((sum, count) => sum + count, 0) ===
  26. 1;
  27. const tooltipTitle = (
  28. <Fragment>
  29. <TooltipTimeLabel>
  30. <DateTime date={startTs * 1000} format={dateLabelFormat} />
  31. {!representsSingleJob && (
  32. <Fragment>
  33. <Text>{'\u2014'}</Text>
  34. <DateTime date={endTs * 1000} format={dateLabelFormat} />
  35. </Fragment>
  36. )}
  37. </TooltipTimeLabel>
  38. <StatusCountContainer>
  39. {/* Visually hidden but kept here for accessibility */}
  40. <HiddenHeader>
  41. <tr>
  42. <td>{t('Status')}</td>
  43. <td>{t('Environment')}</td>
  44. <td>{t('Count')}</td>
  45. </tr>
  46. </HiddenHeader>
  47. <tbody>
  48. {Object.entries(envMapping).map(([envName, statusCounts]) =>
  49. Object.entries(statusCounts).map(
  50. ([status, count]) =>
  51. count > 0 && (
  52. <tr key={`${envName}:${status}`}>
  53. {/* TODO(davidenwang): fix types to remove "as" here */}
  54. <StatusLabel status={status as CheckInStatus}>
  55. {statusToText[status]}
  56. </StatusLabel>
  57. {/* TODO(davidenwang): handle long env names */}
  58. <EnvLabel>{envName}</EnvLabel>
  59. <StatusCount>{count}</StatusCount>
  60. </tr>
  61. )
  62. )
  63. )}
  64. </tbody>
  65. </StatusCountContainer>
  66. </Fragment>
  67. );
  68. return (
  69. <Tooltip title={tooltipTitle} skipWrapper {...props}>
  70. {children}
  71. </Tooltip>
  72. );
  73. }
  74. const StatusCountContainer = styled('table')`
  75. width: 100%;
  76. margin: 0;
  77. `;
  78. const TooltipTimeLabel = styled('div')`
  79. display: flex;
  80. margin-bottom: ${space(0.5)};
  81. justify-content: center;
  82. `;
  83. const HiddenHeader = styled('thead')`
  84. display: block;
  85. overflow: hidden;
  86. height: 0;
  87. width: 0;
  88. `;
  89. const StatusLabel = styled('td')<{status: CheckInStatus}>`
  90. color: ${p => p.theme[tickStyle[p.status].labelColor]};
  91. text-align: left;
  92. `;
  93. const StatusCount = styled('td')`
  94. font-variant-numeric: tabular-nums;
  95. `;
  96. const EnvLabel = styled('td')`
  97. padding: ${space(0.25)} ${space(0.5)};
  98. `;