diff --git a/static/app/views/insights/pages/ai/aiOverviewPage.tsx b/static/app/views/insights/pages/ai/aiOverviewPage.tsx index f6d0c7be62651a..efb354aed1bf06 100644 --- a/static/app/views/insights/pages/ai/aiOverviewPage.tsx +++ b/static/app/views/insights/pages/ai/aiOverviewPage.tsx @@ -47,13 +47,13 @@ import { } from 'sentry/views/performance/utils'; export const AI_COLUMN_TITLES = [ - 'transaction', - 'operation', - 'project', - 'tpm', - 'p50()', - 'p95()', - 'users', + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'p50()'}, + {title: 'p95()'}, + {title: 'users'}, ]; function AiOverviewPage() { diff --git a/static/app/views/insights/pages/backend/backendOverviewPage.tsx b/static/app/views/insights/pages/backend/backendOverviewPage.tsx index 1b78987b2cac4e..ff19a33302a390 100644 --- a/static/app/views/insights/pages/backend/backendOverviewPage.tsx +++ b/static/app/views/insights/pages/backend/backendOverviewPage.tsx @@ -47,17 +47,17 @@ import { } from 'sentry/views/performance/utils'; export const BACKEND_COLUMN_TITLES = [ - 'http method', - 'transaction', - 'operation', - 'project', - 'tpm', - 'p50()', - 'p95()', - 'failure rate', - 'apdex', - 'users', - 'user misery', + {title: 'http method'}, + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'p50()'}, + {title: 'p95()'}, + {title: 'failure rate'}, + {title: 'apdex'}, + {title: 'users'}, + {title: 'user misery'}, ]; function BackendOverviewPage() { diff --git a/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx b/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx index 1270d7ab712307..9a081f2e7a3e4b 100644 --- a/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx +++ b/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx @@ -3,6 +3,7 @@ import styled from '@emotion/styled'; import Feature from 'sentry/components/acl/feature'; import {COL_WIDTH_UNDEFINED} from 'sentry/components/gridEditable'; import * as Layout from 'sentry/components/layouts/thirds'; +import ExternalLink from 'sentry/components/links/externalLink'; import {NoAccess} from 'sentry/components/noAccess'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; @@ -10,6 +11,7 @@ import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; import TransactionNameSearchBar from 'sentry/components/performance/searchBar'; import * as TeamKeyTransactionManager from 'sentry/components/performance/teamKeyTransactionsManager'; +import {tct} from 'sentry/locale'; import {trackAnalytics} from 'sentry/utils/analytics'; import { canUseMetricsData, @@ -47,16 +49,25 @@ import { ProjectPerformanceType, } from 'sentry/views/performance/utils'; +const DURATION_TOOLTIP = tct( + 'A heuristic measuring when a pageload or navigation completes. Based on whether the initial load of the webpage has become idle [link:Learn more.]', + { + link: ( + + ), + } +); + export const FRONTEND_COLUMN_TITLES = [ - 'transaction', - 'operation', - 'project', - 'tpm', - 'p50()', - 'p75()', - 'p95()', - 'users', - 'user misery', + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'p50()', tooltip: DURATION_TOOLTIP}, + {title: 'p75()', tooltip: DURATION_TOOLTIP}, + {title: 'p95()', tooltip: DURATION_TOOLTIP}, + {title: 'users'}, + {title: 'user misery'}, ]; function FrontendOverviewPage() { diff --git a/static/app/views/insights/pages/mobile/mobileOverviewPage.tsx b/static/app/views/insights/pages/mobile/mobileOverviewPage.tsx index dc98ca6d8c7653..393375c6feb6ec 100644 --- a/static/app/views/insights/pages/mobile/mobileOverviewPage.tsx +++ b/static/app/views/insights/pages/mobile/mobileOverviewPage.tsx @@ -51,26 +51,26 @@ import { } from 'sentry/views/performance/utils'; const MOBILE_COLUMN_TITLES = [ - 'transaction', - 'operation', - 'project', - 'tpm', - 'slow frame %', - 'frozen frame %', - 'users', - 'user misery', + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'slow frame %'}, + {title: 'frozen frame %'}, + {title: 'users'}, + {title: 'user misery'}, ]; const REACT_NATIVE_COLUMN_TITLES = [ - 'transaction', - 'operation', - 'project', - 'tpm', - 'slow frame %', - 'frozen frame %', - 'stall %', - 'users', - 'user misery', + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'slow frame %'}, + {title: 'frozen frame %'}, + {title: 'stall %'}, + {title: 'users'}, + {title: 'user misery'}, ]; function MobileOverviewPage() { @@ -124,7 +124,11 @@ function MobileOverviewPage() { ); if (organization.features.includes('mobile-vitals')) { - columnTitles = [...columnTitles.slice(0, 5), 'ttid', ...columnTitles.slice(5, 0)]; + columnTitles = [ + ...columnTitles.slice(0, 5), + {title: 'ttid'}, + ...columnTitles.slice(5, 0), + ]; tripleChartRowCharts.push( ...[ PerformanceWidgetSetting.TIME_TO_INITIAL_DISPLAY, diff --git a/static/app/views/performance/landing/data.tsx b/static/app/views/performance/landing/data.tsx index 84833e8ae26af8..171d4acc8de49b 100644 --- a/static/app/views/performance/landing/data.tsx +++ b/static/app/views/performance/landing/data.tsx @@ -1,60 +1,60 @@ export const FRONTEND_PAGELOAD_COLUMN_TITLES = [ - 'transaction', - 'project', - 'tpm', - 'FCP', - 'LCP', - 'FID', - 'CLS', - 'users', - 'user misery', + {title: 'transaction'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'FCP'}, + {title: 'LCP'}, + {title: 'FID'}, + {title: 'CLS'}, + {title: 'users'}, + {title: 'user misery'}, ]; export const FRONTEND_OTHER_COLUMN_TITLES = [ - 'transaction', - 'operation', - 'project', - 'tpm', - 'p50()', - 'p75()', - 'p95()', - 'users', - 'user misery', + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'p50()'}, + {title: 'p75()'}, + {title: 'p95()'}, + {title: 'users'}, + {title: 'user misery'}, ]; export const BACKEND_COLUMN_TITLES = [ - 'http method', - 'transaction', - 'operation', - 'project', - 'tpm', - 'p50', - 'p95', - 'failure rate', - 'apdex', - 'users', - 'user misery', + {title: 'http method'}, + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'p50'}, + {title: 'p95'}, + {title: 'failure rate'}, + {title: 'apdex'}, + {title: 'users'}, + {title: 'user misery'}, ]; export const MOBILE_COLUMN_TITLES = [ - 'transaction', - 'operation', - 'project', - 'tpm', - 'slow frame %', - 'frozen frame %', - 'users', - 'user misery', + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'slow frame %'}, + {title: 'frozen frame %'}, + {title: 'users'}, + {title: 'user misery'}, ]; export const REACT_NATIVE_COLUMN_TITLES = [ - 'transaction', - 'operation', - 'project', - 'tpm', - 'slow frame %', - 'frozen frame %', - 'stall %', - 'users', - 'user misery', + {title: 'transaction'}, + {title: 'operation'}, + {title: 'project'}, + {title: 'tpm'}, + {title: 'slow frame %'}, + {title: 'frozen frame %'}, + {title: 'stall %'}, + {title: 'users'}, + {title: 'user misery'}, ]; diff --git a/static/app/views/performance/landing/index.spec.tsx b/static/app/views/performance/landing/index.spec.tsx index d5682aca554c07..687c19a260a089 100644 --- a/static/app/views/performance/landing/index.spec.tsx +++ b/static/app/views/performance/landing/index.spec.tsx @@ -198,7 +198,7 @@ describe('Performance > Landing > Index', function () { expect(columnHeaders).toHaveLength(REACT_NATIVE_COLUMN_TITLES.length); for (const [index, title] of columnHeaders.entries()) { - expect(title).toHaveTextContent(REACT_NATIVE_COLUMN_TITLES[index]!); + expect(title).toHaveTextContent(REACT_NATIVE_COLUMN_TITLES[index].title!); } }); diff --git a/static/app/views/performance/landing/views/mobileView.tsx b/static/app/views/performance/landing/views/mobileView.tsx index 649ca11f077535..87b2c66f0b1d4c 100644 --- a/static/app/views/performance/landing/views/mobileView.tsx +++ b/static/app/views/performance/landing/views/mobileView.tsx @@ -32,7 +32,11 @@ export function MobileView(props: BasePerformanceViewProps) { ]; if (organization.features.includes('mobile-vitals')) { - columnTitles = [...columnTitles.slice(0, 5), 'ttid', ...columnTitles.slice(5, 0)]; + columnTitles = [ + ...columnTitles.slice(0, 5), + {title: 'ttid'}, + ...columnTitles.slice(5, 0), + ]; allowedCharts.push( ...[ PerformanceWidgetSetting.TIME_TO_INITIAL_DISPLAY, diff --git a/static/app/views/performance/table.tsx b/static/app/views/performance/table.tsx index 4e220b99915365..a88bbf69a39433 100644 --- a/static/app/views/performance/table.tsx +++ b/static/app/views/performance/table.tsx @@ -1,4 +1,4 @@ -import {Component, useEffect} from 'react'; +import {Component, type ReactNode, useEffect} from 'react'; import styled from '@emotion/styled'; import type {Location, LocationDescriptorObject} from 'history'; @@ -11,9 +11,11 @@ import SortLink from 'sentry/components/gridEditable/sortLink'; import Link from 'sentry/components/links/link'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import Pagination from 'sentry/components/pagination'; +import QuestionTooltip from 'sentry/components/questionTooltip'; import {Tooltip} from 'sentry/components/tooltip'; import {IconStar} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; +import {space} from 'sentry/styles/space'; import type {Organization} from 'sentry/types/organization'; import type {Project} from 'sentry/types/project'; import {trackAnalytics} from 'sentry/utils/analytics'; @@ -55,6 +57,15 @@ import { UNPARAMETERIZED_TRANSACTION, } from './utils'; +type ColumnTitle = { + title: string | ReactNode; + tooltip?: string | ReactNode; +}; + +const COLUMN_TITLES_OPTIONAL_TOOLTIP = COLUMN_TITLES.map(title => { + return {title}; +}); + type Props = { eventView: EventView; location: Location; @@ -62,7 +73,7 @@ type Props = { projects: Project[]; setError: (msg: string | undefined) => void; withStaticFilters: boolean; - columnTitles?: string[]; + columnTitles?: ColumnTitle[]; domainViewFilters?: DomainViewFilters; summaryConditions?: string; }; @@ -402,7 +413,7 @@ class _Table extends Component { renderHeadCell( tableMeta: TableData['meta'], column: TableColumn, - title: React.ReactNode + title: ColumnTitle ): React.ReactNode { const {eventView, location} = this.props; @@ -437,7 +448,7 @@ class _Table extends Component { const sortLink = ( { ); } - return sortLink; + + if (!title.tooltip) { + return sortLink; + } + return ( +
+ {sortLink} + +
+ ); } renderHeadCellWithMeta = (tableMeta: TableData['meta']) => { - const columnTitles = this.props.columnTitles ?? COLUMN_TITLES; + const columnTitles = this.props.columnTitles ?? COLUMN_TITLES_OPTIONAL_TOOLTIP; return (column: TableColumn, index: number): React.ReactNode => this.renderHeadCell(tableMeta, column, columnTitles[index]); }; @@ -479,7 +499,9 @@ class _Table extends Component { /> ); - return [this.renderHeadCell(tableData?.meta, teamKeyTransactionColumn, star)]; + return [ + this.renderHeadCell(tableData?.meta, teamKeyTransactionColumn, {title: star}), + ]; } return [this.renderBodyCell(tableData, teamKeyTransactionColumn, dataRow)]; } @@ -627,4 +649,12 @@ const UnparameterizedTooltipWrapper = styled('div')` justify-content: center; `; +const Header = styled('div')` + display: grid; + grid-template-columns: repeat(2, max-content); + align-items: center; + padding: ${space(1.5)}; + grid-column-gap: ${space(0.5)}; +`; + export default Table;