forked from VinokurovVE/tests
275 lines
11 KiB
TypeScript
275 lines
11 KiB
TypeScript
import { AppBar, Autocomplete, Box, Chip, CircularProgress, Dialog, Divider, Grid, IconButton, Paper, TextField, Toolbar, Typography, colors } from "@mui/material"
|
||
import { useBoilers, useCities, useRegions, useServers, useServersInfo } from "../hooks/swrHooks"
|
||
import { Fragment, useEffect, useState } from "react"
|
||
import { IBoiler, ICity, IRegion } from "../interfaces/fuel"
|
||
import { DataGrid, GridColDef } from "@mui/x-data-grid"
|
||
import ServerData from "../components/ServerData"
|
||
import { IServer, IServersInfo } from "../interfaces/servers"
|
||
import { Close, Cloud, CloudOff, Storage } from "@mui/icons-material"
|
||
import { BarChart } from "@mui/x-charts"
|
||
import FullFeaturedCrudGrid from "../components/TableEditable"
|
||
|
||
export default function Servers() {
|
||
const [open, setOpen] = useState(false)
|
||
const [options, setOptions] = useState<IRegion[]>([])
|
||
const [search, setSearch] = useState<string | null>(null)
|
||
const [debouncedSearch, setDebouncedSearch] = useState<string | null>("")
|
||
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
|
||
const { regions, isLoading } = useRegions(10, 1, debouncedSearch)
|
||
|
||
useEffect(() => {
|
||
const handler = setTimeout(() => {
|
||
setDebouncedSearch(search)
|
||
}, 500)
|
||
|
||
return () => {
|
||
clearTimeout(handler)
|
||
}
|
||
}, [search])
|
||
|
||
useEffect(() => {
|
||
if (regions) {
|
||
setOptions([...regions])
|
||
}
|
||
}, [regions])
|
||
|
||
const handleInputChange = (value: string) => {
|
||
setSearch(value)
|
||
}
|
||
|
||
const handleOptionChange = (value: IRegion | null) => {
|
||
setSelectedOption(value)
|
||
}
|
||
|
||
const [citiesOpen, setCitiesOpen] = useState(false)
|
||
const [citiesPage, setCitiesPage] = useState(1)
|
||
const [citiesSearch, setCitiesSearch] = useState('')
|
||
const [debouncedCitySearch, setDebouncedCitySearch] = useState('')
|
||
const { cities, isLoading: citiesLoading } = useCities(10, citiesPage, debouncedCitySearch)
|
||
const [citiesOptions, setCitiesOptions] = useState<ICity[]>([])
|
||
const [selectedCityOption, setSelectedCityOption] = useState<ICity | null>(null)
|
||
|
||
const handleCityInputChange = (value: string) => {
|
||
setCitiesSearch(value)
|
||
}
|
||
|
||
const handleCityOptionChange = (value: ICity | null) => {
|
||
setSelectedCityOption(value)
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (cities) {
|
||
setCitiesOptions([...cities])
|
||
}
|
||
}, [cities])
|
||
|
||
useEffect(() => {
|
||
const handler = setTimeout(() => {
|
||
setDebouncedCitySearch(citiesSearch)
|
||
}, 500)
|
||
|
||
return () => {
|
||
clearTimeout(handler)
|
||
}
|
||
}, [citiesSearch])
|
||
|
||
useEffect(() => {
|
||
setCitiesPage(1)
|
||
setCitiesSearch("")
|
||
}, [])
|
||
|
||
const { servers, isLoading: serversLoading } = useServers(selectedOption?.id, 0, 10)
|
||
|
||
const serversColumns: GridColDef[] = [
|
||
//{ field: 'id', headerName: 'ID', type: "number" },
|
||
{ field: 'name', headerName: 'Название', type: "string", editable: true },
|
||
]
|
||
|
||
const [serverDataOpen, setServerDataOpen] = useState(false)
|
||
const [currentServerData, setCurrentServerData] = useState<any | null>(null)
|
||
|
||
const { serversInfo } = useServersInfo(selectedOption?.id)
|
||
|
||
return (
|
||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%' }}>
|
||
<Dialog
|
||
fullScreen
|
||
open={serverDataOpen}
|
||
onClose={() => {
|
||
setServerDataOpen(false)
|
||
}}
|
||
aria-labelledby="modal-modal-title"
|
||
aria-describedby="modal-modal-description">
|
||
<AppBar sx={{ position: 'sticky' }}>
|
||
<Toolbar>
|
||
<IconButton
|
||
edge="start"
|
||
color="inherit"
|
||
onClick={() => {
|
||
setServerDataOpen(false)
|
||
}}
|
||
aria-label="close"
|
||
>
|
||
<Close />
|
||
</IconButton>
|
||
</Toolbar>
|
||
</AppBar>
|
||
|
||
{currentServerData &&
|
||
<ServerData
|
||
id={currentServerData?.id}
|
||
region_id={currentServerData?.region_id}
|
||
name={currentServerData?.name}
|
||
/>
|
||
}
|
||
</Dialog>
|
||
|
||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%', p: '16px' }}>
|
||
<Typography variant='h6' fontWeight='600'>
|
||
Servers by region
|
||
</Typography>
|
||
|
||
<Autocomplete
|
||
open={open}
|
||
onOpen={() => {
|
||
setOpen(true)
|
||
}}
|
||
onClose={() => {
|
||
setOpen(false)
|
||
}}
|
||
onInputChange={(_, value) => handleInputChange(value)}
|
||
onChange={(_, value) => handleOptionChange(value)}
|
||
filterOptions={(x) => x}
|
||
isOptionEqualToValue={(option: IRegion, value: IRegion) => option.name === value.name}
|
||
getOptionLabel={(option: IRegion) => option.name ? option.name : ""}
|
||
options={options}
|
||
loading={isLoading}
|
||
value={selectedOption}
|
||
renderInput={(params) => (
|
||
<TextField
|
||
{...params}
|
||
label="Район"
|
||
InputProps={{
|
||
...params.InputProps,
|
||
endAdornment: (
|
||
<Fragment>
|
||
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
|
||
{params.InputProps.endAdornment}
|
||
</Fragment>
|
||
)
|
||
}}
|
||
/>
|
||
)}
|
||
/>
|
||
|
||
<Autocomplete
|
||
hidden
|
||
|
||
open={citiesOpen}
|
||
onOpen={() => {
|
||
setCitiesOpen(true)
|
||
}}
|
||
onClose={() => {
|
||
setCitiesOpen(false)
|
||
}}
|
||
onInputChange={(_, value) => handleCityInputChange(value)}
|
||
onChange={(_, value) => handleCityOptionChange(value)}
|
||
filterOptions={(x) => x}
|
||
isOptionEqualToValue={(option: ICity, value: ICity) => option.name === value.name}
|
||
getOptionLabel={(option: ICity) => option.name ? option.name : ""}
|
||
options={citiesOptions}
|
||
loading={citiesLoading}
|
||
value={selectedCityOption}
|
||
renderInput={(params) => (
|
||
<TextField
|
||
{...params}
|
||
label="Город"
|
||
InputProps={{
|
||
...params.InputProps,
|
||
endAdornment: (
|
||
<Fragment>
|
||
{citiesLoading ? <CircularProgress color="inherit" size={20} /> : null}
|
||
{params.InputProps.endAdornment}
|
||
</Fragment>
|
||
)
|
||
}}
|
||
/>
|
||
)}
|
||
/>
|
||
|
||
{servers &&
|
||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%' }}>
|
||
<Typography variant='h6' fontWeight='600'>
|
||
Информация
|
||
</Typography>
|
||
|
||
{serversInfo &&
|
||
<Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 1, sm: 1, md: 2, lg: 3, xl: 4 }}>
|
||
{serversInfo.map((serverInfo: IServersInfo) => (
|
||
<Grid key={`si-${serverInfo.id}`} item xs={1} sm={1} md={1}>
|
||
<Paper sx={{ display: 'flex', flexDirection: 'column', gap: '16px', p: '16px' }}>
|
||
<Typography fontWeight={600}>
|
||
{serverInfo.name}
|
||
</Typography>
|
||
|
||
<Divider />
|
||
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||
<Typography>
|
||
Количество IP:
|
||
</Typography>
|
||
|
||
<Typography variant="h6" fontWeight={600}>
|
||
{serverInfo.IPs_count}
|
||
</Typography>
|
||
</Box>
|
||
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||
<Typography>
|
||
Количество серверов:
|
||
</Typography>
|
||
|
||
<Typography variant="h6" fontWeight={600}>
|
||
{serverInfo.servers_count}
|
||
</Typography>
|
||
</Box>
|
||
|
||
<Chip
|
||
icon={serverInfo.status === "Online" ? <Cloud /> : serverInfo.status === "Offline" ? <CloudOff /> : <CloudOff />}
|
||
variant="outlined"
|
||
label={serverInfo.status}
|
||
color={serverInfo.status === "Online" ? "success" : serverInfo.status === "Offline" ? "error" : "error"}
|
||
/>
|
||
</Paper>
|
||
</Grid>
|
||
))}
|
||
</Grid>
|
||
}
|
||
</Box>
|
||
}
|
||
|
||
{serversLoading ?
|
||
<CircularProgress />
|
||
:
|
||
servers &&
|
||
<FullFeaturedCrudGrid
|
||
initialRows={servers}
|
||
columns={serversColumns}
|
||
actions
|
||
onRowClick={(params, event, details) => {
|
||
setCurrentServerData(params.row)
|
||
setServerDataOpen(true)
|
||
}}
|
||
/>
|
||
}
|
||
|
||
{/* <BarChart
|
||
xAxis={[{ scaleType: 'band', data: ['group A', 'group B', 'group C'] }]}
|
||
series={[{ data: [4, 3, 5] }, { data: [1, 6, 3] }, { data: [2, 5, 6] }]}
|
||
width={500}
|
||
height={300}
|
||
/> */}
|
||
</Box>
|
||
</Box>
|
||
)
|
||
} |