miniAggregateWaterfall.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import styled from '@emotion/styled';
  2. import type {Location} from 'history';
  3. import {LinkButton} from 'sentry/components/button';
  4. import {noFilter} from 'sentry/components/events/interfaces/spans/filter';
  5. import {ActualMinimap} from 'sentry/components/events/interfaces/spans/header';
  6. import {useSpanWaterfallModelFromTransaction} from 'sentry/components/events/interfaces/spans/useSpanWaterfallModelFromTransaction';
  7. import OpsBreakdown from 'sentry/components/events/opsBreakdown';
  8. import LoadingIndicator from 'sentry/components/loadingIndicator';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. import {trackAnalytics} from 'sentry/utils/analytics';
  12. import {useLocation} from 'sentry/utils/useLocation';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import {LandingDisplayField} from 'sentry/views/insights/browser/webVitals/views/pageOverview';
  15. type Props = {
  16. transaction: string;
  17. aggregateSpansLocation?: Location;
  18. };
  19. export function MiniAggregateWaterfall({transaction, aggregateSpansLocation}: Props) {
  20. const location = useLocation();
  21. const organization = useOrganization();
  22. // Pageload transactions don't seem to store http.method, so don't include one here
  23. const {waterfallModel, event, isLoading} =
  24. useSpanWaterfallModelFromTransaction(transaction);
  25. if (isLoading) {
  26. return <LoadingIndicator />;
  27. }
  28. const AggregateSpanWaterfallLocation = aggregateSpansLocation ?? {
  29. ...location,
  30. query: {
  31. ...location.query,
  32. tab: LandingDisplayField.SPANS,
  33. },
  34. };
  35. const minimap = (
  36. <ActualMinimap
  37. spans={waterfallModel.getWaterfall({
  38. viewStart: 0,
  39. viewEnd: 1,
  40. })}
  41. generateBounds={waterfallModel.generateBounds({
  42. viewStart: 0,
  43. viewEnd: 1,
  44. })}
  45. dividerPosition={0}
  46. rootSpan={waterfallModel.rootSpan.span}
  47. />
  48. );
  49. const opsBreakdown = (
  50. <OpsBreakdown operationNameFilters={noFilter} event={event} topN={3} hideHeader />
  51. );
  52. return (
  53. <span>
  54. <MinimapContainer>{minimap}</MinimapContainer>
  55. <BreakdownContainer>{opsBreakdown}</BreakdownContainer>
  56. <LinkButton
  57. aria-label={t('View Full Waterfall')}
  58. size="sm"
  59. to={AggregateSpanWaterfallLocation}
  60. onClick={() => {
  61. trackAnalytics('insight.vital.overview.open_full_waterfall', {
  62. organization,
  63. });
  64. }}
  65. >
  66. {t('View Full Waterfall')}
  67. </LinkButton>
  68. </span>
  69. );
  70. }
  71. const MinimapContainer = styled('div')`
  72. position: relative;
  73. height: 120px;
  74. `;
  75. // Not ideal, but OpsBreakdown has margins in nested components. Easiest way to update them for now.
  76. const BreakdownContainer = styled('div')`
  77. > div {
  78. margin: 0;
  79. }
  80. margin: ${space(2)} 0;
  81. `;