diff --git a/static/app/components/preprod/preprodBuildsTable.tsx b/static/app/components/preprod/preprodBuildsTable.tsx index 59d7af5fbb3c6a..c7609d6e2b8e82 100644 --- a/static/app/components/preprod/preprodBuildsTable.tsx +++ b/static/app/components/preprod/preprodBuildsTable.tsx @@ -15,8 +15,8 @@ import {IconCheckmark, IconCommit} from 'sentry/icons'; import {t} from 'sentry/locale'; import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes'; import { - formattedDownloadSize, - formattedInstallSize, + formattedPrimaryMetricDownloadSize, + formattedPrimaryMetricInstallSize, getLabels, getPlatformIconFromPlatform, } from 'sentry/views/preprod/utils/labelUtils'; @@ -137,11 +137,11 @@ export function PreprodBuildsTable({ - {formattedInstallSize(build)} + {formattedPrimaryMetricInstallSize(build.size_info)} - {formattedDownloadSize(build)} + {formattedPrimaryMetricDownloadSize(build.size_info)} diff --git a/static/app/views/preprod/buildComparison/header/buildCompareHeaderContent.tsx b/static/app/views/preprod/buildComparison/header/buildCompareHeaderContent.tsx index 2cdf444f03e0b2..16af33f26fca8f 100644 --- a/static/app/views/preprod/buildComparison/header/buildCompareHeaderContent.tsx +++ b/static/app/views/preprod/buildComparison/header/buildCompareHeaderContent.tsx @@ -18,8 +18,8 @@ import { type BuildDetailsApiResponse, } from 'sentry/views/preprod/types/buildDetailsTypes'; import { - formattedDownloadSize, - formattedInstallSize, + formattedPrimaryMetricDownloadSize, + formattedPrimaryMetricInstallSize, getLabels, getPlatformIconFromPlatform, getReadablePlatformLabel, @@ -100,7 +100,9 @@ export function BuildCompareHeaderContent(props: BuildCompareHeaderContentProps) - {formattedInstallSize(buildDetails)} + + {formattedPrimaryMetricInstallSize(buildDetails.size_info)} + )} @@ -108,7 +110,9 @@ export function BuildCompareHeaderContent(props: BuildCompareHeaderContentProps) - {formattedDownloadSize(buildDetails)} + + {formattedPrimaryMetricDownloadSize(buildDetails.size_info)} + )} diff --git a/static/app/views/preprod/buildComparison/main/sizeCompareSelectionContent.tsx b/static/app/views/preprod/buildComparison/main/sizeCompareSelectionContent.tsx index 233c4ffc42775e..afcc6a8eed719a 100644 --- a/static/app/views/preprod/buildComparison/main/sizeCompareSelectionContent.tsx +++ b/static/app/views/preprod/buildComparison/main/sizeCompareSelectionContent.tsx @@ -23,7 +23,6 @@ import { } from 'sentry/icons'; import {IconBranch} from 'sentry/icons/iconBranch'; import {t} from 'sentry/locale'; -import {formatBytesBase10} from 'sentry/utils/bytes/formatBytesBase10'; import parseLinkHeader from 'sentry/utils/parseLinkHeader'; import {useApiQuery, useMutation, type UseApiQueryResult} from 'sentry/utils/queryClient'; import {decodeScalar} from 'sentry/utils/queryString'; @@ -39,6 +38,10 @@ import { type BuildDetailsApiResponse, } from 'sentry/views/preprod/types/buildDetailsTypes'; import type {ListBuildsApiResponse} from 'sentry/views/preprod/types/listBuildsTypes'; +import { + formattedPrimaryMetricDownloadSize, + formattedPrimaryMetricInstallSize, +} from 'sentry/views/preprod/utils/labelUtils'; import {SizeCompareSelectedBuilds} from './sizeCompareSelectedBuilds'; @@ -249,13 +252,13 @@ function BuildItem({build, isSelected, onSelect}: BuildItemProps) { {isSizeInfoCompleted(sizeInfo) && ( - {formatBytesBase10(sizeInfo.install_size_bytes)} + {formattedPrimaryMetricInstallSize(sizeInfo)} )} {isSizeInfoCompleted(sizeInfo) && ( - {formatBytesBase10(sizeInfo.download_size_bytes)} + {formattedPrimaryMetricDownloadSize(sizeInfo)} )} diff --git a/static/app/views/preprod/buildDetails/buildDetails.spec.tsx b/static/app/views/preprod/buildDetails/buildDetails.spec.tsx index b50f4258e449a3..d6746315ea1b8c 100644 --- a/static/app/views/preprod/buildDetails/buildDetails.spec.tsx +++ b/static/app/views/preprod/buildDetails/buildDetails.spec.tsx @@ -6,6 +6,7 @@ import { import {render, screen, waitFor} from 'sentry-test/reactTestingLibrary'; +import {MetricsArtifactType} from 'sentry/views/preprod/types/appSizeTypes'; import {BuildDetailsSizeAnalysisState} from 'sentry/views/preprod/types/buildDetailsTypes'; import BuildDetails from './buildDetails'; @@ -98,8 +99,13 @@ describe('BuildDetails', () => { body: PreprodBuildDetailsWithSizeInfoFixture( { state: BuildDetailsSizeAnalysisState.COMPLETED, - install_size_bytes: 1024000, - download_size_bytes: 512000, + size_metrics: [ + { + metrics_artifact_type: MetricsArtifactType.MAIN_ARTIFACT, + install_size_bytes: 1024000, + download_size_bytes: 512000, + }, + ], }, { vcs_info: PreprodVcsInfoFullFixture(), @@ -168,8 +174,13 @@ describe('BuildDetails', () => { } return PreprodBuildDetailsWithSizeInfoFixture({ state: BuildDetailsSizeAnalysisState.COMPLETED, - install_size_bytes: 1024000, - download_size_bytes: 512000, + size_metrics: [ + { + metrics_artifact_type: MetricsArtifactType.MAIN_ARTIFACT, + install_size_bytes: 1024000, + download_size_bytes: 512000, + }, + ], }); }, }); @@ -215,8 +226,13 @@ describe('BuildDetails', () => { method: 'GET', body: PreprodBuildDetailsWithSizeInfoFixture({ state: BuildDetailsSizeAnalysisState.COMPLETED, - install_size_bytes: 1024000, - download_size_bytes: 512000, + size_metrics: [ + { + metrics_artifact_type: MetricsArtifactType.MAIN_ARTIFACT, + install_size_bytes: 1024000, + download_size_bytes: 512000, + }, + ], }), }); diff --git a/static/app/views/preprod/buildDetails/sidebar/buildDetailsSidebarAppInfo.tsx b/static/app/views/preprod/buildDetails/sidebar/buildDetailsSidebarAppInfo.tsx index 762b76b3177d76..aa3ff6e65e9c8d 100644 --- a/static/app/views/preprod/buildDetails/sidebar/buildDetailsSidebarAppInfo.tsx +++ b/static/app/views/preprod/buildDetails/sidebar/buildDetailsSidebarAppInfo.tsx @@ -2,7 +2,7 @@ import styled from '@emotion/styled'; import {PlatformIcon} from 'platformicons'; import {CodeBlock} from '@sentry/scraps/code'; -import {Flex} from '@sentry/scraps/layout'; +import {Flex, Stack} from '@sentry/scraps/layout'; import {Heading, Text} from '@sentry/scraps/text'; import {Tooltip} from '@sentry/scraps/tooltip'; @@ -12,12 +12,16 @@ import {t} from 'sentry/locale'; import {formatBytesBase10} from 'sentry/utils/bytes/formatBytesBase10'; import {getFormat, getFormattedDate, getUtcToSystem} from 'sentry/utils/dates'; import {openInstallModal} from 'sentry/views/preprod/components/installModal'; +import {MetricsArtifactType} from 'sentry/views/preprod/types/appSizeTypes'; import { BuildDetailsSizeAnalysisState, + getMainArtifactSizeMetric, type BuildDetailsAppInfo, type BuildDetailsSizeInfo, } from 'sentry/views/preprod/types/buildDetailsTypes'; import { + formattedPrimaryMetricDownloadSize, + formattedPrimaryMetricInstallSize, getLabels, getPlatformIconFromPlatform, getReadableArtifactTypeLabel, @@ -40,6 +44,101 @@ export function BuildDetailsSidebarAppInfo(props: BuildDetailsSidebarAppInfoProp timeZone: true, }); + let sizeInfoGroup = null; + if ( + props.sizeInfo && + props.sizeInfo.state === BuildDetailsSizeAnalysisState.COMPLETED + ) { + const primarySizeMetric = getMainArtifactSizeMetric(props.sizeInfo); + const watchAppMetrics = props.sizeInfo.size_metrics.find( + metric => metric.metrics_artifact_type === MetricsArtifactType.WATCH_ARTIFACT + ); + + let installSizeContent = ( + {formattedPrimaryMetricInstallSize(props.sizeInfo)} + ); + let downloadSizeContent = ( + {formattedPrimaryMetricDownloadSize(props.sizeInfo)} + ); + if (watchAppMetrics) { + installSizeContent = ( + + + + {t('App')}: + + + {formatBytesBase10(primarySizeMetric?.install_size_bytes ?? 0)} + + + + + {t('Watch')}: + + + {formatBytesBase10(watchAppMetrics.install_size_bytes)} + + + + } + position="left" + > + + {formattedPrimaryMetricInstallSize(props.sizeInfo)} + + + ); + downloadSizeContent = ( + + + + {t('App')}: + + + {formatBytesBase10(watchAppMetrics.download_size_bytes)} + + + + + {t('Watch')}: + + + {formatBytesBase10(watchAppMetrics.download_size_bytes)} + + + + } + position="left" + > + + {formattedPrimaryMetricDownloadSize(props.sizeInfo)} + + + ); + } + + sizeInfoGroup = ( + + + + {labels.installSizeLabel} + + {installSizeContent} + + + + {labels.downloadSizeLabel} + + {downloadSizeContent} + + + ); + } + return ( @@ -49,27 +148,7 @@ export function BuildDetailsSidebarAppInfo(props: BuildDetailsSidebarAppInfoProp {props.appInfo.name && {props.appInfo.name}} - {props.sizeInfo && - props.sizeInfo.state === BuildDetailsSizeAnalysisState.COMPLETED && ( - - - - {labels.installSizeLabel} - - - {formatBytesBase10(props.sizeInfo.install_size_bytes)} - - - - - {labels.downloadSizeLabel} - - - {formatBytesBase10(props.sizeInfo.download_size_bytes)} - - - - )} + {sizeInfoGroup} diff --git a/static/app/views/preprod/types/buildDetailsTypes.ts b/static/app/views/preprod/types/buildDetailsTypes.ts index 41cdccea695152..9ded2c20700f2e 100644 --- a/static/app/views/preprod/types/buildDetailsTypes.ts +++ b/static/app/views/preprod/types/buildDetailsTypes.ts @@ -1,3 +1,6 @@ +/* eslint-disable typescript-sort-keys/interface */ +import {MetricsArtifactType} from 'sentry/views/preprod/types/appSizeTypes'; + import type {Platform} from './sharedTypes'; export interface BuildDetailsApiResponse { @@ -42,6 +45,12 @@ export interface BuildDetailsVcsInfo { provider?: string | null; } +interface BuildDetailsSizeInfoSizeMetric { + metrics_artifact_type: MetricsArtifactType; + install_size_bytes: number; + download_size_bytes: number; +} + interface BuildDetailsSizeInfoPending { state: BuildDetailsSizeAnalysisState.PENDING; } @@ -51,9 +60,8 @@ interface BuildDetailsSizeInfoProcessing { } interface BuildDetailsSizeInfoCompleted { - download_size_bytes: number; - install_size_bytes: number; state: BuildDetailsSizeAnalysisState.COMPLETED; + size_metrics: BuildDetailsSizeInfoSizeMetric[]; } interface BuildDetailsSizeInfoFailed { @@ -83,6 +91,14 @@ export function isSizeInfoProcessing( ); } +export function getMainArtifactSizeMetric( + sizeInfo: BuildDetailsSizeInfoCompleted +): BuildDetailsSizeInfoSizeMetric | undefined { + return sizeInfo.size_metrics.find( + metric => metric.metrics_artifact_type === MetricsArtifactType.MAIN_ARTIFACT + ); +} + export enum BuildDetailsState { UPLOADING = 0, UPLOADED = 1, diff --git a/static/app/views/preprod/utils/labelUtils.tsx b/static/app/views/preprod/utils/labelUtils.tsx index c6153e1a511bb0..0c9dbe3bc4b232 100644 --- a/static/app/views/preprod/utils/labelUtils.tsx +++ b/static/app/views/preprod/utils/labelUtils.tsx @@ -3,8 +3,9 @@ import {formatBytesBase10} from 'sentry/utils/bytes/formatBytesBase10'; import {unreachable} from 'sentry/utils/unreachable'; import { BuildDetailsArtifactType, + getMainArtifactSizeMetric, isSizeInfoCompleted, - type BuildDetailsApiResponse, + type BuildDetailsSizeInfo, } from 'sentry/views/preprod/types/buildDetailsTypes'; import type {Platform} from 'sentry/views/preprod/types/sharedTypes'; @@ -114,16 +115,30 @@ export function getReadablePlatformLabel(platform: Platform): string { } } -export function formattedInstallSize(build: BuildDetailsApiResponse): string { - if (isSizeInfoCompleted(build?.size_info)) { - return formatBytesBase10(build.size_info.install_size_bytes); +export function formattedPrimaryMetricInstallSize( + sizeInfo: BuildDetailsSizeInfo | undefined +): string { + if (isSizeInfoCompleted(sizeInfo)) { + const primarySizeMetric = getMainArtifactSizeMetric(sizeInfo); + if (!primarySizeMetric) { + return '-'; + } + + return formatBytesBase10(primarySizeMetric.install_size_bytes); } return '-'; } -export function formattedDownloadSize(build: BuildDetailsApiResponse): string { - if (isSizeInfoCompleted(build?.size_info)) { - return formatBytesBase10(build.size_info.download_size_bytes); +export function formattedPrimaryMetricDownloadSize( + sizeInfo: BuildDetailsSizeInfo | undefined +): string { + if (isSizeInfoCompleted(sizeInfo)) { + const primarySizeMetric = getMainArtifactSizeMetric(sizeInfo); + if (!primarySizeMetric) { + return '-'; + } + + return formatBytesBase10(primarySizeMetric.download_size_bytes); } return '-'; }