forked from VinokurovVE/tests
Servers API
This commit is contained in:
6
frontend_reactjs/package-lock.json
generated
6
frontend_reactjs/package-lock.json
generated
@ -11,6 +11,7 @@
|
||||
"-": "^0.0.1",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@fontsource/open-sans": "^5.0.28",
|
||||
"@js-preview/docx": "^1.6.2",
|
||||
"@js-preview/excel": "^1.7.8",
|
||||
"@js-preview/pdf": "^2.0.2",
|
||||
@ -2494,6 +2495,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
|
||||
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
|
||||
},
|
||||
"node_modules/@fontsource/open-sans": {
|
||||
"version": "5.0.28",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz",
|
||||
"integrity": "sha512-hBvJHY76pJT/JynGUB5EXWhnzjYfLdcMn655J5p1v9lTT9HdQSy+keq2KPVXO2Htlg998BBa3p6u/jlrZ6w0kg=="
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
|
@ -13,6 +13,7 @@
|
||||
"-": "^0.0.1",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@fontsource/open-sans": "^5.0.28",
|
||||
"@js-preview/docx": "^1.6.2",
|
||||
"@js-preview/excel": "^1.7.8",
|
||||
"@js-preview/pdf": "^2.0.2",
|
||||
|
@ -1,21 +0,0 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
interface ICard{
|
||||
firstname: string
|
||||
lastname: string
|
||||
email: string
|
||||
}
|
||||
|
||||
function Card(props:ICard) {
|
||||
const [curr_card, setCard] = useState<ICard>({firstname:"Иван",lastname:"Петров", email:"email@test.ru"});
|
||||
useEffect(()=>{setCard(props);},[curr_card])
|
||||
return (
|
||||
<div className='block p-6 max-w-sm bg-gray-300
|
||||
rounded-lg border border-gray-500 align-items: center;'>
|
||||
<div className='text-4xl text-center'>{curr_card.lastname} {curr_card.firstname}</div>
|
||||
<div className='text-sm text-center'>{curr_card.email}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Card
|
@ -1,35 +0,0 @@
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
|
||||
interface Props {
|
||||
rows: any,
|
||||
columns: any,
|
||||
checkboxSelection?: boolean
|
||||
}
|
||||
|
||||
export default function DataTable(props: Props) {
|
||||
return (
|
||||
<DataGrid
|
||||
autoHeight
|
||||
style={{ width: "100%" }}
|
||||
rows={props.rows}
|
||||
columns={props.columns}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { page: 0, pageSize: 10 },
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[10, 20, 50, 100]}
|
||||
checkboxSelection={props.checkboxSelection}
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
onProcessRowUpdateError={(error)=>{
|
||||
console.log(error)
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { useDocuments, useFolders } from '../hooks/swrHooks'
|
||||
import { useDocuments, useDownload, useFolders } from '../hooks/swrHooks'
|
||||
import { IDocument, IDocumentFolder } from '../interfaces/documents'
|
||||
import { Box, Breadcrumbs, Button, Card, CardActionArea, CircularProgress, Divider, IconButton, Input, InputLabel, LinearProgress, Link, List, ListItem, ListItemButton, SxProps } from '@mui/material'
|
||||
import { Cancel, Close, Download, Folder, InsertDriveFile, Upload, UploadFile } from '@mui/icons-material'
|
||||
@ -45,7 +45,29 @@ function ItemFolder({ folder, index, handleFolderClick, ...props }: FolderProps)
|
||||
)
|
||||
}
|
||||
|
||||
const handleSave = async (file: Blob, filename: string) => {
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(file)
|
||||
link.download = filename
|
||||
link.click()
|
||||
link.remove()
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}
|
||||
|
||||
function ItemDocument({ doc, index, handleDocumentClick, ...props }: DocumentProps) {
|
||||
const [shouldFetch, setShouldFetch] = useState(false)
|
||||
|
||||
const { file, isLoading } = useDownload(shouldFetch ? doc?.document_folder_id : null, shouldFetch ? doc?.id : null)
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldFetch) {
|
||||
if (file) {
|
||||
handleSave(file, doc.name)
|
||||
setShouldFetch(false)
|
||||
}
|
||||
}
|
||||
}, [shouldFetch, file])
|
||||
|
||||
return (
|
||||
<ListItemButton>
|
||||
<Box
|
||||
@ -59,11 +81,17 @@ function ItemDocument({ doc, index, handleDocumentClick, ...props }: DocumentPro
|
||||
<Box>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
console.log("TODO: save")
|
||||
if (!isLoading) {
|
||||
setShouldFetch(true)
|
||||
}
|
||||
}}
|
||||
sx={{ ml: 'auto' }}
|
||||
>
|
||||
{isLoading ?
|
||||
<CircularProgress size={24} variant='indeterminate' />
|
||||
:
|
||||
<Download />
|
||||
}
|
||||
</IconButton>
|
||||
</Box>
|
||||
</ListItemButton>
|
||||
|
@ -1,57 +0,0 @@
|
||||
export interface Props {
|
||||
showModal: boolean;
|
||||
}
|
||||
|
||||
export default function Modal(props:Props){
|
||||
return(<>
|
||||
{props.showModal &&
|
||||
<div id="crud-modal" tabIndex={-1} className="bg-black opacity-75 overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full" onClick={()=> console.log("click")}>
|
||||
<div className="relative p-4 w-full max-w-md max-h-full" >
|
||||
<div className="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||
<div className="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
Create New Product
|
||||
</h3>
|
||||
<button type="button" className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-toggle="crud-modal">
|
||||
<svg className="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
||||
</svg>
|
||||
<span className="sr-only">Close modal</span>
|
||||
</button>
|
||||
</div>
|
||||
<form className="p-4 md:p-5">
|
||||
<div className="grid gap-4 mb-4 grid-cols-2">
|
||||
<div className="col-span-2">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Name</label>
|
||||
<input type="text" name="name" id="name" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="Type product name" />
|
||||
</div>
|
||||
<div className="col-span-2 sm:col-span-1">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Price</label>
|
||||
<input type="number" name="price" id="price" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="$2999" />
|
||||
</div>
|
||||
<div className="col-span-2 sm:col-span-1">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Category</label>
|
||||
<select id="category" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500">
|
||||
<option >Select category</option>
|
||||
<option value="TV">TV/Monitors</option>
|
||||
<option value="PC">PC</option>
|
||||
<option value="GA">Gaming/Console</option>
|
||||
<option value="PH">Phones</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Product Description</label>
|
||||
<textarea id="description" rows={4} className="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Write product description here"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" className="text-white inline-flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
|
||||
<svg className="me-1 -ms-1 w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clipRule="evenodd"></path></svg>
|
||||
Add new product
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> }
|
||||
|
||||
</>)
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
interface IRoleCard{
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
|
||||
function RoleCard(props:IRoleCard) {
|
||||
const [curr_card, setCard] = useState<IRoleCard>({id: 1, name: "Тест"});
|
||||
useEffect(()=>{setCard(props);},[curr_card])
|
||||
return (
|
||||
<div className='block p-6 max-w-sm bg-gray-300
|
||||
rounded-lg border border-gray-500 align-items: center;'>
|
||||
<div className='text-4xl text-center'>{curr_card.name}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RoleCard
|
@ -68,7 +68,7 @@ function DocxViewer({
|
||||
jsPreviewDocx.init(previewContainerRef.current, {
|
||||
breakPages: true,
|
||||
inWrapper: true,
|
||||
ignoreHeight: true
|
||||
ignoreHeight: true,
|
||||
})
|
||||
.preview(url)
|
||||
}
|
||||
|
@ -2,3 +2,10 @@ export const USER_DATA_KEY = 'userData';
|
||||
export const TOKEN_AUTH_KEY = 'authToken'
|
||||
export const TOKEN_ISSUED_DATE_KEY = 'tokenIssuedDate';
|
||||
export const TOKEN_EXPIRY_DURATION = 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
export const BASE_URL = {
|
||||
auth: import.meta.env.VITE_API_AUTH_URL,
|
||||
info: import.meta.env.VITE_API_INFO_URL,
|
||||
fuel: import.meta.env.VITE_API_FUEL_URL,
|
||||
servers: import.meta.env.VITE_API_SERVERS_URL
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
import useSWR from "swr";
|
||||
import RoleService from "../services/RoleService";
|
||||
import UserService from "../services/UserService";
|
||||
import { blobFetcher, fetcher } from "../http/axiosInstance";
|
||||
import { fetcher } from "../http/axiosInstance";
|
||||
import { fileTypeFromBlob } from "file-type/core";
|
||||
import { BASE_URL } from "../constants";
|
||||
|
||||
export function useRoles() {
|
||||
const { data, error, isLoading } = useSWR(`/auth/roles`, RoleService.getRoles)
|
||||
@ -66,10 +67,10 @@ export function useDocuments(folder_id?: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export function useDownload(folder_id?: number, id?: number) {
|
||||
export function useDownload(folder_id?: number | null, id?: number | null) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
folder_id && id ? `/info/document/${folder_id}&${id}` : null,
|
||||
folder_id && id ? blobFetcher : null,
|
||||
folder_id && id ? (url) => fetcher(url, BASE_URL.info, "blob") : null,
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
@ -98,7 +99,7 @@ export function useFileType(fileName?: string, file?: Blob) {
|
||||
}
|
||||
}
|
||||
|
||||
export function useReport(city_id: number) {
|
||||
export function useReport(city_id?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
city_id ? `/info/reports/${city_id}?to_export=false` : null,
|
||||
fetcher,
|
||||
@ -113,3 +114,173 @@ export function useReport(city_id: number) {
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// API general
|
||||
|
||||
export function useAddress(limit?: number, page?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
`/general/address?limit=${limit || 10}&page=${page || 1}`,
|
||||
(url) => fetcher(url, import.meta.env.VITE_API_FUEL_URL),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
address: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
export function useBoilers(limit?: number, page?: number, search?: string) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
`/general/boilers?limit=${limit || 10}&page=${page || 1}&search=${search || ""}`,
|
||||
(url) => fetcher(url, BASE_URL.fuel),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
boilers: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
// Servers
|
||||
|
||||
export function useServers(region_id?: number, offset?: number, limit?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
region_id ? `/api/servers?region_id=${region_id}&offset=${offset || 0}&limit=${limit || 10}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
servers: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
export function useServersInfo(region_id?: number, offset?: number, limit?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
region_id ? `/api/servers_info?region_id=${region_id}&offset=${offset || 0}&limit=${limit || 10}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
serversInfo: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
export function useServer(server_id?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
server_id ? `/api/server/${server_id}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
server: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
export function useServerIps(server_id?: number, offset?: number, limit?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
server_id ? `/api/servers?server_id=${server_id}&offset=${offset || 0}&limit=${limit || 10}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
serverIps: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
// Hardware
|
||||
|
||||
export function useHardwares(server_id?: number, offset?: number, limit?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
server_id ? `/api/hardwares?server_id=${server_id}&offset=${offset || 0}&limit=${limit || 10}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
hardwares: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function useHardware(hardware_id?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
hardware_id ? `/api/hardware/${hardware_id}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
hardware: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
// Storage
|
||||
|
||||
export function useStorages(hardware_id?: number, offset?: number, limit?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
hardware_id ? `/api/storages?hardware_id=${hardware_id}&offset=${offset || 0}&limit=${limit || 10}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
storages: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
||||
|
||||
export function useStorage(storage_id?: number) {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
storage_id ? `/api/storage/${storage_id}` : null,
|
||||
(url) => fetcher(url, BASE_URL.servers),
|
||||
{
|
||||
revalidateOnFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
storage: data,
|
||||
isLoading,
|
||||
isError: error
|
||||
}
|
||||
}
|
@ -1,27 +1,10 @@
|
||||
import axios from 'axios';
|
||||
import axios, { ResponseType } from 'axios';
|
||||
import { useAuthStore } from '../store/auth';
|
||||
|
||||
export const axiosInstanceAuth = axios.create({
|
||||
baseURL: `${import.meta.env.VITE_API_AUTH_URL}`,
|
||||
});
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: `${import.meta.env.VITE_API_CORE_URL}`,
|
||||
baseURL: import.meta.env.VITE_API_INFO_URL,
|
||||
});
|
||||
|
||||
axiosInstanceAuth.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = useAuthStore.getState().token;
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
axiosInstance.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = useAuthStore.getState().token;
|
||||
@ -35,13 +18,12 @@ axiosInstance.interceptors.request.use(
|
||||
}
|
||||
);
|
||||
|
||||
export const fetcher = (url: string) => axiosInstance.get(url, {
|
||||
export const fetcher = (url: string, baseURL?: string, responseType?: ResponseType) => axiosInstance.get(url, {
|
||||
baseURL: baseURL || import.meta.env.VITE_API_INFO_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}).then(res => res.data)
|
||||
export const blobFetcher = (url: string) => axiosInstance.get(url, {
|
||||
responseType: "blob"
|
||||
},
|
||||
responseType: responseType ? responseType : "json"
|
||||
}).then(res => res.data)
|
||||
|
||||
export default axiosInstance;
|
27
frontend_reactjs/src/interfaces/servers.ts
Normal file
27
frontend_reactjs/src/interfaces/servers.ts
Normal file
@ -0,0 +1,27 @@
|
||||
export interface IServer {
|
||||
id: number;
|
||||
name: string;
|
||||
region_id: number;
|
||||
}
|
||||
|
||||
export interface IServerIP {
|
||||
name: string;
|
||||
is_actual: boolean;
|
||||
ip: string;
|
||||
server_id: number;
|
||||
}
|
||||
|
||||
export interface IHardware {
|
||||
name: string;
|
||||
os_info: string;
|
||||
ram: string;
|
||||
processor: string;
|
||||
server_id: number;
|
||||
}
|
||||
|
||||
export interface IStorage {
|
||||
name: string;
|
||||
size: string;
|
||||
storage_type: string;
|
||||
hardware_id: number;
|
||||
}
|
@ -65,7 +65,7 @@ const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open'
|
||||
}),
|
||||
width: theme.spacing(7),
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: theme.spacing(9),
|
||||
//width: theme.spacing(9),
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
@ -1,3 +1,4 @@
|
||||
import "@fontsource/open-sans";
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
@ -9,6 +10,23 @@ import { ruRU } from '@mui/material/locale'
|
||||
|
||||
const theme = createTheme(
|
||||
{
|
||||
typography: {
|
||||
fontFamily: [
|
||||
'Open Sans'
|
||||
].join(',')
|
||||
},
|
||||
components: {
|
||||
MuiButtonBase: {
|
||||
defaultProps: {
|
||||
//disableRipple: true,
|
||||
}
|
||||
},
|
||||
MuiButtonGroup: {
|
||||
defaultProps: {
|
||||
//disableRipple: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
palette: {
|
||||
primary: { main: '#1976d2' },
|
||||
},
|
||||
|
@ -1,101 +1,20 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { Button, Typography } from "@mui/material"
|
||||
import axiosInstance from "../http/axiosInstance"
|
||||
import DataTable from "../components/DataTable"
|
||||
import { GridColDef } from "@mui/x-data-grid"
|
||||
import { useServers } from "../hooks/swrHooks"
|
||||
|
||||
export default function ApiTest() {
|
||||
const [state, setState] = useState<any>(null)
|
||||
const [exportData, setExportData] = useState<any>(null)
|
||||
|
||||
const fetch = async () => {
|
||||
await axiosInstance.get(`/info/reports/0?to_export=true`, {
|
||||
responseType: 'blob'
|
||||
}).then(response => {
|
||||
setExportData(response.data)
|
||||
console.log(response.data)
|
||||
|
||||
const url = window.URL.createObjectURL(response.data)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute('download', 'report.xlsx')
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
})
|
||||
}
|
||||
|
||||
const fetchBlob = async () => {
|
||||
// await axiosInstance.get(`/info/document/1&2`, {
|
||||
// responseType: 'blob'
|
||||
// }).then(response => {
|
||||
// setState(response)
|
||||
// })
|
||||
|
||||
await axiosInstance.get(`/info/reports/0`).then(response => {
|
||||
setState(JSON.parse(response.data))
|
||||
})
|
||||
}
|
||||
|
||||
const columns: GridColDef[] =
|
||||
[
|
||||
{ field: 'id', headerName: "№", type: "number", width: 90 },
|
||||
{ field: 'region', headerName: 'Регион', type: "string", width: 90, },
|
||||
{ field: 'city', headerName: 'Город', type: "string", width: 130 },
|
||||
{ field: 'name_type', headerName: 'Вид объекта', type: "string", width: 90, },
|
||||
{ field: 'name', headerName: 'Наименование', type: "string", width: 90, },
|
||||
// { field: 'code', headerName: 'Код', type: "string", width: 130 },
|
||||
// { field: 'code_city', headerName: '', type: "string", width: 90, },
|
||||
// { field: 'code_fuel', headerName: '', type: "string", width: 90, },
|
||||
// { field: 'code_master', headerName: '', type: "string", width: 90, },
|
||||
// { field: 'code_region', headerName: '', type: "string", width: 90, },
|
||||
// { field: 'code_type', headerName: '', type: "string", width: 90, },
|
||||
{ field: 'num', headerName: 'Инвентарный код', type: "string", width: 90, },
|
||||
{ field: 'fuel_type', headerName: 'Тип топлива', type: "string", width: 90, },
|
||||
{ field: 'fuel', headerName: 'Топливо', type: "string", width: 90, },
|
||||
{ field: 'zone', headerName: 'Мертвая зона', type: "string", width: 90, },
|
||||
{ field: 'active', headerName: 'Активность', type: "boolean", width: 70 },
|
||||
// { field: 'full_name', headerName: 'Полное наименование', type: "string", width: 90, },
|
||||
];
|
||||
const { servers } = useServers(32, 0, 10)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
<Button onClick={() => {
|
||||
fetchBlob()
|
||||
}}>
|
||||
Получить таблицу
|
||||
</Button>
|
||||
|
||||
<Button onClick={() => {
|
||||
fetch()
|
||||
}}>
|
||||
Экспорт
|
||||
{servers && JSON.stringify(servers)}
|
||||
</Button>
|
||||
|
||||
{state &&
|
||||
<DataTable
|
||||
checkboxSelection={false}
|
||||
columns={
|
||||
[
|
||||
{ field: 'id', headerName: '№', width: 70 },
|
||||
...Object.keys(state).map(key => ({
|
||||
field: key,
|
||||
headerName: key.charAt(0).toUpperCase() + key.slice(1),
|
||||
width: 150
|
||||
}))
|
||||
]
|
||||
}
|
||||
rows={
|
||||
[...new Set(Object.keys(state).flatMap(key => Object.keys(state[key])))].map(id => {
|
||||
const row: any = { id: Number(id) };
|
||||
Object.keys(state).forEach(key => {
|
||||
row[key] = state[key][id];
|
||||
});
|
||||
return row;
|
||||
})
|
||||
} />
|
||||
}
|
||||
</Typography>
|
||||
</>
|
||||
)
|
||||
|
@ -1,7 +1,15 @@
|
||||
import { Box, Card, Typography } from "@mui/material";
|
||||
|
||||
export default function Main() {
|
||||
return (
|
||||
<>
|
||||
Главная
|
||||
</>
|
||||
<Box>
|
||||
<Typography variant='h6' fontWeight='700'>
|
||||
Последние файлы
|
||||
</Typography>
|
||||
|
||||
<Card>
|
||||
|
||||
</Card>
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { Box, Button, Typography } from "@mui/material"
|
||||
import axiosInstance from "../http/axiosInstance"
|
||||
import DataTable from "../components/DataTable"
|
||||
import { DataGrid } from "@mui/x-data-grid"
|
||||
|
||||
export default function Reports() {
|
||||
const [state, setState] = useState<any>(null)
|
||||
@ -43,27 +43,42 @@ export default function Reports() {
|
||||
</Box>
|
||||
|
||||
{state &&
|
||||
<DataTable
|
||||
checkboxSelection={false}
|
||||
columns={
|
||||
[
|
||||
<DataGrid
|
||||
autoHeight
|
||||
style={{ width: "100%" }}
|
||||
rows={[...new Set(Object.keys(state).flatMap(key => Object.keys(state[key])))].map(id => {
|
||||
const row: any = { id: Number(id) };
|
||||
Object.keys(state).forEach(key => {
|
||||
row[key] = state[key][id];
|
||||
});
|
||||
return row;
|
||||
})}
|
||||
columns={[
|
||||
{ field: 'id', headerName: '№', width: 70 },
|
||||
...Object.keys(state).map(key => ({
|
||||
field: key,
|
||||
headerName: key.charAt(0).toUpperCase() + key.slice(1),
|
||||
width: 150
|
||||
}))
|
||||
]
|
||||
}
|
||||
rows={
|
||||
[...new Set(Object.keys(state).flatMap(key => Object.keys(state[key])))].map(id => {
|
||||
const row: any = { id: Number(id) };
|
||||
Object.keys(state).forEach(key => {
|
||||
row[key] = state[key][id];
|
||||
});
|
||||
return row;
|
||||
})
|
||||
} />
|
||||
]}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { page: 0, pageSize: 10 },
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[10, 20, 50, 100]}
|
||||
checkboxSelection={false}
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
onProcessRowUpdateError={(error) => {
|
||||
console.log(error)
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</Box>
|
||||
</>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { Box, Button, CircularProgress } from '@mui/material'
|
||||
import DataTable from '../components/DataTable'
|
||||
import { GridColDef } from '@mui/x-data-grid'
|
||||
import { DataGrid, GridColDef } from '@mui/x-data-grid'
|
||||
import { useRoles } from '../hooks/swrHooks'
|
||||
import CreateRoleModal from '../components/modals/CreateRoleModal'
|
||||
|
||||
@ -36,7 +35,28 @@ export default function Roles() {
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
|
||||
<DataTable rows={roles} columns={columns} />
|
||||
<DataGrid
|
||||
autoHeight
|
||||
style={{ width: "100%" }}
|
||||
rows={roles}
|
||||
columns={columns}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { page: 0, pageSize: 10 },
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[10, 20, 50, 100]}
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
onProcessRowUpdateError={(error) => {
|
||||
console.log(error)
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import { Box, Button, CircularProgress } from "@mui/material"
|
||||
import DataTable from "../components/DataTable"
|
||||
import { GridColDef } from "@mui/x-data-grid"
|
||||
import { DataGrid, GridColDef } from "@mui/x-data-grid"
|
||||
import { useRoles, useUsers } from "../hooks/swrHooks"
|
||||
import { IRole } from "../interfaces/role"
|
||||
import { useState } from "react"
|
||||
@ -56,7 +55,29 @@ export default function Settings() {
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
|
||||
<DataTable rows={users} columns={columns} />
|
||||
<DataGrid
|
||||
autoHeight
|
||||
style={{ width: "100%" }}
|
||||
rows={users}
|
||||
columns={columns}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { page: 0, pageSize: 10 },
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[10, 20, 50, 100]}
|
||||
checkboxSelection
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
onProcessRowUpdateError={(error) => {
|
||||
console.log(error)
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import { Box, Button, CircularProgress } from "@mui/material"
|
||||
import DataTable from "../components/DataTable"
|
||||
import { GridColDef } from "@mui/x-data-grid"
|
||||
import { DataGrid, GridColDef } from "@mui/x-data-grid"
|
||||
import { useRoles, useUsers } from "../hooks/swrHooks"
|
||||
import { IRole } from "../interfaces/role"
|
||||
import { useState } from "react"
|
||||
@ -51,7 +50,29 @@ export default function Users() {
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
|
||||
<DataTable rows={users} columns={columns} />
|
||||
<DataGrid
|
||||
autoHeight
|
||||
style={{ width: "100%" }}
|
||||
rows={users}
|
||||
columns={columns}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { page: 0, pageSize: 10 },
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[10, 20, 50, 100]}
|
||||
checkboxSelection
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
onProcessRowUpdateError={(error) => {
|
||||
console.log(error)
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -1,19 +1,24 @@
|
||||
import axiosInstance, { axiosInstanceAuth } from "../http/axiosInstance";
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
import { BASE_URL } from "../constants";
|
||||
import axiosInstance from "../http/axiosInstance";
|
||||
|
||||
export default class AuthService {
|
||||
static async login(data: any) {
|
||||
return await axiosInstanceAuth.post(`/auth/login`, data, {
|
||||
const config: AxiosRequestConfig = {
|
||||
baseURL: BASE_URL.auth,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default class AuthService {
|
||||
static async login(data: any) {
|
||||
return await axiosInstance.post(`/auth/login`, data, config)
|
||||
}
|
||||
|
||||
static async refreshToken(token: string) {
|
||||
return await axiosInstanceAuth.post(`/auth/refresh_token/${token}`)
|
||||
return await axiosInstance.post(`/auth/refresh_token/${token}`, null, config)
|
||||
}
|
||||
|
||||
static async getCurrentUser(token: string) {
|
||||
return await axiosInstanceAuth.get(`/auth/get_current_user/${token}`)
|
||||
return await axiosInstance.get(`/auth/get_current_user/${token}`, config)
|
||||
}
|
||||
}
|
13
frontend_reactjs/src/services/FuelService.ts
Normal file
13
frontend_reactjs/src/services/FuelService.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
import axiosInstance from "../http/axiosInstance";
|
||||
import { BASE_URL } from "../constants";
|
||||
|
||||
const config: AxiosRequestConfig = {
|
||||
baseURL: BASE_URL.fuel
|
||||
}
|
||||
|
||||
export default class FuelService {
|
||||
static async getAddress(limit?: number, page?: number) {
|
||||
return await axiosInstance.get(`/general/address?limit=${limit || 10}&page=${page || 1}`, config)
|
||||
}
|
||||
}
|
@ -1,18 +1,24 @@
|
||||
import axiosInstance, { axiosInstanceAuth } from "../http/axiosInstance";
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
import axiosInstance from "../http/axiosInstance";
|
||||
import { IRoleCreate } from "../interfaces/role";
|
||||
import { BASE_URL } from "../constants";
|
||||
|
||||
const config: AxiosRequestConfig = {
|
||||
baseURL: BASE_URL.auth
|
||||
}
|
||||
|
||||
export default class RoleService {
|
||||
static async getRoles() {
|
||||
return await axiosInstanceAuth.get(`/auth/roles`)
|
||||
return await axiosInstance.get(`/auth/roles`, config)
|
||||
}
|
||||
|
||||
static async createRole(data: IRoleCreate) {
|
||||
return await axiosInstanceAuth.post(`/auth/roles/`, data)
|
||||
return await axiosInstance.post(`/auth/roles/`, data, config)
|
||||
}
|
||||
|
||||
|
||||
static async getRoleById(id: number) {
|
||||
return await axiosInstanceAuth.get(`/auth/roles/${id}`)
|
||||
return await axiosInstance.get(`/auth/roles/${id}`, config)
|
||||
}
|
||||
|
||||
// static async deleteRole(id: number) {
|
||||
|
42
frontend_reactjs/src/services/ServersService.ts
Normal file
42
frontend_reactjs/src/services/ServersService.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import axios, { AxiosRequestConfig } from "axios";
|
||||
import axiosInstance from "../http/axiosInstance";
|
||||
import { IHardware, IServer, IServerIP, IStorage } from "../interfaces/servers";
|
||||
import { BASE_URL } from "../constants";
|
||||
|
||||
const config: AxiosRequestConfig = {
|
||||
baseURL: BASE_URL.servers
|
||||
}
|
||||
|
||||
export default class ServerService {
|
||||
static async removeServer(server_id: number) {
|
||||
return await axiosInstance.delete(`/api/server/${server_id}`, config)
|
||||
}
|
||||
|
||||
static async addServer(data: IServer) {
|
||||
return await axiosInstance.post(`/api/server/`, data, config)
|
||||
}
|
||||
|
||||
static async removeHardware(hardware_id: number) {
|
||||
return await axiosInstance.delete(`/api/hardware/${hardware_id}`, config)
|
||||
}
|
||||
|
||||
static async addHardware(data: IHardware) {
|
||||
return await axiosInstance.post(`/api/hardware`, data, config)
|
||||
}
|
||||
|
||||
static async removeStorage(storage_id: number) {
|
||||
return await axiosInstance.delete(`/api/storage/${storage_id}`, config)
|
||||
}
|
||||
|
||||
static async addStorage(data: IStorage) {
|
||||
return await axiosInstance.post(`/api/storage`, data, config)
|
||||
}
|
||||
|
||||
static async addServerIp(data: IServerIP) {
|
||||
return await axiosInstance.post(`/api/server_ip`, data, config)
|
||||
}
|
||||
|
||||
static async removeServerIp(ip_id: number) {
|
||||
return await axiosInstance.delete(`/api/server_ip/${ip_id}`, config)
|
||||
}
|
||||
}
|
@ -1,17 +1,23 @@
|
||||
import axiosInstance, { axiosInstanceAuth } from "../http/axiosInstance";
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
import axiosInstance from "../http/axiosInstance";
|
||||
import { UserCreds, UserData } from "../interfaces/auth";
|
||||
import { BASE_URL } from "../constants";
|
||||
|
||||
const config: AxiosRequestConfig = {
|
||||
baseURL: BASE_URL.auth
|
||||
}
|
||||
|
||||
export default class UserService {
|
||||
static async createUser(data: any) {
|
||||
return await axiosInstanceAuth.post(`/auth/user`, data)
|
||||
return await axiosInstance.post(`/auth/user`, data, config)
|
||||
}
|
||||
|
||||
static async getCurrentUser(token: string) {
|
||||
return await axiosInstanceAuth.get(`/auth/get_current_user/${token}`)
|
||||
return await axiosInstance.get(`/auth/get_current_user/${token}`, config)
|
||||
}
|
||||
|
||||
static async getUsers() {
|
||||
return await axiosInstanceAuth.get(`/auth/user`)
|
||||
return await axiosInstance.get(`/auth/user`, config)
|
||||
}
|
||||
|
||||
// static async deleteUser(id: number) {
|
||||
@ -19,14 +25,14 @@ export default class UserService {
|
||||
// }
|
||||
|
||||
static async getUser(id: number) {
|
||||
return await axiosInstanceAuth.get(`/auth/user/${id}`)
|
||||
return await axiosInstance.get(`/auth/user/${id}`, config)
|
||||
}
|
||||
|
||||
static async updatePassword(data: UserCreds) {
|
||||
return await axiosInstanceAuth.put(`/auth/user/password_change`, data)
|
||||
return await axiosInstance.put(`/auth/user/password_change`, data, config)
|
||||
}
|
||||
|
||||
static async updateUser(data: UserData) {
|
||||
return await axiosInstanceAuth.put(`/auth/user`, data)
|
||||
return await axiosInstance.put(`/auth/user`, data, config)
|
||||
}
|
||||
}
|
@ -1148,6 +1148,11 @@
|
||||
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz"
|
||||
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
||||
|
||||
"@fontsource/open-sans@^5.0.28":
|
||||
version "5.0.28"
|
||||
resolved "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz"
|
||||
integrity sha512-hBvJHY76pJT/JynGUB5EXWhnzjYfLdcMn655J5p1v9lTT9HdQSy+keq2KPVXO2Htlg998BBa3p6u/jlrZ6w0kg==
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.14":
|
||||
version "0.11.14"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz"
|
||||
|
Reference in New Issue
Block a user