traceTimeline.tsx 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import {useRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import ErrorBoundary from 'sentry/components/errorBoundary';
  4. import Placeholder from 'sentry/components/placeholder';
  5. import type {Event} from 'sentry/types';
  6. import {useDimensions} from 'sentry/utils/useDimensions';
  7. import useOrganization from 'sentry/utils/useOrganization';
  8. import {useUser} from 'sentry/utils/useUser';
  9. import {hasTraceTimelineFeature} from 'sentry/views/issueDetails/traceTimeline/utils';
  10. import {TraceTimelineEvents} from './traceTimelineEvents';
  11. import {useTraceTimelineEvents} from './useTraceTimelineEvents';
  12. interface TraceTimelineProps {
  13. event: Event;
  14. }
  15. export function TraceTimeline({event}: TraceTimelineProps) {
  16. const user = useUser();
  17. const organization = useOrganization({allowNull: true});
  18. const timelineRef = useRef<HTMLDivElement>(null);
  19. const {width} = useDimensions({elementRef: timelineRef});
  20. const hasFeature = hasTraceTimelineFeature(organization, user);
  21. const {isError, isLoading, data} = useTraceTimelineEvents({event}, hasFeature);
  22. if (!hasFeature) {
  23. return null;
  24. }
  25. if (isError || (!isLoading && data.length === 0)) {
  26. // display placeholder to reduce layout shift
  27. return <div style={{height: 45}} />;
  28. }
  29. return (
  30. <ErrorBoundary mini>
  31. <div>
  32. <Stacked ref={timelineRef}>
  33. {isLoading ? (
  34. <Placeholder height="45px" />
  35. ) : (
  36. <TimelineEventsContainer>
  37. <TimelineOutline />
  38. {/* Sets a min width of 200 for testing */}
  39. <TraceTimelineEvents event={event} width={Math.max(width, 200)} />
  40. </TimelineEventsContainer>
  41. )}
  42. </Stacked>
  43. </div>
  44. </ErrorBoundary>
  45. );
  46. }
  47. /**
  48. * Displays the container the dots appear inside of
  49. */
  50. const TimelineOutline = styled('div')`
  51. position: absolute;
  52. left: 0;
  53. top: 5px;
  54. width: 100%;
  55. height: 6px;
  56. border: 1px solid ${p => p.theme.innerBorder};
  57. border-radius: ${p => p.theme.borderRadius};
  58. `;
  59. /**
  60. * Render all child elements directly on top of each other.
  61. *
  62. * This implementation does not remove the stack of elements from the document
  63. * flow, so width/height is reserved.
  64. *
  65. * An alternative would be to use `position:absolute;` in which case the size
  66. * would not be part of document flow and other elements could render behind.
  67. */
  68. const Stacked = styled('div')`
  69. display: grid;
  70. grid-template: 1fr / 1fr;
  71. > * {
  72. grid-area: 1 / 1;
  73. }
  74. `;
  75. const TimelineEventsContainer = styled('div')`
  76. position: relative;
  77. height: 45px;
  78. padding-top: 10px;
  79. `;