checkInTooltip.tsx 3.1 KB

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