forked from VinokurovVE/tests
Tables, cards, (servers)
This commit is contained in:
275
frontend_reactjs/src/pages/Servers.tsx
Normal file
275
frontend_reactjs/src/pages/Servers.tsx
Normal file
@ -0,0 +1,275 @@
|
||||
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>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user