1- import React , { useCallback , useMemo } from "react" ;
1+ import React , { useCallback , useLayoutEffect , useMemo , useRef , useState } from "react" ;
22import dayjs from "dayjs" ;
33import {
44 AddCircleRounded ,
@@ -14,7 +14,6 @@ import { List, AutoSizer, CellMeasurer } from "react-virtualized";
1414
1515import { useGithubInfo , useDataStore } from "store" ;
1616import { Author } from "components/Common/Author" ;
17- import type { IssueLinkedMessage } from "components/Common/GithubIssueLink" ;
1817import { renderIssueLinkedNodes } from "components/Common/GithubIssueLink" ;
1918
2019import { getCommitListDetail } from "./Detail.util" ;
@@ -27,6 +26,10 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
2726 const selectedData = useDataStore ( ( state ) => state . selectedData ) ;
2827 const { owner, repo } = useGithubInfo ( ) ;
2928
29+ const [ hoverIndex , setHoverIndex ] = useState < number | null > ( null ) ;
30+ const prevIndexRef = useRef < number | null > ( null ) ;
31+ const listRef = useRef < List > ( null ) ;
32+
3033 const commitNodeListInCluster = useMemo (
3134 ( ) =>
3235 selectedData ?. filter ( ( selected ) => selected . commitNodeList [ 0 ] . clusterId === clusterId ) [ 0 ] . commitNodeList ?? [ ] ,
@@ -40,14 +43,35 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
4043 const { cache, virtualizedItems, showScrollIndicator, handleRowsRendered } =
4144 useVirtualizedList ( commitNodeListInCluster ) ;
4245
46+ useLayoutEffect ( ( ) => {
47+ const [ currentIndex , prevIndex ] = [ hoverIndex , prevIndexRef . current ] ;
48+ const refreshRowHeight = ( index : number ) => {
49+ cache . clear ( index , 0 ) ;
50+ listRef . current ?. recomputeRowHeights ( index ) ;
51+ } ;
52+
53+ requestAnimationFrame ( ( ) => {
54+ if ( prevIndex != null ) refreshRowHeight ( prevIndex ) ;
55+ if ( currentIndex != null ) {
56+ refreshRowHeight ( currentIndex ) ;
57+ requestAnimationFrame ( ( ) => {
58+ listRef . current ?. scrollToRow ?.( currentIndex ) ;
59+ } ) ;
60+ }
61+ prevIndexRef . current = currentIndex ;
62+ } ) ;
63+ } , [ hoverIndex , cache ] ) ;
64+
4365 const renderCommitItem = useCallback (
44- ( props : { index : number ; key : string } ) => {
45- const { index, key } = props ;
66+ ( props : { index : number ; key : string ; expanded : boolean } ) => {
67+ const { index, key, expanded } = props ;
4668 const item = virtualizedItems [ index ] ;
69+ const showMessageBody = ! ( index === 1 && commitNodeListInCluster . length > 1 ) ;
4770
4871 if ( item . type === "summary" ) {
4972 return < DetailSummary commitNodeListInCluster = { item . data } /> ;
5073 }
74+
5175 return (
5276 < MemoizedCommitItem
5377 key = { key }
@@ -56,7 +80,8 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
5680 repo = { repo }
5781 authSrcMap = { authSrcMap }
5882 handleCommitIdCopy = { handleCommitIdCopy }
59- linkedMessage = { issueLinkedMessage }
83+ showMessageBody = { showMessageBody }
84+ expanded = { expanded }
6085 />
6186 ) ;
6287 } ,
@@ -72,25 +97,18 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
7297 columnIndex = { 0 }
7398 rowIndex = { index }
7499 >
75- < div style = { style } > { renderCommitItem ( { index, key } ) } </ div >
100+ < div
101+ style = { style }
102+ onMouseEnter = { ( ) => setHoverIndex ( index ) }
103+ onMouseLeave = { ( ) => setHoverIndex ( null ) }
104+ >
105+ { renderCommitItem ( { index, key, expanded : hoverIndex === index } ) }
106+ </ div >
76107 </ CellMeasurer >
77108 ) ,
78- [ cache , renderCommitItem ]
109+ [ cache , renderCommitItem , hoverIndex ]
79110 ) ;
80111
81- const issueLinkedMessage : IssueLinkedMessage = useMemo ( ( ) => {
82- const message = commitNodeListInCluster ?. [ 0 ] ?. commit ?. message ;
83- if ( ! message ) return { title : [ ] , body : null } ;
84-
85- const [ title , ...rest ] = message . split ( "\n" ) ;
86- const body = rest . filter ( ( line ) => line . trim ( ) ) . join ( "\n" ) ;
87-
88- return {
89- title : renderIssueLinkedNodes ( title , owner , repo ) ,
90- body : body ? renderIssueLinkedNodes ( body , owner , repo ) : null ,
91- } ;
92- } , [ commitNodeListInCluster , owner , repo ] ) ;
93-
94112 if ( ! selectedData || selectedData . length === 0 ) return null ;
95113
96114 return (
@@ -99,6 +117,7 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
99117 { ( { height, width } ) => {
100118 return (
101119 < List
120+ ref = { listRef }
102121 height = { height }
103122 width = { width }
104123 rowCount = { virtualizedItems . length }
@@ -107,6 +126,7 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
107126 onRowsRendered = { handleRowsRendered }
108127 className = "detail__virtualized-list"
109128 estimatedRowSize = { 120 }
129+ deferredMeasurementCache = { cache }
110130 />
111131 ) ;
112132 } }
@@ -123,8 +143,25 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
123143
124144export default Detail ;
125145
126- function CommitItem ( { commit, owner, repo, authSrcMap, handleCommitIdCopy, linkedMessage } : CommitItemProps ) {
146+ function CommitItem ( {
147+ commit,
148+ owner,
149+ repo,
150+ authSrcMap,
151+ handleCommitIdCopy,
152+ showMessageBody,
153+ expanded,
154+ } : CommitItemProps ) {
127155 const { id, message, author, commitDate } = commit ;
156+
157+ const { issueLinkedTitle, body } = useMemo ( ( ) => {
158+ const [ title , ...bodyLines ] = message . split ( "\n" ) ;
159+ return {
160+ issueLinkedTitle : renderIssueLinkedNodes ( title , owner , repo ) ,
161+ body : bodyLines . filter ( Boolean ) . join ( "\n" ) ,
162+ } ;
163+ } , [ message , owner , repo ] ) ;
164+
128165 return (
129166 < div className = "detail__commit-item" >
130167 < div className = "commit-item__detail" >
@@ -137,13 +174,7 @@ function CommitItem({ commit, owner, repo, authSrcMap, handleCommitIdCopy, linke
137174 src = { authSrcMap [ author . names . toString ( ) ] }
138175 />
139176 ) }
140- < div className = "commit-message__title" >
141- { ( ( ) => {
142- const messageLines = message . split ( "\n" ) ;
143- const title = messageLines [ 0 ] ;
144- return linkedMessage . title . length > 0 ? linkedMessage . title : title ;
145- } ) ( ) }
146- </ div >
177+ < div className = "commit-message__title" > { issueLinkedTitle } </ div >
147178 < div className = "commit-item__meta" >
148179 < span className = "commit-item__author-name" > { author . names [ 0 ] } </ span >
149180 < span className = "commit-item__date" > { dayjs ( commitDate ) . format ( "YY. M. DD. a h:mm" ) } </ span >
@@ -167,17 +198,9 @@ function CommitItem({ commit, owner, repo, authSrcMap, handleCommitIdCopy, linke
167198 </ div >
168199 </ div >
169200 </ div >
170- { ( ( ) => {
171- const messageLines = message . split ( "\n" ) ;
172- const body = messageLines
173- . slice ( 1 )
174- . filter ( ( line : string ) => line . trim ( ) )
175- . join ( "\n" ) ;
176-
177- return body ? (
178- < div className = "commit-message__body" > { linkedMessage . body ? linkedMessage . body : body } </ div >
179- ) : null ;
180- } ) ( ) }
201+ { showMessageBody && body && (
202+ < div className = { `commit-message__body${ expanded ? "--visible" : "" } ` } > { expanded ? body : null } </ div >
203+ ) }
181204 </ div >
182205 </ div >
183206 </ div >
0 commit comments