github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/webapp/javascript/pages/adhoc/AdhocDiff.tsx (about) 1 import React, { useEffect, useState } from 'react'; 2 import 'react-dom'; 3 import { Maybe } from '@webapp/util/fp'; 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 { Profile } from '@pyroscope/models/src'; 8 import FileList from '@webapp/components/FileList'; 9 import useExportToFlamegraphDotCom from '@webapp/components/exportToFlamegraphDotCom.hook'; 10 import ExportData from '@webapp/components/ExportData'; 11 import { 12 fetchAllProfiles, 13 fetchDiffProfile, 14 fetchProfile, 15 selectedSelectedProfileId, 16 selectProfileId, 17 selectShared, 18 selectDiffProfile, 19 uploadFile, 20 } from '@webapp/redux/reducers/adhoc'; 21 import useColorMode from '@webapp/hooks/colorMode.hook'; 22 import { Tabs, Tab, TabPanel } from '@webapp/ui/Tabs'; 23 import adhocStyles from './Adhoc.module.scss'; 24 import adhocComparisonStyles from './AdhocComparison.module.scss'; 25 import FileUploader from './components/FileUploader'; 26 27 function AdhocDiff() { 28 const dispatch = useAppDispatch(); 29 const leftProfileId = useAppSelector(selectProfileId('left')); 30 const rightProfileId = useAppSelector(selectProfileId('right')); 31 useColorMode(); 32 const selectedProfileIdLeft = useAppSelector( 33 selectedSelectedProfileId('left') 34 ); 35 const selectedProfileIdRight = useAppSelector( 36 selectedSelectedProfileId('right') 37 ); 38 const { profilesList } = useAppSelector(selectShared); 39 const diffProfile = useAppSelector(selectDiffProfile); 40 const exportToFlamegraphDotComFn = useExportToFlamegraphDotCom( 41 diffProfile.unwrapOr(undefined) 42 ); 43 const [tabIndexLeft, setTabIndexLeft] = useState(0); 44 const [tabIndexRight, setTabIndexRight] = useState(0); 45 46 useEffect(() => { 47 dispatch(fetchAllProfiles()); 48 }, [dispatch]); 49 50 useEffect(() => { 51 if (leftProfileId.isJust && rightProfileId.isJust) { 52 dispatch( 53 fetchDiffProfile({ 54 leftId: leftProfileId.value, 55 rightId: rightProfileId.value, 56 }) 57 ); 58 } 59 }, [ 60 dispatch, 61 leftProfileId.unwrapOr(undefined), 62 rightProfileId.unwrapOr(undefined), 63 ]); 64 65 const flamegraph = ( 66 profile: Maybe<Profile>, 67 exportToFn: ReturnType<typeof useExportToFlamegraphDotCom> 68 ) => { 69 if (profile.isNothing) { 70 return <></>; 71 } 72 73 return ( 74 <FlamegraphRenderer 75 profile={profile.value} 76 showCredit={false} 77 panesOrientation="vertical" 78 ExportData={ 79 <ExportData 80 flamebearer={profile.value} 81 exportJSON 82 exportFlamegraphDotCom 83 exportFlamegraphDotComFn={exportToFn} 84 /> 85 } 86 /> 87 ); 88 }; 89 90 return ( 91 <div> 92 <div className="main-wrapper"> 93 <div 94 className="comparison-container" 95 data-testid="comparison-container" 96 > 97 <Box className={adhocComparisonStyles.comparisonPane}> 98 <Tabs 99 value={tabIndexLeft} 100 onChange={(e, value) => setTabIndexLeft(value)} 101 > 102 <Tab label="Upload" /> 103 <Tab label="Pyroscope data" /> 104 </Tabs> 105 <TabPanel value={tabIndexLeft} index={0}> 106 <FileUploader 107 className={adhocStyles.tabPanel} 108 setFile={async ({ file, spyName, units }) => { 109 await dispatch( 110 uploadFile({ file, spyName, units, side: 'left' }) 111 ); 112 setTabIndexLeft(1); 113 }} 114 /> 115 </TabPanel> 116 <TabPanel value={tabIndexLeft} index={1}> 117 {profilesList.type === 'loaded' && ( 118 <FileList 119 className={adhocStyles.tabPanel} 120 profilesList={profilesList.profilesList} 121 selectedProfileId={selectedProfileIdLeft} 122 onProfileSelected={(id: string) => { 123 dispatch(fetchProfile({ id, side: 'left' })); 124 }} 125 /> 126 )} 127 </TabPanel> 128 </Box> 129 <Box className={adhocComparisonStyles.comparisonPane}> 130 <Tabs 131 value={tabIndexRight} 132 onChange={(e, value) => setTabIndexRight(value)} 133 > 134 <Tab label="Upload" /> 135 <Tab label="Pyroscope data" /> 136 </Tabs> 137 <TabPanel value={tabIndexRight} index={0}> 138 <FileUploader 139 className={adhocStyles.tabPanel} 140 setFile={async ({ file, spyName, units }) => { 141 await dispatch( 142 uploadFile({ file, spyName, units, side: 'right' }) 143 ); 144 setTabIndexRight(1); 145 }} 146 /> 147 </TabPanel> 148 <TabPanel value={tabIndexRight} index={1}> 149 {profilesList.type === 'loaded' && ( 150 <FileList 151 className={adhocStyles.tabPanel} 152 profilesList={profilesList.profilesList} 153 selectedProfileId={selectedProfileIdRight} 154 onProfileSelected={(id: string) => { 155 dispatch(fetchProfile({ id, side: 'right' })); 156 }} 157 /> 158 )} 159 </TabPanel> 160 </Box> 161 </div> 162 <Box>{flamegraph(diffProfile, exportToFlamegraphDotComFn)}</Box> 163 </div> 164 </div> 165 ); 166 } 167 168 export default AdhocDiff;