github.com/pelicanplatform/pelican@v1.0.5/web_ui/frontend/components/ServerTable.tsx (about) 1 import {Table, TableCell, TableBody, TableContainer, TableHead, TableRow, Paper, Typography, Box} from '@mui/material'; 2 import React, { 3 FunctionComponent, 4 ReactElement, 5 ReactNode, 6 useCallback, 7 useEffect, 8 useMemo, 9 useRef, 10 useState 11 } from "react"; 12 import {Skeleton} from "@mui/material"; 13 import Link from "next/link"; 14 15 import DataTable, {Record} from "@/components/DataTable"; 16 import {TableCellOverflow} from "@/components/Cell"; 17 18 19 interface ExportData extends Record { 20 "Type": string 21 "Local Path": string 22 "Namespace Prefix": string 23 } 24 25 const TableCellOverflowLink: React.JSX.ElementType = ({ children, ...props }) => { 26 27 if (children === null){ 28 children = "" 29 } 30 31 return ( 32 <TableCellOverflow sx={{color: "blue", cursor: "pointer"}} {...props}> 33 <Link href={children as string}> 34 {children as string} 35 </Link> 36 </TableCellOverflow> 37 ) 38 } 39 40 41 42 interface Server extends Record { 43 name: string 44 authUrl: string 45 url: string 46 webUrl: string 47 type: string 48 latitude: number 49 longitude: number 50 } 51 52 53 interface ServerTableProps { 54 type?: "cache" | "origin" 55 } 56 57 export const ServerTable = ({type} : ServerTableProps) => { 58 59 const [data, setData] = useState<Server[] | undefined>(undefined); 60 const [error, setError] = useState<string | undefined>(undefined); 61 62 const keyToName = { 63 "name": { 64 name: "Name", 65 cellNode: TableCellOverflow 66 }, 67 "authUrl": { 68 name: "Auth URL", 69 cellNode: TableCellOverflowLink 70 }, 71 "url": { 72 name: "URL", 73 cellNode: TableCellOverflowLink 74 }, 75 "webUrl": { 76 name: "Web URL", 77 cellNode: TableCellOverflowLink 78 } 79 } 80 81 const getData = useCallback(async () => { 82 const url = new URL("/api/v1.0/director_ui/servers", window.location.origin) 83 if (type){ 84 url.searchParams.append("server_type", type) 85 } 86 87 let response = await fetch(url) 88 if (response.ok) { 89 const responseData: Server[] = await response.json() 90 responseData.sort((a, b) => a.name.localeCompare(b.name)) 91 setData(responseData) 92 93 } else { 94 setError("Failed to fetch config, response status: " + response.status) 95 } 96 }, [type]) 97 98 useEffect(() => { 99 getData() 100 }, []) 101 102 if(error){ 103 return ( 104 <Box p={1}> 105 <Typography sx={{color: "red"}} variant={"subtitle2"}>{error}</Typography> 106 </Box> 107 ) 108 } 109 110 return ( 111 <> 112 {data ? <DataTable columnMap={keyToName} data={data} /> : <Skeleton variant={"rectangular"} height={200} width={"100%"} />} 113 </> 114 ) 115 }