Browse Source

feat(discover): Get samples works with dataset selector (#75253)

Only show get samples when transactions dataset is selected
Append `event.type:transaction` to `/dynamic-sampling/custom-rules/`
call
if transactions dataset is selected (since event.type:transaction
condition
is redundant and we don't expect the user to add it) otherwise, it fails
validation.
Shruthi 7 months ago
parent
commit
147ad51317

+ 54 - 2
static/app/components/dynamicSampling/investigationRule.spec.tsx

@@ -4,6 +4,7 @@ import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
 import {addErrorMessage} from 'sentry/actionCreators/indicator';
 import {InvestigationRuleCreation} from 'sentry/components/dynamicSampling/investigationRule';
 import EventView from 'sentry/utils/discover/eventView';
+import {DiscoverDatasets} from 'sentry/utils/discover/types';
 
 jest.mock('sentry/actionCreators/indicator');
 
@@ -36,7 +37,15 @@ describe('InvestigationRule', function () {
     };
   }
 
-  function initComponentEnvironment({hasRule}) {
+  function initComponentEnvironment({
+    hasRule,
+    dataset,
+    query,
+  }: {
+    hasRule: boolean;
+    dataset?: DiscoverDatasets;
+    query?: string;
+  }) {
     initialize();
 
     if (hasRule) {
@@ -60,7 +69,8 @@ describe('InvestigationRule', function () {
       version: 2,
       fields: ['transaction', 'count()'],
       projects: [project.id],
-      query: 'event.type:transaction',
+      query: query ?? 'event.type:transaction',
+      dataset,
     });
   }
 
@@ -214,6 +224,48 @@ describe('InvestigationRule', function () {
     expect(sencondResponse).toHaveBeenCalledTimes(1);
   });
 
+  it('appends event type condiiton if dataset is transactions', async function () {
+    initComponentEnvironment({
+      hasRule: false,
+      dataset: DiscoverDatasets.TRANSACTIONS,
+      query: 'branch:main',
+    });
+    organization.features = ['performance-discover-dataset-selector'];
+
+    const createRule = MockApiClient.addMockResponse({
+      url: '/organizations/org-slug/dynamic-sampling/custom-rules/',
+      method: 'POST',
+    });
+
+    render(
+      <InvestigationRuleCreation buttonProps={{}} eventView={eventView} numSamples={1} />,
+      {organization}
+    );
+    // wait for the button to appear
+    const button = await screen.findByRole('button', {name: buttonText});
+    expect(button).toBeInTheDocument();
+    // make sure we are not showing the label
+    const labels = screen.queryAllByText(labelText);
+    expect(labels).toHaveLength(0);
+
+    // check we did call the endpoint to check if a rule exists
+    expect(getRuleMock).toHaveBeenCalledWith(
+      '/organizations/org-slug/dynamic-sampling/custom-rules/',
+      expect.objectContaining({
+        query: expect.objectContaining({query: 'event.type:transaction (branch:main)'}),
+      })
+    );
+
+    // now the user creates a rule
+    await userEvent.click(button);
+    expect(createRule).toHaveBeenCalledWith(
+      '/organizations/org-slug/dynamic-sampling/custom-rules/',
+      expect.objectContaining({
+        data: expect.objectContaining({query: 'event.type:transaction (branch:main)'}),
+      })
+    );
+  });
+
   it('should show an error when creating a new rule fails', async function () {
     initComponentEnvironment({hasRule: false});
     const createRule = MockApiClient.addMockResponse({

+ 22 - 4
static/app/components/dynamicSampling/investigationRule.tsx

@@ -13,6 +13,7 @@ import {space} from 'sentry/styles/space';
 import type {Organization} from 'sentry/types/organization';
 import {trackAnalytics} from 'sentry/utils/analytics';
 import type EventView from 'sentry/utils/discover/eventView';
+import {DiscoverDatasets} from 'sentry/utils/discover/types';
 import type {ApiQueryKey} from 'sentry/utils/queryClient';
 import {useApiQuery, useMutation, useQueryClient} from 'sentry/utils/queryClient';
 import type RequestError from 'sentry/utils/requestError/requestError';
@@ -20,6 +21,7 @@ import useApi from 'sentry/utils/useApi';
 import useOrganization from 'sentry/utils/useOrganization';
 import {Datasource} from 'sentry/views/alerts/rules/metric/types';
 import {getQueryDatasource} from 'sentry/views/alerts/utils';
+import {hasDatasetSelector} from 'sentry/views/dashboards/utils';
 
 // Number of samples under which we can trigger an investigation rule
 const INVESTIGATION_MAX_SAMPLES_TRIGGER = 5;
@@ -179,12 +181,21 @@ const InvestigationInProgressNotification = styled('span')`
 `;
 
 function InvestigationRuleCreationInternal(props: PropsInternal) {
+  const {organization, eventView} = props;
   const projects = [...props.eventView.project];
-  const organization = props.organization;
-  const period = props.eventView.statsPeriod || null;
-  const query = props.eventView.getQuery();
+  const period = eventView.statsPeriod || null;
+
+  const isTransactionsDataset =
+    hasDatasetSelector(organization) &&
+    eventView.dataset === DiscoverDatasets.TRANSACTIONS;
+
+  const query = isTransactionsDataset
+    ? appendEventTypeCondition(eventView.getQuery())
+    : eventView.getQuery();
   const isTransactionQueryMissing =
-    getQueryDatasource(query)?.source !== Datasource.TRANSACTION;
+    getQueryDatasource(query)?.source !== Datasource.TRANSACTION &&
+    !isTransactionsDataset;
+
   const createInvestigationRule = useCreateInvestigationRuleMutation();
   const {
     data: rule,
@@ -290,3 +301,10 @@ const StyledIconQuestion = styled(IconQuestion)`
   position: relative;
   top: 2px;
 `;
+
+function appendEventTypeCondition(query: string) {
+  if (query.length > 0) {
+    return `event.type:transaction (${query})`;
+  }
+  return 'event.type:transaction';
+}

+ 20 - 9
static/app/views/discover/table/tableActions.tsx

@@ -15,7 +15,10 @@ import {trackAnalytics} from 'sentry/utils/analytics';
 import {parseCursor} from 'sentry/utils/cursor';
 import type {TableData} from 'sentry/utils/discover/discoverQuery';
 import type EventView from 'sentry/utils/discover/eventView';
+import {SavedQueryDatasets} from 'sentry/utils/discover/types';
 import {useLocation} from 'sentry/utils/useLocation';
+import useOrganization from 'sentry/utils/useOrganization';
+import {hasDatasetSelector} from 'sentry/views/dashboards/utils';
 
 import {downloadAsCsv} from '../utils';
 
@@ -30,6 +33,7 @@ type Props = {
   showTags: boolean;
   tableData: TableData | null | undefined;
   title: string;
+  queryDataset?: SavedQueryDatasets;
   supportsInvestigationRule?: boolean;
 };
 
@@ -159,21 +163,28 @@ function FeatureWrapper(props: FeatureWrapperProps) {
 }
 
 function TableActions(props: Props) {
+  const {tableData, queryDataset, supportsInvestigationRule} = props;
   const location = useLocation();
+  const organization = useOrganization();
   const cursor = location?.query?.cursor;
   const cursorOffset = parseCursor(cursor)?.offset ?? 0;
-  const numSamples = props.tableData?.data?.length ?? null;
+  const numSamples = tableData?.data?.length ?? null;
   const totalNumSamples = numSamples === null ? null : numSamples + cursorOffset;
+
+  const isTransactions =
+    hasDatasetSelector(organization) && queryDataset === SavedQueryDatasets.TRANSACTIONS;
+
   return (
     <Fragment>
-      {props.supportsInvestigationRule && (
-        <InvestigationRuleCreation
-          {...props}
-          buttonProps={{size: 'sm'}}
-          numSamples={totalNumSamples}
-          key="investigationRuleCreation"
-        />
-      )}
+      {supportsInvestigationRule &&
+        (!hasDatasetSelector(organization) || isTransactions) && (
+          <InvestigationRuleCreation
+            {...props}
+            buttonProps={{size: 'sm'}}
+            numSamples={totalNumSamples}
+            key="investigationRuleCreation"
+          />
+        )}
       <FeatureWrapper {...props} key="edit">
         {renderEditButton}
       </FeatureWrapper>

+ 2 - 0
static/app/views/discover/table/tableView.tsx

@@ -672,6 +672,7 @@ function TableView(props: TableViewProps) {
       location,
       onChangeShowTags,
       showTags,
+      queryDataset,
     } = props;
 
     return (
@@ -687,6 +688,7 @@ function TableView(props: TableViewProps) {
         onChangeShowTags={onChangeShowTags}
         showTags={showTags}
         supportsInvestigationRule
+        queryDataset={queryDataset}
       />
     );
   }