widgetDetails.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import {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 {isCustomMetric} from 'sentry/utils/metrics';
  8. import type {MetricWidgetQueryParams} from 'sentry/utils/metrics/types';
  9. import {CodeLocations} from 'sentry/views/ddm/codeLocations';
  10. import {useDDMContext} from 'sentry/views/ddm/context';
  11. import {SampleTable} from 'sentry/views/ddm/sampleTable';
  12. enum Tab {
  13. SAMPLES = 'samples',
  14. CODE_LOCATIONS = 'codeLocations',
  15. }
  16. const constructQueryString = (queryObject: Record<string, string>) => {
  17. return Object.entries(queryObject)
  18. .map(([key, value]) => `${key}:"${value}"`)
  19. .join(' ');
  20. };
  21. export function WidgetDetails() {
  22. const {
  23. selectedWidgetIndex,
  24. widgets,
  25. focusArea,
  26. highlightedSampleId,
  27. setHighlightedSampleId,
  28. } = useDDMContext();
  29. const [selectedTab, setSelectedTab] = useState(Tab.SAMPLES);
  30. // the tray is minimized when the main content is maximized
  31. const selectedWidget = widgets[selectedWidgetIndex] as
  32. | MetricWidgetQueryParams
  33. | undefined;
  34. const isCodeLocationsDisabled =
  35. selectedWidget?.mri && !isCustomMetric({mri: selectedWidget.mri});
  36. if (isCodeLocationsDisabled && selectedTab === Tab.CODE_LOCATIONS) {
  37. setSelectedTab(Tab.SAMPLES);
  38. }
  39. const handleSampleRowHover = (sampleId?: string) => {
  40. setHighlightedSampleId(sampleId);
  41. };
  42. return (
  43. <TrayWrapper>
  44. <Tabs value={selectedTab} onChange={setSelectedTab}>
  45. <TabList>
  46. <TabList.Item key={Tab.SAMPLES}>{t('Samples')}</TabList.Item>
  47. <TabList.Item
  48. textValue={t('Code Location')}
  49. key={Tab.CODE_LOCATIONS}
  50. disabled={isCodeLocationsDisabled}
  51. >
  52. <Tooltip
  53. title={t(
  54. 'This metric is automatically collected by Sentry. It is not bound to a specific line of your code.'
  55. )}
  56. disabled={!isCodeLocationsDisabled}
  57. >
  58. <span style={{pointerEvents: 'all'}}>{t('Code Location')}</span>
  59. </Tooltip>
  60. </TabList.Item>
  61. </TabList>
  62. <ContentWrapper>
  63. <TabPanels>
  64. <TabPanels.Item key={Tab.SAMPLES}>
  65. <SampleTable
  66. mri={selectedWidget?.mri}
  67. query={
  68. selectedWidget?.focusedSeries?.groupBy
  69. ? `${selectedWidget.query} ${constructQueryString(
  70. selectedWidget.focusedSeries.groupBy
  71. )}`.trim()
  72. : selectedWidget?.query
  73. }
  74. {...focusArea?.selection?.range}
  75. highlightedRow={highlightedSampleId}
  76. onRowHover={handleSampleRowHover}
  77. />
  78. </TabPanels.Item>
  79. <TabPanels.Item key={Tab.CODE_LOCATIONS}>
  80. <CodeLocations mri={selectedWidget?.mri} {...focusArea?.selection?.range} />
  81. </TabPanels.Item>
  82. </TabPanels>
  83. </ContentWrapper>
  84. </Tabs>
  85. </TrayWrapper>
  86. );
  87. }
  88. const TrayWrapper = styled('div')`
  89. padding-top: ${space(4)};
  90. display: grid;
  91. grid-template-rows: auto auto 1fr;
  92. `;
  93. const ContentWrapper = styled('div')`
  94. position: relative;
  95. padding: ${space(2)} 0;
  96. `;