1- import { FC , useState } from 'react'
1+ import { FC , useRef , useState } from 'react'
22import { FileInPreview , ItemInPreview } from '@shared/types/file-in-preview'
33import cn from 'classnames'
44import styles from './ResponsePreview.module.scss'
@@ -25,12 +25,50 @@ type Props = {
2525}
2626
2727export const ResponsePreview : FC < Props > = ( props ) => {
28- const [ last_clicked_file_index , set_last_clicked_file_index ] = useState (
29- props . items . findIndex ( ( i ) => i . type == 'file' )
28+ const [ last_clicked_file_index , set_last_clicked_file_index ] = useState ( 0 )
29+ const [ expanded_text_items , set_expanded_text_items ] = useState < Set < number > > (
30+ new Set ( )
3031 )
32+ const scroll_top_ref = useRef ( 0 )
33+ const scrollable_ref = useRef < any > ( null )
34+
35+ const toggle_expanded_text_item = (
36+ index : number ,
37+ element : HTMLDivElement
38+ ) => {
39+ const scrollable_instance = scrollable_ref . current
40+ if ( scrollable_instance ) {
41+ const scroll_container = scrollable_instance . getScrollElement ( )
42+ if ( scroll_container ) {
43+ const scroll_container_rect = scroll_container . getBoundingClientRect ( )
44+ const element_rect = element . getBoundingClientRect ( )
45+
46+ if ( element_rect . top < scroll_container_rect . top ) {
47+ // Element's top edge is above the scrollable viewport's top edge.
48+ // Restore scroll position to the distance of this top edge to the top.
49+ const element_position_in_scrollable_content =
50+ scroll_container . scrollTop +
51+ element_rect . top -
52+ scroll_container_rect . top -
53+ 4
54+ scroll_top_ref . current = element_position_in_scrollable_content
55+ }
56+ }
57+ }
58+
59+ set_expanded_text_items ( ( prev ) => {
60+ const new_set = new Set ( prev )
61+ if ( new_set . has ( index ) ) {
62+ new_set . delete ( index )
63+ } else {
64+ new_set . add ( index )
65+ }
66+ return new_set
67+ } )
68+ }
3169
3270 const files_in_preview = props . items . filter (
33- ( i ) => i . type == 'file'
71+ ( i ) => 'file_path' in i
3472 ) as FileInPreview [ ]
3573 const fallback_count = files_in_preview . filter ( ( f ) => f . is_fallback ) . length
3674
@@ -45,7 +83,14 @@ export const ResponsePreview: FC<Props> = (props) => {
4583 }
4684
4785 return (
48- < Scrollable >
86+ < Scrollable
87+ ref = { scrollable_ref }
88+ initial_scroll_top = { scroll_top_ref . current }
89+ scroll_trigger = { expanded_text_items . size }
90+ on_scroll = { ( top ) => {
91+ scroll_top_ref . current = top
92+ } }
93+ >
4994 < div className = { styles . container } >
5095 { props . raw_instructions && (
5196 < div
@@ -71,7 +116,7 @@ export const ResponsePreview: FC<Props> = (props) => {
71116 ) }
72117 < div className = { styles . list } >
73118 { props . items . map ( ( item , index ) => {
74- if ( item . type == 'file' ) {
119+ if ( 'file_path' in item ) {
75120 const file = item
76121 const last_slash_index = file . file_path . lastIndexOf ( '/' )
77122 const file_name = file . file_path . substring ( last_slash_index + 1 )
@@ -138,7 +183,7 @@ export const ResponsePreview: FC<Props> = (props) => {
138183 { ( file . is_fallback || file . is_replaced ) && (
139184 < IconButton
140185 codicon_icon = "sparkle"
141- title = { `Fix the file with Intelligent Update API tool${
186+ title = { `Call Intelligent Update API tool${
142187 file . diff_fallback_method == 'recount'
143188 ? ' (fallback used: git apply with --recount flag)'
144189 : file . diff_fallback_method ==
@@ -156,6 +201,18 @@ export const ResponsePreview: FC<Props> = (props) => {
156201 } }
157202 />
158203 ) }
204+ < IconButton
205+ codicon_icon = "diff-single"
206+ title = "Open Changes"
207+ on_click = { ( e ) => {
208+ e . stopPropagation ( )
209+ set_last_clicked_file_index ( index )
210+ props . on_focus_file ( {
211+ file_path : file . file_path ,
212+ workspace_name : file . workspace_name
213+ } )
214+ } }
215+ />
159216 < IconButton
160217 codicon_icon = "go-to-file"
161218 title = "Go To File"
@@ -188,7 +245,16 @@ export const ResponsePreview: FC<Props> = (props) => {
188245 </ div >
189246 )
190247 } else {
191- return < TextItem key = { index } content = { item . content } />
248+ return (
249+ < TextItem
250+ key = { index }
251+ content = { item . content }
252+ is_expanded = { expanded_text_items . has ( index ) }
253+ on_toggle = { ( element ) =>
254+ toggle_expanded_text_item ( index , element )
255+ }
256+ />
257+ )
192258 }
193259 } ) }
194260 </ div >
0 commit comments