From 66bc93a7b6d425f6ccb4047173dad5c675f39598 Mon Sep 17 00:00:00 2001 From: Max Topolsky Date: Wed, 21 Jan 2026 09:25:43 -0500 Subject: [PATCH 1/4] fix(preprod): Filter insight diff tabs by status Ensure unresolved/resolved tabs only show matching diff rows and recompute potential savings from the filtered items. --- .../main/insightComparisonSection.tsx | 121 ++++++++++++++++-- 1 file changed, 113 insertions(+), 8 deletions(-) diff --git a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx index 82bb7fd0f33bdd..0cc538348df176 100644 --- a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx +++ b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx @@ -10,6 +10,8 @@ import {FileInsightItemDiffTable} from 'sentry/views/preprod/buildComparison/mai import {GroupInsightItemDiffTable} from 'sentry/views/preprod/buildComparison/main/insights/groupInsightDiffTable'; import {InsightDiffRow} from 'sentry/views/preprod/buildComparison/main/insights/insightDiffRow'; import type { + DiffItem, + DiffType, InsightDiffItem, InsightStatus, } from 'sentry/views/preprod/types/appSizeTypes'; @@ -37,25 +39,128 @@ const FILE_DIFF_INSIGHT_TYPES = [ const GROUP_DIFF_INSIGHT_TYPES = ['duplicate_files', 'loose_images']; +const UNRESOLVED_DIFF_TYPES = new Set(['added', 'increased']); +const RESOLVED_DIFF_TYPES = new Set(['removed', 'decreased']); + +function sumDiffItems(diffItems: DiffItem[]): number { + return diffItems.reduce((total, item) => total + (item.size_diff ?? 0), 0); +} + +function filterDiffItems( + diffItems: DiffItem[], + allowedTypes: Set, + fallbackType: DiffType +): DiffItem[] { + return diffItems.flatMap(item => { + const children = Array.isArray(item.diff_items) ? item.diff_items : []; + const filteredChildren = children.filter(child => allowedTypes.has(child.type)); + const hasAllowedType = allowedTypes.has(item.type); + + if (!hasAllowedType && filteredChildren.length === 0) { + return []; + } + + if (filteredChildren.length === 0) { + return [ + item.diff_items + ? { + ...item, + diff_items: undefined, + } + : item, + ]; + } + + const childTypes = new Set(filteredChildren.map(child => child.type)); + const inferredType = childTypes.size === 1 ? filteredChildren[0]!.type : fallbackType; + + return [ + { + ...item, + type: inferredType, + size_diff: sumDiffItems(filteredChildren), + diff_items: filteredChildren, + }, + ]; + }); +} + +function getFilteredInsight( + insight: InsightDiffItem, + tab: 'all' | InsightStatus +): InsightDiffItem | null { + if (tab === 'all') { + return insight; + } + + if (tab === 'new') { + return insight.status === 'new' ? insight : null; + } + + if (tab === 'unresolved' && insight.status !== 'unresolved') { + return null; + } + + const allowedTypes = tab === 'unresolved' ? UNRESOLVED_DIFF_TYPES : RESOLVED_DIFF_TYPES; + const fallbackType = tab === 'unresolved' ? 'increased' : 'decreased'; + const filteredFileDiffs = filterDiffItems( + insight.file_diffs, + allowedTypes, + fallbackType + ); + const filteredGroupDiffs = filterDiffItems( + insight.group_diffs, + allowedTypes, + fallbackType + ); + const filteredItems = [...filteredFileDiffs, ...filteredGroupDiffs]; + + if (filteredItems.length === 0) { + return null; + } + + return { + ...insight, + file_diffs: filteredFileDiffs, + group_diffs: filteredGroupDiffs, + total_savings_change: sumDiffItems(filteredItems), + }; +} + export function InsightComparisonSection({ insightDiffItems, totalInstallSizeBytes, }: InsightComparisonSectionProps) { - const [selectedTab, setSelectedTab] = useState<'all' | InsightStatus>('all'); + type InsightTab = 'all' | InsightStatus; + const [selectedTab, setSelectedTab] = useState('all'); const filteredInsights = useMemo(() => { - if (selectedTab === 'all') { - return insightDiffItems; - } - return insightDiffItems.filter(insight => insight.status === selectedTab); + return insightDiffItems + .map(insight => getFilteredInsight(insight, selectedTab)) + .filter((insight): insight is InsightDiffItem => Boolean(insight)); }, [insightDiffItems, selectedTab]); const statusCounts = useMemo(() => { + let newCount = 0; + let unresolvedCount = 0; + let resolvedCount = 0; + for (const insight of insightDiffItems) { + if (getFilteredInsight(insight, 'new')) { + newCount += 1; + } + if (getFilteredInsight(insight, 'unresolved')) { + unresolvedCount += 1; + } + if (getFilteredInsight(insight, 'resolved')) { + resolvedCount += 1; + } + } + return { all: insightDiffItems.length, - new: insightDiffItems.filter(i => i.status === 'new').length, - unresolved: insightDiffItems.filter(i => i.status === 'unresolved').length, - resolved: insightDiffItems.filter(i => i.status === 'resolved').length, + new: newCount, + unresolved: unresolvedCount, + resolved: resolvedCount, }; }, [insightDiffItems]); From 09b1abf01a1fc7def517c638ea179e969f82b71b Mon Sep 17 00:00:00 2001 From: Max Topolsky Date: Fri, 23 Jan 2026 10:46:59 -0500 Subject: [PATCH 2/4] more --- .../main/insightComparisonSection.tsx | 88 +++++++++++-------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx index 0cc538348df176..a4b40d54afd451 100644 --- a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx +++ b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx @@ -56,32 +56,30 @@ function filterDiffItems( const filteredChildren = children.filter(child => allowedTypes.has(child.type)); const hasAllowedType = allowedTypes.has(item.type); - if (!hasAllowedType && filteredChildren.length === 0) { - return []; - } + if (children.length > 0) { + if (filteredChildren.length === 0) { + return []; + } + + const childTypes = new Set(filteredChildren.map(child => child.type)); + const inferredType = + childTypes.size === 1 ? filteredChildren[0]!.type : fallbackType; - if (filteredChildren.length === 0) { return [ - item.diff_items - ? { - ...item, - diff_items: undefined, - } - : item, + { + ...item, + type: inferredType, + size_diff: sumDiffItems(filteredChildren), + diff_items: filteredChildren, + }, ]; } - const childTypes = new Set(filteredChildren.map(child => child.type)); - const inferredType = childTypes.size === 1 ? filteredChildren[0]!.type : fallbackType; + if (!hasAllowedType) { + return []; + } - return [ - { - ...item, - type: inferredType, - size_diff: sumDiffItems(filteredChildren), - diff_items: filteredChildren, - }, - ]; + return [item]; }); } @@ -134,36 +132,48 @@ export function InsightComparisonSection({ type InsightTab = 'all' | InsightStatus; const [selectedTab, setSelectedTab] = useState('all'); - const filteredInsights = useMemo(() => { - return insightDiffItems - .map(insight => getFilteredInsight(insight, selectedTab)) - .filter((insight): insight is InsightDiffItem => Boolean(insight)); - }, [insightDiffItems, selectedTab]); + const tabbedInsights = useMemo(() => { + const byTab: Record = { + all: [], + new: [], + unresolved: [], + resolved: [], + }; - const statusCounts = useMemo(() => { - let newCount = 0; - let unresolvedCount = 0; - let resolvedCount = 0; for (const insight of insightDiffItems) { - if (getFilteredInsight(insight, 'new')) { - newCount += 1; + byTab.all.push(insight); + + if (insight.status === 'new') { + byTab.new.push(insight); } - if (getFilteredInsight(insight, 'unresolved')) { - unresolvedCount += 1; + + if (insight.status === 'unresolved') { + const unresolvedInsight = getFilteredInsight(insight, 'unresolved'); + if (unresolvedInsight) { + byTab.unresolved.push(unresolvedInsight); + } } - if (getFilteredInsight(insight, 'resolved')) { - resolvedCount += 1; + + const resolvedInsight = getFilteredInsight(insight, 'resolved'); + if (resolvedInsight) { + byTab.resolved.push(resolvedInsight); } } return { - all: insightDiffItems.length, - new: newCount, - unresolved: unresolvedCount, - resolved: resolvedCount, + byTab, + counts: { + all: byTab.all.length, + new: byTab.new.length, + unresolved: byTab.unresolved.length, + resolved: byTab.resolved.length, + }, }; }, [insightDiffItems]); + const filteredInsights = tabbedInsights.byTab[selectedTab]; + const statusCounts = tabbedInsights.counts; + if (insightDiffItems.length === 0) { return null; } From 55ae8dd2dba494dced035b62b6e6149f90cfe58e Mon Sep 17 00:00:00 2001 From: Max Topolsky Date: Fri, 23 Jan 2026 13:54:59 -0500 Subject: [PATCH 3/4] fix --- .../main/insightComparisonSection.tsx | 74 ++++++++----------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx index a4b40d54afd451..5b03a416898050 100644 --- a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx +++ b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx @@ -43,7 +43,7 @@ const UNRESOLVED_DIFF_TYPES = new Set(['added', 'increased']); const RESOLVED_DIFF_TYPES = new Set(['removed', 'decreased']); function sumDiffItems(diffItems: DiffItem[]): number { - return diffItems.reduce((total, item) => total + (item.size_diff ?? 0), 0); + return diffItems.reduce((total, item) => total + item.size_diff, 0); } function filterDiffItems( @@ -52,55 +52,37 @@ function filterDiffItems( fallbackType: DiffType ): DiffItem[] { return diffItems.flatMap(item => { - const children = Array.isArray(item.diff_items) ? item.diff_items : []; - const filteredChildren = children.filter(child => allowedTypes.has(child.type)); - const hasAllowedType = allowedTypes.has(item.type); - - if (children.length > 0) { - if (filteredChildren.length === 0) { - return []; - } - - const childTypes = new Set(filteredChildren.map(child => child.type)); - const inferredType = - childTypes.size === 1 ? filteredChildren[0]!.type : fallbackType; - - return [ - { - ...item, - type: inferredType, - size_diff: sumDiffItems(filteredChildren), - diff_items: filteredChildren, - }, - ]; + const children = item.diff_items ?? []; + if (children.length === 0) { + return allowedTypes.has(item.type) ? [item] : []; } - if (!hasAllowedType) { + const filteredChildren = children.filter(child => allowedTypes.has(child.type)); + if (filteredChildren.length === 0) { return []; } - return [item]; + const firstType = filteredChildren[0]!.type; + const inferredType = filteredChildren.every(child => child.type === firstType) + ? firstType + : fallbackType; + + return [ + { + ...item, + type: inferredType, + size_diff: sumDiffItems(filteredChildren), + diff_items: filteredChildren, + }, + ]; }); } -function getFilteredInsight( +function filterInsightByDiffTypes( insight: InsightDiffItem, - tab: 'all' | InsightStatus + allowedTypes: Set, + fallbackType: DiffType ): InsightDiffItem | null { - if (tab === 'all') { - return insight; - } - - if (tab === 'new') { - return insight.status === 'new' ? insight : null; - } - - if (tab === 'unresolved' && insight.status !== 'unresolved') { - return null; - } - - const allowedTypes = tab === 'unresolved' ? UNRESOLVED_DIFF_TYPES : RESOLVED_DIFF_TYPES; - const fallbackType = tab === 'unresolved' ? 'increased' : 'decreased'; const filteredFileDiffs = filterDiffItems( insight.file_diffs, allowedTypes, @@ -148,13 +130,21 @@ export function InsightComparisonSection({ } if (insight.status === 'unresolved') { - const unresolvedInsight = getFilteredInsight(insight, 'unresolved'); + const unresolvedInsight = filterInsightByDiffTypes( + insight, + UNRESOLVED_DIFF_TYPES, + 'increased' + ); if (unresolvedInsight) { byTab.unresolved.push(unresolvedInsight); } } - const resolvedInsight = getFilteredInsight(insight, 'resolved'); + const resolvedInsight = filterInsightByDiffTypes( + insight, + RESOLVED_DIFF_TYPES, + 'decreased' + ); if (resolvedInsight) { byTab.resolved.push(resolvedInsight); } From f99b65b8b053bf6a422ae7980c985a93ae77c00d Mon Sep 17 00:00:00 2001 From: Max Topolsky Date: Fri, 23 Jan 2026 15:28:38 -0500 Subject: [PATCH 4/4] change names to help w insight confusion --- .../main/insightComparisonSection.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx index 5b03a416898050..7bd1dd13928be6 100644 --- a/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx +++ b/static/app/views/preprod/buildComparison/main/insightComparisonSection.tsx @@ -39,8 +39,8 @@ const FILE_DIFF_INSIGHT_TYPES = [ const GROUP_DIFF_INSIGHT_TYPES = ['duplicate_files', 'loose_images']; -const UNRESOLVED_DIFF_TYPES = new Set(['added', 'increased']); -const RESOLVED_DIFF_TYPES = new Set(['removed', 'decreased']); +const UNRESOLVED_ITEM_TYPES = new Set(['added', 'increased']); +const RESOLVED_ITEM_TYPES = new Set(['removed', 'decreased']); function sumDiffItems(diffItems: DiffItem[]): number { return diffItems.reduce((total, item) => total + item.size_diff, 0); @@ -78,7 +78,7 @@ function filterDiffItems( }); } -function filterInsightByDiffTypes( +function filterInsightByLineItemTypes( insight: InsightDiffItem, allowedTypes: Set, fallbackType: DiffType @@ -130,9 +130,9 @@ export function InsightComparisonSection({ } if (insight.status === 'unresolved') { - const unresolvedInsight = filterInsightByDiffTypes( + const unresolvedInsight = filterInsightByLineItemTypes( insight, - UNRESOLVED_DIFF_TYPES, + UNRESOLVED_ITEM_TYPES, 'increased' ); if (unresolvedInsight) { @@ -140,9 +140,9 @@ export function InsightComparisonSection({ } } - const resolvedInsight = filterInsightByDiffTypes( + const resolvedInsight = filterInsightByLineItemTypes( insight, - RESOLVED_DIFF_TYPES, + RESOLVED_ITEM_TYPES, 'decreased' ); if (resolvedInsight) {