github.com/pelicanplatform/pelican@v1.0.5/web_ui/frontend/components/StatusBox.tsx (about) 1 /*************************************************************** 2 * 3 * Copyright (C) 2023, Pelican Project, Morgridge Institute for Research 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); you 6 * may not use this file except in compliance with the License. You may 7 * obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ***************************************************************/ 18 19 import {Box, Grid, Skeleton, Typography} from "@mui/material"; 20 import {useEffect, useState} from "react"; 21 import {DateTime} from "luxon"; 22 import { alpha, useTheme } from "@mui/material"; 23 24 interface StatusDisplayProps { 25 component: string; 26 status: string; 27 message?: string; 28 } 29 30 function StatusDisplay({component, status, message}: StatusDisplayProps) { 31 32 const theme = useTheme() 33 34 let backgroundColor: string 35 switch (status) { 36 case "ok": 37 backgroundColor = theme.palette.success.light 38 break 39 case "warning": 40 backgroundColor = theme.palette.warning.light 41 break 42 case "critical": 43 backgroundColor = theme.palette.error.light 44 break 45 default: 46 backgroundColor = theme.palette.warning.light 47 } 48 49 let backgroundColorFinal = alpha(backgroundColor, 0.5) 50 51 switch (component) { 52 case "xrootd": 53 component = "XRootD" 54 break 55 case "web-ui": 56 component = "Web UI" 57 break 58 case "cmsd": 59 component = "CMSD" 60 break 61 case "federation": 62 component = "Federation" 63 break 64 case "director": 65 component = "Director" 66 break 67 default: 68 } 69 70 return ( 71 <Box p={1} px={2} display={"flex"} flexDirection={"column"} bgcolor={backgroundColorFinal} borderRadius={2} mb={1}> 72 <Box> 73 <Typography> 74 {component} 75 </Typography> 76 </Box> 77 { message ? 78 <Box> 79 <Typography variant={"body2"}> 80 {message} 81 </Typography> 82 </Box> : 83 undefined 84 } 85 </Box> 86 ) 87 } 88 89 90 export default function StatusBox() { 91 92 const [status, setStatus] = useState<any>(undefined) 93 const [updated, setUpdated] = useState<DateTime>(DateTime.now()) 94 const [error, setError] = useState<string | undefined>(undefined) 95 96 let getStatus = async () => { 97 let response = await fetch("/api/v1.0/health") 98 99 if(response.ok) { 100 let data = await response.json() 101 setUpdated(DateTime.now()) 102 setStatus(data) 103 } else { 104 setError("Error fetching status json: " + response.status) 105 } 106 107 } 108 109 useEffect(() => { 110 getStatus() 111 112 const interval = setInterval(() => getStatus(), 60000); 113 return () => clearInterval(interval) 114 }, []) 115 116 if(status === undefined || error !== undefined) { 117 return ( 118 <Box> 119 <Box minHeight={"300px"}> 120 { 121 error ? 122 <Typography sx={{color: "red"}} variant={"subtitle2"}>{error}</Typography> : 123 <Skeleton variant="rectangular" height={250} /> 124 } 125 </Box> 126 </Box> 127 ) 128 } 129 130 let statusComponents: any[] = [] 131 try { 132 statusComponents = Object.entries(status['components']).map(([component, status]: [string, any]) => { 133 return ( 134 <StatusDisplay key={component} component={component} status={status['status']} message={status['message']}/> 135 ) 136 }) 137 } catch (e) { 138 setError("Error parsing status json: " + e) 139 } 140 141 142 143 144 return ( 145 <Box> 146 <Box> 147 {statusComponents} 148 </Box> 149 <Box> 150 <Typography sx={{color: "grey"}} variant={"subtitle2"}>Last Updated: {updated.toLocaleString(DateTime.DATETIME_MED)}</Typography> 151 </Box> 152 </Box> 153 ) 154 }