github.com/pelicanplatform/pelican@v1.0.5/web_ui/frontend/components/graphs/Graph.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  "use client"
    19  
    20  import {useEffect, useState} from "react";
    21  import {
    22      Chart as ChartJS,
    23      CategoryScale,
    24      LinearScale,
    25      TimeScale,
    26      PointElement,
    27      LineElement,
    28      Title,
    29      Tooltip,
    30      Legend,
    31      ChartOptions,
    32      Colors
    33  } from 'chart.js';
    34  
    35  
    36  import zoomPlugin from 'chartjs-plugin-zoom';
    37  import 'chartjs-adapter-luxon';
    38  
    39  import {BoxProps} from "@mui/material";
    40  
    41  import {Line} from "react-chartjs-2";
    42  import {Box, Skeleton, Typography} from "@mui/material";
    43  
    44  import {getDataFunction} from "@/components/graphs/prometheus";
    45  import {ChartData} from "chart.js";
    46  
    47  const defaultOptions: Partial<ChartOptions<"line">> = {
    48      scales: {
    49          x: {
    50              type: 'time',
    51              time: {
    52                  round: 'second',
    53              }
    54          }
    55      }
    56  }
    57  
    58  interface GraphProps {
    59      getData: getDataFunction;
    60      drawer?: any;
    61      options?: ChartOptions<"line">
    62      boxProps?: BoxProps;
    63  }
    64  
    65  export default function Graph({getData, options, boxProps, drawer}: GraphProps) {
    66  
    67      let [data, _setData] = useState<ChartData<"line", any, any>>()
    68      let [loading, setLoading] = useState<boolean>(true)
    69      let [error, setError] = useState<string>("")
    70  
    71  
    72      async function setData() {
    73          try {
    74              let response = await getData()
    75              _setData(response)
    76              setLoading(false)
    77              if(response.datasets[0].data.length == 0){
    78                  let date = new Date(Date.now()).toLocaleTimeString()
    79                  setError(`No data returned by database as of ${date}; Plot will auto-refresh`)
    80              } else {
    81                  setError("")
    82              }
    83          } catch (e: any) {
    84              let date = new Date(Date.now()).toLocaleString()
    85              setError(date + " : " + e.message + "; Plot will auto-refresh")
    86          }
    87      }
    88  
    89      useEffect(() => {
    90  
    91          ChartJS.register(
    92              CategoryScale,
    93              LinearScale,
    94              PointElement,
    95              LineElement,
    96              Title,
    97              Tooltip,
    98              Legend,
    99              TimeScale,
   100              zoomPlugin,
   101              Colors
   102          );
   103  
   104  
   105          // Do the initial data fetch
   106          setData()
   107  
   108          // Refetch the data every minute
   109          const interval = setInterval(() => setData(), 60000);
   110          return () => clearInterval(interval);
   111  
   112      }, [getData])
   113  
   114      return (
   115          <Box>
   116              { loading || !data ?
   117                  <Box borderRadius={2} overflow={"hidden"}><Skeleton variant={"rectangular"} width={"100%"} height={"300px"} /></Box> :
   118                  <>
   119                      <Box m={"auto"} {...boxProps}>
   120                          <Line
   121                              data={data}
   122                              options={{
   123                                  ...defaultOptions,
   124                                  ...options
   125                              }}
   126                          />
   127                      </Box>
   128                      <Box display={"flex"}>
   129                          { drawer ? drawer : undefined }
   130                      </Box>
   131                  </>
   132              }
   133              <Box display={"flex"} pt={1}>
   134                  <Typography m={"auto"} color={"red"} variant={"body2"}>{error}</Typography>
   135              </Box>
   136          </Box>
   137      )
   138  
   139  }