import {Component, Fragment} from 'react'; import {browserHistory, withRouter, WithRouterProps} from 'react-router'; import styled from '@emotion/styled'; import {Location} from 'history'; import DropdownControl, {DropdownItem} from 'sentry/components/dropdownControl'; import SearchBar from 'sentry/components/events/searchBar'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import * as TeamKeyTransactionManager from 'sentry/components/performance/teamKeyTransactionsManager'; import {MAX_QUERY_LENGTH} from 'sentry/constants'; import {t} from 'sentry/locale'; import space from 'sentry/styles/space'; import {Organization, Project} from 'sentry/types'; import {trackAnalyticsEvent} from 'sentry/utils/analytics'; import EventView from 'sentry/utils/discover/eventView'; import {generateAggregateFields} from 'sentry/utils/discover/fields'; import {decodeScalar} from 'sentry/utils/queryString'; import Teams from 'sentry/utils/teams'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import Charts from '../charts/index'; import { getBackendAxisOptions, getFrontendAxisOptions, getFrontendOtherAxisOptions, getMobileAxisOptions, } from '../data'; import Table from '../table'; import {getTransactionSearchQuery} from '../utils'; import DoubleAxisDisplay from './display/doubleAxisDisplay'; import { BACKEND_COLUMN_TITLES, FRONTEND_OTHER_COLUMN_TITLES, FRONTEND_PAGELOAD_COLUMN_TITLES, MOBILE_COLUMN_TITLES, REACT_NATIVE_COLUMN_TITLES, } from './data'; import { checkIsReactNative, getCurrentLandingDisplay, getDefaultDisplayFieldForPlatform, getDisplayAxes, LANDING_DISPLAYS, LandingDisplayField, LEFT_AXIS_QUERY_KEY, RIGHT_AXIS_QUERY_KEY, } from './utils'; import {BackendCards, FrontendCards, MobileCards} from './vitalsCards'; type Props = { eventView: EventView; handleSearch: (searchQuery: string) => void; location: Location; organization: Organization; projects: Project[]; setError: (msg: string | undefined) => void; } & WithRouterProps; type State = {}; class LandingContent extends Component { getSummaryConditions(query: string) { const parsed = new MutableSearch(query); parsed.freeText = []; return parsed.formatString(); } handleLandingDisplayChange = (field: string) => { const {location, organization, eventView, projects} = this.props; const newQuery = {...location.query}; delete newQuery[LEFT_AXIS_QUERY_KEY]; delete newQuery[RIGHT_AXIS_QUERY_KEY]; const defaultDisplay = getDefaultDisplayFieldForPlatform(projects, eventView); const currentDisplay = decodeScalar(location.query.landingDisplay); // Transaction op can affect the display and show no results if it is explicitly set. const query = decodeScalar(location.query.query, ''); const searchConditions = new MutableSearch(query); searchConditions.removeFilter('transaction.op'); trackAnalyticsEvent({ eventKey: 'performance_views.landingv2.display_change', eventName: 'Performance Views: Landing v2 Display Change', organization_id: parseInt(organization.id, 10), change_to_display: field, default_display: defaultDisplay, current_display: currentDisplay, is_default: defaultDisplay === currentDisplay, }); browserHistory.push({ pathname: location.pathname, query: { ...newQuery, query: searchConditions.formatString(), landingDisplay: field, }, }); }; renderSelectedDisplay(display) { switch (display) { case LandingDisplayField.ALL: return this.renderLandingAll(); case LandingDisplayField.FRONTEND_PAGELOAD: return this.renderLandingFrontend(true); case LandingDisplayField.FRONTEND_OTHER: return this.renderLandingFrontend(false); case LandingDisplayField.BACKEND: return this.renderLandingBackend(); case LandingDisplayField.MOBILE: return this.renderLandingMobile(); default: throw new Error(`Unknown display: ${display}`); } } renderLandingFrontend = isPageload => { const {organization, location, projects, eventView, setError} = this.props; const columnTitles = isPageload ? FRONTEND_PAGELOAD_COLUMN_TITLES : FRONTEND_OTHER_COLUMN_TITLES; const axisOptions = isPageload ? getFrontendAxisOptions(organization) : getFrontendOtherAxisOptions(organization); const {leftAxis, rightAxis} = getDisplayAxes(axisOptions, location); return ( {isPageload && ( )} ); }; renderLandingBackend = () => { const {organization, location, projects, eventView, setError} = this.props; const axisOptions = getBackendAxisOptions(organization); const {leftAxis, rightAxis} = getDisplayAxes(axisOptions, location); const columnTitles = BACKEND_COLUMN_TITLES; return (
); }; renderLandingMobile = () => { const {organization, location, projects, eventView, setError} = this.props; const axisOptions = getMobileAxisOptions(organization); const {leftAxis, rightAxis} = getDisplayAxes(axisOptions, location); // only react native should contain the stall percentage column const isReactNative = checkIsReactNative(eventView); const columnTitles = isReactNative ? REACT_NATIVE_COLUMN_TITLES : MOBILE_COLUMN_TITLES; return (
); }; renderLandingAll = () => { const {organization, location, router, projects, eventView, setError} = this.props; return (
); }; render() { const {organization, location, eventView, projects, handleSearch} = this.props; const currentLandingDisplay = getCurrentLandingDisplay(location, projects, eventView); const filterString = getTransactionSearchQuery(location, eventView.query); return ( {LANDING_DISPLAYS.filter( ({isShown}) => !isShown || isShown(organization) ).map(({label, field}) => ( {label} ))} {({teams, initiallyLoaded}) => initiallyLoaded ? ( {this.renderSelectedDisplay(currentLandingDisplay.field)} ) : ( ) } ); } } const SearchContainer = styled('div')` display: grid; gap: ${space(2)}; margin-bottom: ${space(2)}; @media (min-width: ${p => p.theme.breakpoints[0]}) { grid-template-columns: 1fr min-content; } `; export default withRouter(LandingContent);