detailsTimeline.tsx 3.9 KB

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