cronDetailsTimeline.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import {useRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import {
  4. deleteMonitorEnvironment,
  5. setEnvironmentIsMuted,
  6. } from 'sentry/actionCreators/monitors';
  7. import Panel from 'sentry/components/panels/panel';
  8. import Text from 'sentry/components/text';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. import type {Organization} from 'sentry/types';
  12. import {setApiQueryData, useQueryClient} from 'sentry/utils/queryClient';
  13. import useApi from 'sentry/utils/useApi';
  14. import {useDimensions} from 'sentry/utils/useDimensions';
  15. import useRouter from 'sentry/utils/useRouter';
  16. import {
  17. GridLineOverlay,
  18. GridLineTimeLabels,
  19. } from 'sentry/views/monitors/components/overviewTimeline/gridLines';
  20. import {TimelineTableRow} from 'sentry/views/monitors/components/overviewTimeline/timelineTableRow';
  21. import type {Monitor} from 'sentry/views/monitors/types';
  22. import {makeMonitorDetailsQueryKey} from 'sentry/views/monitors/utils';
  23. import {useMonitorStats} from './overviewTimeline/useMonitorStats';
  24. import {useTimeWindowConfig} from './overviewTimeline/useTimeWindowConfig';
  25. interface Props {
  26. monitor: Monitor;
  27. organization: Organization;
  28. }
  29. export function CronDetailsTimeline({monitor, organization}: Props) {
  30. const {location} = useRouter();
  31. const api = useApi();
  32. const queryClient = useQueryClient();
  33. const elementRef = useRef<HTMLDivElement>(null);
  34. const {width: timelineWidth} = useDimensions<HTMLDivElement>({elementRef});
  35. const timeWindowConfig = useTimeWindowConfig({timelineWidth});
  36. const {data: monitorStats, isLoading} = useMonitorStats({
  37. monitors: [monitor.id],
  38. timeWindowConfig,
  39. });
  40. const monitorDetailsQueryKey = makeMonitorDetailsQueryKey(
  41. organization,
  42. monitor.project.slug,
  43. monitor.slug,
  44. {...location.query}
  45. );
  46. const handleDeleteEnvironment = async (env: string) => {
  47. const success = await deleteMonitorEnvironment(api, organization.slug, monitor, env);
  48. if (!success) {
  49. return;
  50. }
  51. setApiQueryData(queryClient, monitorDetailsQueryKey, (oldMonitorDetails: Monitor) => {
  52. const newEnvList = oldMonitorDetails.environments.filter(e => e.name !== env);
  53. const newMonitorDetails = {
  54. ...oldMonitorDetails,
  55. environments: newEnvList,
  56. };
  57. return newMonitorDetails;
  58. });
  59. };
  60. const handleToggleMuteEnvironment = async (env: string, isMuted: boolean) => {
  61. const resp = await setEnvironmentIsMuted(
  62. api,
  63. organization.slug,
  64. monitor,
  65. env,
  66. isMuted
  67. );
  68. if (resp === null) {
  69. return;
  70. }
  71. setApiQueryData(queryClient, monitorDetailsQueryKey, (oldMonitorDetails: Monitor) => {
  72. const oldMonitorEnvIdx = oldMonitorDetails.environments.findIndex(
  73. monitorEnv => monitorEnv.name === env
  74. );
  75. if (oldMonitorEnvIdx < 0) {
  76. return oldMonitorDetails;
  77. }
  78. oldMonitorDetails.environments[oldMonitorEnvIdx] = {
  79. ...oldMonitorDetails.environments[oldMonitorEnvIdx],
  80. isMuted,
  81. };
  82. return oldMonitorDetails;
  83. });
  84. };
  85. return (
  86. <TimelineContainer>
  87. <TimelineWidthTracker ref={elementRef} />
  88. <Header>
  89. <TimelineTitle>{t('Check-Ins')}</TimelineTitle>
  90. <GridLineTimeLabels timeWindowConfig={timeWindowConfig} width={timelineWidth} />
  91. </Header>
  92. <StyledGridLineOverlay
  93. allowZoom={!isLoading}
  94. showCursor={!isLoading}
  95. timeWindowConfig={timeWindowConfig}
  96. width={timelineWidth}
  97. />
  98. <TimelineTableRow
  99. monitor={monitor}
  100. bucketedData={monitorStats?.[monitor.id]}
  101. timeWindowConfig={timeWindowConfig}
  102. width={timelineWidth}
  103. onDeleteEnvironment={handleDeleteEnvironment}
  104. onToggleMuteEnvironment={handleToggleMuteEnvironment}
  105. singleMonitorView
  106. />
  107. </TimelineContainer>
  108. );
  109. }
  110. const TimelineContainer = styled(Panel)`
  111. display: grid;
  112. grid-template-columns: 135px 1fr;
  113. `;
  114. const Header = styled('div')`
  115. grid-column: 1/-1;
  116. display: grid;
  117. grid-template-columns: subgrid;
  118. border-bottom: 1px solid ${p => p.theme.border};
  119. `;
  120. const StyledGridLineOverlay = styled(GridLineOverlay)`
  121. grid-column: 2;
  122. `;
  123. const TimelineWidthTracker = styled('div')`
  124. position: absolute;
  125. width: 100%;
  126. grid-row: 1;
  127. grid-column: 2;
  128. `;
  129. const TimelineTitle = styled(Text)`
  130. ${p => p.theme.text.cardTitle};
  131. padding: ${space(2)};
  132. grid-column: 1;
  133. `;