diff --git a/static/app/views/performance/charts/chart.tsx b/static/app/views/performance/charts/chart.tsx index 8f6c7049c3615e..5094e5cd231a10 100644 --- a/static/app/views/performance/charts/chart.tsx +++ b/static/app/views/performance/charts/chart.tsx @@ -5,6 +5,7 @@ import min from 'lodash/min'; import AreaChart from 'app/components/charts/areaChart'; import ChartZoom from 'app/components/charts/chartZoom'; +import LineChart from 'app/components/charts/lineChart'; import {DateString} from 'app/types'; import {Series} from 'app/types/echarts'; import {axisLabelFormatter, tooltipFormatter} from 'app/utils/discover/charts'; @@ -24,6 +25,7 @@ type Props = { disableXAxis?: boolean; chartColors?: string[]; loading: boolean; + isLineChart?: boolean; }; // adapted from https://stackoverflow.com/questions/11397239/rounding-up-for-a-graph-maximum @@ -68,6 +70,7 @@ function Chart({ disableMultiAxis, disableXAxis, chartColors, + isLineChart, }: Props) { const theme = useTheme(); @@ -176,6 +179,9 @@ function Chart({ }; if (loading) { + if (isLineChart) { + return ; + } return ; } const series = data.map((values, i: number) => ({ @@ -193,16 +199,31 @@ function Chart({ utc={utc} xAxisIndex={disableMultiAxis ? undefined : [0, 1]} > - {zoomRenderProps => ( - - )} + {zoomRenderProps => { + if (isLineChart) { + return ( + + ); + } + + return ( + + ); + }} ); } diff --git a/static/app/views/performance/data.tsx b/static/app/views/performance/data.tsx index 92b2f47872628d..1fc9f621923380 100644 --- a/static/app/views/performance/data.tsx +++ b/static/app/views/performance/data.tsx @@ -52,6 +52,7 @@ export enum PERFORMANCE_TERM { STALL_PERCENTAGE = 'stallPercentage', MOST_ISSUES = 'mostIssues', MOST_ERRORS = 'mostErrors', + SLOW_HTTP_SPANS = 'slowHTTPSpans', } export type TooltipOption = SelectValue & { @@ -361,6 +362,7 @@ export const PERFORMANCE_TERMS: Record = { frozenFrames: () => t('The count of the number of frozen frames in the transaction.'), mostErrors: () => t('Transactions with the most associated errors.'), mostIssues: () => t('The most instances of an issue for a related transaction.'), + slowHTTPSpans: () => t('The transactions with the slowest spans of a certain type.'), stallPercentage: () => t( 'The percentage of the transaction duration in which the application is in a stalled state.' diff --git a/static/app/views/performance/landing/content.tsx b/static/app/views/performance/landing/content.tsx index 978e7f19895fdd..a594ba140854a4 100644 --- a/static/app/views/performance/landing/content.tsx +++ b/static/app/views/performance/landing/content.tsx @@ -5,7 +5,6 @@ import {Location} from 'history'; import DropdownControl, {DropdownItem} from 'app/components/dropdownControl'; import SearchBar from 'app/components/events/searchBar'; -import FeatureBadge from 'app/components/featureBadge'; import * as TeamKeyTransactionManager from 'app/components/performance/teamKeyTransactionsManager'; import {MAX_QUERY_LENGTH} from 'app/constants'; import {t} from 'app/locale'; @@ -296,7 +295,7 @@ class LandingContent extends Component { > {LANDING_DISPLAYS.filter( ({isShown}) => !isShown || isShown(organization) - ).map(({badge, label, field}) => ( + ).map(({label, field}) => ( { isActive={field === currentLandingDisplay.field} > {label} - {badge && } ))} diff --git a/static/app/views/performance/landing/index.tsx b/static/app/views/performance/landing/index.tsx index 70edcbe1fe9fe3..82622d514a910d 100644 --- a/static/app/views/performance/landing/index.tsx +++ b/static/app/views/performance/landing/index.tsx @@ -4,7 +4,6 @@ import {Location} from 'history'; import Button from 'app/components/button'; import SearchBar from 'app/components/events/searchBar'; -import FeatureBadge from 'app/components/featureBadge'; import GlobalSdkUpdateAlert from 'app/components/globalSdkUpdateAlert'; import * as Layout from 'app/components/layouts/thirds'; import NavTabs from 'app/components/navTabs'; @@ -101,14 +100,13 @@ function _PerformanceLanding(props: Props) { - {shownLandingDisplays.map(({badge, label, field}) => ( + {shownLandingDisplays.map(({label, field}) => (
  • handleLandingDisplayChange(field, location)}> {t(label)} - {badge && }
  • ))} diff --git a/static/app/views/performance/landing/utils.tsx b/static/app/views/performance/landing/utils.tsx index 7ec0c426f3121e..c32890938ef787 100644 --- a/static/app/views/performance/landing/utils.tsx +++ b/static/app/views/performance/landing/utils.tsx @@ -57,7 +57,6 @@ export const LANDING_DISPLAYS = [ field: LandingDisplayField.MOBILE, isShown: (organization: Organization) => organization.features.includes('performance-mobile-vitals'), - badge: 'new' as const, }, ]; diff --git a/static/app/views/performance/landing/views/backendView.tsx b/static/app/views/performance/landing/views/backendView.tsx index 9ea996256793ba..e43fd0185821fa 100644 --- a/static/app/views/performance/landing/views/backendView.tsx +++ b/static/app/views/performance/landing/views/backendView.tsx @@ -1,18 +1,47 @@ import {usePageError} from 'app/utils/performance/contexts/pageError'; +import {PerformanceDisplayProvider} from 'app/utils/performance/contexts/performanceDisplayContext'; import Table from '../../table'; +import {PROJECT_PERFORMANCE_TYPE} from '../../utils'; import {BACKEND_COLUMN_TITLES} from '../data'; +import {DoubleChartRow, TripleChartRow} from '../widgets/components/widgetChartRow'; +import {PerformanceWidgetSetting} from '../widgets/widgetDefinitions'; import {BasePerformanceViewProps} from './types'; export function BackendView(props: BasePerformanceViewProps) { return ( -
    - - + +
    + + +
    + + ); } diff --git a/static/app/views/performance/landing/views/frontendOtherView.tsx b/static/app/views/performance/landing/views/frontendOtherView.tsx index d6a23a18205f8c..1bf2f94192dc6c 100644 --- a/static/app/views/performance/landing/views/frontendOtherView.tsx +++ b/static/app/views/performance/landing/views/frontendOtherView.tsx @@ -14,7 +14,7 @@ export function FrontendOtherView(props: BasePerformanceViewProps) { -
    +
    -
    - + +
    + + +
    + + ); } diff --git a/static/app/views/performance/landing/widgets/components/queryHandler.tsx b/static/app/views/performance/landing/widgets/components/queryHandler.tsx index da20b7672cec39..75c84401d0358d 100644 --- a/static/app/views/performance/landing/widgets/components/queryHandler.tsx +++ b/static/app/views/performance/landing/widgets/components/queryHandler.tsx @@ -41,8 +41,6 @@ export function QueryHandler( organization={props.queryProps.organization} orgSlug={props.queryProps.organization.slug} query={props.queryProps.eventView.getQueryWithAdditionalConditions()} - eventView={props.queryProps.eventView} - location={props.queryProps.location} widgetData={props.widgetData} > {results => { diff --git a/static/app/views/performance/landing/widgets/components/widgetHeader.tsx b/static/app/views/performance/landing/widgets/components/widgetHeader.tsx index 8d805b0d6c19c3..24b026bbe80b2a 100644 --- a/static/app/views/performance/landing/widgets/components/widgetHeader.tsx +++ b/static/app/views/performance/landing/widgets/components/widgetHeader.tsx @@ -17,10 +17,12 @@ export function WidgetHeader( return ( - - {title} - - +
    + +
    {title}
    + +
    +
    {Subtitle ? : null}
    diff --git a/static/app/views/performance/landing/widgets/types.tsx b/static/app/views/performance/landing/widgets/types.tsx index 8c8b8990a3a799..2f1b8490c9a196 100644 --- a/static/app/views/performance/landing/widgets/types.tsx +++ b/static/app/views/performance/landing/widgets/types.tsx @@ -48,9 +48,7 @@ export type QueryFC = FunctionComponent< team?: Readonly; query?: string; orgSlug: string; - location: Location; organization: OrganizationSummary; - eventView: EventView; widgetData: T; } >; diff --git a/static/app/views/performance/landing/widgets/widgetDefinitions.tsx b/static/app/views/performance/landing/widgets/widgetDefinitions.tsx index 19a5ea8e0c071e..e3b552563d23de 100644 --- a/static/app/views/performance/landing/widgets/widgetDefinitions.tsx +++ b/static/app/views/performance/landing/widgets/widgetDefinitions.tsx @@ -23,6 +23,7 @@ export enum PerformanceWidgetSetting { FID_HISTOGRAM = 'fid_histogram', APDEX_AREA = 'apdex_area', P50_DURATION_AREA = 'p50_duration_area', + P75_DURATION_AREA = 'p75_duration_area', P95_DURATION_AREA = 'p95_duration_area', P99_DURATION_AREA = 'p99_duration_area', P75_LCP_AREA = 'p75_lcp_area', @@ -34,6 +35,16 @@ export enum PerformanceWidgetSetting { MOST_REGRESSED = 'most_regressed', MOST_RELATED_ERRORS = 'most_related_errors', MOST_RELATED_ISSUES = 'most_related_issues', + SLOW_HTTP_OPS = 'slow_http_ops', + SLOW_DB_OPS = 'slow_db_ops', + SLOW_RESOURCE_OPS = 'slow_resource_ops', + SLOW_BROWSER_OPS = 'slow_browser_ops', + COLD_STARTUP_AREA = 'cold_startup_area', + WARM_STARTUP_AREA = 'warm_startup_area', + SLOW_FRAMES_AREA = 'slow_frames_area', + FROZEN_FRAMES_AREA = 'frozen_frames_area', + MOST_SLOW_FRAMES = 'most_slow_frames', + MOST_FROZEN_FRAMES = 'most_frozen_frames', } const WIDGET_PALETTE = CHART_PALETTE[5]; @@ -105,6 +116,13 @@ export const WIDGET_DEFINITIONS: ({ dataType: GenericPerformanceWidgetDataType.area, chartColor: WIDGET_PALETTE[3], }, + [PerformanceWidgetSetting.P75_DURATION_AREA]: { + title: t('p75 Duration'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.P75), + fields: ['p75(transaction.duration)'], // TODO(k-fish): Check + dataType: GenericPerformanceWidgetDataType.area, + chartColor: WIDGET_PALETTE[3], + }, [PerformanceWidgetSetting.P95_DURATION_AREA]: { title: t('p95 Duration'), titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.P95), @@ -140,20 +158,90 @@ export const WIDGET_DEFINITIONS: ({ dataType: GenericPerformanceWidgetDataType.area, chartColor: WIDGET_PALETTE[0], }, + [PerformanceWidgetSetting.COLD_STARTUP_AREA]: { + title: t('Cold Startup Time'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.APP_START_COLD), + fields: ['p75(measurements.app_start_cold)'], + dataType: GenericPerformanceWidgetDataType.area, + chartColor: WIDGET_PALETTE[4], + }, + [PerformanceWidgetSetting.WARM_STARTUP_AREA]: { + title: t('Warm Startup Time'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.APP_START_WARM), + fields: ['p75(measurements.app_start_warm)'], + dataType: GenericPerformanceWidgetDataType.area, + chartColor: WIDGET_PALETTE[3], + }, + [PerformanceWidgetSetting.SLOW_FRAMES_AREA]: { + title: t('Slow Frames'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.SLOW_FRAMES), + fields: ['p75(measurements.frames_slow_rate)'], + dataType: GenericPerformanceWidgetDataType.area, + chartColor: WIDGET_PALETTE[0], + }, + [PerformanceWidgetSetting.FROZEN_FRAMES_AREA]: { + title: t('Frozen Frames'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.FROZEN_FRAMES), + fields: ['p75(measurements.frames_frozen_rate)'], + dataType: GenericPerformanceWidgetDataType.area, + chartColor: WIDGET_PALETTE[5], + }, [PerformanceWidgetSetting.MOST_RELATED_ERRORS]: { title: t('Most Related Errors'), - titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.USER_MISERY), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.MOST_ERRORS), fields: [`failure_count()`], dataType: GenericPerformanceWidgetDataType.line_list, chartColor: WIDGET_PALETTE[0], }, [PerformanceWidgetSetting.MOST_RELATED_ISSUES]: { title: t('Most Related Issues'), - titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.USER_MISERY), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.MOST_ISSUES), fields: [`count()`], dataType: GenericPerformanceWidgetDataType.line_list, chartColor: WIDGET_PALETTE[0], }, + [PerformanceWidgetSetting.SLOW_HTTP_OPS]: { + title: t('Slow HTTP Ops'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.SLOW_HTTP_SPANS), + fields: [`p75(spans.http)`], + dataType: GenericPerformanceWidgetDataType.line_list, + chartColor: WIDGET_PALETTE[0], + }, + [PerformanceWidgetSetting.SLOW_BROWSER_OPS]: { + title: t('Slow Browser Ops'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.SLOW_HTTP_SPANS), + fields: [`p75(spans.browser)`], + dataType: GenericPerformanceWidgetDataType.line_list, + chartColor: WIDGET_PALETTE[0], + }, + [PerformanceWidgetSetting.SLOW_RESOURCE_OPS]: { + title: t('Slow Resource Ops'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.SLOW_HTTP_SPANS), + fields: [`p75(spans.resource)`], + dataType: GenericPerformanceWidgetDataType.line_list, + chartColor: WIDGET_PALETTE[0], + }, + [PerformanceWidgetSetting.SLOW_DB_OPS]: { + title: t('Slow DB Ops'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.SLOW_HTTP_SPANS), + fields: [`p75(spans.db)`], + dataType: GenericPerformanceWidgetDataType.line_list, + chartColor: WIDGET_PALETTE[0], + }, + [PerformanceWidgetSetting.MOST_SLOW_FRAMES]: { + title: t('Most Slow Frames'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.SLOW_FRAMES), + fields: ['p75(measurements.frames_slow_rate)'], + dataType: GenericPerformanceWidgetDataType.line_list, + chartColor: WIDGET_PALETTE[0], + }, + [PerformanceWidgetSetting.MOST_FROZEN_FRAMES]: { + title: t('Most Frozen Frames'), + titleTooltip: getTermHelp(organization, PERFORMANCE_TERM.FROZEN_FRAMES), + fields: ['p75(measurements.frames_frozen_rate)'], + dataType: GenericPerformanceWidgetDataType.line_list, + chartColor: WIDGET_PALETTE[0], + }, [PerformanceWidgetSetting.MOST_IMPROVED]: { title: t('Most Improved'), titleTooltip: t( diff --git a/static/app/views/performance/landing/widgets/widgets/histogramWidget.tsx b/static/app/views/performance/landing/widgets/widgets/histogramWidget.tsx index 3d39713bb103da..a06a124d7d03ca 100644 --- a/static/app/views/performance/landing/widgets/widgets/histogramWidget.tsx +++ b/static/app/views/performance/landing/widgets/widgets/histogramWidget.tsx @@ -39,12 +39,18 @@ export function HistogramWidget(props: Props) { chart: { fields: props.fields, component: provided => ( - + ), transform: transformHistogramQuery, }, }; - }, [props.eventView, props.fields, props.organization.slug]); + }, [props.eventView.query, props.fields[0], props.organization.slug]); const onFilterChange = () => {}; diff --git a/static/app/views/performance/landing/widgets/widgets/lineChartListWidget.tsx b/static/app/views/performance/landing/widgets/widgets/lineChartListWidget.tsx index d20645d424899f..b1b6b0ff7b0566 100644 --- a/static/app/views/performance/landing/widgets/widgets/lineChartListWidget.tsx +++ b/static/app/views/performance/landing/widgets/widgets/lineChartListWidget.tsx @@ -14,10 +14,12 @@ import space from 'app/styles/space'; import {Organization} from 'app/types'; import DiscoverQuery from 'app/utils/discover/discoverQuery'; import EventView from 'app/utils/discover/eventView'; +import {getAggregateAlias} from 'app/utils/discover/fields'; import {MutableSearch} from 'app/utils/tokenizeSearch'; import withApi from 'app/utils/withApi'; import _DurationChart from 'app/views/performance/charts/chart'; import {transactionSummaryRouteWithQuery} from 'app/views/performance/transactionSummary/utils'; +import {getPerformanceDuration} from 'app/views/performance/utils'; import {excludeTransaction} from '../../utils'; import {GenericPerformanceWidget} from '../components/performanceWidget'; @@ -56,98 +58,126 @@ export function LineChartListWidget(props: Props) { ); } - const Queries = { - list: useMemo>( - () => ({ - fields: props.fields[0], - component: provided => { - const eventView = provided.eventView.clone(); - eventView.sorts = [{kind: 'desc', field: props.fields[0]}]; - if (props.chartSetting === PerformanceWidgetSetting.MOST_RELATED_ISSUES) { - eventView.fields = [ - {field: 'issue'}, - {field: 'transaction'}, - {field: 'title'}, - {field: 'project.id'}, - {field: props.fields[0]}, - ]; - eventView.additionalConditions.setFilterValues('event.type', ['error']); - eventView.additionalConditions.setFilterValues('!tags[transaction]', ['']); - const mutableSearch = new MutableSearch(eventView.query); - mutableSearch.removeFilter('transaction.duration'); - eventView.query = mutableSearch.formatString(); - } else { - eventView.fields = [ - {field: 'transaction'}, - {field: 'project.id'}, - {field: props.fields[0]}, - ]; - } - return ; - }, - transform: transformDiscoverToList, - }), - [props.eventView, props.fields, props.chartSetting, props.organization.slug] - ), - chart: useMemo>( - () => ({ - enabled: widgetData => { - return !!widgetData?.list?.data?.length; - }, - fields: props.fields[0], - component: provided => { - const eventView = provided.eventView.clone(); - eventView.additionalConditions.setFilterValues('transaction', [ - provided.widgetData.list.data[selectedListIndex].transaction as string, + const slowList = [ + PerformanceWidgetSetting.SLOW_HTTP_OPS, + PerformanceWidgetSetting.SLOW_DB_OPS, + PerformanceWidgetSetting.SLOW_BROWSER_OPS, + PerformanceWidgetSetting.SLOW_RESOURCE_OPS, + PerformanceWidgetSetting.MOST_SLOW_FRAMES, + PerformanceWidgetSetting.MOST_FROZEN_FRAMES, + ]; + const isSlowestType = slowList.includes(props.chartSetting); + + const eventView = props.eventView.clone(); + + const listQuery = useMemo>( + () => ({ + fields: props.fields[0], + component: provided => { + eventView.sorts = [{kind: 'desc', field: props.fields[0]}]; + if (props.chartSetting === PerformanceWidgetSetting.MOST_RELATED_ISSUES) { + eventView.fields = [ + {field: 'issue'}, + {field: 'transaction'}, + {field: 'title'}, + {field: 'project.id'}, + {field: props.fields[0]}, + ]; + eventView.additionalConditions.setFilterValues('event.type', ['error']); + eventView.additionalConditions.setFilterValues('!tags[transaction]', ['']); + const mutableSearch = new MutableSearch(eventView.query); + mutableSearch.removeFilter('transaction.duration'); + eventView.query = mutableSearch.formatString(); + } else if (isSlowestType) { + eventView.additionalConditions.setFilterValues('epm()', ['>0.01']); + eventView.fields = [ + {field: 'transaction'}, + {field: 'project.id'}, + {field: 'epm()'}, + {field: props.fields[0]}, + ]; + } else { + // Most related errors + eventView.fields = [ + {field: 'transaction'}, + {field: 'project.id'}, + {field: props.fields[0]}, + ]; + } + return ( + + ); + }, + transform: transformDiscoverToList, + }), + [props.eventView.query, props.fields[0], props.organization.slug] + ); + + const chartQuery = useMemo>(() => { + return { + enabled: widgetData => { + return !!widgetData?.list?.data?.length; + }, + fields: props.fields[0], + component: provided => { + eventView.additionalConditions.setFilterValues('transaction', [ + provided.widgetData.list.data[selectedListIndex].transaction as string, + ]); + if (props.chartSetting === PerformanceWidgetSetting.MOST_RELATED_ISSUES) { + eventView.fields = [ + {field: 'issue'}, + {field: 'issue.id'}, + {field: 'transaction'}, + {field: props.fields[0]}, + ]; + eventView.additionalConditions.setFilterValues('issue', [ + provided.widgetData.list.data[selectedListIndex].issue as string, ]); - if (props.chartSetting === PerformanceWidgetSetting.MOST_RELATED_ISSUES) { - eventView.fields = [ - {field: 'issue'}, - {field: 'issue.id'}, - {field: 'transaction'}, - {field: props.fields[0]}, - ]; - eventView.additionalConditions.setFilterValues('issue', [ - provided.widgetData.list.data[selectedListIndex].issue as string, - ]); - eventView.additionalConditions.setFilterValues('event.type', ['error']); - eventView.additionalConditions.setFilterValues('!tags[transaction]', ['']); - const mutableSearch = new MutableSearch(eventView.query); - mutableSearch.removeFilter('transaction.duration'); - eventView.query = mutableSearch.formatString(); - } else { - eventView.fields = [{field: 'transaction'}, {field: props.fields[0]}]; - } - return ( - - ); - }, - transform: transformEventsRequestToArea, - }), - [ - props.eventView, - props.fields, - props.organization.slug, - props.chartSetting, - selectedListIndex, - ] - ), + eventView.additionalConditions.setFilterValues('event.type', ['error']); + eventView.additionalConditions.setFilterValues('!tags[transaction]', ['']); + const mutableSearch = new MutableSearch(eventView.query); + mutableSearch.removeFilter('transaction.duration'); + eventView.query = mutableSearch.formatString(); + } else { + eventView.fields = [{field: 'transaction'}, {field: props.fields[0]}]; + } + return ( + + ); + }, + transform: transformEventsRequestToArea, + }; + }, [ + props.eventView.query, + props.fields[0], + props.organization.slug, + selectedListIndex, + ]); + + const Queries = { + list: listQuery, + chart: chartQuery, }; return ( @@ -167,6 +197,7 @@ export function LineChartListWidget(props: Props) { disableMultiAxis disableXAxis chartColors={props.chartColor ? [props.chartColor] : undefined} + isLineChart /> ), height: 160, @@ -178,17 +209,50 @@ export function LineChartListWidget(props: Props) { setSelectedIndex={setSelectListIndex} items={provided.widgetData.list.data.map(listItem => () => { const transaction = listItem.transaction as string; + + const additionalQuery: Record = {}; + + if (props.chartSetting === PerformanceWidgetSetting.SLOW_HTTP_OPS) { + additionalQuery.breakdown = 'http'; + additionalQuery.display = 'latency'; + } else if (props.chartSetting === PerformanceWidgetSetting.SLOW_DB_OPS) { + additionalQuery.breakdown = 'db'; + additionalQuery.display = 'latency'; + } else if ( + props.chartSetting === PerformanceWidgetSetting.SLOW_BROWSER_OPS + ) { + additionalQuery.breakdown = 'browser'; + additionalQuery.display = 'latency'; + } else if ( + props.chartSetting === PerformanceWidgetSetting.SLOW_RESOURCE_OPS + ) { + additionalQuery.breakdown = 'resource'; + additionalQuery.display = 'latency'; + } + const transactionTarget = transactionSummaryRouteWithQuery({ orgSlug: props.organization.slug, projectID: listItem['project.id'] as string, transaction, query: props.eventView.getGlobalSelectionQuery(), + additionalQuery, }); + + const fieldString = getAggregateAlias(props.fields[0]); + + const valueMap = { + [PerformanceWidgetSetting.MOST_RELATED_ERRORS]: listItem.failure_count, + [PerformanceWidgetSetting.MOST_RELATED_ISSUES]: listItem.issue, + slowest: getPerformanceDuration(listItem[fieldString] as number), + }; + const rightValue = + valueMap[isSlowestType ? 'slowest' : props.chartSetting]; + switch (props.chartSetting) { case PerformanceWidgetSetting.MOST_RELATED_ISSUES: return ( - + @@ -196,7 +260,7 @@ export function LineChartListWidget(props: Props) { - {listItem.issue} + {rightValue} @@ -212,10 +276,10 @@ export function LineChartListWidget(props: Props) { default: return ( - + - {listItem.failure_count} + {rightValue} diff --git a/static/app/views/performance/landing/widgets/widgets/singleFieldAreaWidget.tsx b/static/app/views/performance/landing/widgets/widgets/singleFieldAreaWidget.tsx index 86335f4fd470f9..d10655b6c24965 100644 --- a/static/app/views/performance/landing/widgets/widgets/singleFieldAreaWidget.tsx +++ b/static/app/views/performance/landing/widgets/widgets/singleFieldAreaWidget.tsx @@ -51,13 +51,14 @@ export function SingleFieldAreaWidget(props: Props) { includeTransformedData partial currentSeriesName={props.fields[0]} + eventView={props.eventView} query={props.eventView.getQueryWithAdditionalConditions()} /> ), transform: transformEventsRequestToArea, }, }; - }, [props.eventView, props.fields, props.organization.slug]); + }, [props.eventView.query, props.fields[0], props.organization.slug]); return ( diff --git a/static/app/views/performance/landing/widgets/widgets/trendsWidget.tsx b/static/app/views/performance/landing/widgets/widgets/trendsWidget.tsx index a77c8cc40c8dea..3eb9552030e6f3 100644 --- a/static/app/views/performance/landing/widgets/widgets/trendsWidget.tsx +++ b/static/app/views/performance/landing/widgets/widgets/trendsWidget.tsx @@ -86,7 +86,7 @@ export function TrendsWidget(props: Props) { transform: transformTrendsDiscover, }, }; - }, [_eventView, trendChangeType]); + }, [eventView.query, eventView.fields, trendChangeType]); return ( diff --git a/static/app/views/performance/landing/widgets/widgets/vitalWidget.tsx b/static/app/views/performance/landing/widgets/widgets/vitalWidget.tsx index 3ef075d9dadd16..28bfd0f7d7b691 100644 --- a/static/app/views/performance/landing/widgets/widgets/vitalWidget.tsx +++ b/static/app/views/performance/landing/widgets/widgets/vitalWidget.tsx @@ -57,7 +57,7 @@ export function VitalWidget(props: Props) { () => ({ fields: props.fields[0], component: provided => { - const _eventView = provided.eventView.clone(); + const _eventView = props.eventView.clone(); const fieldFromProps = props.fields.map(field => ({ field, @@ -73,7 +73,14 @@ export function VitalWidget(props: Props) { ]; const mutableSearch = new MutableSearch(_eventView.query); _eventView.query = mutableSearch.formatString(); - return ; + return ( + + ); }, transform: transformDiscoverToList, }), diff --git a/static/app/views/performance/transactionSummary/utils.tsx b/static/app/views/performance/transactionSummary/utils.tsx index 59c9bfc8a8dfca..a3bbf574426725 100644 --- a/static/app/views/performance/transactionSummary/utils.tsx +++ b/static/app/views/performance/transactionSummary/utils.tsx @@ -32,6 +32,7 @@ export function transactionSummaryRouteWithQuery({ trendFunction, trendColumn, showTransactions, + additionalQuery, }: { orgSlug: string; transaction: string; @@ -42,6 +43,7 @@ export function transactionSummaryRouteWithQuery({ unselectedSeries?: string | string[]; projectID?: string | string[]; showTransactions?: TransactionFilterOptions; + additionalQuery?: Record; }) { const pathname = generateTransactionSummaryRoute({ orgSlug, @@ -62,6 +64,7 @@ export function transactionSummaryRouteWithQuery({ display, trendFunction, trendColumn, + ...additionalQuery, }, }; }