Skip to content

Commit 3b504c0

Browse files
committed
show inherited changelog entries by walking backwards for uncovered GPUs
1 parent 39f7403 commit 3b504c0

3 files changed

Lines changed: 77 additions & 55 deletions

File tree

packages/app/src/components/inference/ui/ChartDisplay.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,7 @@ export default function ChartDisplay() {
130130
intermediateDates,
131131
loading: changelogsLoading,
132132
totalDatesQueried,
133-
} = useComparisonChangelogs(
134-
selectedGPUs,
135-
selectedPrecisions,
136-
selectedDateRange,
137-
dateRangeAvailableDates,
138-
);
133+
} = useComparisonChangelogs(selectedGPUs, selectedDateRange, dateRangeAvailableDates);
139134

140135
const { unofficialRunInfo, getOverlayData, isUnofficialRun } = useUnofficialRun();
141136

packages/app/src/components/inference/ui/ComparisonChangelog.tsx

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,73 @@ export default function ComparisonChangelog({
3030
}: ComparisonChangelogProps) {
3131
const [isExpanded, setIsExpanded] = useState(false);
3232

33-
// Filter changelog entries to only show those matching selected GPUs and precisions
33+
// Filter changelog entries to only show those matching selected GPUs and precisions.
34+
// For GPUs without a direct entry on a date, walk backwards to the most recent prior changelog.
3435
const filteredChangelogs = useMemo(() => {
3536
const precSet = new Set(selectedPrecisions);
37+
const sorted = [...changelogs].sort(
38+
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
39+
);
3640

37-
return changelogs
38-
.map((item) => ({
39-
...item,
40-
entries: item.entries.filter((entry) =>
41-
entry.config_keys.some((key) => {
42-
const precision = key.split('-')[1];
43-
return (
44-
precSet.has(precision) && selectedGPUs.some((gpu) => configKeyMatchesHwKey(key, gpu))
41+
const matchesGpu = (key: string) => {
42+
const precision = key.split('-')[1];
43+
return precSet.has(precision) && selectedGPUs.some((gpu) => configKeyMatchesHwKey(key, gpu));
44+
};
45+
46+
return sorted
47+
.map((item) => {
48+
// Direct entries matching selected GPUs/precisions
49+
const directEntries = item.entries.filter((entry) => entry.config_keys.some(matchesGpu));
50+
51+
// Find GPUs that have direct entries on this date
52+
const coveredGPUs = new Set<string>();
53+
for (const entry of directEntries) {
54+
for (const key of entry.config_keys) {
55+
if (!matchesGpu(key)) continue;
56+
for (const gpu of selectedGPUs) {
57+
if (configKeyMatchesHwKey(key, gpu)) coveredGPUs.add(gpu);
58+
}
59+
}
60+
}
61+
62+
// For uncovered GPUs, walk backwards through earlier dates
63+
const inheritedEntries: {
64+
config_keys: string[];
65+
description: string;
66+
pr_link: string | null;
67+
inheritedFromDate: string;
68+
}[] = [];
69+
70+
for (const gpu of selectedGPUs) {
71+
if (coveredGPUs.has(gpu)) continue;
72+
// Walk backwards through sorted changelogs before this date
73+
for (let i = sorted.indexOf(item) - 1; i >= 0; i--) {
74+
const prior = sorted[i];
75+
const match = prior.entries.find((entry) =>
76+
entry.config_keys.some((key) => matchesGpu(key) && configKeyMatchesHwKey(key, gpu)),
4577
);
46-
}),
47-
),
48-
}))
49-
.filter((item) => item.entries.length > 0);
50-
}, [changelogs, selectedGPUs, selectedPrecisions]);
78+
if (match) {
79+
// Avoid duplicates if same entry covers multiple uncovered GPUs
80+
if (
81+
!inheritedEntries.some(
82+
(e) => e.inheritedFromDate === prior.date && e.description === match.description,
83+
)
84+
) {
85+
inheritedEntries.push({ ...match, inheritedFromDate: prior.date });
86+
}
87+
break;
88+
}
89+
}
90+
}
5191

52-
const sortedChangelogs = useMemo(
53-
() =>
54-
[...filteredChangelogs].sort(
55-
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
56-
),
57-
[filteredChangelogs],
58-
);
92+
return {
93+
...item,
94+
entries: directEntries,
95+
inheritedEntries,
96+
};
97+
})
98+
.filter((item) => item.entries.length > 0 || item.inheritedEntries.length > 0);
99+
}, [changelogs, selectedGPUs, selectedPrecisions]);
59100

60101
const handleToggle = () => {
61102
const newState = !isExpanded;
@@ -95,13 +136,13 @@ export default function ComparisonChangelog({
95136
}`}
96137
>
97138
<div className="px-4 pt-2 pb-4 flex flex-col gap-3">
98-
{sortedChangelogs.length === 0 ? (
139+
{filteredChangelogs.length === 0 ? (
99140
<p className="text-sm text-muted-foreground">
100141
No config changelog data matching the selected GPUs and precisions for this date
101142
range. Changelog tracking began Dec 30, 2025.
102143
</p>
103144
) : (
104-
sortedChangelogs.map((item) => (
145+
filteredChangelogs.map((item) => (
105146
<div key={item.date} className="flex flex-col gap-1">
106147
<div className="flex items-center gap-2 flex-wrap">
107148
<span className="text-sm font-semibold">{item.date}</span>
@@ -144,6 +185,15 @@ export default function ComparisonChangelog({
144185
{formatChangelogDescription(entry.description)}
145186
</div>
146187
))}
188+
{item.inheritedEntries.map((entry, entryIndex) => (
189+
<div
190+
key={`inherited-${entryIndex}`}
191+
className="text-sm text-muted-foreground pl-5 italic"
192+
>
193+
<span className="text-xs opacity-70">(from {entry.inheritedFromDate})</span>{' '}
194+
{formatChangelogDescription(entry.description)}
195+
</div>
196+
))}
147197
</div>
148198
))
149199
)}

packages/app/src/hooks/api/use-comparison-changelogs.ts

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useQueries } from '@tanstack/react-query';
22
import { useMemo } from 'react';
33

44
import { fetchWorkflowInfo, type ChangelogRow, type WorkflowInfoResponse } from '@/lib/api';
5-
import { configKeyMatchesHwKey } from '@/components/inference/utils/changelogFormatters';
65

76
export interface ComparisonChangelog {
87
date: string;
@@ -17,7 +16,6 @@ export interface ComparisonChangelog {
1716

1817
export function useComparisonChangelogs(
1918
selectedGPUs: string[],
20-
selectedPrecisions: string[],
2119
selectedDateRange: { startDate: string; endDate: string },
2220
availableDates: string[],
2321
) {
@@ -68,35 +66,14 @@ export function useComparisonChangelogs(
6866
return results;
6967
}, [isComparisonMode, datesInRange, queries]);
7068

71-
// Intermediate dates with changelog entries matching selected GPUs/precisions (excluding start/end)
69+
// Intermediate dates with any changelog entries (excluding start/end)
7270
const intermediateDates = useMemo(() => {
7371
if (!isComparisonMode) return [];
74-
const precSet = new Set(selectedPrecisions);
7572
return changelogs
76-
.filter(
77-
(c) =>
78-
c.date !== selectedDateRange.startDate &&
79-
c.date !== selectedDateRange.endDate &&
80-
c.entries.some((entry) =>
81-
entry.config_keys.some((key) => {
82-
const precision = key.split('-')[1];
83-
return (
84-
precSet.has(precision) &&
85-
selectedGPUs.some((gpu) => configKeyMatchesHwKey(key, gpu))
86-
);
87-
}),
88-
),
89-
)
73+
.filter((c) => c.date !== selectedDateRange.startDate && c.date !== selectedDateRange.endDate)
9074
.map((c) => c.date)
9175
.sort();
92-
}, [
93-
isComparisonMode,
94-
changelogs,
95-
selectedGPUs,
96-
selectedPrecisions,
97-
selectedDateRange.startDate,
98-
selectedDateRange.endDate,
99-
]);
76+
}, [isComparisonMode, changelogs, selectedDateRange.startDate, selectedDateRange.endDate]);
10077

10178
const loading = queries.some((q) => q.isLoading);
10279

0 commit comments

Comments
 (0)