import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import Alert from 'sentry/components/alert'; import SearchBar from 'sentry/components/performance/searchBar'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {NewQuery} from 'sentry/types/organization'; import {defined} from 'sentry/utils'; import EventView from 'sentry/utils/discover/eventView'; import {DiscoverDatasets} from 'sentry/utils/discover/types'; import {decodeScalar} from 'sentry/utils/queryString'; import {escapeFilterValue, MutableSearch} from 'sentry/utils/tokenizeSearch'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useRouter from 'sentry/utils/useRouter'; import {useReleaseSelection} from 'sentry/views/insights/common/queries/useReleases'; import {appendReleaseFilters} from 'sentry/views/insights/common/utils/releaseComparison'; import {TOP_SCREENS} from 'sentry/views/insights/mobile/constants'; import {getFreeTextFromQuery} from 'sentry/views/insights/mobile/screenload/components/screensView'; import {useTableQuery} from 'sentry/views/insights/mobile/screenload/components/tables/screensTable'; import {YAxis, YAXIS_COLUMNS} from 'sentry/views/insights/mobile/screenload/constants'; import {transformReleaseEvents} from 'sentry/views/insights/mobile/screenload/utils'; import {TopScreensChart} from 'sentry/views/insights/mobile/ui/components/charts/topScreensChart'; import {UIScreensTable} from 'sentry/views/insights/mobile/ui/components/tables/uiScreensTable'; import {Referrer} from 'sentry/views/insights/mobile/ui/referrers'; import {SpanMetricsField} from 'sentry/views/insights/types'; import {prepareQueryForLandingPage} from 'sentry/views/performance/data'; import {getTransactionSearchQuery} from 'sentry/views/performance/utils'; const Y_AXES = [YAxis.SLOW_FRAMES, YAxis.FROZEN_FRAMES, YAxis.FRAMES_DELAY]; const Y_AXIS_COLUMNS = [ 'avg(mobile.slow_frames)', 'avg(mobile.frozen_frames)', 'avg(mobile.frames_delay)', ]; export function UIScreens() { const theme = useTheme(); const router = useRouter(); const {selection} = usePageFilters(); const location = useLocation(); const organization = useOrganization(); const {query: locationQuery} = location; const { primaryRelease, secondaryRelease, isLoading: isReleasesLoading, } = useReleaseSelection(); const query = new MutableSearch(['transaction.op:ui.load']); const searchQuery = decodeScalar(locationQuery.query, ''); if (searchQuery) { query.addStringFilter(prepareQueryForLandingPage(searchQuery, false)); } const queryString = appendReleaseFilters(query, primaryRelease, secondaryRelease); // TODO: Replace with a default sort on the count column when added const orderby = decodeScalar(locationQuery.sort, ''); const newQuery: NewQuery = { name: '', fields: [ SpanMetricsField.PROJECT_ID, 'transaction', `division_if(mobile.slow_frames,mobile.total_frames,release,${primaryRelease})`, `division_if(mobile.slow_frames,mobile.total_frames,release,${secondaryRelease})`, `division_if(mobile.frozen_frames,mobile.total_frames,release,${primaryRelease})`, `division_if(mobile.frozen_frames,mobile.total_frames,release,${secondaryRelease})`, `avg_if(mobile.frames_delay,release,${primaryRelease})`, `avg_if(mobile.frames_delay,release,${secondaryRelease})`, `avg_compare(mobile.frames_delay,release,${primaryRelease},${secondaryRelease})`, ], query: queryString, dataset: DiscoverDatasets.SPANS_METRICS, version: 2, projects: selection.projects, }; newQuery.orderby = orderby; const tableEventView = EventView.fromNewQueryWithLocation(newQuery, location); const { data: topTransactionsData, isPending: topTransactionsLoading, pageLinks, } = useTableQuery({ eventView: tableEventView, enabled: !isReleasesLoading, referrer: Referrer.OVERVIEW_SCREENS_TABLE, }); const topTransactions = topTransactionsData?.data?.slice(0, 5).map(datum => datum.transaction as string) ?? []; // TODO: Fill with transaction.op filter const topEventsQuery = new MutableSearch([]); const topEventsQueryString = `${appendReleaseFilters( topEventsQuery, primaryRelease, secondaryRelease )} ${ topTransactions.length > 0 ? escapeFilterValue( `transaction:[${topTransactions.map(name => `"${name}"`).join()}]` ) : '' }`.trim(); const {data: releaseEvents, isPending: isReleaseEventsLoading} = useTableQuery({ eventView: EventView.fromNewQueryWithPageFilters( { name: '', fields: ['transaction', 'release', ...Y_AXIS_COLUMNS], yAxis: Y_AXIS_COLUMNS, query: topEventsQueryString, dataset: DiscoverDatasets.SPANS_METRICS, version: 2, }, selection ), enabled: !topTransactionsLoading, referrer: Referrer.MOBILE_UI_BAR_CHART, }); if (!defined(primaryRelease) && !isReleasesLoading) { return ( {t( 'No screens found on recent releases. Please try a single iOS or Android project, a single environment or a smaller date range.' )} ); } const tableSearchFilters = new MutableSearch(['transaction.op:ui.load']); const derivedQuery = getTransactionSearchQuery(location, tableEventView.query); const transformedReleaseEvents = transformReleaseEvents({ yAxes: Y_AXES, primaryRelease, secondaryRelease, colorPalette: theme.charts.getColorPalette(TOP_SCREENS - 2), releaseEvents, topTransactions, }); return ( { router.push({ pathname: router.location.pathname, query: { ...location.query, cursor: undefined, query: String(search).trim() || undefined, }, }); }} organization={organization} query={getFreeTextFromQuery(derivedQuery)} placeholder={t('Search for Screen')} additionalConditions={ new MutableSearch( appendReleaseFilters(tableSearchFilters, primaryRelease, secondaryRelease) ) } /> ); } const Layout = styled('div')` display: flex; flex-direction: column; gap: ${space(1)}; `; const ChartContainer = styled('div')` display: grid; grid-template-columns: 33% 33% 33%; gap: ${space(1)}; `;