widgetDetails.tsx 3.9 KB

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