This commit is contained in:
cracklesparkle
2024-07-18 11:48:56 +09:00
parent 4283bd20bb
commit cf3fda43e4
20 changed files with 259 additions and 340 deletions

View File

@ -1,5 +1,5 @@
import { Box, Chip, Divider, Paper, Typography } from '@mui/material'
import React, { PropsWithChildren, ReactElement, ReactNode } from 'react'
import { Divider, Paper, Typography } from '@mui/material'
import { PropsWithChildren } from 'react'
interface CardInfoProps extends PropsWithChildren {
label: string;

View File

@ -1,7 +1,5 @@
import { Cloud } from '@mui/icons-material';
import { Chip, SvgIconTypeMap } from '@mui/material'
import { OverridableComponent } from '@mui/material/OverridableComponent';
import React, { ReactElement } from 'react'
import { Chip } from '@mui/material'
import { ReactElement } from 'react'
interface CardInfoChipProps {
status: boolean;

View File

@ -1,6 +1,4 @@
import { Box, Typography } from '@mui/material'
import React from 'react'
interface CardInfoLabelProps {
label: string;
value: string | number;

View File

@ -1,79 +0,0 @@
import { Autocomplete, CircularProgress, TextField } from '@mui/material'
import React, { Fragment, useEffect, useState } from 'react'
interface DataGridCellAutocompleteProps {
selectedOption: any;
setSelectedOption: any;
isLoading: boolean;
setDebouncedSearch: any;
options: any;
setOptions: any;
}
export default function DataGridCellAutocomplete({
selectedOption,
setSelectedOption,
isLoading,
setDebouncedSearch,
options,
setOptions
}: DataGridCellAutocompleteProps) {
const [open, setOpen] = useState(false)
const [search, setSearch] = useState<string | null>("")
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearch(search)
}, 500)
return () => {
clearTimeout(handler)
}
}, [search])
const handleInputChange = (value: string) => {
setSearch(value)
}
const handleOptionChange = (value: any | null) => {
setSelectedOption(value)
}
return (
<Autocomplete
sx={{ flexGrow: '1' }}
open={open}
onOpen={() => {
setOpen(true)
}}
onClose={() => {
setOpen(false)
}}
onInputChange={(_, value) => handleInputChange(value)}
onChange={(_, value) => handleOptionChange(value)}
filterOptions={(x) => x}
isOptionEqualToValue={(option: any, value: any) => option.name === value.name}
getOptionLabel={(option: any) => option.name ? option.name : ""}
options={options}
loading={isLoading}
value={selectedOption}
renderInput={(params) => (
<TextField
{...params}
size='small'
label="Район"
variant='standard'
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}}
/>
)}
/>
)
}

View File

@ -3,8 +3,9 @@ import { IServer } from '../interfaces/servers'
import { useServerIps } from '../hooks/swrHooks'
import FullFeaturedCrudGrid from './TableEditable'
import { GridColDef } from '@mui/x-data-grid'
import { AxiosResponse } from 'axios'
function ServerData({ id, name, region_id }: IServer) {
function ServerData({ id }: IServer) {
const { serverIps } = useServerIps(id, 0, 10)
const serverIpsColumns: GridColDef[] = [
@ -24,9 +25,16 @@ function ServerData({ id, name, region_id }: IServer) {
columns={serverIpsColumns}
actions
onRowClick={(params, event, details) => {
console.log(params.id, event, details)
//setCurrentServerData(params.row)
//setServerDataOpen(true)
}}
onSave={undefined}
onDelete={function (data: any): Promise<AxiosResponse<any, any>> {
console.log(data)
throw new Error('Function not implemented.')
}}
loading={false}
/>
}
</Box>

View File

@ -1,7 +1,7 @@
import { AppBar, Autocomplete, CircularProgress, Dialog, IconButton, TextField, Toolbar } from '@mui/material'
import React, { Fragment, useEffect, useState } from 'react'
import { Fragment, useEffect, useState } from 'react'
import { IRegion } from '../interfaces/fuel'
import { useHardwares, useRegions, useServerIps, useServers } from '../hooks/swrHooks'
import { useHardwares, useServers } from '../hooks/swrHooks'
import FullFeaturedCrudGrid from './TableEditable'
import ServerService from '../services/ServersService'
import { GridColDef } from '@mui/x-data-grid'
@ -95,41 +95,37 @@ export default function ServerHardware() {
:
hardwares &&
<FullFeaturedCrudGrid
autoComplete={
<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="Сервер"
size='small'
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}}
/>
)}
/>
}
autoComplete={<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="Сервер"
size='small'
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}} />
)} />}
onSave={(id: any) => {
console.log(id)
}}
@ -140,8 +136,7 @@ export default function ServerHardware() {
onRowClick={(params, event, details) => {
setCurrentServerData(params.row)
setServerDataOpen(true)
}}
/>
}} loading={false} />
}
</>
)

View File

@ -1,7 +1,7 @@
import { AppBar, Autocomplete, CircularProgress, Dialog, IconButton, TextField, Toolbar } from '@mui/material'
import React, { Fragment, useEffect, useState } from 'react'
import { Fragment, useEffect, useState } from 'react'
import { IRegion } from '../interfaces/fuel'
import { useRegions, useServerIps, useServers } from '../hooks/swrHooks'
import { useServerIps, useServers } from '../hooks/swrHooks'
import FullFeaturedCrudGrid from './TableEditable'
import ServerService from '../services/ServersService'
import { GridColDef } from '@mui/x-data-grid'
@ -93,41 +93,37 @@ export default function ServerIpsView() {
:
serverIps &&
<FullFeaturedCrudGrid
autoComplete={
<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}
size='small'
label="Сервер"
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}}
/>
)}
/>
}
autoComplete={<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}
size='small'
label="Сервер"
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}} />
)} />}
onSave={(id: any) => {
console.log(id)
}}
@ -138,8 +134,7 @@ export default function ServerIpsView() {
onRowClick={(params, event, details) => {
setCurrentServerData(params.row)
setServerDataOpen(true)
}}
/>
}} loading={false} />
}
</>
)

View File

@ -1,34 +1,26 @@
import { AppBar, Autocomplete, CircularProgress, Dialog, IconButton, TextField, Toolbar } from '@mui/material'
import React, { Fragment, useEffect, useState } from 'react'
import { Fragment, useEffect, useState } from 'react'
import { IRegion } from '../interfaces/fuel'
import { useHardwares, useRegions, useServerIps, useServers, useStorages } from '../hooks/swrHooks'
import { useHardwares, useStorages } from '../hooks/swrHooks'
import FullFeaturedCrudGrid from './TableEditable'
import ServerService from '../services/ServersService'
import { GridColDef } from '@mui/x-data-grid'
import { Close } from '@mui/icons-material'
import ServerData from './ServerData'
import { useDebounce } from '@uidotdev/usehooks'
export default function ServerStorage() {
const [open, setOpen] = useState(false)
const [options, setOptions] = useState<IRegion[]>([])
const [search, setSearch] = useState<string | null>("")
const [debouncedSearch, setDebouncedSearch] = useState<string | null>("")
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
const { hardwares, isLoading } = useHardwares()
const debouncedSearch = useDebounce(search, 500)
const [serverDataOpen, setServerDataOpen] = useState(false)
const [currentServerData, setCurrentServerData] = useState<any | null>(null)
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearch(search)
}, 500)
return () => {
clearTimeout(handler)
}
}, [search])
useEffect(() => {
if (hardwares) {
setOptions([...hardwares])
@ -92,41 +84,37 @@ export default function ServerStorage() {
:
storages &&
<FullFeaturedCrudGrid
autoComplete={
<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}
size='small'
label="Hardware"
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}}
/>
)}
/>
}
autoComplete={<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}
size='small'
label="Hardware"
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}} />
)} />}
onSave={(id: any) => {
console.log(id)
}}
@ -138,6 +126,7 @@ export default function ServerStorage() {
setCurrentServerData(params.row)
setServerDataOpen(true)
}}
loading={false}
/>
}
</>

View File

@ -1,5 +1,5 @@
import { AppBar, Autocomplete, Box, Chip, CircularProgress, Dialog, Divider, Grid, IconButton, Paper, TextField, Toolbar, Typography } from '@mui/material'
import React, { Fragment, useEffect, useState } from 'react'
import { AppBar, Autocomplete, Box, CircularProgress, Dialog, Grid, IconButton, TextField, Toolbar } from '@mui/material'
import { Fragment, useEffect, useState } from 'react'
import { IRegion } from '../interfaces/fuel'
import { useRegions, useServers, useServersInfo } from '../hooks/swrHooks'
import FullFeaturedCrudGrid from './TableEditable'
@ -11,47 +11,30 @@ import { IServersInfo } from '../interfaces/servers'
import CardInfo from './CardInfo/CardInfo'
import CardInfoLabel from './CardInfo/CardInfoLabel'
import CardInfoChip from './CardInfo/CardInfoChip'
import DataGridCellAutocomplete from './DataGridCellAutocomplete'
import { useDebounce } from '@uidotdev/usehooks'
export default function ServersView() {
const [open, setOpen] = useState(false)
const [editOpen, setEditOpen] = useState(false)
const [options, setOptions] = useState<IRegion[]>([])
const [search, setSearch] = useState<string | null>("")
const [debouncedSearch, setDebouncedSearch] = useState<string | null>("")
//const [debouncedSearch, setDebouncedSearch] = useState<string | null>("")
const debouncedSearch = useDebounce(search, 500)
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
const { regions, isLoading } = useRegions(10, 1, debouncedSearch)
const { serversInfo } = useServersInfo(selectedOption?.id)
const [serverDataOpen, setServerDataOpen] = useState(false)
const [currentServerData, setCurrentServerData] = useState<any | null>(null)
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 { servers, isLoading: serversLoading } = useServers(selectedOption?.id, 0, 10)
const serversColumns: GridColDef[] = [
@ -60,16 +43,40 @@ export default function ServersView() {
{
field: 'region_id',
editable: true,
renderCell: (params) => (
<div>
{params.value}
</div>
),
renderEditCell: (params: GridRenderCellParams) => (
<DataGridCellAutocomplete
selectedOption={params.value}
setSelectedOption={(value: any) => {
<Autocomplete
sx={{ display: 'flex', flexGrow: '1' }}
onInputChange={(_, value) => setSearch(value)}
onChange={(_, value) => {
params.value = value
}}
isLoading={isLoading}
setDebouncedSearch={setDebouncedSearch}
isOptionEqualToValue={(option: IRegion, value: IRegion) => option.name === value.name}
getOptionLabel={(option: IRegion) => option.name ? option.name : ""}
options={options}
setOptions={setOptions}
loading={isLoading}
value={params.value}
renderInput={(params) => (
<TextField
{...params}
size='small'
variant='standard'
label="Район"
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}}
/>
)}
/>
),
width: 200
@ -131,59 +138,47 @@ export default function ServersView() {
</Box>
}
{serversLoading ?
<CircularProgress />
:
servers &&
<FullFeaturedCrudGrid
autoComplete={
<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}
size='small'
label="Район"
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}}
/>
)}
/>
}
onSave={(id: any) => {
console.log(id)
}}
onDelete={ServerService.removeServer}
initialRows={servers}
columns={serversColumns}
actions
onRowClick={(params, event, details) => {
setCurrentServerData(params.row)
setServerDataOpen(true)
}}
/>
}
<FullFeaturedCrudGrid
loading={serversLoading}
autoComplete={
<Autocomplete
onInputChange={(_, value) => setSearch(value)}
onChange={(_, value) => setSelectedOption(value)}
isOptionEqualToValue={(option: IRegion, value: IRegion) => option.id === value.id}
getOptionLabel={(option: IRegion) => option.name ? option.name : ""}
options={options}
loading={isLoading}
value={selectedOption}
renderInput={(params) => (
<TextField
{...params}
size='small'
label="Район"
InputProps={{
...params.InputProps,
endAdornment: (
<Fragment>
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</Fragment>
)
}}
/>
)}
/>
}
onSave={(id: any) => {
console.log(id)
}}
onDelete={ServerService.removeServer}
initialRows={servers}
columns={serversColumns}
actions
onRowClick={(params, event, details) => {
setCurrentServerData(params.row)
setServerDataOpen(true)
}}
/>
</>
)
}

View File

@ -1,4 +1,4 @@
import * as React from 'react';
import { useEffect, useState } from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import AddIcon from '@mui/icons-material/Add';
@ -19,12 +19,8 @@ import {
GridRowModel,
GridRowEditStopReasons,
GridSlots,
GridRowProps,
GridRow,
useGridApiContext,
} from '@mui/x-data-grid';
import { AxiosResponse } from 'axios';
import { Autocomplete } from '@mui/material';
interface EditToolbarProps {
setRows: (newRows: (oldRows: GridRowsProp) => GridRowsProp) => void;
@ -90,6 +86,7 @@ interface DataGridProps {
onSave: any;
onDelete: (data: any) => Promise<AxiosResponse<any, any>>;
autoComplete?: React.ReactElement | null;
loading: boolean;
}
export default function FullFeaturedCrudGrid({
@ -99,10 +96,11 @@ export default function FullFeaturedCrudGrid({
onRowClick,
onSave,
onDelete,
autoComplete
autoComplete,
loading
}: DataGridProps) {
const [rows, setRows] = React.useState(initialRows);
const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>({});
const [rows, setRows] = useState(initialRows);
const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => {
if (params.reason === GridRowEditStopReasons.rowFocusOut) {
@ -147,6 +145,12 @@ export default function FullFeaturedCrudGrid({
setRowModesModel(newRowModesModel);
};
useEffect(() => {
if (initialRows) {
setRows(initialRows)
}
}, [initialRows])
const actionColumns: GridColDef[] = [
{
field: 'actions',
@ -210,7 +214,8 @@ export default function FullFeaturedCrudGrid({
}}
>
<DataGrid
rows={rows}
loading={loading}
rows={rows || []}
columns={actions ? [...columns, ...actionColumns] : columns}
editMode="row"
rowModesModel={rowModesModel}

View File

@ -184,12 +184,12 @@ export function useBoilers(limit?: number, page?: number, search?: string) {
// Servers
export function useServers(region_id?: number, offset?: number, limit?: number) {
export function useServers(region_id?: number | null, offset?: number, limit?: number) {
const { data, error, isLoading } = useSWR(
region_id ? `/api/servers?region_id=${region_id}&offset=${offset || 0}&limit=${limit || 10}` : `/api/servers?offset=${offset || 0}&limit=${limit || 10}`,
(url: string) => fetcher(url, BASE_URL.servers),
{
revalidateOnFocus: false
revalidateOnFocus: false,
}
)

View File

@ -11,7 +11,6 @@ import Divider from '@mui/material/Divider';
import IconButton from '@mui/material/IconButton';
import Container from '@mui/material/Container';
import MenuIcon from '@mui/icons-material/Menu';
import { Api, Assignment, Cloud, Dashboard, Factory, Home, People, Shield, Storage, } from '@mui/icons-material';
import { colors, ListItem, ListItemButton, ListItemIcon, ListItemText, } from '@mui/material';
import { Outlet, useNavigate } from 'react-router-dom';
import { UserData } from '../interfaces/auth';

View File

@ -9,7 +9,7 @@ import { createTheme } from '@mui/material'
import { ruRU } from '@mui/material/locale'
import { getDarkMode, usePrefStore } from "./store/preferences.ts";
const darkTheme = createTheme(
const mainTheme = createTheme(
{
typography: {
fontFamily: [
@ -28,6 +28,11 @@ const darkTheme = createTheme(
}
}
},
}
)
const darkTheme = createTheme(
{
palette: {
mode: "dark",
primary: { main: '#1976d2' },
@ -38,23 +43,6 @@ const darkTheme = createTheme(
const lightTheme = createTheme(
{
typography: {
fontFamily: [
'Inter'
].join(',')
},
components: {
MuiButtonBase: {
defaultProps: {
//disableRipple: true,
}
},
MuiButtonGroup: {
defaultProps: {
//disableRipple: true,
}
}
},
palette: {
mode: "light",
primary: { main: '#1976d2' },
@ -82,7 +70,7 @@ function ThemedApp() {
}, [])
return (
<ThemeProvider theme={prefStore.darkMode ? darkTheme : lightTheme}>
<ThemeProvider theme={prefStore.darkMode ? { ...mainTheme, ...darkTheme } : { ...mainTheme, ...lightTheme }}>
<App />
</ThemeProvider>
)

View File

@ -1,6 +1,6 @@
import { Box, Typography } from '@mui/material'
import { DataGrid, GridColDef } from '@mui/x-data-grid'
import React, { useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import { IBoiler } from '../interfaces/fuel'
import { useBoilers } from '../hooks/swrHooks'

View File

@ -9,6 +9,7 @@ export default function Servers() {
const [currentTab, setCurrentTab] = useState(0)
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
console.log(event)
setCurrentTab(newValue);
}

View File

@ -10,7 +10,7 @@ const config: AxiosRequestConfig = {
}
export default class AuthService {
static async login(data: FormData) {
static async login(data: URLSearchParams) {
return await axiosInstance.post(`/auth/login`, data, config)
}