github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/webapp/javascript/components/Footer.tsx (about) 1 import React from 'react'; 2 3 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 4 import { faDownload } from '@fortawesome/free-solid-svg-icons/faDownload'; 5 import { Maybe } from 'true-myth'; 6 import { BuildInfo, buildInfo, latestVersionInfo } from '../util/buildInfo'; 7 8 const START_YEAR = '2020'; 9 10 function copyrightYears(start: string, end: string) { 11 return start === end ? start : `${start} – ${end}`; 12 } 13 14 function buildInfoStr(buildInfo: BuildInfo) { 15 return ` 16 BUILD INFO: 17 js_version: ${buildInfo.jsVersion} 18 goos: ${buildInfo?.goos} 19 goarch: ${buildInfo?.goarch} 20 go_version: ${buildInfo?.goVersion} 21 version: ${buildInfo?.version} 22 time: ${buildInfo?.time} 23 gitSHA: ${buildInfo?.gitSHA} 24 gitDirty: ${buildInfo?.gitDirty} 25 embeddedAssets: ${buildInfo?.useEmbeddedAssets} 26 `.replace(/^\s+/gm, ''); 27 } 28 29 function NewerVersionCheck() { 30 const { version } = buildInfo(); 31 const maybeLatestVersionInfo = latestVersionInfo(); 32 33 if (maybeLatestVersionInfo.isNothing) { 34 return null; 35 } 36 37 const latestVersion = maybeLatestVersionInfo.value.latest_version; 38 39 interface Version { 40 major: number; 41 minor: number; 42 patch: number; 43 } 44 45 const splitVersion = function (s: string): Maybe<Version> { 46 // Since we control the format, there's no need for a complex parser 47 const split = s.split('.'); 48 if (split.length !== 3) { 49 return Maybe.nothing(); 50 } 51 52 return Maybe.of({ 53 // handle cases like v1.0.0 54 major: parseInt(split[0].replace('v', ''), 10), 55 minor: parseInt(split[1], 10), 56 patch: parseInt(split[2], 10), 57 }); 58 }; 59 60 const isUpdateAvailable = function (v1: Maybe<Version>, v2: Maybe<Version>) { 61 // we can't infer anything 62 if (v1.isNothing || v2.isNothing) { 63 return false; 64 } 65 66 const v1Value = v1.value; 67 const v2Value = v2.value; 68 69 // Compare major 70 if (v2Value.major > v1Value.major) { 71 return true; 72 } 73 if (v2Value.major < v1Value.major) { 74 return false; 75 } 76 // major value is equal 77 78 // compare minor 79 if (v2Value.minor > v1Value.minor) { 80 return true; 81 } 82 if (v2Value.minor < v1Value.minor) { 83 return false; 84 } 85 86 // minor is the same 87 // compare patch 88 if (v2Value.patch > v1Value.patch) { 89 return true; 90 } 91 if (v2Value.patch < v1Value.patch) { 92 return false; 93 } 94 95 return false; 96 }; 97 98 const currVersionObj = splitVersion(version); 99 const latestVersionObj = splitVersion(latestVersion); 100 101 if (!isUpdateAvailable(currVersionObj, latestVersionObj)) { 102 return null; 103 } 104 105 return ( 106 <span> 107 | 108 <a 109 href="https://pyroscope.io/downloads?utm_source=pyroscope_footer" 110 rel="noreferrer" 111 target="_blank" 112 > 113 <FontAwesomeIcon icon={faDownload} /> 114 115 <span>{`Newer Version Available (${latestVersion})`}</span> 116 </a> 117 </span> 118 ); 119 } 120 121 function Footer() { 122 const info = buildInfo(); 123 124 return ( 125 <footer className="footer" title={buildInfoStr(info)}> 126 <span> 127 {`© Pyroscope ${copyrightYears( 128 START_YEAR, 129 new Date().getFullYear().toFixed() 130 )}`} 131 </span> 132 | 133 <span>{info.version}</span> 134 <NewerVersionCheck /> 135 </footer> 136 ); 137 } 138 139 export default Footer;