@@ -5,6 +5,7 @@ import styles from './ResponsePreview.module.scss'
55import { Checkbox } from '../../common/Checkbox'
66import { IconButton } from '../IconButton/IconButton'
77import { TextItem } from './components'
8+ import { Scrollable } from '../Scrollable'
89
910type Props = {
1011 items : ItemInPreview [ ]
@@ -25,163 +26,190 @@ type Props = {
2526
2627export const ResponsePreview : FC < Props > = ( props ) => {
2728 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 ( )
31+ )
32+
33+ const toggle_expanded_text_item = ( index : number ) => {
34+ set_expanded_text_items ( ( prev ) => {
35+ const new_set = new Set ( prev )
36+ if ( new_set . has ( index ) ) {
37+ new_set . delete ( index )
38+ } else {
39+ new_set . add ( index )
40+ }
41+ return new_set
42+ } )
43+ }
2844
2945 const files_in_preview = props . items . filter (
3046 ( i ) => 'file_path' in i
3147 ) as FileInPreview [ ]
3248 const fallback_count = files_in_preview . filter ( ( f ) => f . is_fallback ) . length
3349
3450 return (
35- < div className = { styles . container } >
36- { props . raw_instructions && (
37- < div className = { styles . instructions } title = { props . raw_instructions } >
38- { props . raw_instructions }
39- </ div >
40- ) }
41- { fallback_count > 0 && (
42- < div className = { styles . info } >
43- { files_in_preview . length > 1
44- ? `${ fallback_count } of ${ files_in_preview . length } files`
45- : 'The file' } { ' ' }
46- required a fallback diff integration method, which may lead to
47- inaccuracies. Looks off? Click{ ' ' }
48- < span className = "codicon codicon-sparkle" /> action to fix a file with
49- the Intelligent Update API tool.
50- </ div >
51- ) }
52- < div className = { styles . list } >
53- { props . items . map ( ( item , index ) => {
54- if ( 'file_path' in item ) {
55- const file = item
56- const last_slash_index = file . file_path . lastIndexOf ( '/' )
57- const file_name = file . file_path . substring ( last_slash_index + 1 )
58- const dir_path =
59- last_slash_index > - 1
60- ? file . file_path . substring ( 0 , last_slash_index )
61- : ''
62- return (
63- < div
64- key = { index }
65- className = { cn ( styles . list__file , {
66- [ styles [ 'list__file--selected' ] ] :
67- index == last_clicked_file_index
68- } ) }
69- onClick = { ( ) => {
70- set_last_clicked_file_index ( index )
71- props . on_focus_file ( {
72- file_path : file . file_path ,
73- workspace_name : file . workspace_name
74- } )
75- } }
76- role = "button"
77- title = { `${ file . file_path } ${
78- file . diff_fallback_method == 'search_and_replace'
79- ? '\nUsed aggressive fallback method. Call Intelligent Update API tool, if needed.'
80- : ''
81- } `}
82- >
83- < div className = { styles [ 'list__file__left' ] } >
84- { files_in_preview . length > 1 && (
85- < Checkbox
86- checked = { file . is_checked }
87- on_change = { ( checked ) => {
88- props . on_toggle_file ( {
89- file_path : file . file_path ,
90- workspace_name : file . workspace_name ,
91- is_checked : checked
92- } )
93- } }
94- />
95- ) }
96- < div
97- className = { cn ( styles [ 'list__file__left__label' ] , {
98- [ styles [ 'list__file__left__label--new' ] ] : file . is_new ,
99- [ styles [ 'list__file__left__label--deleted' ] ] :
100- file . is_deleted
101- } ) }
102- >
103- < span >
104- { file . diff_fallback_method == 'search_and_replace' &&
105- '⚠ ' }
106- { file_name }
107- </ span >
51+ < Scrollable key = { expanded_text_items . size } >
52+ < div className = { styles . container } >
53+ { props . raw_instructions && (
54+ < div className = { styles . instructions } title = { props . raw_instructions } >
55+ { props . raw_instructions }
56+ </ div >
57+ ) }
58+ { fallback_count > 0 && (
59+ < div className = { styles . info } >
60+ { files_in_preview . length > 1
61+ ? `${ fallback_count } of ${ files_in_preview . length } files`
62+ : 'The file' } { ' ' }
63+ required a fallback diff integration method, which may lead to
64+ inaccuracies. Looks off? Click{ ' ' }
65+ < span className = "codicon codicon-sparkle" /> action to fix a file
66+ with the Intelligent Update API tool.
67+ </ div >
68+ ) }
69+ < div className = { styles . list } >
70+ { props . items . map ( ( item , index ) => {
71+ if ( 'file_path' in item ) {
72+ const file = item
73+ const last_slash_index = file . file_path . lastIndexOf ( '/' )
74+ const file_name = file . file_path . substring ( last_slash_index + 1 )
75+ const dir_path =
76+ last_slash_index > - 1
77+ ? file . file_path . substring ( 0 , last_slash_index )
78+ : ''
79+ return (
80+ < div
81+ key = { index }
82+ className = { cn ( styles . list__file , {
83+ [ styles [ 'list__file--selected' ] ] :
84+ index == last_clicked_file_index
85+ } ) }
86+ onClick = { ( ) => {
87+ set_last_clicked_file_index ( index )
88+ props . on_focus_file ( {
89+ file_path : file . file_path ,
90+ workspace_name : file . workspace_name
91+ } )
92+ } }
93+ role = "button"
94+ title = { `${ file . file_path } ${
95+ file . diff_fallback_method == 'search_and_replace'
96+ ? '\nUsed aggressive fallback method. Call Intelligent Update API tool, if needed.'
97+ : ''
98+ } `}
99+ >
100+ < div className = { styles [ 'list__file__left' ] } >
101+ { files_in_preview . length > 1 && (
102+ < Checkbox
103+ checked = { file . is_checked }
104+ on_change = { ( checked ) => {
105+ props . on_toggle_file ( {
106+ file_path : file . file_path ,
107+ workspace_name : file . workspace_name ,
108+ is_checked : checked
109+ } )
110+ } }
111+ />
112+ ) }
113+ < div
114+ className = { cn ( styles [ 'list__file__left__label' ] , {
115+ [ styles [ 'list__file__left__label--new' ] ] : file . is_new ,
116+ [ styles [ 'list__file__left__label--deleted' ] ] :
117+ file . is_deleted
118+ } ) }
119+ >
120+ < span >
121+ { file . diff_fallback_method == 'search_and_replace' &&
122+ '⚠ ' }
123+ { file_name }
124+ </ span >
108125
109- < span >
110- { props . has_multiple_workspaces && file . workspace_name
111- ? `${ file . workspace_name } /`
112- : '' }
113- { dir_path }
114- </ span >
126+ < span >
127+ { props . has_multiple_workspaces && file . workspace_name
128+ ? `${ file . workspace_name } /`
129+ : '' }
130+ { dir_path }
131+ </ span >
132+ </ div >
115133 </ div >
116- </ div >
117- < div className = { styles . list__file__right } >
118- < div className = { styles [ 'list__file__actions' ] } >
119- { ( file . is_fallback || file . is_replaced ) && (
134+ < div className = { styles . list__file__right } >
135+ < div className = { styles [ 'list__file__actions' ] } >
136+ { ( file . is_fallback || file . is_replaced ) && (
137+ < IconButton
138+ codicon_icon = "sparkle"
139+ title = { `Call Intelligent Update API tool${
140+ file . diff_fallback_method == 'recount'
141+ ? ' (fallback used: git apply with --recount flag)'
142+ : file . diff_fallback_method ==
143+ 'search_and_replace'
144+ ? ' (fallback used: search and replace matching fragments)'
145+ : ''
146+ } `}
147+ on_click = { ( e ) => {
148+ e . stopPropagation ( )
149+ set_last_clicked_file_index ( index )
150+ props . on_intelligent_update ( {
151+ file_path : file . file_path ,
152+ workspace_name : file . workspace_name
153+ } )
154+ } }
155+ />
156+ ) }
120157 < IconButton
121- codicon_icon = "sparkle"
122- title = { `Call Intelligent Update API tool${
123- file . diff_fallback_method == 'recount'
124- ? ' (fallback used: git apply with --recount flag)'
125- : file . diff_fallback_method == 'search_and_replace'
126- ? ' (fallback used: search and replace matching fragments)'
127- : ''
128- } `}
158+ codicon_icon = "diff-single"
159+ title = "Open Changes"
129160 on_click = { ( e ) => {
130161 e . stopPropagation ( )
131162 set_last_clicked_file_index ( index )
132- props . on_intelligent_update ( {
163+ props . on_focus_file ( {
133164 file_path : file . file_path ,
134165 workspace_name : file . workspace_name
135166 } )
136167 } }
137168 />
169+ < IconButton
170+ codicon_icon = "go-to-file"
171+ title = "Go To File"
172+ on_click = { ( e ) => {
173+ e . stopPropagation ( )
174+ props . on_go_to_file ( {
175+ file_path : file . file_path ,
176+ workspace_name : file . workspace_name
177+ } )
178+ } }
179+ />
180+ </ div >
181+ { ! file . is_deleted && (
182+ < div className = { styles [ 'list__file__line-numbers' ] } >
183+ < span
184+ className = { styles [ 'list__file__line-numbers__added' ] }
185+ >
186+ +{ file . lines_added }
187+ </ span >
188+ < span
189+ className = {
190+ styles [ 'list__file__line-numbers__removed' ]
191+ }
192+ >
193+ -{ file . lines_removed }
194+ </ span >
195+ </ div >
138196 ) }
139- < IconButton
140- codicon_icon = "diff-single"
141- title = "Open Changes"
142- on_click = { ( e ) => {
143- e . stopPropagation ( )
144- set_last_clicked_file_index ( index )
145- props . on_focus_file ( {
146- file_path : file . file_path ,
147- workspace_name : file . workspace_name
148- } )
149- } }
150- />
151- < IconButton
152- codicon_icon = "go-to-file"
153- title = "Go To File"
154- on_click = { ( e ) => {
155- e . stopPropagation ( )
156- props . on_go_to_file ( {
157- file_path : file . file_path ,
158- workspace_name : file . workspace_name
159- } )
160- } }
161- />
162197 </ div >
163- { ! file . is_deleted && (
164- < div className = { styles [ 'list__file__line-numbers' ] } >
165- < span
166- className = { styles [ 'list__file__line-numbers__added' ] }
167- >
168- +{ file . lines_added }
169- </ span >
170- < span
171- className = { styles [ 'list__file__line-numbers__removed' ] }
172- >
173- -{ file . lines_removed }
174- </ span >
175- </ div >
176- ) }
177198 </ div >
178- </ div >
179- )
180- } else {
181- return < TextItem key = { index } content = { item . content } />
182- }
183- } ) }
199+ )
200+ } else {
201+ return (
202+ < TextItem
203+ key = { index }
204+ content = { item . content }
205+ is_expanded = { expanded_text_items . has ( index ) }
206+ on_toggle = { ( ) => toggle_expanded_text_item ( index ) }
207+ />
208+ )
209+ }
210+ } ) }
211+ </ div >
184212 </ div >
185- </ div >
213+ </ Scrollable >
186214 )
187215}
0 commit comments