widgetDetails.tsx 4.1 KB

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