widgetDetails.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import {useCallback, useMemo, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {TabList, TabPanels, Tabs} from 'sentry/components/tabs';
  4. import {Tooltip} from 'sentry/components/tooltip';
  5. import {t} from 'sentry/locale';
  6. import {space} from 'sentry/styles/space';
  7. import {trackAnalytics} from 'sentry/utils/analytics';
  8. import {isCustomMetric} from 'sentry/utils/metrics';
  9. import type {MetricWidgetQueryParams} from 'sentry/utils/metrics/types';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. import {CodeLocations} from 'sentry/views/ddm/codeLocations';
  12. import {useDDMContext} from 'sentry/views/ddm/context';
  13. import {SampleTable} from 'sentry/views/ddm/sampleTable';
  14. import {getQueryWithFocusedSeries} from 'sentry/views/ddm/utils';
  15. enum Tab {
  16. SAMPLES = 'samples',
  17. CODE_LOCATIONS = 'codeLocations',
  18. }
  19. export function WidgetDetails() {
  20. const organization = useOrganization();
  21. const {selectedWidgetIndex, widgets, focusArea, setHighlightedSampleId} =
  22. useDDMContext();
  23. const [selectedTab, setSelectedTab] = useState(Tab.SAMPLES);
  24. const selectedWidget = widgets[selectedWidgetIndex] as
  25. | MetricWidgetQueryParams
  26. | undefined;
  27. const isCodeLocationsDisabled =
  28. selectedWidget?.mri && !isCustomMetric({mri: selectedWidget.mri});
  29. if (isCodeLocationsDisabled && selectedTab === Tab.CODE_LOCATIONS) {
  30. setSelectedTab(Tab.SAMPLES);
  31. }
  32. const queryWithFocusedSeries = useMemo(
  33. () => selectedWidget && getQueryWithFocusedSeries(selectedWidget),
  34. [selectedWidget]
  35. );
  36. const handleSampleRowHover = useCallback(
  37. (sampleId?: string) => {
  38. setHighlightedSampleId(sampleId);
  39. },
  40. [setHighlightedSampleId]
  41. );
  42. const handleTabChange = useCallback(
  43. (tab: Tab) => {
  44. if (tab === Tab.CODE_LOCATIONS) {
  45. trackAnalytics('ddm.code-locations', {
  46. organization,
  47. });
  48. }
  49. setSelectedTab(tab);
  50. },
  51. [organization]
  52. );
  53. return (
  54. <TrayWrapper>
  55. <Tabs value={selectedTab} onChange={handleTabChange}>
  56. <TabList>
  57. <TabList.Item key={Tab.SAMPLES}>{t('Sampled Events')}</TabList.Item>
  58. <TabList.Item
  59. textValue={t('Code Location')}
  60. key={Tab.CODE_LOCATIONS}
  61. disabled={isCodeLocationsDisabled}
  62. >
  63. <Tooltip
  64. title={t(
  65. 'This metric is automatically collected by Sentry. It is not bound to a specific line of your code.'
  66. )}
  67. disabled={!isCodeLocationsDisabled}
  68. >
  69. <span style={{pointerEvents: 'all'}}>{t('Code Location')}</span>
  70. </Tooltip>
  71. </TabList.Item>
  72. </TabList>
  73. <ContentWrapper>
  74. <TabPanels>
  75. <TabPanels.Item key={Tab.SAMPLES}>
  76. <SampleTable
  77. mri={selectedWidget?.mri}
  78. query={queryWithFocusedSeries}
  79. {...focusArea?.selection?.range}
  80. onRowHover={handleSampleRowHover}
  81. />
  82. </TabPanels.Item>
  83. <TabPanels.Item key={Tab.CODE_LOCATIONS}>
  84. <CodeLocations mri={selectedWidget?.mri} {...focusArea?.selection?.range} />
  85. </TabPanels.Item>
  86. </TabPanels>
  87. </ContentWrapper>
  88. </Tabs>
  89. </TrayWrapper>
  90. );
  91. }
  92. const TrayWrapper = styled('div')`
  93. padding-top: ${space(4)};
  94. display: grid;
  95. grid-template-rows: auto auto 1fr;
  96. `;
  97. const ContentWrapper = styled('div')`
  98. position: relative;
  99. padding: ${space(2)} 0;
  100. `;