Skip to content

Commit cc22538

Browse files
authored
Frontend to show watch app size metrics (#103199)
<img width="365" height="179" alt="Screenshot 2025-11-11 at 3 36 29 PM" src="https://github.com/user-attachments/assets/70be4022-7233-4cd1-a582-4609e1e3679f" /> <img width="324" height="159" alt="Screenshot 2025-11-11 at 3 36 27 PM" src="https://github.com/user-attachments/assets/e8a2b295-ed80-460b-8a3c-e4ad88084da3" /> The above screenshots are correct, I just duplicated the original size metric and changed the artifact type to `WATCH` Resolves EME-580
1 parent 045edfa commit cc22538

File tree

7 files changed

+181
-48
lines changed

7 files changed

+181
-48
lines changed

static/app/components/preprod/preprodBuildsTable.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import {IconCheckmark, IconCommit} from 'sentry/icons';
1515
import {t} from 'sentry/locale';
1616
import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes';
1717
import {
18-
formattedDownloadSize,
19-
formattedInstallSize,
18+
formattedPrimaryMetricDownloadSize,
19+
formattedPrimaryMetricInstallSize,
2020
getLabels,
2121
getPlatformIconFromPlatform,
2222
} from 'sentry/views/preprod/utils/labelUtils';
@@ -137,11 +137,11 @@ export function PreprodBuildsTable({
137137
</SimpleTable.RowCell>
138138

139139
<SimpleTable.RowCell>
140-
<Text>{formattedInstallSize(build)}</Text>
140+
<Text>{formattedPrimaryMetricInstallSize(build.size_info)}</Text>
141141
</SimpleTable.RowCell>
142142

143143
<SimpleTable.RowCell>
144-
<Text>{formattedDownloadSize(build)}</Text>
144+
<Text>{formattedPrimaryMetricDownloadSize(build.size_info)}</Text>
145145
</SimpleTable.RowCell>
146146

147147
<SimpleTable.RowCell>

static/app/views/preprod/buildComparison/header/buildCompareHeaderContent.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import {
1818
type BuildDetailsApiResponse,
1919
} from 'sentry/views/preprod/types/buildDetailsTypes';
2020
import {
21-
formattedDownloadSize,
22-
formattedInstallSize,
21+
formattedPrimaryMetricDownloadSize,
22+
formattedPrimaryMetricInstallSize,
2323
getLabels,
2424
getPlatformIconFromPlatform,
2525
getReadablePlatformLabel,
@@ -100,15 +100,19 @@ export function BuildCompareHeaderContent(props: BuildCompareHeaderContentProps)
100100
<Tooltip title={labels.installSizeDescription}>
101101
<Flex gap="sm" align="center">
102102
<IconCode size="sm" color="gray300" />
103-
<Text underline="dotted">{formattedInstallSize(buildDetails)}</Text>
103+
<Text underline="dotted">
104+
{formattedPrimaryMetricInstallSize(buildDetails.size_info)}
105+
</Text>
104106
</Flex>
105107
</Tooltip>
106108
)}
107109
{isSizeInfoCompleted(buildDetails.size_info) && (
108110
<Tooltip title={labels.downloadSizeDescription}>
109111
<Flex gap="sm" align="center">
110112
<IconDownload size="sm" color="gray300" />
111-
<Text underline="dotted">{formattedDownloadSize(buildDetails)}</Text>
113+
<Text underline="dotted">
114+
{formattedPrimaryMetricDownloadSize(buildDetails.size_info)}
115+
</Text>
112116
</Flex>
113117
</Tooltip>
114118
)}

static/app/views/preprod/buildComparison/main/sizeCompareSelectionContent.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import {
2323
} from 'sentry/icons';
2424
import {IconBranch} from 'sentry/icons/iconBranch';
2525
import {t} from 'sentry/locale';
26-
import {formatBytesBase10} from 'sentry/utils/bytes/formatBytesBase10';
2726
import parseLinkHeader from 'sentry/utils/parseLinkHeader';
2827
import {useApiQuery, useMutation, type UseApiQueryResult} from 'sentry/utils/queryClient';
2928
import {decodeScalar} from 'sentry/utils/queryString';
@@ -39,6 +38,10 @@ import {
3938
type BuildDetailsApiResponse,
4039
} from 'sentry/views/preprod/types/buildDetailsTypes';
4140
import type {ListBuildsApiResponse} from 'sentry/views/preprod/types/listBuildsTypes';
41+
import {
42+
formattedPrimaryMetricDownloadSize,
43+
formattedPrimaryMetricInstallSize,
44+
} from 'sentry/views/preprod/utils/labelUtils';
4245

4346
import {SizeCompareSelectedBuilds} from './sizeCompareSelectedBuilds';
4447

@@ -249,13 +252,13 @@ function BuildItem({build, isSelected, onSelect}: BuildItemProps) {
249252
{isSizeInfoCompleted(sizeInfo) && (
250253
<Flex align="center" gap="sm">
251254
<IconCode size="xs" color="gray300" />
252-
<Text>{formatBytesBase10(sizeInfo.install_size_bytes)}</Text>
255+
<Text>{formattedPrimaryMetricInstallSize(sizeInfo)}</Text>
253256
</Flex>
254257
)}
255258
{isSizeInfoCompleted(sizeInfo) && (
256259
<Flex align="center" gap="sm">
257260
<IconDownload size="xs" color="gray300" />
258-
<Text>{formatBytesBase10(sizeInfo.download_size_bytes)}</Text>
261+
<Text>{formattedPrimaryMetricDownloadSize(sizeInfo)}</Text>
259262
</Flex>
260263
)}
261264
</Flex>

static/app/views/preprod/buildDetails/buildDetails.spec.tsx

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66

77
import {render, screen, waitFor} from 'sentry-test/reactTestingLibrary';
88

9+
import {MetricsArtifactType} from 'sentry/views/preprod/types/appSizeTypes';
910
import {BuildDetailsSizeAnalysisState} from 'sentry/views/preprod/types/buildDetailsTypes';
1011

1112
import BuildDetails from './buildDetails';
@@ -98,8 +99,13 @@ describe('BuildDetails', () => {
9899
body: PreprodBuildDetailsWithSizeInfoFixture(
99100
{
100101
state: BuildDetailsSizeAnalysisState.COMPLETED,
101-
install_size_bytes: 1024000,
102-
download_size_bytes: 512000,
102+
size_metrics: [
103+
{
104+
metrics_artifact_type: MetricsArtifactType.MAIN_ARTIFACT,
105+
install_size_bytes: 1024000,
106+
download_size_bytes: 512000,
107+
},
108+
],
103109
},
104110
{
105111
vcs_info: PreprodVcsInfoFullFixture(),
@@ -168,8 +174,13 @@ describe('BuildDetails', () => {
168174
}
169175
return PreprodBuildDetailsWithSizeInfoFixture({
170176
state: BuildDetailsSizeAnalysisState.COMPLETED,
171-
install_size_bytes: 1024000,
172-
download_size_bytes: 512000,
177+
size_metrics: [
178+
{
179+
metrics_artifact_type: MetricsArtifactType.MAIN_ARTIFACT,
180+
install_size_bytes: 1024000,
181+
download_size_bytes: 512000,
182+
},
183+
],
173184
});
174185
},
175186
});
@@ -215,8 +226,13 @@ describe('BuildDetails', () => {
215226
method: 'GET',
216227
body: PreprodBuildDetailsWithSizeInfoFixture({
217228
state: BuildDetailsSizeAnalysisState.COMPLETED,
218-
install_size_bytes: 1024000,
219-
download_size_bytes: 512000,
229+
size_metrics: [
230+
{
231+
metrics_artifact_type: MetricsArtifactType.MAIN_ARTIFACT,
232+
install_size_bytes: 1024000,
233+
download_size_bytes: 512000,
234+
},
235+
],
220236
}),
221237
});
222238

static/app/views/preprod/buildDetails/sidebar/buildDetailsSidebarAppInfo.tsx

Lines changed: 101 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import styled from '@emotion/styled';
22
import {PlatformIcon} from 'platformicons';
33

44
import {CodeBlock} from '@sentry/scraps/code';
5-
import {Flex} from '@sentry/scraps/layout';
5+
import {Flex, Stack} from '@sentry/scraps/layout';
66
import {Heading, Text} from '@sentry/scraps/text';
77
import {Tooltip} from '@sentry/scraps/tooltip';
88

@@ -12,12 +12,16 @@ import {t} from 'sentry/locale';
1212
import {formatBytesBase10} from 'sentry/utils/bytes/formatBytesBase10';
1313
import {getFormat, getFormattedDate, getUtcToSystem} from 'sentry/utils/dates';
1414
import {openInstallModal} from 'sentry/views/preprod/components/installModal';
15+
import {MetricsArtifactType} from 'sentry/views/preprod/types/appSizeTypes';
1516
import {
1617
BuildDetailsSizeAnalysisState,
18+
getMainArtifactSizeMetric,
1719
type BuildDetailsAppInfo,
1820
type BuildDetailsSizeInfo,
1921
} from 'sentry/views/preprod/types/buildDetailsTypes';
2022
import {
23+
formattedPrimaryMetricDownloadSize,
24+
formattedPrimaryMetricInstallSize,
2125
getLabels,
2226
getPlatformIconFromPlatform,
2327
getReadableArtifactTypeLabel,
@@ -40,6 +44,101 @@ export function BuildDetailsSidebarAppInfo(props: BuildDetailsSidebarAppInfoProp
4044
timeZone: true,
4145
});
4246

47+
let sizeInfoGroup = null;
48+
if (
49+
props.sizeInfo &&
50+
props.sizeInfo.state === BuildDetailsSizeAnalysisState.COMPLETED
51+
) {
52+
const primarySizeMetric = getMainArtifactSizeMetric(props.sizeInfo);
53+
const watchAppMetrics = props.sizeInfo.size_metrics.find(
54+
metric => metric.metrics_artifact_type === MetricsArtifactType.WATCH_ARTIFACT
55+
);
56+
57+
let installSizeContent = (
58+
<Text size="md">{formattedPrimaryMetricInstallSize(props.sizeInfo)}</Text>
59+
);
60+
let downloadSizeContent = (
61+
<Text size="md">{formattedPrimaryMetricDownloadSize(props.sizeInfo)}</Text>
62+
);
63+
if (watchAppMetrics) {
64+
installSizeContent = (
65+
<Tooltip
66+
title={
67+
<Stack align="start">
68+
<Flex gap="sm">
69+
<Text size="md" bold>
70+
{t('App')}:
71+
</Text>
72+
<Text size="md">
73+
{formatBytesBase10(primarySizeMetric?.install_size_bytes ?? 0)}
74+
</Text>
75+
</Flex>
76+
<Flex gap="sm">
77+
<Text size="md" bold>
78+
{t('Watch')}:
79+
</Text>
80+
<Text size="md">
81+
{formatBytesBase10(watchAppMetrics.install_size_bytes)}
82+
</Text>
83+
</Flex>
84+
</Stack>
85+
}
86+
position="left"
87+
>
88+
<Text size="md" underline="dotted">
89+
{formattedPrimaryMetricInstallSize(props.sizeInfo)}
90+
</Text>
91+
</Tooltip>
92+
);
93+
downloadSizeContent = (
94+
<Tooltip
95+
title={
96+
<Stack align="start">
97+
<Flex gap="sm">
98+
<Text size="md" bold>
99+
{t('App')}:
100+
</Text>
101+
<Text size="md">
102+
{formatBytesBase10(watchAppMetrics.download_size_bytes)}
103+
</Text>
104+
</Flex>
105+
<Flex gap="sm">
106+
<Text size="md" bold>
107+
{t('Watch')}:
108+
</Text>
109+
<Text size="md">
110+
{formatBytesBase10(watchAppMetrics.download_size_bytes)}
111+
</Text>
112+
</Flex>
113+
</Stack>
114+
}
115+
position="left"
116+
>
117+
<Text size="md" underline="dotted">
118+
{formattedPrimaryMetricDownloadSize(props.sizeInfo)}
119+
</Text>
120+
</Tooltip>
121+
);
122+
}
123+
124+
sizeInfoGroup = (
125+
<Flex gap="sm">
126+
<Flex direction="column" gap="xs" flex={1}>
127+
<Tooltip title={labels.installSizeDescription} position="left">
128+
<Heading as="h4">{labels.installSizeLabel}</Heading>
129+
</Tooltip>
130+
{installSizeContent}
131+
</Flex>
132+
<Flex direction="column" gap="xs" flex={1}>
133+
<Tooltip title={labels.downloadSizeDescription} position="left">
134+
<Heading as="h4">{labels.downloadSizeLabel}</Heading>
135+
</Tooltip>
136+
{downloadSizeContent}
137+
</Flex>
138+
</Flex>
139+
);
140+
}
141+
43142
return (
44143
<Flex direction="column" gap="xl">
45144
<Flex align="center" gap="sm">
@@ -49,27 +148,7 @@ export function BuildDetailsSidebarAppInfo(props: BuildDetailsSidebarAppInfoProp
49148
{props.appInfo.name && <Heading as="h3">{props.appInfo.name}</Heading>}
50149
</Flex>
51150

52-
{props.sizeInfo &&
53-
props.sizeInfo.state === BuildDetailsSizeAnalysisState.COMPLETED && (
54-
<Flex gap="sm">
55-
<Flex direction="column" gap="xs" flex={1}>
56-
<Tooltip title={labels.installSizeDescription} position="left">
57-
<Heading as="h4">{labels.installSizeLabel}</Heading>
58-
</Tooltip>
59-
<Text size="md">
60-
{formatBytesBase10(props.sizeInfo.install_size_bytes)}
61-
</Text>
62-
</Flex>
63-
<Flex direction="column" gap="xs" flex={1}>
64-
<Tooltip title={labels.downloadSizeDescription} position="left">
65-
<Heading as="h4">{labels.downloadSizeLabel}</Heading>
66-
</Tooltip>
67-
<Text size="md">
68-
{formatBytesBase10(props.sizeInfo.download_size_bytes)}
69-
</Text>
70-
</Flex>
71-
</Flex>
72-
)}
151+
{sizeInfoGroup}
73152

74153
<Flex wrap="wrap" gap="md">
75154
<Flex gap="2xs" align="center">

static/app/views/preprod/types/buildDetailsTypes.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/* eslint-disable typescript-sort-keys/interface */
2+
import {MetricsArtifactType} from 'sentry/views/preprod/types/appSizeTypes';
3+
14
import type {Platform} from './sharedTypes';
25

36
export interface BuildDetailsApiResponse {
@@ -42,6 +45,12 @@ export interface BuildDetailsVcsInfo {
4245
provider?: string | null;
4346
}
4447

48+
interface BuildDetailsSizeInfoSizeMetric {
49+
metrics_artifact_type: MetricsArtifactType;
50+
install_size_bytes: number;
51+
download_size_bytes: number;
52+
}
53+
4554
interface BuildDetailsSizeInfoPending {
4655
state: BuildDetailsSizeAnalysisState.PENDING;
4756
}
@@ -51,9 +60,8 @@ interface BuildDetailsSizeInfoProcessing {
5160
}
5261

5362
interface BuildDetailsSizeInfoCompleted {
54-
download_size_bytes: number;
55-
install_size_bytes: number;
5663
state: BuildDetailsSizeAnalysisState.COMPLETED;
64+
size_metrics: BuildDetailsSizeInfoSizeMetric[];
5765
}
5866

5967
interface BuildDetailsSizeInfoFailed {
@@ -83,6 +91,14 @@ export function isSizeInfoProcessing(
8391
);
8492
}
8593

94+
export function getMainArtifactSizeMetric(
95+
sizeInfo: BuildDetailsSizeInfoCompleted
96+
): BuildDetailsSizeInfoSizeMetric | undefined {
97+
return sizeInfo.size_metrics.find(
98+
metric => metric.metrics_artifact_type === MetricsArtifactType.MAIN_ARTIFACT
99+
);
100+
}
101+
86102
export enum BuildDetailsState {
87103
UPLOADING = 0,
88104
UPLOADED = 1,

static/app/views/preprod/utils/labelUtils.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import {formatBytesBase10} from 'sentry/utils/bytes/formatBytesBase10';
33
import {unreachable} from 'sentry/utils/unreachable';
44
import {
55
BuildDetailsArtifactType,
6+
getMainArtifactSizeMetric,
67
isSizeInfoCompleted,
7-
type BuildDetailsApiResponse,
8+
type BuildDetailsSizeInfo,
89
} from 'sentry/views/preprod/types/buildDetailsTypes';
910
import type {Platform} from 'sentry/views/preprod/types/sharedTypes';
1011

@@ -114,16 +115,30 @@ export function getReadablePlatformLabel(platform: Platform): string {
114115
}
115116
}
116117

117-
export function formattedInstallSize(build: BuildDetailsApiResponse): string {
118-
if (isSizeInfoCompleted(build?.size_info)) {
119-
return formatBytesBase10(build.size_info.install_size_bytes);
118+
export function formattedPrimaryMetricInstallSize(
119+
sizeInfo: BuildDetailsSizeInfo | undefined
120+
): string {
121+
if (isSizeInfoCompleted(sizeInfo)) {
122+
const primarySizeMetric = getMainArtifactSizeMetric(sizeInfo);
123+
if (!primarySizeMetric) {
124+
return '-';
125+
}
126+
127+
return formatBytesBase10(primarySizeMetric.install_size_bytes);
120128
}
121129
return '-';
122130
}
123131

124-
export function formattedDownloadSize(build: BuildDetailsApiResponse): string {
125-
if (isSizeInfoCompleted(build?.size_info)) {
126-
return formatBytesBase10(build.size_info.download_size_bytes);
132+
export function formattedPrimaryMetricDownloadSize(
133+
sizeInfo: BuildDetailsSizeInfo | undefined
134+
): string {
135+
if (isSizeInfoCompleted(sizeInfo)) {
136+
const primarySizeMetric = getMainArtifactSizeMetric(sizeInfo);
137+
if (!primarySizeMetric) {
138+
return '-';
139+
}
140+
141+
return formatBytesBase10(primarySizeMetric.download_size_bytes);
127142
}
128143
return '-';
129144
}

0 commit comments

Comments
 (0)