Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions static/app/components/preprod/preprodBuildsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface PreprodBuildsTableProps {
projectSlug: string;
error?: boolean;
hasSearchQuery?: boolean;
onRowClick?: (build: BuildDetailsApiResponse) => void;
pageLinks?: string | null;
}

Expand All @@ -36,6 +37,7 @@ export function PreprodBuildsTable({
isLoading,
error,
pageLinks,
onRowClick,
organizationSlug,
projectSlug,
hasSearchQuery,
Expand All @@ -59,7 +61,7 @@ export function PreprodBuildsTable({

return (
<SimpleTable.Row key={build.id}>
<FullRowLink to={linkUrl}>
<FullRowLink to={linkUrl} onClick={() => onRowClick?.(build)}>
<InteractionStateLayer />
<SimpleTable.RowCell justify="start">
{build.app_info?.name || build.app_info?.app_id ? (
Expand Down Expand Up @@ -176,7 +178,7 @@ export function PreprodBuildsTable({
</SimpleTable.Empty>
);
} else {
tableContent = <Fragment>{builds.map(renderBuildRow)}</Fragment>;
tableContent = <Fragment>{builds.map(build => renderBuildRow(build))}</Fragment>;
}

return (
Expand Down
4 changes: 4 additions & 0 deletions static/app/utils/analytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ import type {OnboardingEventParameters} from './analytics/onboardingAnalyticsEve
import {onboardingEventMap} from './analytics/onboardingAnalyticsEvents';
import type {PerformanceEventParameters} from './analytics/performanceAnalyticsEvents';
import {performanceEventMap} from './analytics/performanceAnalyticsEvents';
import type {PreprodBuildEventParameters} from './analytics/preprodBuildAnalyticsEvents';
import {preprodBuildEventMap} from './analytics/preprodBuildAnalyticsEvents';
import type {ProfilingEventParameters} from './analytics/profilingAnalyticsEvents';
import {profilingEventMap} from './analytics/profilingAnalyticsEvents';
import type {ProjectCreationEventParameters} from './analytics/projectCreationAnalyticsEvents';
Expand Down Expand Up @@ -113,6 +115,7 @@ interface EventParameters
MonitorsEventParameters,
PerformanceEventParameters,
ProfilingEventParameters,
PreprodBuildEventParameters,
ReleasesEventParameters,
ReplayEventParameters,
SearchEventParameters,
Expand Down Expand Up @@ -151,6 +154,7 @@ const allEventMap: Record<string, string | null> = {
...monitorsEventMap,
...nextJsInsightsEventMap,
...performanceEventMap,
...preprodBuildEventMap,
...tracingEventMap,
...profilingEventMap,
...exploreAnalyticsEventMap,
Expand Down
48 changes: 48 additions & 0 deletions static/app/utils/analytics/preprodBuildAnalyticsEvents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type {Organization} from 'sentry/types/organization';

type BasePreprodBuildEvent = {
organization: Organization;
build_id?: string;
platform?: string | null;
project_slug?: string;
project_type?: string | null;
};

export type PreprodBuildEventParameters = {
'preprod.builds.compare.go_to_build_details': BasePreprodBuildEvent & {
slot?: 'head' | 'base';
};
'preprod.builds.compare.select_base_build': BasePreprodBuildEvent;
'preprod.builds.compare.trigger_comparison': BasePreprodBuildEvent;
'preprod.builds.details.compare_build_clicked': BasePreprodBuildEvent;
'preprod.builds.details.delete_build': BasePreprodBuildEvent;
'preprod.builds.details.expand_insight': BasePreprodBuildEvent & {
insight_key: string;
};
'preprod.builds.details.open_insight_details_modal': BasePreprodBuildEvent & {
insight_key: string;
};
'preprod.builds.details.open_insights_sidebar': BasePreprodBuildEvent & {
source: 'metric_card' | 'insight_table';
};
'preprod.builds.release.build_row_clicked': BasePreprodBuildEvent;
};

type PreprodBuildAnalyticsKey = keyof PreprodBuildEventParameters;

export const preprodBuildEventMap: Record<PreprodBuildAnalyticsKey, string | null> = {
'preprod.builds.release.build_row_clicked': 'Preprod Builds: Release Build Row Clicked',
'preprod.builds.details.open_insights_sidebar':
'Preprod Build Details: Insights Sidebar Opened',
'preprod.builds.details.expand_insight': 'Preprod Build Details: Insight Expanded',
'preprod.builds.details.open_insight_details_modal':
'Preprod Build Details: Open Insight Details Modal',
'preprod.builds.details.delete_build': 'Preprod Build Details: Delete Build',
'preprod.builds.details.compare_build_clicked':
'Preprod Build Details: Compare Clicked',
'preprod.builds.compare.go_to_build_details':
'Preprod Build Comparison: Go to Build Details',
'preprod.builds.compare.select_base_build': 'Preprod Build Comparison: Base Selected',
'preprod.builds.compare.trigger_comparison':
'Preprod Build Comparison: Compare Triggered',
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {Text} from '@sentry/scraps/text';

import {IconClose, IconCommit, IconFocus, IconLock, IconTelescope} from 'sentry/icons';
import {t} from 'sentry/locale';
import ProjectsStore from 'sentry/stores/projectsStore';
import {trackAnalytics} from 'sentry/utils/analytics';
import useOrganization from 'sentry/utils/useOrganization';
import {useParams} from 'sentry/utils/useParams';
import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes';
Expand All @@ -15,20 +17,42 @@ interface BuildButtonProps {
buildDetails: BuildDetailsApiResponse;
icon: React.ReactNode;
label: string;
projectType: string | null;
slot: 'head' | 'base';
onRemove?: () => void;
}

function BuildButton({buildDetails, icon, label, onRemove}: BuildButtonProps) {
function BuildButton({
buildDetails,
icon,
label,
onRemove,
slot,
projectType,
}: BuildButtonProps) {
const organization = useOrganization();
const {projectId} = useParams<{projectId: string}>();
const sha = buildDetails.vcs_info?.head_sha?.substring(0, 7);
const branchName = buildDetails.vcs_info?.head_ref;
const buildId = buildDetails.id;

const buildUrl = `/organizations/${organization.slug}/preprod/${projectId}/${buildId}/`;
const platform = buildDetails.app_info?.platform ?? null;

return (
<LinkButton to={buildUrl}>
<LinkButton
to={buildUrl}
onClick={() =>
trackAnalytics('preprod.builds.compare.go_to_build_details', {
organization,
build_id: buildId,
project_slug: projectId,
platform,
project_type: projectType,
slot,
})
}
>
<Flex align="center" gap="sm">
{icon}
<Text size="sm" variant="accent" bold>
Expand Down Expand Up @@ -107,12 +131,20 @@ export function SizeCompareSelectedBuilds({
onClearBaseBuild,
onTriggerComparison,
}: SizeCompareSelectedBuildsProps) {
const organization = useOrganization();
const {projectId} = useParams<{projectId: string}>();
const platform = headBuildDetails.app_info?.platform ?? null;
const project = ProjectsStore.getBySlug(projectId);
const projectType = project?.platform ?? null;

return (
<ComparisonContainer>
<BuildButton
buildDetails={headBuildDetails}
icon={<IconLock size="xs" locked />}
label={t('Head')}
slot="head"
projectType={projectType}
/>

<Text>{t('vs')}</Text>
Expand All @@ -123,6 +155,8 @@ export function SizeCompareSelectedBuilds({
icon={<IconFocus size="xs" color="purple400" />}
label={t('Base')}
onRemove={onClearBaseBuild}
slot="base"
projectType={projectType}
/>
) : (
<SelectBuild>
Expand All @@ -134,6 +168,13 @@ export function SizeCompareSelectedBuilds({
<Button
onClick={() => {
if (baseBuildDetails) {
trackAnalytics('preprod.builds.compare.trigger_comparison', {
organization,
project_slug: projectId,
platform,
build_id: headBuildDetails.id,
project_type: projectType,
});
onTriggerComparison();
}
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
} from 'sentry/icons';
import {IconBranch} from 'sentry/icons/iconBranch';
import {t} from 'sentry/locale';
import ProjectsStore from 'sentry/stores/projectsStore';
import {trackAnalytics} from 'sentry/utils/analytics';
import parseLinkHeader from 'sentry/utils/parseLinkHeader';
import {useApiQuery, useMutation, type UseApiQueryResult} from 'sentry/utils/queryClient';
import {decodeScalar} from 'sentry/utils/queryString';
Expand Down Expand Up @@ -62,6 +64,8 @@ export function SizeCompareSelectionContent({
const {projectId} = useParams<{
projectId: string;
}>();
const project = ProjectsStore.getBySlug(projectId);
const projectType = project?.platform ?? null;
const [selectedBaseBuild, setSelectedBaseBuild] = useState<
BuildDetailsApiResponse | undefined
>(baseBuildDetails);
Expand Down Expand Up @@ -179,7 +183,19 @@ export function SizeCompareSelectionContent({
key={build.id}
build={build}
isSelected={selectedBaseBuild === build}
onSelect={() => setSelectedBaseBuild(build)}
onSelect={() => {
setSelectedBaseBuild(build);
trackAnalytics('preprod.builds.compare.select_base_build', {
organization,
build_id: build.id,
project_slug: projectId,
platform:
build.app_info?.platform ??
headBuildDetails.app_info?.platform ??
null,
project_type: projectType,
});
}}
/>
);
})}
Expand Down
5 changes: 5 additions & 0 deletions static/app/views/preprod/buildDetails/buildDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicato
import * as Layout from 'sentry/components/layouts/thirds';
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
import {t} from 'sentry/locale';
import ProjectsStore from 'sentry/stores/projectsStore';
import {
fetchMutation,
useApiQuery,
Expand Down Expand Up @@ -95,6 +96,8 @@ export default function BuildDetails() {
const buildDetails = buildDetailsQuery.data;
const version = buildDetails?.app_info?.version;
const buildNumber = buildDetails?.app_info?.build_number;
const project = ProjectsStore.getBySlug(projectId);
const projectType = project?.platform ?? null;

let title = t('Build details');
if (
Expand Down Expand Up @@ -136,6 +139,7 @@ export default function BuildDetails() {
buildDetailsQuery={buildDetailsQuery}
projectId={projectId}
artifactId={artifactId}
projectType={projectType}
/>
</Layout.Header>

Expand All @@ -156,6 +160,7 @@ export default function BuildDetails() {
isRerunning={isRerunning}
buildDetailsData={buildDetailsQuery.data}
isBuildDetailsPending={buildDetailsQuery.isLoading}
projectType={projectType}
/>
</BuildDetailsMain>
</UrlParamBatchProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from 'sentry/icons';
import {t} from 'sentry/locale';
import ProjectsStore from 'sentry/stores/projectsStore';
import {trackAnalytics} from 'sentry/utils/analytics';
import type {UseApiQueryResult} from 'sentry/utils/queryClient';
import type RequestError from 'sentry/utils/requestError/requestError';
import {useIsSentryEmployee} from 'sentry/utils/useIsSentryEmployee';
Expand Down Expand Up @@ -61,12 +62,13 @@ interface BuildDetailsHeaderContentProps {
artifactId: string;
buildDetailsQuery: UseApiQueryResult<BuildDetailsApiResponse, RequestError>;
projectId: string;
projectType: string | null;
}

export function BuildDetailsHeaderContent(props: BuildDetailsHeaderContentProps) {
const organization = useOrganization();
const isSentryEmployee = useIsSentryEmployee();
const {buildDetailsQuery, projectId, artifactId} = props;
const {buildDetailsQuery, projectId, artifactId, projectType} = props;
const {
isDeletingArtifact,
handleDeleteArtifact,
Expand Down Expand Up @@ -128,6 +130,27 @@ export function BuildDetailsHeaderContent(props: BuildDetailsHeaderContentProps)

const version = `v${buildDetailsData.app_info.version ?? 'Unknown'} (${buildDetailsData.app_info.build_number ?? 'Unknown'})`;

const handleCompareClick = () => {
trackAnalytics('preprod.builds.details.compare_build_clicked', {
organization,
platform: buildDetailsData.app_info?.platform ?? null,
build_id: buildDetailsData.id,
project_type: projectType,
project_slug: projectId,
});
};

const handleConfirmDelete = () => {
handleDeleteArtifact();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we want analytics here?

trackAnalytics('preprod.builds.details.delete_build', {
organization,
platform: buildDetailsData.app_info?.platform ?? null,
build_id: buildDetailsData.id,
project_slug: projectId,
project_type: projectType,
});
};

return (
<React.Fragment>
<Layout.HeaderContent>
Expand All @@ -152,6 +175,7 @@ export function BuildDetailsHeaderContent(props: BuildDetailsHeaderContentProps)
/>
<Link
to={`/organizations/${organization.slug}/preprod/${projectId}/compare/${buildDetailsData.id}/`}
onClick={handleCompareClick}
>
<Button size="sm" priority="default" icon={<IconTelescope />}>
{t('Compare Build')}
Expand All @@ -162,7 +186,7 @@ export function BuildDetailsHeaderContent(props: BuildDetailsHeaderContentProps)
'Are you sure you want to delete this build? This action cannot be undone and will permanently remove all associated files and data.'
)}
confirmInput={artifactId}
onConfirm={handleDeleteArtifact}
onConfirm={handleConfirmDelete}
>
{({open: openDeleteModal}) => {
const menuItems: MenuItemProps[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface BuildDetailsMainContentProps {
onRerunAnalysis: () => void;
buildDetailsData?: BuildDetailsApiResponse | null;
isBuildDetailsPending?: boolean;
projectType?: string | null;
}

export function BuildDetailsMainContent(props: BuildDetailsMainContentProps) {
Expand All @@ -48,6 +49,7 @@ export function BuildDetailsMainContent(props: BuildDetailsMainContentProps) {
appSizeQuery,
buildDetailsData,
isBuildDetailsPending = false,
projectType,
} = props;
const {
data: appSizeData,
Expand Down Expand Up @@ -305,6 +307,7 @@ export function BuildDetailsMainContent(props: BuildDetailsMainContentProps) {
processedInsights={processedInsights}
totalSize={totalSize}
platform={buildDetailsData?.app_info?.platform ?? null}
projectType={projectType}
onOpenInsightsSidebar={openInsightsSidebar}
/>

Expand Down Expand Up @@ -353,7 +356,8 @@ export function BuildDetailsMainContent(props: BuildDetailsMainContentProps) {

<AppSizeInsights
processedInsights={processedInsights}
platform={validatedPlatform(buildDetailsData?.app_info?.platform)}
platform={validatedPlatform(buildDetailsData?.app_info?.platform ?? undefined)}
projectType={projectType}
/>
</Stack>
);
Expand Down
Loading
Loading