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  }