11// src/LogTable.js
22import React , { useState } from "react" ;
3- import { useSortBy , useTable } from "react-table" ;
3+ import { useSortBy , useTable , useBlockLayout , useResizeColumns } from "react-table" ;
44import { FixedSizeList as List } from "react-window" ;
55import AutoSizer from "react-virtualized-auto-sizer" ;
66import _ from "lodash" ;
77
8+ const CELL_PADDING = 24 ;
9+
10+ function getDisplayText ( col , entry ) {
11+ const raw = typeof col . accessor === "function" ? col . accessor ( entry ) : _ . get ( entry , col . accessor ) ;
12+ if ( raw === undefined || raw === null ) return "" ;
13+ const str = typeof raw === "object" ? JSON . stringify ( raw ) : String ( raw ) ;
14+ if ( col . trim ) return str . replace ( col . trim , "" ) ;
15+ return str ;
16+ }
17+
18+ function computeColumnWidths ( columns , data ) {
19+ const sampleSize = Math . min ( data . length , 200 ) ;
20+
21+ const canvas = document . createElement ( "canvas" ) ;
22+ const context = canvas . getContext ( "2d" ) ;
23+ context . font = "16px Times-Roman" ;
24+
25+ columns . forEach ( ( col ) => {
26+ const headerStr = col . Header || "" ;
27+ let maxWidthPx = context . measureText ( headerStr ) . width ;
28+
29+ for ( let i = 0 ; i < sampleSize ; i ++ ) {
30+ const text = getDisplayText ( col , data [ i ] ) ;
31+ if ( text ) {
32+ const textWidth = context . measureText ( text ) . width ;
33+ if ( textWidth > maxWidthPx ) maxWidthPx = textWidth ;
34+ }
35+ }
36+ const fitted = Math . ceil ( maxWidthPx + CELL_PADDING ) ;
37+ col . width = Math . min ( fitted , col . width ) ;
38+ } ) ;
39+ }
40+
841function Table ( { columns, data, onSelectionChange, listRef, selectedRow, centerOnLocation } ) {
9- const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable (
42+ const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, totalColumnsWidth } = useTable (
1043 {
1144 columns,
1245 data,
1346 autoResetSortBy : false ,
1447 } ,
15- useSortBy
48+ useBlockLayout ,
49+ useSortBy ,
50+ useResizeColumns
1651 ) ;
1752
1853 const handleRowSelection = React . useCallback (
@@ -94,7 +129,7 @@ function Table({ columns, data, onSelectionChange, listRef, selectedRow, centerO
94129 key = { key }
95130 { ...restCellProps }
96131 className = { `logtable-cell ${ cell . column . className || "" } ` }
97- style = { { width : cell . column . width } }
132+ style = { restCellProps . style }
98133 >
99134 { cell . render ( "Cell" ) }
100135 </ div >
@@ -103,7 +138,7 @@ function Table({ columns, data, onSelectionChange, listRef, selectedRow, centerO
103138 </ div >
104139 ) ;
105140 } ,
106- [ prepareRow , rows , selectedRow , handleRowSelection , centerOnLocation ]
141+ [ prepareRow , rows , selectedRow , handleRowSelection , centerOnLocation , totalColumnsWidth ]
107142 ) ;
108143
109144 return (
@@ -116,8 +151,8 @@ function Table({ columns, data, onSelectionChange, listRef, selectedRow, centerO
116151 >
117152 < AutoSizer >
118153 { ( { height, width } ) => (
119- < div >
120- < div { ...getTableProps ( ) } >
154+ < div style = { { width , overflowX : "auto" , overflowY : "hidden" } } >
155+ < div { ...getTableProps ( ) } style = { { minWidth : "100%" , width : totalColumnsWidth } } >
121156 < div >
122157 { headerGroups . map ( ( headerGroup ) => {
123158 const { key, ...restHeaderGroupProps } = headerGroup . getHeaderGroupProps ( ) ;
@@ -130,9 +165,14 @@ function Table({ columns, data, onSelectionChange, listRef, selectedRow, centerO
130165 key = { key }
131166 { ...restColumnProps }
132167 className = { `logtable-header-cell ${ column . className || "" } ` }
133- style = { { width : column . width } }
168+ style = { { ... restColumnProps . style , position : "relative" } }
134169 >
135170 { column . render ( "Header" ) }
171+ < div
172+ { ...column . getResizerProps ( ) }
173+ className = { `resizer ${ column . isResizing ? "isResizing" : "" } ` }
174+ onClick = { ( e ) => e . stopPropagation ( ) }
175+ />
136176 </ div >
137177 ) ;
138178 } ) }
@@ -143,11 +183,13 @@ function Table({ columns, data, onSelectionChange, listRef, selectedRow, centerO
143183 < div { ...getTableBodyProps ( ) } >
144184 < List
145185 ref = { listRef }
146- height = { height - 100 }
186+ height = { height - 54 }
147187 itemCount = { rows . length }
148- itemSize = { 35 }
149- width = { width }
188+ itemSize = { 32 }
189+ width = { totalColumnsWidth > width ? totalColumnsWidth : width }
150190 overscanCount = { 10 }
191+ itemData = { totalColumnsWidth }
192+ style = { { overflowX : "hidden" } }
151193 >
152194 { Row }
153195 </ List >
@@ -168,9 +210,9 @@ function LogTable(props) {
168210 const data = React . useMemo ( ( ) => {
169211 return props . logData . tripLogs . getLogs_ ( new Date ( minTime ) , new Date ( maxTime ) , props . filters ) . value ( ) ;
170212 } , [ props . logData . tripLogs , minTime , maxTime , props . filters ] ) ;
171- const columnShortWidth = 50 ;
172- const columnRegularWidth = 120 ;
173- const columnLargeWidth = 152 ;
213+ const columnShortWidth = 100 ;
214+ const columnRegularWidth = 130 ;
215+ const columnLargeWidth = 190 ;
174216 const columns = React . useMemo ( ( ) => {
175217 const stdColumns = _ . filter (
176218 [
@@ -185,7 +227,8 @@ function LogTable(props) {
185227 {
186228 Header : "Method" ,
187229 accessor : "@type" ,
188- Cell : ( { cell : { value } } ) => < TrimCell value = { value } trim = "type.googleapis.com/maps.fleetengine." /> ,
230+ Cell : TrimCellRenderer ,
231+ trim : "type.googleapis.com/maps.fleetengine." ,
189232 width : columnRegularWidth ,
190233 className : "logtable-cell" ,
191234 solutionTypes : [ "ODRD" , "LMFS" ] ,
@@ -199,25 +242,25 @@ function LogTable(props) {
199242 }
200243 } ,
201244 width : columnShortWidth ,
202- maxWidth : columnShortWidth ,
203245 className : "logtable-cell short-column" ,
204246 solutionTypes : [ "ODRD" , "LMFS" ] ,
205247 } ,
206248 {
207249 Header : "Sensor" ,
208250 accessor : "lastlocation.rawlocationsensor" ,
209251 id : "lastlocation_rawlocationsensor" ,
210- Cell : ( { cell : { value } } ) => < TrimCell value = { value } trim = "LOCATION_SENSOR_" /> ,
252+ Cell : TrimCellRenderer ,
253+ trim : "LOCATION_SENSOR_" ,
211254 width : columnShortWidth ,
212- maxWidth : columnShortWidth ,
213255 className : "logtable-cell" ,
214256 solutionTypes : [ "ODRD" , "LMFS" ] ,
215257 } ,
216258 {
217259 Header : "Location" ,
218260 accessor : "lastlocation.locationsensor" ,
219261 id : "lastlocation_locationsensor" ,
220- Cell : ( { cell : { value } } ) => < TrimCell value = { value } trim = "_LOCATION_PROVIDER" /> ,
262+ Cell : TrimCellRenderer ,
263+ trim : "_LOCATION_PROVIDER" ,
221264 width : columnRegularWidth ,
222265 className : "logtable-cell" ,
223266 solutionTypes : [ "ODRD" , "LMFS" ] ,
@@ -232,24 +275,25 @@ function LogTable(props) {
232275 }
233276 return null ;
234277 } ,
235- width : 90 ,
236- maxWidth : 90 ,
278+ width : columnRegularWidth ,
237279 className : "logtable-cell" ,
238280 solutionTypes : [ "ODRD" ] ,
239281 } ,
240282 {
241283 Header : "Vehicle State" ,
242284 accessor : "response.vehiclestate" ,
243285 id : "response_vehiclestate" ,
244- Cell : ( { cell : { value } } ) => < TrimCell value = { value } trim = "VEHICLE_STATE_" /> ,
286+ Cell : TrimCellRenderer ,
287+ trim : "VEHICLE_STATE_" ,
245288 width : columnRegularWidth ,
246289 className : "logtable-cell" ,
247290 solutionTypes : [ "ODRD" ] ,
248291 } ,
249292 {
250293 Header : "Task State" ,
251294 accessor : "response.state" ,
252- Cell : ( { cell : { value } } ) => < TrimCell value = { value } trim = "TASK_STATE_" /> ,
295+ Cell : TrimCellRenderer ,
296+ trim : "TASK_STATE_" ,
253297 width : columnRegularWidth ,
254298 className : "logtable-cell" ,
255299 solutionTypes : [ "LMFS" ] ,
@@ -258,7 +302,8 @@ function LogTable(props) {
258302 Header : "Trip Status" ,
259303 accessor : "response.tripstatus" ,
260304 id : "response_tripstatus" ,
261- Cell : ( { cell : { value } } ) => < TrimCell value = { value } trim = "TRIP_STATUS_" /> ,
305+ Cell : TrimCellRenderer ,
306+ trim : "TRIP_STATUS_" ,
262307 width : columnLargeWidth ,
263308 className : "logtable-cell" ,
264309 solutionTypes : [ "ODRD" ] ,
@@ -290,7 +335,8 @@ function LogTable(props) {
290335 {
291336 Header : "Nav Status" ,
292337 accessor : "navStatus" ,
293- Cell : ( { cell : { value } } ) => < TrimCell value = { value } trim = "NAVIGATION_STATUS_" /> ,
338+ Cell : TrimCellRenderer ,
339+ trim : "NAVIGATION_STATUS_" ,
294340 width : columnLargeWidth ,
295341 className : "logtable-cell" ,
296342 solutionTypes : [ "ODRD" , "LMFS" ] ,
@@ -315,14 +361,9 @@ function LogTable(props) {
315361 } ,
316362 } ) ;
317363 } ) ;
318- const headers = [
319- {
320- Header : "Event Logs Table (click row to view full log entry and long click to also center map)" ,
321- columns : stdColumns ,
322- } ,
323- ] ;
324- return headers ;
325- } , [ props . extraColumns , props . logData . solutionType ] ) ;
364+ computeColumnWidths ( stdColumns , data ) ;
365+ return stdColumns ;
366+ } , [ props . extraColumns , props . logData . solutionType , data ] ) ;
326367
327368 const handleRowSelection = React . useCallback (
328369 ( rowIndex , rowData ) => {
@@ -365,8 +406,9 @@ function LogTable(props) {
365406 ) ;
366407}
367408
368- // Helper method for removing common substrings in cells
369- const TrimCell = ( { value, trim } ) => {
409+ const TrimCellRenderer = ( { cell } ) => {
410+ const { value } = cell ;
411+ const trim = cell . column . trim ;
370412 return < > { value && value . replace ( trim , "" ) } </ > ;
371413} ;
372414
0 commit comments