trayContent.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import {useContext, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Button} from 'sentry/components/button';
  4. import EmptyMessage from 'sentry/components/emptyMessage';
  5. import {SplitPanelContext} from 'sentry/components/splitPanel';
  6. import {TabList, Tabs} from 'sentry/components/tabs';
  7. import {Tooltip} from 'sentry/components/tooltip';
  8. import {IconChevron, IconSearch} from 'sentry/icons';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. import {isCustomMetric, MetricWidgetQueryParams} from 'sentry/utils/metrics';
  12. import {formatMRI} from 'sentry/utils/metrics/mri';
  13. import {CodeLocations} from 'sentry/views/ddm/codeLocations';
  14. import {useDDMContext} from 'sentry/views/ddm/context';
  15. import {TraceTable} from 'sentry/views/ddm/traceTable';
  16. enum Tab {
  17. SAMPLES = 'samples',
  18. CODE_LOCATIONS = 'codeLocations',
  19. }
  20. export function TrayContent() {
  21. const {selectedWidgetIndex, widgets} = useDDMContext();
  22. const [selectedTab, setSelectedTab] = useState(Tab.CODE_LOCATIONS);
  23. const {isMaximized, maximiseSize, resetSize} = useContext(SplitPanelContext);
  24. // the tray is minimized when the main content is maximized
  25. const trayIsMinimized = isMaximized;
  26. const selectedWidget = widgets[selectedWidgetIndex] as
  27. | MetricWidgetQueryParams
  28. | undefined;
  29. const isCodeLocationsDisabled =
  30. selectedWidget?.mri && !isCustomMetric({mri: selectedWidget.mri});
  31. if (isCodeLocationsDisabled && selectedTab === Tab.CODE_LOCATIONS) {
  32. setSelectedTab(Tab.SAMPLES);
  33. }
  34. return (
  35. <TrayWrapper>
  36. <Header>
  37. <Title>
  38. {selectedWidget?.mri
  39. ? formatMRI(selectedWidget.mri)
  40. : t('Choose a metric to display data')}
  41. </Title>
  42. <ToggleButton
  43. size="xs"
  44. isMinimized={trayIsMinimized}
  45. icon={<IconChevron />}
  46. onClick={trayIsMinimized ? resetSize : maximiseSize}
  47. aria-label={trayIsMinimized ? t('show') : t('hide')}
  48. />
  49. </Header>
  50. <Tabs value={selectedTab} onChange={setSelectedTab}>
  51. <StyledTabList>
  52. <TabList.Item
  53. textValue={t('Code Location')}
  54. key={Tab.CODE_LOCATIONS}
  55. disabled={isCodeLocationsDisabled}
  56. >
  57. <Tooltip
  58. title={t(
  59. 'This metric is automatically collected by Sentry. It is not bound to a specific line of your code.'
  60. )}
  61. disabled={!isCodeLocationsDisabled}
  62. >
  63. <span style={{pointerEvents: 'all'}}>{t('Code Location')}</span>
  64. </Tooltip>
  65. </TabList.Item>
  66. <TabList.Item key={Tab.SAMPLES}>{t('Samples')}</TabList.Item>
  67. </StyledTabList>
  68. </Tabs>
  69. <ContentWrapper>
  70. {!selectedWidget?.mri ? (
  71. <CenterContent>
  72. <EmptyMessage
  73. style={{margin: 'auto'}}
  74. icon={<IconSearch size="xxl" />}
  75. title={t('Nothing to show!')}
  76. description={t('Choose a metric to display data.')}
  77. />
  78. </CenterContent>
  79. ) : selectedTab === Tab.SAMPLES ? (
  80. <TraceTable
  81. // Force re-render when selectedWidget changes so the mocked data updates
  82. // TODO: remove this when we have real data
  83. key={selectedWidget.mri}
  84. />
  85. ) : (
  86. <CodeLocations mri={selectedWidget.mri} />
  87. )}
  88. </ContentWrapper>
  89. </TrayWrapper>
  90. );
  91. }
  92. const TrayWrapper = styled('div')`
  93. height: 100%;
  94. background-color: ${p => p.theme.background};
  95. z-index: ${p => p.theme.zIndex.sidebar};
  96. display: grid;
  97. grid-template-rows: auto auto 1fr;
  98. `;
  99. const Header = styled('div')`
  100. display: flex;
  101. flex-direction: row;
  102. justify-content: space-between;
  103. align-items: center;
  104. padding: 0 ${space(4)};
  105. height: 32px;
  106. background-color: ${p => p.theme.backgroundSecondary};
  107. `;
  108. const Title = styled('div')`
  109. font-size: ${p => p.theme.fontSizeLarge};
  110. font-weight: bold;
  111. `;
  112. const ToggleButton = styled(Button)<{isMinimized}>`
  113. & svg {
  114. transform: rotate(${p => (p.isMinimized ? '0deg' : '180deg')});
  115. }
  116. `;
  117. const StyledTabList = styled(TabList)`
  118. padding: 0 ${space(4)};
  119. background-color: ${p => p.theme.backgroundSecondary};
  120. `;
  121. const ContentWrapper = styled('div')`
  122. position: relative;
  123. padding: ${space(2)} ${space(4)};
  124. overflow: auto;
  125. `;
  126. const CenterContent = styled('div')`
  127. display: flex;
  128. justify-content: center;
  129. align-items: center;
  130. height: 100%;
  131. `;