dataSetStep.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import {useEffect, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import Alert from 'sentry/components/alert';
  4. import FeatureBadge from 'sentry/components/badge/featureBadge';
  5. import {Button} from 'sentry/components/button';
  6. import type {RadioGroupProps} from 'sentry/components/forms/controls/radioGroup';
  7. import RadioGroup from 'sentry/components/forms/controls/radioGroup';
  8. import ExternalLink from 'sentry/components/links/externalLink';
  9. import {IconClose} from 'sentry/icons';
  10. import {t, tct} from 'sentry/locale';
  11. import {space} from 'sentry/styles/space';
  12. import {DatasetSource} from 'sentry/utils/discover/types';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import {DisplayType, type WidgetType} from 'sentry/views/dashboards/types';
  15. import {hasDatasetSelector} from 'sentry/views/dashboards/utils';
  16. import {DATASET_LABEL_MAP} from 'sentry/views/discover/savedQuery/datasetSelectorTabs';
  17. import {DataSet} from '../utils';
  18. import {BuildStep} from './buildStep';
  19. function DiscoverSplitAlert({onDismiss, splitDecision}) {
  20. const splitAlertMessage = splitDecision
  21. ? tct(
  22. "We're splitting our datasets up to make it a bit easier to digest. We defaulted this widget to [splitDecision]. Edit as you see fit.",
  23. {splitDecision: DATASET_LABEL_MAP[splitDecision]}
  24. )
  25. : null;
  26. return (
  27. <Alert
  28. type="warning"
  29. showIcon
  30. trailingItems={
  31. <StyledCloseButton
  32. icon={<IconClose size="sm" />}
  33. aria-label={t('Close')}
  34. onClick={onDismiss}
  35. size="zero"
  36. borderless
  37. />
  38. }
  39. >
  40. {splitAlertMessage}
  41. </Alert>
  42. );
  43. }
  44. interface Props {
  45. dataSet: DataSet;
  46. displayType: DisplayType;
  47. onChange: (dataSet: DataSet) => void;
  48. source?: DatasetSource;
  49. splitDecision?: WidgetType;
  50. }
  51. export function DataSetStep({
  52. dataSet,
  53. onChange,
  54. displayType,
  55. splitDecision,
  56. source,
  57. }: Props) {
  58. const [showSplitAlert, setShowSplitAlert] = useState<boolean>(
  59. source === DatasetSource.FORCED
  60. );
  61. const organization = useOrganization();
  62. const disabledChoices: RadioGroupProps<string>['disabledChoices'] = [];
  63. const hasDatasetSelectorFeature = hasDatasetSelector(organization);
  64. useEffect(() => {
  65. setShowSplitAlert(!!splitDecision);
  66. }, [splitDecision]);
  67. if (displayType !== DisplayType.TABLE) {
  68. disabledChoices.push([
  69. DataSet.ISSUES,
  70. t('This dataset is restricted to tabular visualization.'),
  71. ]);
  72. }
  73. const datasetChoices = new Map<string, string | React.ReactNode>();
  74. if (hasDatasetSelectorFeature) {
  75. // TODO: Finalize description copy
  76. datasetChoices.set(DataSet.ERRORS, t('Errors (TypeError, InvalidSearchQuery, etc)'));
  77. datasetChoices.set(DataSet.TRANSACTIONS, t('Transactions'));
  78. }
  79. if (!hasDatasetSelectorFeature) {
  80. datasetChoices.set(DataSet.EVENTS, t('Errors and Transactions'));
  81. }
  82. if (organization.features.includes('dashboards-eap')) {
  83. datasetChoices.set(
  84. DataSet.SPANS,
  85. <FeatureBadgeAlignmentWrapper aria-label={t('Spans')}>
  86. {t('Spans')} <FeatureBadge type="alpha" />
  87. </FeatureBadgeAlignmentWrapper>
  88. );
  89. }
  90. datasetChoices.set(DataSet.ISSUES, t('Issues (States, Assignment, Time, etc.)'));
  91. datasetChoices.set(DataSet.RELEASES, t('Releases (Sessions, Crash rates)'));
  92. return (
  93. <BuildStep
  94. title={t('Choose your dataset')}
  95. description={tct(
  96. `This reflects the type of information you want to use. To learn more, [link: read the docs].`,
  97. {
  98. link: (
  99. <ExternalLink href="https://docs.sentry.io/product/dashboards/widget-builder/#choose-your-dataset" />
  100. ),
  101. }
  102. )}
  103. >
  104. {showSplitAlert && hasDatasetSelectorFeature && (
  105. <DiscoverSplitAlert
  106. onDismiss={() => setShowSplitAlert(false)}
  107. splitDecision={splitDecision}
  108. />
  109. )}
  110. <DataSetChoices
  111. label="dataSet"
  112. value={dataSet}
  113. choices={[...datasetChoices.entries()]}
  114. disabledChoices={disabledChoices}
  115. onChange={newDataSet => {
  116. onChange(newDataSet as DataSet);
  117. }}
  118. orientInline
  119. />
  120. </BuildStep>
  121. );
  122. }
  123. const DataSetChoices = styled(RadioGroup)`
  124. display: flex;
  125. flex-wrap: wrap;
  126. gap: ${space(2)};
  127. `;
  128. const StyledCloseButton = styled(Button)`
  129. background-color: transparent;
  130. transition: opacity 0.1s linear;
  131. &:hover,
  132. &:focus {
  133. background-color: transparent;
  134. opacity: 1;
  135. }
  136. `;
  137. const FeatureBadgeAlignmentWrapper = styled('div')`
  138. ${FeatureBadge} {
  139. position: relative;
  140. top: -1px;
  141. }
  142. `;