Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 1 addition & 27 deletions static/app/components/modals/projectCreationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,35 +119,12 @@ export default function ProjectCreationModal({
},
});

let ruleId: string | undefined;
if (alertRuleConfig.shouldCreateCustomRule) {
const ruleData = await api.requestPromise(
`/projects/${organization.slug}/${projectData.slug}/rules/`,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint is deprecated and will be deleted soon

{
method: 'POST',
data: {
name: alertRuleConfig.name,
conditions: alertRuleConfig.conditions,
actions: alertRuleConfig.actions,
actionMatch: alertRuleConfig.actionMatch,
frequency: alertRuleConfig.frequency,
},
}
);
ruleId = ruleData.id;
}

ProjectsStore.onCreateSuccess(projectData, organization.slug);
clearIndicators();
trackAnalytics('project_modal.created', {
organization,
issue_alert: alertRuleConfig.defaultRules
? 'Default'
: alertRuleConfig.shouldCreateCustomRule
? 'Custom'
: 'No Rule',
issue_alert: alertRuleConfig.defaultRules ? 'Default' : 'No Rule',
project_id: projectData.id,
rule_id: ruleId || '',
});

addSuccessMessage(`Created project ${projectData.slug}`);
Expand Down Expand Up @@ -179,9 +156,6 @@ export default function ProjectCreationModal({
<Subtitle>{t('Set your alert frequency')}</Subtitle>
<IssueAlertOptions
alertSetting={alertForm?.alertSetting}
interval={alertForm?.interval}
metric={alertForm?.metric}
threshold={alertForm?.threshold}
onFieldChange={(field, value) => {
setAlertForm(prev => ({
...prev,
Expand Down
56 changes: 1 addition & 55 deletions static/app/components/onboarding/scm/scmAlertFrequency.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import {Input} from '@sentry/scraps/input';
import {Grid, Stack} from '@sentry/scraps/layout';
import {Select} from '@sentry/scraps/select';
import {Text} from '@sentry/scraps/text';
import {Stack} from '@sentry/scraps/layout';

import {ScmAlertOptionCard} from 'sentry/components/onboarding/scm/scmAlertOptionCard';
import {t} from 'sentry/locale';
import {
type AlertRuleOptions,
INTERVAL_CHOICES,
METRIC_CHOICES,
RuleAction,
} from 'sentry/views/projectInstall/issueAlertOptions';

Expand All @@ -21,13 +16,9 @@ interface ScmAlertFrequencyProps extends Partial<AlertRuleOptions> {

export function ScmAlertFrequency({
alertSetting = RuleAction.DEFAULT_ALERT,
interval = '1m',
metric = 0,
threshold = '10',
onFieldChange,
}: ScmAlertFrequencyProps) {
const isDefaultSelected = alertSetting === RuleAction.DEFAULT_ALERT;
const isCustomSelected = alertSetting === RuleAction.CUSTOMIZED_ALERTS;
const isLaterSelected = alertSetting === RuleAction.CREATE_ALERT_LATER;

return (
Expand All @@ -39,51 +30,6 @@ export function ScmAlertFrequency({
onSelect={() => onFieldChange('alertSetting', RuleAction.DEFAULT_ALERT)}
/>

<ScmAlertOptionCard
label={t('Custom threshold')}
isSelected={isCustomSelected}
onSelect={() => onFieldChange('alertSetting', RuleAction.CUSTOMIZED_ALERTS)}
>
{isCustomSelected && (
<Stack gap="lg">
<Stack gap="xs">
<Text size="md" density="comfortable">
{t('When there are more than')}
</Text>
<Grid gap="xl" columns={{'screen:sm': '1fr', 'screen:md': '1fr 1fr'}}>
<Input
size="md"
type="number"
min="0"
placeholder="10"
value={threshold}
onChange={e => onFieldChange('threshold', e.target.value)}
/>
<Select
size="md"
value={metric}
options={METRIC_CHOICES}
onChange={option => onFieldChange('metric', option.value)}
menuPortalTarget={document.body}
/>
</Grid>
</Stack>
<Stack gap="xs">
<Text size="md" density="comfortable">
{t('a unique error in')}
</Text>
<Select
size="md"
value={interval}
options={INTERVAL_CHOICES}
onChange={option => onFieldChange('interval', option.value)}
menuPortalTarget={document.body}
/>
</Stack>
</Stack>
)}
</ScmAlertOptionCard>

<ScmAlertOptionCard
label={t("I'll set up alerts later")}
isSelected={isLaterSelected}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export function ScmAlertFrequencySection({
// Summarize the current selection in the collapsed header.
const alertSettingLabel: Record<RuleAction, [string, TagVariant]> = {
[RuleAction.DEFAULT_ALERT]: [t('High priority issues'), 'info'],
[RuleAction.CUSTOMIZED_ALERTS]: [t('Custom'), 'info'],
[RuleAction.CREATE_ALERT_LATER]: [t('Off'), 'muted'],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe('useScmProjectCreation', () => {
);
expect(onProjectCreated).toHaveBeenCalledWith('python');
expect(onSuccess).toHaveBeenCalledWith(
expect.objectContaining({project: createdProject, reused: false, ruleIds: []})
expect.objectContaining({project: createdProject, reused: false})
);
// The slug must be persisted before completion so the duplicate-prevention
// handoff to SDK setup survives a failure later in the sequence.
Expand Down
20 changes: 0 additions & 20 deletions static/app/components/onboarding/scm/useScmProjectCreation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,22 @@ import {addErrorMessage} from 'sentry/actionCreators/indicator';
import {linkProjectToRepository} from 'sentry/components/onboarding/scm/linkProjectToRepository';
import {useCreateProjectAndRules} from 'sentry/components/onboarding/useCreateProjectAndRules';
import {t} from 'sentry/locale';
import type {IssueAlertRule} from 'sentry/types/alerts';
import type {Repository} from 'sentry/types/integrations';
import type {OnboardingSelectedSDK} from 'sentry/types/onboarding';
import type {Team} from 'sentry/types/organization';
import type {Project} from 'sentry/types/project';
import {useOrganization} from 'sentry/utils/useOrganization';
import {useProjects} from 'sentry/utils/useProjects';
import {useTeams} from 'sentry/utils/useTeams';
import type {useCreateNotificationAction} from 'sentry/views/projectInstall/issueAlertNotificationOptions';
import type {RequestDataFragment} from 'sentry/views/projectInstall/issueAlertOptions';

type CreateNotificationAction = ReturnType<
typeof useCreateNotificationAction
>['createNotificationAction'];

export interface ScmProjectCreationResult {
project: Project;
/**
* True when an already-created project was reused (back-nav with an
* unchanged platform) instead of creating a new one.
*/
reused: boolean;
ruleIds: string[];
notificationRule?: IssueAlertRule;
}

interface UseScmProjectCreationOptions {
Expand Down Expand Up @@ -62,15 +54,8 @@ interface CreateOrReuseProjectOptions {
* default (email) rules only.
*/
alertRuleConfig?: Partial<RequestDataFragment>;
/**
* Creates the messaging-integration notification rule, if one is configured.
* Defaults to a no-op (email-only creation).
*/
createNotificationAction?: CreateNotificationAction;
}

const noopNotificationAction: CreateNotificationAction = () => {};

/**
* Shared project + alert-rule creation for the SCM onboarding flow. Both
* experiment branches call this from their respective creation boundaries:
Expand Down Expand Up @@ -105,7 +90,6 @@ export function useScmProjectCreation({
async ({
platform,
alertRuleConfig,
createNotificationAction,
onSuccess,
}: CreateOrReuseProjectOptions): Promise<ScmProjectCreationResult | undefined> => {
if (isCreatingRef.current) {
Expand All @@ -123,7 +107,6 @@ export function useScmProjectCreation({
const result: ScmProjectCreationResult = {
project: existingProject,
reused: true,
ruleIds: [],
};
onSuccess(result);
return result;
Expand All @@ -142,7 +125,6 @@ export function useScmProjectCreation({
platform,
team: firstAdminTeam?.slug,
alertRuleConfig: alertRuleConfig ?? {defaultRules: true},
createNotificationAction: createNotificationAction ?? noopNotificationAction,
})
.catch(error => {
addErrorMessage(t('Failed to create project'));
Expand All @@ -166,8 +148,6 @@ export function useScmProjectCreation({
const result: ScmProjectCreationResult = {
project: creation.project,
reused: false,
ruleIds: creation.ruleIds,
notificationRule: creation.notificationRule,
};
onSuccess(result);
return result;
Expand Down
13 changes: 0 additions & 13 deletions static/app/components/onboarding/scm/useScmProjectDetails.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {act, renderHookWithProviders, waitFor} from 'sentry-test/reactTestingLib
import {ProjectsStore} from 'sentry/stores/projectsStore';
import {TeamStore} from 'sentry/stores/teamStore';
import type {OnboardingSelectedSDK} from 'sentry/types/onboarding';
import * as analytics from 'sentry/utils/analytics';
import {MultipleCheckboxOptions} from 'sentry/views/projectInstall/issueAlertNotificationOptions';
import {
DEFAULT_ISSUE_ALERT_OPTIONS_VALUES,
Expand Down Expand Up @@ -105,18 +104,6 @@ describe('useScmProjectDetails', () => {
jest.restoreAllMocks();
});

it('tracks threshold edits for SCM project creation', () => {
const trackAnalyticsSpy = jest.spyOn(analytics, 'trackAnalytics');
const {result} = renderDetails();

act(() => result.current.onAlertChange('threshold', '10'));

expect(trackAnalyticsSpy).toHaveBeenCalledWith(
'project_creation.alert_threshold_edited',
expect.objectContaining({field: 'threshold', variant: 'scm'})
);
});

it('requires an integration channel when notifying via integration', () => {
TeamStore.loadInitialData([adminTeam]);
ProjectsStore.loadInitialData([]);
Expand Down
32 changes: 6 additions & 26 deletions static/app/components/onboarding/scm/useScmProjectDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,8 @@ export function useScmProjectDetails({
);

// Provides the messaging-integration notification picker (notificationProps,
// rendered in ScmAlertFrequencySection) and the side-effect that creates the
// chosen notification rule at project creation.
const {createNotificationAction, notificationProps} = useScmNotificationAction(
// rendered in ScmAlertFrequencySection).
const {notificationProps} = useScmNotificationAction(
restoredNotificationSelectionRef.current
);

Expand Down Expand Up @@ -213,18 +212,11 @@ export function useScmProjectDetails({
if (key === 'alertSetting') {
const optionMap: Record<number, string> = {
[RuleAction.DEFAULT_ALERT]: 'high_priority',
[RuleAction.CUSTOMIZED_ALERTS]: 'custom',
[RuleAction.CREATE_ALERT_LATER]: 'create_later',
};
trackAnalytics('project_creation.project_details_alert_selected', {
organization,
option: optionMap[value as number] ?? String(value),
variant: 'scm',
});
} else if (key === 'threshold' || key === 'metric' || key === 'interval') {
trackAnalytics('project_creation.alert_threshold_edited', {
organization,
field: key,
option: optionMap[value] ?? String(value),
variant: 'scm',
});
}
Expand Down Expand Up @@ -320,9 +312,6 @@ export function useScmProjectDetails({
projectNameResolved === savedForm.projectName &&
teamSlugResolved === savedForm.teamSlug &&
alertRuleConfig.alertSetting === savedAlert?.alertSetting &&
alertRuleConfig.interval === savedAlert?.interval &&
alertRuleConfig.metric === savedAlert?.metric &&
alertRuleConfig.threshold === savedAlert?.threshold &&
isEqual(
hasNotificationAction ? buildNotificationSelection(notificationProps) : undefined,
savedForm?.notificationSelection
Expand Down Expand Up @@ -350,13 +339,10 @@ export function useScmProjectDetails({
notificationSelection,
};
// Mirror the legacy project_creation_page.created `issue_alert` breakdown
// (see createProject.tsx): Custom > Default > No Rule, derived from the
// configured alert setting.
// (see createProject.tsx): Default > No Rule, derived from the configured
// alert setting.
let issueAlert: 'Custom' | 'Default' | 'No Rule';
switch (alertRuleConfig.alertSetting) {
case RuleAction.CUSTOMIZED_ALERTS:
issueAlert = 'Custom';
break;
case RuleAction.CREATE_ALERT_LATER:
issueAlert = 'No Rule';
break;
Expand All @@ -377,8 +363,6 @@ export function useScmProjectDetails({
project_id: existingProject.id,
platform: selectedPlatform.key,
issue_alert: issueAlert,
notification_rule_created: false,
rule_ids: [],
variant: 'scm',
});
onComplete({project: existingProject, projectDetailsForm: submittedForm});
Expand All @@ -391,7 +375,6 @@ export function useScmProjectDetails({
platform: selectedPlatform,
team: isOrgMemberWithNoAccess ? undefined : teamSlugResolved,
alertRuleConfig: getRequestDataFragment(alertRuleConfig),
createNotificationAction,
})
.catch(error => {
trackAnalytics('project_creation.project_details_create_failed', {
Expand All @@ -411,7 +394,7 @@ export function useScmProjectDetails({
if (!creation) {
return;
}
const {project, ruleIds, notificationRule} = creation;
const {project} = creation;

if (selectedRepository?.id) {
await linkProjectToRepository({
Expand All @@ -426,8 +409,6 @@ export function useScmProjectDetails({
project_id: project.id,
platform: selectedPlatform.key,
issue_alert: issueAlert,
notification_rule_created: !!notificationRule,
rule_ids: ruleIds,
variant: 'scm',
});

Expand All @@ -440,7 +421,6 @@ export function useScmProjectDetails({
accessTeams,
alertRuleConfig,
canSubmit,
createNotificationAction,
createProjectAndRules,
existingProject,
hasNotificationAction,
Expand Down
Loading
Loading