diff --git a/static/app/views/alerts/create.tsx b/static/app/views/alerts/create.tsx index 8686478f02fe43..87e71136857e3c 100644 --- a/static/app/views/alerts/create.tsx +++ b/static/app/views/alerts/create.tsx @@ -3,6 +3,7 @@ import {browserHistory, RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import * as Layout from 'app/components/layouts/thirds'; +import LoadingIndicator from 'app/components/loadingIndicator'; import SentryDocumentTitle from 'app/components/sentryDocumentTitle'; import {t} from 'app/locale'; import space from 'app/styles/space'; @@ -10,6 +11,7 @@ import {Organization, Project} from 'app/types'; import {trackAnalyticsEvent} from 'app/utils/analytics'; import EventView from 'app/utils/discover/eventView'; import {uniqueId} from 'app/utils/guid'; +import Teams from 'app/utils/teams'; import BuilderBreadCrumbs from 'app/views/alerts/builder/builderBreadCrumbs'; import IncidentRulesCreate from 'app/views/alerts/incidentRules/create'; import IssueRuleEditor from 'app/views/alerts/issueRuleEditor'; @@ -128,20 +130,35 @@ class Create extends Component { - {(!hasMetricAlerts || alertType === 'issue') && ( - - )} - - {hasMetricAlerts && alertType === 'metric' && ( - - )} + + {({teams, initiallyLoaded}) => + initiallyLoaded ? ( + + {(!hasMetricAlerts || alertType === 'issue') && ( + id)} + /> + )} + + {hasMetricAlerts && alertType === 'metric' && ( + id)} + /> + )} + + ) : ( + + ) + } + diff --git a/static/app/views/alerts/edit.tsx b/static/app/views/alerts/edit.tsx index 82566f28eb2492..47c6ebd1415f3c 100644 --- a/static/app/views/alerts/edit.tsx +++ b/static/app/views/alerts/edit.tsx @@ -3,11 +3,13 @@ import {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import * as Layout from 'app/components/layouts/thirds'; +import LoadingIndicator from 'app/components/loadingIndicator'; import SentryDocumentTitle from 'app/components/sentryDocumentTitle'; import {t} from 'app/locale'; import space from 'app/styles/space'; import {Organization, Project} from 'app/types'; import {trackAnalyticsEvent} from 'app/utils/analytics'; +import Teams from 'app/utils/teams'; import BuilderBreadCrumbs from 'app/views/alerts/builder/builderBreadCrumbs'; import IncidentRulesDetails from 'app/views/alerts/incidentRules/details'; import IssueEditor from 'app/views/alerts/issueRuleEditor'; @@ -83,20 +85,32 @@ class ProjectAlertsEditor extends Component { - {(!hasMetricAlerts || alertType === 'issue') && ( - - )} - {hasMetricAlerts && alertType === 'metric' && ( - - )} + + {({teams, initiallyLoaded}) => + initiallyLoaded ? ( + + {(!hasMetricAlerts || alertType === 'issue') && ( + id)} + /> + )} + {hasMetricAlerts && alertType === 'metric' && ( + id)} + /> + )} + + ) : ( + + ) + } + diff --git a/static/app/views/alerts/incidentRules/create.tsx b/static/app/views/alerts/incidentRules/create.tsx index 4a281cf4a97f0d..5fafb98c2470fe 100644 --- a/static/app/views/alerts/incidentRules/create.tsx +++ b/static/app/views/alerts/incidentRules/create.tsx @@ -1,9 +1,8 @@ import {RouteComponentProps} from 'react-router'; -import {Organization, Project, Team} from 'app/types'; +import {Organization, Project} from 'app/types'; import {metric} from 'app/utils/analytics'; import EventView from 'app/utils/discover/eventView'; -import withTeams from 'app/utils/withTeams'; import { createDefaultRule, createRuleFromEventView, @@ -23,7 +22,7 @@ type Props = { organization: Organization; project: Project; eventView: EventView | undefined; - teams: Team[]; + userTeamIds: string[]; wizardTemplate?: WizardRuleTemplate; sessionId?: string; isCustomMetric?: boolean; @@ -41,15 +40,14 @@ function IncidentRulesCreate(props: Props) { router.push(`/organizations/${orgId}/alerts/rules/`); } - const {project, eventView, wizardTemplate, sessionId, teams, ...otherProps} = props; + const {project, eventView, wizardTemplate, sessionId, userTeamIds, ...otherProps} = + props; const defaultRule = eventView ? createRuleFromEventView(eventView) : wizardTemplate ? createRuleFromWizardTemplate(wizardTemplate) : createDefaultRule(); - const userTeamIds = teams.filter(({isMember}) => isMember).map(({id}) => id); - const projectTeamIds = new Set(project.teams.map(({id}) => id)); const defaultOwnerId = userTeamIds.find(id => projectTeamIds.has(id)) ?? null; defaultRule.owner = defaultOwnerId && `team:${defaultOwnerId}`; @@ -66,4 +64,4 @@ function IncidentRulesCreate(props: Props) { ); } -export default withTeams(IncidentRulesCreate); +export default IncidentRulesCreate; diff --git a/static/app/views/alerts/incidentRules/details.tsx b/static/app/views/alerts/incidentRules/details.tsx index e496d86edb6ac3..4641be90fe4af9 100644 --- a/static/app/views/alerts/incidentRules/details.tsx +++ b/static/app/views/alerts/incidentRules/details.tsx @@ -1,8 +1,7 @@ import {RouteComponentProps} from 'react-router'; -import {Organization, Project, Team} from 'app/types'; +import {Organization, Project} from 'app/types'; import {metric} from 'app/utils/analytics'; -import withTeams from 'app/utils/withTeams'; import RuleForm from 'app/views/alerts/incidentRules/ruleForm'; import {IncidentRule} from 'app/views/alerts/incidentRules/types'; import AsyncView from 'app/views/asyncView'; @@ -17,7 +16,7 @@ type Props = { organization: Organization; onChangeTitle: (data: string) => void; project: Project; - teams: Team[]; + userTeamIds: string[]; } & RouteComponentProps; type State = { @@ -54,22 +53,18 @@ class IncidentRulesDetails extends AsyncView { }; renderBody() { - const {teams} = this.props; const {ruleId} = this.props.params; const {rule} = this.state; - const userTeamIds = teams.filter(({isMember}) => isMember).map(({id}) => id); - return ( ); } } -export default withTeams(IncidentRulesDetails); +export default IncidentRulesDetails; diff --git a/static/app/views/alerts/issueRuleEditor/index.tsx b/static/app/views/alerts/issueRuleEditor/index.tsx index 2f408e3b904339..8a890455278b5f 100644 --- a/static/app/views/alerts/issueRuleEditor/index.tsx +++ b/static/app/views/alerts/issueRuleEditor/index.tsx @@ -40,7 +40,6 @@ import {isActiveSuperuser} from 'app/utils/isActiveSuperuser'; import recreateRoute from 'app/utils/recreateRoute'; import routeTitleGen from 'app/utils/routeTitle'; import withOrganization from 'app/utils/withOrganization'; -import withTeams from 'app/utils/withTeams'; import { CHANGE_ALERT_CONDITION_IDS, CHANGE_ALERT_PLACEHOLDERS_LABELS, @@ -101,7 +100,7 @@ type RuleTaskResponse = { type Props = { project: Project; organization: Organization; - teams: Team[]; + userTeamIds: string[]; onChangeTitle?: (data: string) => void; } & RouteComponentProps<{orgId: string; projectId: string; ruleId?: string}, {}>; @@ -138,7 +137,7 @@ class IssueRuleEditor extends AsyncView { } getDefaultState() { - const {teams, project} = this.props; + const {userTeamIds, project} = this.props; const defaultState = { ...super.getDefaultState(), configs: null, @@ -149,9 +148,8 @@ class IssueRuleEditor extends AsyncView { }; const projectTeamIds = new Set(project.teams.map(({id}) => id)); - const userTeam = - teams.find(({isMember, id}) => !!isMember && projectTeamIds.has(id)) ?? null; - defaultState.rule.owner = userTeam && `team:${userTeam.id}`; + const userTeamId = userTeamIds.find(id => projectTeamIds.has(id)) ?? null; + defaultState.rule.owner = userTeamId && `team:${userTeamId}`; return defaultState; } @@ -546,7 +544,7 @@ class IssueRuleEditor extends AsyncView { } renderBody() { - const {project, organization, teams} = this.props; + const {project, organization, userTeamIds} = this.props; const {environments} = this.state; const environmentOptions = [ { @@ -563,10 +561,10 @@ class IssueRuleEditor extends AsyncView { const environment = !rule || !rule.environment ? ALL_ENVIRONMENTS_KEY : rule.environment; - const userTeams = teams.filter(({isMember}) => isMember).map(({id}) => id); const ownerId = rule?.owner?.split(':')[1]; // check if superuser or if user is on the alert's team - const canEdit = isActiveSuperuser() || (ownerId ? userTeams.includes(ownerId) : true); + const canEdit = + isActiveSuperuser() || (ownerId ? userTeamIds.includes(ownerId) : true); // Note `key` on `
` below is so that on initial load, we show // the form with a loading mask on top of it, but force a re-render by using @@ -895,7 +893,7 @@ class IssueRuleEditor extends AsyncView { } } -export default withOrganization(withTeams(IssueRuleEditor)); +export default withOrganization(IssueRuleEditor); // TODO(ts): Understand why styled is not correctly inheriting props here const StyledForm = styled(Form)` diff --git a/tests/js/spec/views/alerts/create.spec.jsx b/tests/js/spec/views/alerts/create.spec.jsx index 64d25ae46c1225..22963504c84814 100644 --- a/tests/js/spec/views/alerts/create.spec.jsx +++ b/tests/js/spec/views/alerts/create.spec.jsx @@ -12,6 +12,7 @@ import { import * as memberActionCreators from 'app/actionCreators/members'; import ProjectsStore from 'app/stores/projectsStore'; +import TeamStore from 'app/stores/teamStore'; import {metric, trackAnalyticsEvent} from 'app/utils/analytics'; import AlertsContainer from 'app/views/alerts'; import AlertBuilderProjectProvider from 'app/views/alerts/builder/projectProvider'; @@ -33,6 +34,7 @@ jest.mock('app/utils/analytics', () => ({ })); describe('ProjectAlertsCreate', function () { + TeamStore.loadInitialData([]); const projectAlertRuleDetailsRoutes = [ { path: '/organizations/:orgId/alerts/', diff --git a/tests/js/spec/views/alerts/incidentRules/create.spec.jsx b/tests/js/spec/views/alerts/incidentRules/create.spec.jsx index 61103c7c26b9ac..79ceed3cfc5d96 100644 --- a/tests/js/spec/views/alerts/incidentRules/create.spec.jsx +++ b/tests/js/spec/views/alerts/incidentRules/create.spec.jsx @@ -44,6 +44,7 @@ describe('Incident Rules Create', function () { params={{orgId: organization.slug, projectId: project.slug}} organization={organization} project={project} + userTeamIds={[]} />, routerContext ); diff --git a/tests/js/spec/views/alerts/issueRuleEditor/issueRuleEditor.spec.jsx b/tests/js/spec/views/alerts/issueRuleEditor/issueRuleEditor.spec.jsx index 703440b617769b..08b6bc67b164a1 100644 --- a/tests/js/spec/views/alerts/issueRuleEditor/issueRuleEditor.spec.jsx +++ b/tests/js/spec/views/alerts/issueRuleEditor/issueRuleEditor.spec.jsx @@ -100,6 +100,7 @@ describe('ProjectAlerts -> IssueRuleEditor', function () { routes={projectAlertRuleDetailsRoutes} onChangeTitle={onChangeTitleMock} project={project} + userTeamIds={[]} /> , routerContext