@@ -37,8 +37,8 @@ import {
3737import { Backtrace } from 'firefox-profiler/components/shared/Backtrace' ;
3838
3939import {
40- formatMarkupFromMarkerSchema ,
4140 getSchemaFromMarker ,
41+ formatFromMarkerSchema ,
4242} from 'firefox-profiler/profile-logic/marker-schema' ;
4343import { computeScreenshotSize } from 'firefox-profiler/profile-logic/marker-data' ;
4444
@@ -52,13 +52,15 @@ import type {
5252 PageList ,
5353 MarkerSchemaByName ,
5454 MarkerIndex ,
55+ MarkerFormatType ,
5556 InnerWindowID ,
5657 Page ,
5758 Pid ,
5859 Tid ,
5960 IndexIntoStackTable ,
6061} from 'firefox-profiler/types' ;
6162
63+ import type { StringTable } from 'firefox-profiler/utils/string-table' ;
6264import type { ConnectedProps } from 'firefox-profiler/utils/connect' ;
6365import {
6466 getGCMinorDetails ,
@@ -281,7 +283,7 @@ class MarkerTooltipContents extends React.PureComponent<Props> {
281283 const displayLabel = this . props . showKeys ? key : label || key ;
282284 details . push (
283285 < TooltipDetail key = { schema . name + '-' + key } label = { displayLabel } >
284- { formatMarkupFromMarkerSchema (
286+ { renderMarkerFieldValue (
285287 schema . name ,
286288 format ,
287289 value ,
@@ -558,6 +560,134 @@ class MarkerTooltipContents extends React.PureComponent<Props> {
558560 }
559561}
560562
563+ // This regexp is used to test for URLs and remove their scheme for display.
564+ const URL_SCHEME_REGEXP = / ^ h t t p ( s ? ) : \/ \/ / ;
565+
566+ /**
567+ * This function may return structured markup for some types suchs as table,
568+ * list, or urls. For other types this falls back to formatFromMarkerSchema
569+ * above.
570+ */
571+ export function renderMarkerFieldValue (
572+ markerType : string ,
573+ format : MarkerFormatType ,
574+ value : any ,
575+ stringTable : StringTable ,
576+ threadIdToNameMap ?: Map < Tid , string > ,
577+ processIdToNameMap ?: Map < Pid , string >
578+ ) : React . ReactElement | string {
579+ if ( value === undefined || value === null ) {
580+ console . warn ( `Formatting ${ value } for ${ JSON . stringify ( markerType ) } ` ) ;
581+ return '(empty)' ;
582+ }
583+ if ( format !== 'url' && typeof format !== 'object' && format !== 'list' ) {
584+ return formatFromMarkerSchema (
585+ markerType ,
586+ format ,
587+ value ,
588+ stringTable ,
589+ threadIdToNameMap ,
590+ processIdToNameMap
591+ ) ;
592+ }
593+ if ( typeof format === 'object' ) {
594+ switch ( format . type ) {
595+ case 'table' : {
596+ const { columns } = format ;
597+ if ( ! ( value instanceof Array ) ) {
598+ throw new Error ( 'Expected an array for table type' ) ;
599+ }
600+ const hasHeader = columns . some ( ( column ) => column . label ) ;
601+ return (
602+ < table className = "marker-table-value" >
603+ { hasHeader ? (
604+ < thead >
605+ < tr >
606+ { columns . map ( ( col , i ) => (
607+ < th key = { i } > { col . label || '' } </ th >
608+ ) ) }
609+ </ tr >
610+ </ thead >
611+ ) : null }
612+ < tbody >
613+ { value . map ( ( row , i ) => {
614+ if ( ! ( row instanceof Array ) ) {
615+ throw new Error ( 'Expected an array for table row' ) ;
616+ }
617+
618+ if ( row . length !== columns . length ) {
619+ throw new Error (
620+ `Row ${ i } length doesn't match column count (row: ${ row . length } , cols: ${ columns . length } )`
621+ ) ;
622+ }
623+ return (
624+ < tr key = { i } >
625+ { row . map ( ( cell , i ) => {
626+ return (
627+ < td key = { i } >
628+ { renderMarkerFieldValue (
629+ markerType ,
630+ columns [ i ] . type || 'string' ,
631+ cell ,
632+ stringTable ,
633+ threadIdToNameMap ,
634+ processIdToNameMap
635+ ) }
636+ </ td >
637+ ) ;
638+ } ) }
639+ </ tr >
640+ ) ;
641+ } ) }
642+ </ tbody >
643+ </ table >
644+ ) ;
645+ }
646+ default :
647+ throw new Error (
648+ `Unknown format type ${ JSON . stringify ( format as never ) } `
649+ ) ;
650+ }
651+ }
652+ switch ( format ) {
653+ case 'list' :
654+ if ( ! ( value instanceof Array ) ) {
655+ throw new Error ( 'Expected an array for list format' ) ;
656+ }
657+ return (
658+ < ul className = "marker-list-value" >
659+ { value . map ( ( _entry , i ) => (
660+ < li key = { i } >
661+ { renderMarkerFieldValue (
662+ markerType ,
663+ 'string' ,
664+ value [ i ] ,
665+ stringTable
666+ ) }
667+ </ li >
668+ ) ) }
669+ </ ul >
670+ ) ;
671+ case 'url' : {
672+ if ( ! URL_SCHEME_REGEXP . test ( value ) ) {
673+ return value ;
674+ }
675+ return (
676+ < a
677+ href = { value }
678+ target = "_blank"
679+ rel = "noreferrer"
680+ className = "marker-link-value"
681+ >
682+ { value . replace ( URL_SCHEME_REGEXP , '' ) }
683+ </ a >
684+ ) ;
685+ }
686+ default :
687+ throw new Error ( `Unknown format type ${ JSON . stringify ( format as never ) } ` ) ;
688+ }
689+ }
690+
561691const ConnectedMarkerTooltipContents = explicitConnect <
562692 OwnProps ,
563693 StateProps ,
0 commit comments