diff --git a/static/app/utils/discover/teamKeyTransactionField.tsx b/static/app/utils/discover/teamKeyTransactionField.tsx index 143d2b32593245..03c90a47cd6705 100644 --- a/static/app/utils/discover/teamKeyTransactionField.tsx +++ b/static/app/utils/discover/teamKeyTransactionField.tsx @@ -7,10 +7,9 @@ import TeamKeyTransaction, { import * as TeamKeyTransactionManager from 'app/components/performance/teamKeyTransactionsManager'; import Tooltip from 'app/components/tooltip'; import {IconStar} from 'app/icons'; -import {Organization, Project, Team} from 'app/types'; +import {Organization, Project} from 'app/types'; import {defined} from 'app/utils'; import withProjects from 'app/utils/withProjects'; -import withTeams from 'app/utils/withTeams'; class TitleStar extends Component { render() { @@ -34,7 +33,6 @@ class TitleStar extends Component { } type BaseProps = { - teams: Team[]; organization: Organization; isKeyTransaction: boolean; }; @@ -112,4 +110,4 @@ function TeamKeyTransactionFieldWrapper({ ); } -export default withTeams(withProjects(TeamKeyTransactionFieldWrapper)); +export default withProjects(TeamKeyTransactionFieldWrapper); diff --git a/static/app/views/performance/landing/content.tsx b/static/app/views/performance/landing/content.tsx index a594ba140854a4..886aa7de552307 100644 --- a/static/app/views/performance/landing/content.tsx +++ b/static/app/views/performance/landing/content.tsx @@ -5,18 +5,18 @@ import {Location} from 'history'; import DropdownControl, {DropdownItem} from 'app/components/dropdownControl'; import SearchBar from 'app/components/events/searchBar'; +import LoadingIndicator from 'app/components/loadingIndicator'; import * as TeamKeyTransactionManager from 'app/components/performance/teamKeyTransactionsManager'; import {MAX_QUERY_LENGTH} from 'app/constants'; import {t} from 'app/locale'; import space from 'app/styles/space'; -import {Organization, Project, Team} from 'app/types'; +import {Organization, Project} from 'app/types'; import {trackAnalyticsEvent} from 'app/utils/analytics'; import EventView from 'app/utils/discover/eventView'; import {generateAggregateFields} from 'app/utils/discover/fields'; -import {isActiveSuperuser} from 'app/utils/isActiveSuperuser'; import {decodeScalar} from 'app/utils/queryString'; +import Teams from 'app/utils/teams'; import {MutableSearch} from 'app/utils/tokenizeSearch'; -import withTeams from 'app/utils/withTeams'; import Charts from '../charts/index'; import { @@ -52,7 +52,6 @@ type Props = { eventView: EventView; location: Location; projects: Project[]; - teams: Team[]; setError: (msg: string | undefined) => void; handleSearch: (searchQuery: string) => void; } & WithRouterProps; @@ -265,14 +264,11 @@ class LandingContent extends Component { }; render() { - const {organization, location, eventView, projects, teams, handleSearch} = this.props; + const {organization, location, eventView, projects, handleSearch} = this.props; const currentLandingDisplay = getCurrentLandingDisplay(location, projects, eventView); const filterString = getTransactionSearchQuery(location, eventView.query); - const isSuperuser = isActiveSuperuser(); - const userTeams = teams.filter(({isMember}) => isMember || isSuperuser); - return ( @@ -308,14 +304,22 @@ class LandingContent extends Component { ))} - - {this.renderSelectedDisplay(currentLandingDisplay.field)} - + + {({teams, initiallyLoaded}) => + initiallyLoaded ? ( + + {this.renderSelectedDisplay(currentLandingDisplay.field)} + + ) : ( + + ) + } + ); } @@ -331,4 +335,4 @@ const SearchContainer = styled('div')` } `; -export default withRouter(withTeams(LandingContent)); +export default withRouter(LandingContent); diff --git a/static/app/views/performance/landing/index.tsx b/static/app/views/performance/landing/index.tsx index 82622d514a910d..3c15c096fc7b8f 100644 --- a/static/app/views/performance/landing/index.tsx +++ b/static/app/views/performance/landing/index.tsx @@ -6,18 +6,18 @@ import Button from 'app/components/button'; import SearchBar from 'app/components/events/searchBar'; import GlobalSdkUpdateAlert from 'app/components/globalSdkUpdateAlert'; import * as Layout from 'app/components/layouts/thirds'; +import LoadingIndicator from 'app/components/loadingIndicator'; import NavTabs from 'app/components/navTabs'; import PageHeading from 'app/components/pageHeading'; import * as TeamKeyTransactionManager from 'app/components/performance/teamKeyTransactionsManager'; import {MAX_QUERY_LENGTH} from 'app/constants'; import {t} from 'app/locale'; import space from 'app/styles/space'; -import {Organization, Project, Team} from 'app/types'; +import {Organization, Project} from 'app/types'; import EventView from 'app/utils/discover/eventView'; import {generateAggregateFields} from 'app/utils/discover/fields'; -import {isActiveSuperuser} from 'app/utils/isActiveSuperuser'; import {OpBreakdownFilterProvider} from 'app/utils/performance/contexts/operationBreakdownFilter'; -import withTeams from 'app/utils/withTeams'; +import useTeams from 'app/utils/useTeams'; import Filter, {SpanOperationBreakdownFilter} from '../transactionSummary/filter'; import {getTransactionSearchQuery} from '../utils'; @@ -39,7 +39,6 @@ type Props = { eventView: EventView; location: Location; projects: Project[]; - teams: Team[]; shouldShowOnboarding: boolean; setError: (msg: string | undefined) => void; handleSearch: (searchQuery: string) => void; @@ -54,24 +53,22 @@ const fieldToViewMap: Record> = { [LandingDisplayField.MOBILE]: MobileView, }; -function _PerformanceLanding(props: Props) { +export function PerformanceLanding(props: Props) { const { organization, location, eventView, projects, - teams, handleSearch, handleTrendsClick, shouldShowOnboarding, } = props; + const {teams, initiallyLoaded} = useTeams({provideUserTeams: true}); + const currentLandingDisplay = getCurrentLandingDisplay(location, projects, eventView); const filterString = getTransactionSearchQuery(location, eventView.query); - const isSuperuser = isActiveSuperuser(); - const userTeams = teams.filter(({isMember}) => isMember || isSuperuser); - const [spanFilter, setSpanFilter] = useState(SpanOperationBreakdownFilter.None); const showOnboarding = shouldShowOnboarding; @@ -136,14 +133,18 @@ function _PerformanceLanding(props: Props) { maxQueryLength={MAX_QUERY_LENGTH} /> - - - + {initiallyLoaded ? ( + + + + ) : ( + + )} @@ -151,8 +152,6 @@ function _PerformanceLanding(props: Props) { ); } -export const PerformanceLanding = withTeams(_PerformanceLanding); - const StyledHeading = styled(PageHeading)` line-height: 40px; `; diff --git a/static/app/views/performance/transactionSummary/teamKeyTransactionButton.tsx b/static/app/views/performance/transactionSummary/teamKeyTransactionButton.tsx index 68e16134b2b602..b3124896b876c9 100644 --- a/static/app/views/performance/transactionSummary/teamKeyTransactionButton.tsx +++ b/static/app/views/performance/transactionSummary/teamKeyTransactionButton.tsx @@ -8,12 +8,11 @@ import * as TeamKeyTransactionManager from 'app/components/performance/teamKeyTr import Tooltip from 'app/components/tooltip'; import {IconStar} from 'app/icons'; import {t, tn} from 'app/locale'; -import {Organization, Project, Team} from 'app/types'; +import {Organization, Project} from 'app/types'; import {defined} from 'app/utils'; import EventView from 'app/utils/discover/eventView'; -import {isActiveSuperuser} from 'app/utils/isActiveSuperuser'; +import useTeams from 'app/utils/useTeams'; import withProjects from 'app/utils/withProjects'; -import withTeams from 'app/utils/withTeams'; /** * This can't be a function component because `TeamKeyTransaction` uses @@ -46,7 +45,6 @@ class TitleButton extends Component { type BaseProps = { organization: Organization; transactionName: string; - teams: Team[]; }; type Props = BaseProps & @@ -82,10 +80,11 @@ type WrapperProps = BaseProps & { function TeamKeyTransactionButtonWrapper({ eventView, organization, - teams, projects, ...props }: WrapperProps) { + const {teams, initiallyLoaded} = useTeams({provideUserTeams: true}); + if (eventView.project.length !== 1) { return ; } @@ -96,21 +95,19 @@ function TeamKeyTransactionButtonWrapper({ return ; } - const isSuperuser = isActiveSuperuser(); - const userTeams = teams.filter(({isMember}) => isMember || isSuperuser); - return ( - {results => ( + {({isLoading, ...results}) => ( @@ -120,4 +117,4 @@ function TeamKeyTransactionButtonWrapper({ ); } -export default withTeams(withProjects(TeamKeyTransactionButtonWrapper)); +export default withProjects(TeamKeyTransactionButtonWrapper); diff --git a/static/app/views/performance/vitalDetail/vitalDetailContent.tsx b/static/app/views/performance/vitalDetail/vitalDetailContent.tsx index 4c64c7d755b43b..3506796901f733 100644 --- a/static/app/views/performance/vitalDetail/vitalDetailContent.tsx +++ b/static/app/views/performance/vitalDetail/vitalDetailContent.tsx @@ -11,21 +11,21 @@ import ButtonBar from 'app/components/buttonBar'; import {CreateAlertFromViewButton} from 'app/components/createAlertButton'; import SearchBar from 'app/components/events/searchBar'; import * as Layout from 'app/components/layouts/thirds'; +import LoadingIndicator from 'app/components/loadingIndicator'; import {getParams} from 'app/components/organizations/globalSelectionHeader/getParams'; import * as TeamKeyTransactionManager from 'app/components/performance/teamKeyTransactionsManager'; import {IconChevron} from 'app/icons'; import {IconFlag} from 'app/icons/iconFlag'; import {t} from 'app/locale'; import space from 'app/styles/space'; -import {Organization, Project, Team} from 'app/types'; +import {Organization, Project} from 'app/types'; import {generateQueryWithTag} from 'app/utils'; import EventView from 'app/utils/discover/eventView'; import {WebVital} from 'app/utils/discover/fields'; -import {isActiveSuperuser} from 'app/utils/isActiveSuperuser'; import {decodeScalar} from 'app/utils/queryString'; +import Teams from 'app/utils/teams'; import {MutableSearch} from 'app/utils/tokenizeSearch'; import withProjects from 'app/utils/withProjects'; -import withTeams from 'app/utils/withTeams'; import Breadcrumb from '../breadcrumb'; import {getTransactionSearchQuery} from '../utils'; @@ -42,7 +42,6 @@ type Props = { eventView: EventView; organization: Organization; projects: Project[]; - teams: Team[]; router: InjectedRouter; vitalName: WebVital; @@ -178,7 +177,7 @@ class VitalDetailContent extends React.Component { } render() { - const {location, eventView, organization, vitalName, projects, teams} = this.props; + const {location, eventView, organization, vitalName, projects} = this.props; const {incompatibleAlertNotice} = this.state; const query = decodeScalar(location.query.query, ''); @@ -188,9 +187,6 @@ class VitalDetailContent extends React.Component { const summaryConditions = getSummaryConditions(filterString); const description = vitalDescription[vitalName]; - const isSuperuser = isActiveSuperuser(); - const userTeams = teams.filter(({isMember}) => isMember || isSuperuser); - return ( @@ -238,21 +234,30 @@ class VitalDetailContent extends React.Component { - - - + + + {({teams, initiallyLoaded}) => + initiallyLoaded ? ( + +
+ + ) : ( + + ) + } + @@ -273,4 +278,4 @@ const StyledVitalInfo = styled('div')` margin-bottom: ${space(3)}; `; -export default withTeams(withProjects(VitalDetailContent)); +export default withProjects(VitalDetailContent); diff --git a/tests/js/spec/views/performance/content.spec.jsx b/tests/js/spec/views/performance/content.spec.jsx index 2eb5f636a081fe..71f9fbaf535217 100644 --- a/tests/js/spec/views/performance/content.spec.jsx +++ b/tests/js/spec/views/performance/content.spec.jsx @@ -6,6 +6,7 @@ import {act} from 'sentry-test/reactTestingLibrary'; import * as globalSelection from 'app/actionCreators/globalSelection'; import ProjectsStore from 'app/stores/projectsStore'; +import TeamStore from 'app/stores/teamStore'; import {OrganizationContext} from 'app/views/organizationContext'; import PerformanceContent from 'app/views/performance/content'; import {DEFAULT_MAX_DURATION} from 'app/views/performance/trends/utils'; @@ -63,6 +64,7 @@ function initializeTrendsData(query, addDefaultQuery = true) { describe('Performance > Content', function () { beforeEach(function () { + act(() => void TeamStore.loadInitialData([])); browserHistory.push = jest.fn(); jest.spyOn(globalSelection, 'updateDateTime'); diff --git a/tests/js/spec/views/performance/landing/index.spec.tsx b/tests/js/spec/views/performance/landing/index.spec.tsx index c027103538ca5d..36599443acc4b1 100644 --- a/tests/js/spec/views/performance/landing/index.spec.tsx +++ b/tests/js/spec/views/performance/landing/index.spec.tsx @@ -1,6 +1,8 @@ import {mountWithTheme} from 'sentry-test/enzyme'; import {initializeData} from 'sentry-test/performance/initializePerformanceData'; +import {act} from 'sentry-test/reactTestingLibrary'; +import TeamStore from 'app/stores/teamStore'; import EventView from 'app/utils/discover/eventView'; import {OrganizationContext} from 'app/views/organizationContext'; import {PerformanceLanding} from 'app/views/performance/landing'; @@ -28,6 +30,7 @@ const WrappedComponent = ({data}) => { describe('Performance > Landing > Index', function () { let eventStatsMock: any; let eventsV2Mock: any; + act(() => void TeamStore.loadInitialData([])); beforeEach(function () { // @ts-expect-error MockApiClient.addMockResponse({ diff --git a/tests/js/spec/views/performance/vitalDetail/index.spec.jsx b/tests/js/spec/views/performance/vitalDetail/index.spec.jsx index bd4e12f330299a..a97e08adffbfed 100644 --- a/tests/js/spec/views/performance/vitalDetail/index.spec.jsx +++ b/tests/js/spec/views/performance/vitalDetail/index.spec.jsx @@ -5,6 +5,7 @@ import {initializeOrg} from 'sentry-test/initializeOrg'; import {act} from 'sentry-test/reactTestingLibrary'; import ProjectsStore from 'app/stores/projectsStore'; +import TeamStore from 'app/stores/teamStore'; import {OrganizationContext} from 'app/views/organizationContext'; import VitalDetail from 'app/views/performance/vitalDetail/'; @@ -39,6 +40,7 @@ const WrappedComponent = ({organization, ...rest}) => { describe('Performance > VitalDetail', function () { beforeEach(function () { + act(() => void TeamStore.loadInitialData([])); browserHistory.push = jest.fn(); MockApiClient.addMockResponse({ url: '/organizations/org-slug/projects/',