widgetDetails.tsx 3.0 KB

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