@@ -4,7 +4,7 @@ struct InspectorView: View {
44 @Environment ( AppState . self) private var appState
55 @Environment ( \. theme) private var theme
66 @State private var gitBranch : String ? = nil
7- @State private var showHistory = false
7+ @Environment ( \ . openWindow ) private var openWindow
88
99 var body : some View {
1010 if let session = appState. sessionList. selectedSession {
@@ -21,15 +21,6 @@ struct InspectorView: View {
2121 . font ( . caption)
2222 . foregroundStyle ( theme. red)
2323 }
24- Button {
25- showHistory = true
26- } label: {
27- Image ( systemName: " clock.arrow.trianglehead.counterclockwise.rotate.90 " )
28- . font ( . caption)
29- . foregroundStyle ( theme. muted)
30- }
31- . buttonStyle ( . plain)
32- . help ( " File History " )
3324 }
3425
3526 // Session info grid
@@ -127,26 +118,78 @@ struct InspectorView: View {
127118 }
128119 }
129120
130- // Files touched this session
131- if !appState. chat. filesTouched. isEmpty {
132- DetailSection ( title: " Files Changed ( \( appState. chat. filesTouched. count) ) " ) {
133- ForEach ( appState. chat. filesTouched. prefix ( 10 ) , id: \. self) { path in
134- HStack ( spacing: 4 ) {
135- Image ( systemName: " pencil.circle.fill " )
136- . font ( . system( size: 9 ) )
137- . foregroundStyle ( theme. cyan)
138- Text ( path)
139- . font ( . system( size: 10 , design: . monospaced) )
140- . foregroundStyle ( theme. text)
141- . lineLimit ( 1 )
142- . truncationMode ( . head)
121+ // Files changed — prominent section with diff access
122+ VStack ( alignment: . leading, spacing: 8 ) {
123+ HStack {
124+ Image ( systemName: " doc.text.magnifyingglass " )
125+ . font ( . system( size: 12 ) )
126+ . foregroundStyle ( theme. accent)
127+ Text ( " FILES CHANGED " )
128+ . font ( . caption2. bold ( ) )
129+ . foregroundStyle ( theme. muted)
130+ Spacer ( )
131+ if !appState. chat. filesTouched. isEmpty {
132+ Text ( " \( appState. chat. filesTouched. count) " )
133+ . font ( . caption2. bold ( ) . monospacedDigit ( ) )
134+ . foregroundStyle ( theme. panel)
135+ . padding ( . horizontal, 6 )
136+ . padding ( . vertical, 2 )
137+ . background ( theme. accent, in: Capsule ( ) )
138+ }
139+ }
140+
141+ if appState. chat. filesTouched. isEmpty {
142+ Text ( " No files changed yet " )
143+ . font ( . caption)
144+ . foregroundStyle ( theme. muted. opacity ( 0.7 ) )
145+ . frame ( maxWidth: . infinity, alignment: . center)
146+ . padding ( . vertical, 8 )
147+ } else {
148+ VStack ( spacing: 0 ) {
149+ ForEach ( appState. chat. filesTouched. prefix ( 15 ) , id: \. self) { path in
150+ HStack ( spacing: 6 ) {
151+ Image ( systemName: fileIcon ( for: path) )
152+ . font ( . system( size: 10 ) )
153+ . foregroundStyle ( fileColor ( for: path) )
154+ . frame ( width: 14 )
155+ Text ( shortenPath ( path) )
156+ . font ( . system( size: 10 , design: . monospaced) )
157+ . foregroundStyle ( theme. text)
158+ . lineLimit ( 1 )
159+ . truncationMode ( . middle)
160+ Spacer ( )
161+ }
162+ . padding ( . vertical, 3 )
163+ . padding ( . horizontal, 6 )
164+ }
165+ if appState. chat. filesTouched. count > 15 {
166+ Text ( " + \( appState. chat. filesTouched. count - 15 ) more " )
167+ . font ( . caption2)
168+ . foregroundStyle ( theme. muted)
169+ . padding ( . vertical, 3 )
170+ . padding ( . horizontal, 6 )
143171 }
144172 }
145- if appState. chat. filesTouched. count > 10 {
146- Text ( " …and \( appState. chat. filesTouched. count - 10 ) more " )
147- . font ( . caption2)
148- . foregroundStyle ( theme. muted)
173+ . background ( theme. panel. opacity ( 0.5 ) )
174+ . clipShape ( RoundedRectangle ( cornerRadius: 6 ) )
175+
176+ // Prominent button to open full diff viewer
177+ Button {
178+ openWindow ( id: " file-history " , value: session. id)
179+ } label: {
180+ HStack ( spacing: 6 ) {
181+ Image ( systemName: " arrow.up.left.and.arrow.down.right " )
182+ . font ( . system( size: 11 , weight: . medium) )
183+ Text ( " Open Diff Viewer " )
184+ . font ( . system( size: 12 , weight: . medium) )
185+ }
186+ . frame ( maxWidth: . infinity)
187+ . padding ( . vertical, 7 )
188+ . foregroundStyle ( theme. panel)
189+ . background ( theme. accent, in: RoundedRectangle ( cornerRadius: 6 ) )
149190 }
191+ . buttonStyle ( . plain)
192+ . help ( " Open side-by-side diffs in a separate window " )
150193 }
151194 }
152195
@@ -197,11 +240,6 @@ struct InspectorView: View {
197240 . background ( theme. panel)
198241 . onAppear { loadGitBranch ( for: session) }
199242 . onChange ( of: session. id) { _, _ in loadGitBranch ( for: session) }
200- . sheet ( isPresented: $showHistory) {
201- RunHistoryView ( sessionID: session. id)
202- . environment ( appState)
203- . environment ( \. theme, theme)
204- }
205243 } else {
206244 VStack {
207245 Text ( " No session " )
@@ -232,6 +270,41 @@ struct InspectorView: View {
232270 if total < 60 { return " \( total) s " }
233271 return " \( total / 60 ) m \( total % 60 ) s "
234272 }
273+
274+ private func fileIcon( for path: String ) -> String {
275+ let ext = ( path as NSString ) . pathExtension. lowercased ( )
276+ switch ext {
277+ case " swift " : return " swift "
278+ case " go " : return " chevron.left.forwardslash.chevron.right "
279+ case " ts " , " tsx " , " js " , " jsx " : return " j.square "
280+ case " py " : return " p.square "
281+ case " json " , " yaml " , " yml " , " toml " : return " doc.text "
282+ case " md " : return " doc.richtext "
283+ case " css " , " scss " : return " paintbrush "
284+ case " html " : return " globe "
285+ case " sql " : return " cylinder "
286+ case " sh " , " bash " , " zsh " , " fish " : return " terminal "
287+ default : return " doc "
288+ }
289+ }
290+
291+ private func fileColor( for path: String ) -> Color {
292+ let ext = ( path as NSString ) . pathExtension. lowercased ( )
293+ switch ext {
294+ case " swift " : return theme. orange
295+ case " go " : return theme. cyan
296+ case " ts " , " tsx " , " js " , " jsx " : return theme. yellow
297+ case " py " : return theme. green
298+ case " json " , " yaml " , " yml " , " toml " : return theme. muted
299+ default : return theme. cyan
300+ }
301+ }
302+
303+ private func shortenPath( _ path: String ) -> String {
304+ let components = path. components ( separatedBy: " / " )
305+ if components. count <= 3 { return path }
306+ return components. suffix ( 3 ) . joined ( separator: " / " )
307+ }
235308}
236309
237310// MARK: - Detail helpers
0 commit comments