@@ -14,6 +14,10 @@ interface LogPanelProps {
1414}
1515
1616export function LogPanel ( { responses, selectedIndex, height, nodeStore } : LogPanelProps ) {
17+ // Fixed height calculations
18+ const listHeight = Math . max ( 5 , Math . floor ( height / 2 ) ) ;
19+ const inspectorHeight = height - listHeight - 1 ;
20+
1721 if ( responses . length === 0 ) {
1822 return (
1923 < Box flexDirection = "column" paddingX = { 1 } paddingY = { 1 } height = { height } >
@@ -28,30 +32,22 @@ export function LogPanel({ responses, selectedIndex, height, nodeStore }: LogPan
2832 ) ;
2933 }
3034
31- // Split pane: upper half list, lower half inspector
32- const listHeight = Math . max ( 5 , Math . floor ( ( height - 1 ) * 0.5 ) ) ;
33- const inspectorHeight = Math . max ( 5 , height - listHeight - 1 ) ;
34-
3535 const selectedResponse = responses [ selectedIndex ] ;
3636
3737 return (
38- < Box flexDirection = "column" width = "100%" height = { height } >
39- < Box height = { listHeight } flexDirection = "column" flexShrink = { 0 } >
40- < LogList
41- responses = { responses }
42- selectedIndex = { selectedIndex }
43- height = { listHeight }
44- nodeStore = { nodeStore }
45- />
46- </ Box >
47- < Box flexShrink = { 0 } borderStyle = "single" borderColor = { theme . border . normal } borderTop = { true } borderBottom = { false } borderLeft = { false } borderRight = { false } />
48- < Box height = { inspectorHeight } flexDirection = "column" flexShrink = { 0 } >
49- < LogInspector
50- response = { selectedResponse }
51- nodeStore = { nodeStore }
52- height = { inspectorHeight }
53- />
54- </ Box >
38+ < Box flexDirection = "column" paddingX = { 1 } width = "100%" height = { height } >
39+ < LogList
40+ responses = { responses }
41+ selectedIndex = { selectedIndex }
42+ height = { listHeight }
43+ nodeStore = { nodeStore }
44+ />
45+ < Text color = { theme . border . normal } > { "─" . repeat ( 70 ) } </ Text >
46+ < LogInspector
47+ response = { selectedResponse }
48+ nodeStore = { nodeStore }
49+ height = { inspectorHeight }
50+ />
5551 </ Box >
5652 ) ;
5753}
@@ -62,7 +58,7 @@ function LogList({ responses, selectedIndex, height, nodeStore }: {
6258 height : number ;
6359 nodeStore : NodeStore ;
6460} ) {
65- const visibleCount = Math . max ( 1 , height - 2 ) ;
61+ const visibleCount = Math . max ( 1 , height - 1 ) ;
6662
6763 let startIndex = 0 ;
6864 if ( responses . length > visibleCount ) {
@@ -76,23 +72,21 @@ function LogList({ responses, selectedIndex, height, nodeStore }: {
7672 const visibleResponses = responses . slice ( startIndex , startIndex + visibleCount ) ;
7773
7874 return (
79- < Box flexDirection = "column" paddingX = { 1 } >
80- < Box >
81- < Text color = { theme . fg . muted } >
82- { "TYPE" . padEnd ( 12 ) }
83- { "FROM" . padEnd ( 12 ) }
84- { "TIME" }
85- </ Text >
86- </ Box >
75+ < >
76+ < Text color = { theme . fg . muted } >
77+ { "TYPE" . padEnd ( 12 ) }
78+ { "FROM" . padEnd ( 12 ) }
79+ { "TIME" }
80+ </ Text >
8781 { visibleResponses . map ( ( response , i ) => (
8882 < LogRow
89- key = { response . id || ` ${ response . timestamp } -${ i } `}
83+ key = { `log- ${ response . id || response . timestamp } -${ i } `}
9084 response = { response }
9185 isSelected = { startIndex + i === selectedIndex }
9286 nodeStore = { nodeStore }
9387 />
9488 ) ) }
95- </ Box >
89+ </ >
9690 ) ;
9791}
9892
@@ -109,22 +103,21 @@ function LogRow({ response, isSelected, nodeStore }: {
109103 isSelected : boolean ;
110104 nodeStore : NodeStore ;
111105} ) {
112- const bgColor = isSelected ? theme . bg . selected : undefined ;
113106 const isPosition = isPositionResponse ( response ) ;
114107 const isNodeInfo = isNodeInfoResponse ( response ) ;
115108 const type = isPosition ? "POSITION" : isNodeInfo ? "NODEINFO" : "TRACEROUTE" ;
116109 const typeColor = isPosition ? theme . packet . position : isNodeInfo ? theme . packet . nodeinfo : theme . packet . traceroute ;
117110 const fromName = nodeStore . getNodeName ( response . fromNode ) ;
118111 const time = new Date ( response . timestamp * 1000 ) . toLocaleTimeString ( "en-US" , { hour12 : false } ) ;
112+ const prefix = isSelected ? "▶ " : " " ;
119113
120114 return (
121- < Box backgroundColor = { bgColor } >
122- < Text wrap = "truncate" >
123- < Text color = { typeColor } > { type . padEnd ( 12 ) } </ Text >
124- < Text color = { theme . fg . accent } > { fromName . slice ( 0 , 10 ) . padEnd ( 12 ) } </ Text >
125- < Text color = { theme . fg . secondary } > { time } </ Text >
126- </ Text >
127- </ Box >
115+ < Text >
116+ < Text color = { theme . fg . accent } > { prefix } </ Text >
117+ < Text color = { typeColor } > { type . padEnd ( 12 ) } </ Text >
118+ < Text color = { theme . fg . accent } > { fromName . slice ( 0 , 10 ) . padEnd ( 12 ) } </ Text >
119+ < Text color = { theme . fg . secondary } > { time } </ Text >
120+ </ Text >
128121 ) ;
129122}
130123
@@ -134,11 +127,7 @@ function LogInspector({ response, nodeStore, height }: {
134127 height : number ;
135128} ) {
136129 if ( ! response ) {
137- return (
138- < Box paddingX = { 1 } >
139- < Text color = { theme . fg . muted } > No response selected</ Text >
140- </ Box >
141- ) ;
130+ return < Text color = { theme . fg . muted } > No response selected</ Text > ;
142131 }
143132
144133 const fromName = nodeStore . getNodeName ( response . fromNode ) ;
@@ -149,31 +138,18 @@ function LogInspector({ response, nodeStore, height }: {
149138 const lon = pos . longitudeI != null ? pos . longitudeI / 1e7 : null ;
150139
151140 return (
152- < Box flexDirection = "column" paddingX = { 1 } >
153- < Box >
154- < Text color = { theme . fg . muted } > From: </ Text >
155- < Text color = { theme . fg . accent } > { fromName } </ Text >
156- < Text color = { theme . fg . muted } > ({ formatNodeId ( pos . fromNode ) } )</ Text >
157- </ Box >
141+ < >
142+ < Text > < Text color = { theme . fg . muted } > From: </ Text > < Text color = { theme . fg . accent } > { fromName } </ Text > < Text color = { theme . fg . muted } > ({ formatNodeId ( pos . fromNode ) } )</ Text > </ Text >
158143 { lat != null && lon != null && (
159- < Box >
160- < Text color = { theme . fg . muted } > Position: </ Text >
161- < Text color = { theme . packet . position } > { lat . toFixed ( 6 ) } , { lon . toFixed ( 6 ) } </ Text >
162- </ Box >
144+ < Text > < Text color = { theme . fg . muted } > Position: </ Text > < Text color = { theme . packet . position } > { lat . toFixed ( 6 ) } , { lon . toFixed ( 6 ) } </ Text > </ Text >
163145 ) }
164146 { pos . altitude != null && (
165- < Box >
166- < Text color = { theme . fg . muted } > Altitude: </ Text >
167- < Text color = { theme . fg . primary } > { pos . altitude } m</ Text >
168- </ Box >
147+ < Text > < Text color = { theme . fg . muted } > Altitude: </ Text > < Text color = { theme . fg . primary } > { pos . altitude } m</ Text > </ Text >
169148 ) }
170149 { pos . satsInView != null && (
171- < Box >
172- < Text color = { theme . fg . muted } > Satellites: </ Text >
173- < Text color = { theme . fg . primary } > { pos . satsInView } </ Text >
174- </ Box >
150+ < Text > < Text color = { theme . fg . muted } > Satellites: </ Text > < Text color = { theme . fg . primary } > { pos . satsInView } </ Text > </ Text >
175151 ) }
176- </ Box >
152+ </ >
177153 ) ;
178154 }
179155
@@ -183,29 +159,16 @@ function LogInspector({ response, nodeStore, height }: {
183159 const hwModelName = ni . hwModel != null ? Mesh . HardwareModel [ ni . hwModel ] || `Unknown (${ ni . hwModel } )` : "Unknown" ;
184160
185161 return (
186- < Box flexDirection = "column" paddingX = { 1 } >
187- < Box >
188- < Text color = { theme . fg . muted } > From: </ Text >
189- < Text color = { theme . fg . accent } > { fromName } </ Text >
190- < Text color = { theme . fg . muted } > ({ formatNodeId ( ni . fromNode ) } )</ Text >
191- </ Box >
162+ < >
163+ < Text > < Text color = { theme . fg . muted } > From: </ Text > < Text color = { theme . fg . accent } > { fromName } </ Text > < Text color = { theme . fg . muted } > ({ formatNodeId ( ni . fromNode ) } )</ Text > </ Text >
192164 { ni . longName && (
193- < Box >
194- < Text color = { theme . fg . muted } > Long Name: </ Text >
195- < Text color = { theme . packet . nodeinfo } > { ni . longName } </ Text >
196- </ Box >
165+ < Text > < Text color = { theme . fg . muted } > Long Name: </ Text > < Text color = { theme . packet . nodeinfo } > { ni . longName } </ Text > </ Text >
197166 ) }
198167 { ni . shortName && (
199- < Box >
200- < Text color = { theme . fg . muted } > Short Name: </ Text >
201- < Text color = { theme . packet . nodeinfo } > { ni . shortName } </ Text >
202- </ Box >
168+ < Text > < Text color = { theme . fg . muted } > Short Name: </ Text > < Text color = { theme . packet . nodeinfo } > { ni . shortName } </ Text > </ Text >
203169 ) }
204- < Box >
205- < Text color = { theme . fg . muted } > Hardware: </ Text >
206- < Text color = { theme . fg . primary } > { hwModelName } </ Text >
207- </ Box >
208- </ Box >
170+ < Text > < Text color = { theme . fg . muted } > Hardware: </ Text > < Text color = { theme . fg . primary } > { hwModelName } </ Text > </ Text >
171+ </ >
209172 ) ;
210173 }
211174
@@ -215,42 +178,23 @@ function LogInspector({ response, nodeStore, height }: {
215178 const snrTowards : number [ ] = tr . snrTowards || [ ] ;
216179
217180 return (
218- < Box flexDirection = "column" paddingX = { 1 } >
219- < Box >
220- < Text color = { theme . fg . muted } > To: </ Text >
221- < Text color = { theme . fg . accent } > { fromName } </ Text >
222- < Text color = { theme . fg . muted } > ({ formatNodeId ( tr . fromNode ) } )</ Text >
223- </ Box >
224- < Box >
225- < Text color = { theme . fg . muted } > Hop Limit: </ Text >
226- < Text color = { theme . fg . primary } > { tr . hopLimit } </ Text >
227- { tr . hopLimit === 0 && < Text color = { theme . packet . direct } > (direct ping)</ Text > }
228- </ Box >
181+ < >
182+ < Text > < Text color = { theme . fg . muted } > To: </ Text > < Text color = { theme . fg . accent } > { fromName } </ Text > < Text color = { theme . fg . muted } > ({ formatNodeId ( tr . fromNode ) } )</ Text > </ Text >
183+ < Text > < Text color = { theme . fg . muted } > Hop Limit: </ Text > < Text color = { theme . fg . primary } > { tr . hopLimit } </ Text > { tr . hopLimit === 0 && < Text color = { theme . packet . direct } > (direct ping)</ Text > } </ Text >
229184 { route . length === 0 ? (
230- < Box >
231- < Text color = { theme . packet . direct } > Direct connection (0 hops)</ Text >
232- </ Box >
185+ < Text color = { theme . packet . direct } > Direct connection (0 hops)</ Text >
233186 ) : (
234187 < >
235- < Box >
236- < Text color = { theme . fg . muted } > Route: </ Text >
237- < Text color = { theme . packet . traceroute } > { route . length } hop{ route . length !== 1 ? "s" : "" } </ Text >
238- </ Box >
188+ < Text > < Text color = { theme . fg . muted } > Route: </ Text > < Text color = { theme . packet . traceroute } > { route . length } hop{ route . length !== 1 ? "s" : "" } </ Text > </ Text >
239189 { route . slice ( 0 , height - 4 ) . map ( ( nodeNum , i ) => {
240190 const name = nodeStore . getNodeName ( nodeNum ) ;
241191 const snr = snrTowards [ i ] ;
242192 return (
243- < Box key = { nodeNum } >
244- < Text color = { theme . fg . muted } > { i + 1 } . </ Text >
245- < Text color = { theme . fg . accent } > { name } </ Text >
246- { snr != null && (
247- < Text color = { theme . fg . secondary } > SNR: { ( snr / 4 ) . toFixed ( 1 ) } dB</ Text >
248- ) }
249- </ Box >
193+ < Text key = { `hop-${ i } ` } > < Text color = { theme . fg . muted } > { i + 1 } . </ Text > < Text color = { theme . fg . accent } > { name } </ Text > { snr != null && ( < Text color = { theme . fg . secondary } > SNR: { ( snr / 4 ) . toFixed ( 1 ) } dB</ Text > ) } </ Text >
250194 ) ;
251195 } ) }
252196 </ >
253197 ) }
254- </ Box >
198+ </ >
255199 ) ;
256200}
0 commit comments