44 Check ,
55 ChevronDown ,
66 FileText ,
7+ GitCommit ,
78 Globe ,
89 History ,
910 Languages ,
@@ -41,6 +42,12 @@ import { calculateDocumentStats } from "../utils/stats";
4142
4243type VersionInfoWithCommit = VersionInfo | RepoVersionInfo ;
4344
45+ type VersionGroup = {
46+ commitSha : string ;
47+ isLatest : boolean ;
48+ versions : RepoVersionInfo [ ] ;
49+ } ;
50+
4451type ExecutiveSummaryProps = {
4552 behaviorCacheStats ?: BehaviorCacheStats ;
4653 commitSha ?: string ;
@@ -65,8 +72,47 @@ const formatShortDate = (dateString: string, locale: string): string => {
6572 } ) ;
6673} ;
6774
75+ const formatShortDateTime = ( dateString : string , locale : string ) : string => {
76+ return new Date ( dateString ) . toLocaleString ( locale , {
77+ day : "numeric" ,
78+ hour : "2-digit" ,
79+ minute : "2-digit" ,
80+ month : "short" ,
81+ } ) ;
82+ } ;
83+
6884const formatCommitSha = ( sha : string ) : string => ( sha . length < 7 ? sha : sha . slice ( 0 , 7 ) ) ;
6985
86+ const groupVersionsByCommit = (
87+ versions : VersionInfoWithCommit [ ] ,
88+ latestDocumentId ?: string
89+ ) : VersionGroup [ ] => {
90+ const groups = new Map < string , RepoVersionInfo [ ] > ( ) ;
91+
92+ for ( const version of versions ) {
93+ if ( ! ( "commitSha" in version ) ) continue ;
94+ const sha = version . commitSha ;
95+ if ( ! groups . has ( sha ) ) {
96+ groups . set ( sha , [ ] ) ;
97+ }
98+ groups . get ( sha ) ! . push ( version ) ;
99+ }
100+
101+ const result : VersionGroup [ ] = [ ] ;
102+ let isFirst = true ;
103+
104+ for ( const [ commitSha , groupVersions ] of groups ) {
105+ result . push ( {
106+ commitSha,
107+ isLatest : isFirst && groupVersions . some ( ( v ) => v . id === latestDocumentId ) ,
108+ versions : groupVersions ,
109+ } ) ;
110+ isFirst = false ;
111+ }
112+
113+ return result ;
114+ } ;
115+
70116export const ExecutiveSummary = ( {
71117 behaviorCacheStats,
72118 commitSha,
@@ -93,6 +139,7 @@ export const ExecutiveSummary = ({
93139 const availableLanguages = document . availableLanguages ?? [ ] ;
94140 const isDisabled = isRegenerating || isGeneratingOtherLanguage ;
95141 const isLatestVersion = latestDocumentId === undefined || document . id === latestDocumentId ;
142+ const versionGroups = groupVersionsByCommit ( versions , latestDocumentId ) ;
96143
97144 // Build sets for available vs new languages
98145 const availableLanguageSet = new Set ( availableLanguages . map ( ( l ) => l . language ) ) ;
@@ -251,50 +298,61 @@ export const ExecutiveSummary = ({
251298 </ TooltipTrigger >
252299 < TooltipContent > { t ( "executiveSummary.switchVersionTooltip" ) } </ TooltipContent >
253300 </ Tooltip >
254- < DropdownMenuContent align = "end" className = "w-56 max-h-80 overflow-y-auto" >
301+ < DropdownMenuContent align = "end" className = "w-64 max-h-80 overflow-y-auto" >
255302 < DropdownMenuLabel className = "flex items-center gap-2 px-2 py-2 text-[11px] font-medium uppercase tracking-wider text-muted-foreground/70 bg-muted/40 -mx-1 mb-1 border-b border-border/50" >
256303 < History className = "h-3 w-3" />
257304 { t ( "executiveSummary.versionHistory" ) }
258305 </ DropdownMenuLabel >
259- { versions . map ( ( versionInfo ) => {
260- const isCurrentVersion = versionInfo . version === currentVersion ;
261- // Use document ID for latest check (createdAt DESC sort order)
262- const isLatest = "id" in versionInfo && versionInfo . id === latestDocumentId ;
263- const versionCommitSha =
264- "commitSha" in versionInfo ? versionInfo . commitSha : undefined ;
265- return (
266- < DropdownMenuItem
267- className = { cn (
268- "flex items-center justify-between" ,
269- isCurrentVersion && "bg-muted font-medium"
270- ) }
271- key = { versionInfo . version }
272- onClick = { ( ) => onVersionSwitch ( versionInfo . version ) }
273- >
274- < div className = "flex items-center gap-2" >
275- { isCurrentVersion ? (
276- < Check className = "h-3.5 w-3.5 text-primary" />
277- ) : (
278- < span className = "w-3.5" />
279- ) }
280- < span > { formatShortDate ( versionInfo . createdAt , locale ) } </ span >
281- { versionCommitSha && (
282- < code className = "text-[10px] text-muted-foreground/70 font-mono" >
283- { formatCommitSha ( versionCommitSha ) }
284- </ code >
285- ) }
286- { isLatest && (
287- < span className = "text-muted-foreground" >
288- ({ t ( "executiveSummary.latestLabel" ) } )
289- </ span >
290- ) }
306+ { versionGroups . map ( ( group , groupIndex ) => (
307+ < div key = { group . commitSha } >
308+ { /* Commit group header */ }
309+ < div className = "flex items-center justify-between px-2 py-1.5 text-xs" >
310+ < div className = "flex items-center gap-1.5 text-muted-foreground" >
311+ < GitCommit className = "h-3 w-3" />
312+ < code className = "font-mono" > { formatCommitSha ( group . commitSha ) } </ code >
291313 </ div >
292- < span className = "text-xs text-muted-foreground" >
293- { t ( "executiveSummary.versionLabel" , { version : versionInfo . version } ) }
294- </ span >
295- </ DropdownMenuItem >
296- ) ;
297- } ) }
314+ { group . isLatest && (
315+ < span className = "text-[10px] text-muted-foreground" >
316+ { t ( "executiveSummary.latestLabel" ) }
317+ </ span >
318+ ) }
319+ </ div >
320+
321+ { /* Version items */ }
322+ { group . versions . map ( ( versionInfo ) => {
323+ const isCurrentVersion = versionInfo . version === currentVersion ;
324+ return (
325+ < DropdownMenuItem
326+ className = { cn (
327+ "flex items-center justify-between ml-4" ,
328+ isCurrentVersion && "bg-muted font-medium"
329+ ) }
330+ key = { versionInfo . id }
331+ onClick = { ( ) => onVersionSwitch ( versionInfo . version ) }
332+ >
333+ < div className = "flex items-center gap-2" >
334+ { isCurrentVersion ? (
335+ < Check className = "h-3.5 w-3.5 text-primary" />
336+ ) : (
337+ < span className = "w-3.5" />
338+ ) }
339+ < span > { formatShortDateTime ( versionInfo . createdAt , locale ) } </ span >
340+ </ div >
341+ { group . versions . length > 1 && (
342+ < span className = "text-xs text-muted-foreground" >
343+ { t ( "executiveSummary.versionLabel" , {
344+ version : versionInfo . version ,
345+ } ) }
346+ </ span >
347+ ) }
348+ </ DropdownMenuItem >
349+ ) ;
350+ } ) }
351+
352+ { /* Separator between groups */ }
353+ { groupIndex < versionGroups . length - 1 && < DropdownMenuSeparator /> }
354+ </ div >
355+ ) ) }
298356 </ DropdownMenuContent >
299357 </ DropdownMenu >
300358 ) : (
0 commit comments