github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/webapp/javascript/pages/TracingSingleView.tsx (about) 1 import React, { useEffect } from 'react'; 2 import 'react-dom'; 3 import { format } from 'date-fns'; 4 import { useAppDispatch, useAppSelector } from '@webapp/redux/hooks'; 5 import Box from '@webapp/ui/Box'; 6 import { FlamegraphRenderer } from '@pyroscope/flamegraph/src/FlamegraphRenderer'; 7 import { fetchSingleView } from '@webapp/redux/reducers/tracing'; 8 import useColorMode from '@webapp/hooks/colorMode.hook'; 9 import ExportData from '@webapp/components/ExportData'; 10 import useExportToFlamegraphDotCom from '@webapp/components/exportToFlamegraphDotCom.hook'; 11 import PageTitle from '@webapp/components/PageTitle'; 12 import { isExportToFlamegraphDotComEnabled } from '@webapp/util/features'; 13 import { formatTitle } from './formatTitle'; 14 15 import styles from './TracingSingleView.module.scss'; 16 17 function formatTime(t: string | undefined): string { 18 return format(new Date(1000 * parseInt(t || '0', 10)), 'yyyy-MM-dd HH:mm:ss'); 19 } 20 21 function TracingSingleView() { 22 const dispatch = useAppDispatch(); 23 const { colorMode } = useColorMode(); 24 25 const { queryID, refreshToken, maxNodes, singleView } = useAppSelector( 26 (state) => state.tracing 27 ); 28 29 useEffect(() => { 30 if (queryID && maxNodes) { 31 const fetchData = dispatch(fetchSingleView(null)); 32 return () => fetchData.abort('cancel'); 33 } 34 return undefined; 35 }, [queryID, refreshToken, maxNodes]); 36 37 const getRaw = () => { 38 switch (singleView.type) { 39 case 'loaded': 40 case 'reloading': { 41 return singleView.profile; 42 } 43 44 default: { 45 return undefined; 46 } 47 } 48 }; 49 const exportToFlamegraphDotComFn = useExportToFlamegraphDotCom(getRaw()); 50 51 const flamegraphRenderer = (() => { 52 switch (singleView.type) { 53 case 'loaded': 54 case 'reloading': { 55 return ( 56 <FlamegraphRenderer 57 showCredit={false} 58 profile={singleView.profile} 59 colorMode={colorMode} 60 ExportData={ 61 <ExportData 62 flamebearer={singleView.profile} 63 exportPNG 64 exportJSON 65 exportPprof 66 exportHTML 67 exportFlamegraphDotCom={isExportToFlamegraphDotComEnabled} 68 exportFlamegraphDotComFn={exportToFlamegraphDotComFn} 69 /> 70 } 71 /> 72 ); 73 } 74 75 default: { 76 return 'Loading'; 77 } 78 } 79 })(); 80 81 const header = singleView.mergeMetadata 82 ? (function (mm) { 83 const { appName, startTime, endTime, profilesLength } = mm; 84 return ( 85 <> 86 <div> 87 <strong>App Name:</strong> <span>{appName}</span> 88 </div> 89 <div> 90 <strong>Start Time:</strong> <span>{formatTime(startTime)}</span> 91 </div> 92 <div> 93 <strong>End Time:</strong> <span>{formatTime(endTime)}</span> 94 </div> 95 <div> 96 <strong>Number of Profiles merged:</strong>{' '} 97 <span>{profilesLength}</span> 98 </div> 99 </> 100 ); 101 })(singleView.mergeMetadata) 102 : null; 103 104 return ( 105 <div> 106 <PageTitle title={formatTitle('Tracing')} /> 107 <div className="main-wrapper"> 108 <Box className={styles.header}>{header}</Box> 109 <Box>{flamegraphRenderer}</Box> 110 </div> 111 </div> 112 ); 113 } 114 115 export default TracingSingleView;