@@ -31,6 +31,42 @@ import { docLinks } from '~/util/links'
3131
3232export const handle = { crumb : 'Audit Log' }
3333
34+ /**
35+ * Convert API response JSON from the camel-cased version we get out of the TS
36+ * client back into snake-case, which is what we get from the API. This is truly
37+ * stupid but I can't think of a better way.
38+ */
39+ function camelToSnakeJson ( o : Record < string , unknown > ) : Record < string , unknown > {
40+ const result : Record < string , unknown > = { }
41+
42+ for ( const originalKey in o ) {
43+ if ( ! Object . prototype . hasOwnProperty . call ( o , originalKey ) ) {
44+ continue
45+ }
46+
47+ const snakeKey = originalKey
48+ . replace ( / [ A - Z ] / g, ( letter ) => `_${ letter . toLowerCase ( ) } ` )
49+ . replace ( / ^ _ / , '' )
50+ const value = o [ originalKey ]
51+
52+ if ( value !== null && typeof value === 'object' ) {
53+ if ( Array . isArray ( value ) ) {
54+ result [ snakeKey ] = value . map ( ( item ) =>
55+ item !== null && typeof item === 'object' && ! Array . isArray ( item )
56+ ? camelToSnakeJson ( item as Record < string , unknown > )
57+ : item
58+ )
59+ } else {
60+ result [ snakeKey ] = camelToSnakeJson ( value as Record < string , unknown > )
61+ }
62+ } else {
63+ result [ snakeKey ] = value
64+ }
65+ }
66+
67+ return result
68+ }
69+
3470const Indent = ( { depth } : { depth : number } ) => (
3571 < span className = "inline-block" style = { { width : `${ depth * 4 + 1 } ch` } } />
3672)
@@ -41,6 +77,8 @@ const Primitive = ({ value }: { value: null | boolean | number | string }) => (
4177 </ span >
4278)
4379
80+ // TODO: avoid converting JSON to string and then parsing again. just need a better memo
81+
4482// silly faux highlighting
4583// avoids unnecessary import of a library and all that overhead
4684const HighlightJSON = memo ( ( { jsonString } : { jsonString : string } ) => {
@@ -215,7 +253,10 @@ export default function SiloAuditLogsPage() {
215253 { rowVirtualizer . getVirtualItems ( ) . map ( ( virtualRow ) => {
216254 const log = allItems [ virtualRow . index ]
217255 const isExpanded = expandedItem === virtualRow . index . toString ( )
218- const jsonString = JSON . stringify ( log , null , 2 )
256+ // only bother doing all this computation if we're the expanded row
257+ const jsonString = isExpanded
258+ ? JSON . stringify ( camelToSnakeJson ( log ) , null , 2 )
259+ : ''
219260
220261 const [ userId , siloId ] = match ( log . actor )
221262 . with ( { kind : 'silo_user' } , ( actor ) => [ actor . siloUserId , actor . siloId ] )
@@ -232,7 +273,7 @@ export default function SiloAuditLogsPage() {
232273 transform : `translateY(${ virtualRow . start } px)` ,
233274 } }
234275 >
235- < button
276+ < div
236277 className = { cn (
237278 'grid h-9 w-full cursor-pointer items-center gap-8 px-[var(--content-gutter)] text-left text-sans-md border-secondary' ,
238279 isExpanded ? 'bg-raise' : 'hover:bg-raise' ,
@@ -243,7 +284,6 @@ export default function SiloAuditLogsPage() {
243284 const newValue = isExpanded ? null : virtualRow . index . toString ( )
244285 handleToggle ( newValue )
245286 } }
246- type = "button"
247287 >
248288 { /* TODO: might be especially useful here to get the original UTC timestamp in a tooltip */ }
249289 < div className = "overflow-hidden whitespace-nowrap text-mono-sm" >
@@ -292,7 +332,7 @@ export default function SiloAuditLogsPage() {
292332 { differenceInMilliseconds ( new Date ( log . timeCompleted ) , log . timeStarted ) }
293333 ms
294334 </ div >
295- </ button >
335+ </ div >
296336 { isExpanded && (
297337 < div className = "h-72 border-t px-[var(--content-gutter)] py-3 border-secondary" >
298338 < pre className = "h-full overflow-auto border-l pl-4 text-mono-code border-secondary" >
0 commit comments