diff --git a/client/src/App.tsx b/client/src/App.tsx index 53751ec..a62572e 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -4,12 +4,12 @@ import { BrowserRouter, Route, Routes } from 'react-router-dom'; import AlertComponent from './components/Alert'; import Footer from './components/Footer'; import Header from './components/Header'; -import ServerDetails from './components/ServerDetails'; import SearchState from './data/SearchState'; import ServerData from './data/ServerData'; import About from './pages/About'; import Home from './pages/Home'; import NotFound from './pages/NotFound'; +import ServerDetails from './pages/ServerDetails'; export function App() { const [alertInfo, setAlertInfo] = useState<{ diff --git a/client/src/components/ServerCard.tsx b/client/src/components/ServerCard.tsx index a671f1b..d418bb5 100644 --- a/client/src/components/ServerCard.tsx +++ b/client/src/components/ServerCard.tsx @@ -277,9 +277,11 @@ export default function ServerCard({ server }: { server: ServerData }) { - - - {server.active_sessions} active sessions + + + + {server.active_sessions} active sessions + {server.login_limit !== 1 && ( event.preventDefault()} /> )} - - + + + {/* */} - Updated: {new Date(server.updated).toLocaleString()} - + + Updated: {new Date(server.updated).toLocaleString()} + + ); diff --git a/client/src/components/ServerDetailsModal.tsx b/client/src/components/ServerDetailsModal.tsx new file mode 100644 index 0000000..144b38f --- /dev/null +++ b/client/src/components/ServerDetailsModal.tsx @@ -0,0 +1,79 @@ +import { Info } from '@mui/icons-material'; +import { Card, IconButton, Tooltip, Typography } from '@mui/material'; +import Modal from '@mui/material/Modal'; +import { useState } from 'react'; +import { fetchData } from '../apiUtil'; +import ServerData from '../data/ServerData'; +import ServerSettingsDataGrid from './ServerSettingsDataGrid'; + +export default function ServerDetailsModal({ id }: { id: number }) { + const [server, setServer] = useState(); + const [error, setError] = useState(''); + + const [open, setOpen] = useState(false); + const handleOpen = () => { + let data: ServerData; + const fetchServerData = async () => { + try { + data = await fetchData(`server/${id}`); + } catch (err) { + if (err instanceof Error) { + setError(err.message); + } else { + setError('An unknown error occurred.'); + } + } + setServer(data); + }; + fetchServerData(); + setOpen(true); + }; + const handleClose = () => setOpen(false); + + return ( +
+ + + + + + + + + {!server || !server.settings ? ( + + {error} + + ) : ( + + )} + + + +
+ ); +} diff --git a/client/src/components/ServerSettingsDataGrid.tsx b/client/src/components/ServerSettingsDataGrid.tsx new file mode 100644 index 0000000..8e1a630 --- /dev/null +++ b/client/src/components/ServerSettingsDataGrid.tsx @@ -0,0 +1,87 @@ +import { Box } from '@mui/material'; +import { DataGrid, GridColDef } from '@mui/x-data-grid'; +import { + ServerSetting, + ServerSettings, + ServerSettingsInfo, +} from '../data/ServerData'; + +interface KeyValueRow { + id: number; + key: string; + rawValue: string | number | boolean; + name: string; + value: string | number | boolean; + description: string; +} + +const columns: GridColDef[] = [ + { field: 'key', headerName: 'Key', flex: 4, align: 'right' }, + { field: 'rawValue', headerName: 'Raw Value', flex: 1, align: 'left' }, + { field: 'name', headerName: 'Name', flex: 3, align: 'right' }, + { field: 'value', headerName: 'Value', flex: 1, align: 'left' }, + { field: 'description', headerName: 'Description', flex: 6 }, +]; + +export default function ServerSettingsDataGrid({ + serverSettings, +}: { + serverSettings: ServerSettings; +}) { + const transformValue = ( + v: boolean | string | number, + setting: ServerSetting + ): string | number | boolean => { + return setting.transform?.(v) ?? v; + }; + const rows: KeyValueRow[] = Object.entries(serverSettings).map( + ([key, value], index) => ({ + id: index + 1, + key, + rawValue: value, + name: ServerSettingsInfo[key]?.name || '', + value: + (ServerSettingsInfo[key] && + transformValue(value, ServerSettingsInfo[key]).toString()) || + '', + description: ServerSettingsInfo[key]?.description || '', + }) + ); + + return ( + + 'auto'} + initialState={{ + sorting: { + sortModel: [{ field: 'name', sort: 'asc' }], + }, + filter: { + filterModel: { + items: [{ field: 'name', operator: 'isNotEmpty' }], + }, + }, + columns: { + columnVisibilityModel: { + key: false, + rawValue: false, + }, + }, + }} + sx={{ + '& .MuiDataGrid-cell': { + userSelect: 'text', + py: 1, + }, + }} + /> + + ); +} diff --git a/client/src/components/ServerDetails.tsx b/client/src/pages/ServerDetails.tsx similarity index 77% rename from client/src/components/ServerDetails.tsx rename to client/src/pages/ServerDetails.tsx index df769d4..0a036c1 100644 --- a/client/src/components/ServerDetails.tsx +++ b/client/src/pages/ServerDetails.tsx @@ -15,99 +15,15 @@ import { Typography, alpha, } from '@mui/material'; -import { DataGrid, GridColDef } from '@mui/x-data-grid'; import { useEffect, useState } from 'react'; import { Link, useParams } from 'react-router-dom'; import { fetchData, fetchDemo } from '../apiUtil'; -import ServerData, { - ServerSetting, - ServerSettings, - ServerSettingsInfo, -} from '../data/ServerData'; +import { AlertResponse } from '../components/Alert'; +import ErrorCard from '../components/ErrorCard'; +import ExpansionBar from '../components/ExpansionsBar'; +import ServerSettingsDataGrid from '../components/ServerSettingsDataGrid'; +import ServerData from '../data/ServerData'; import CopyImageIcon from '../images/copy-image.png'; -import { AlertResponse } from './Alert'; -import ErrorCard from './ErrorCard'; -import ExpansionBar from './ExpansionsBar'; - -interface KeyValueRow { - id: number; - key: string; - rawValue: string | number | boolean; - name: string; - value: string | number | boolean; - description: string; -} - -const columns: GridColDef[] = [ - { field: 'key', headerName: 'Key', flex: 4, align: 'right' }, - { field: 'rawValue', headerName: 'Raw Value', flex: 1, align: 'left' }, - { field: 'name', headerName: 'Name', flex: 3, align: 'right' }, - { field: 'value', headerName: 'Value', flex: 1, align: 'left' }, - { field: 'description', headerName: 'Description', flex: 6 }, -]; - -function ServerSettingsDataGrid({ - serverSettings, -}: { - serverSettings: ServerSettings; -}) { - const transformValue = ( - v: boolean | string | number, - setting: ServerSetting - ): string | number | boolean => { - return setting.transform?.(v) ?? v; - }; - const rows: KeyValueRow[] = Object.entries(serverSettings).map( - ([key, value], index) => ({ - id: index + 1, - key, - rawValue: value, - name: ServerSettingsInfo[key]?.name || '', - value: - (ServerSettingsInfo[key] && - transformValue(value, ServerSettingsInfo[key]).toString()) || - '', - description: ServerSettingsInfo[key]?.description || '', - }) - ); - - return ( - - 'auto'} - initialState={{ - sorting: { - sortModel: [{ field: 'name', sort: 'asc' }], - }, - filter: { - filterModel: { - items: [{ field: 'name', operator: 'isNotEmpty' }], - }, - }, - columns: { - columnVisibilityModel: { - key: false, - rawValue: false, - }, - }, - }} - sx={{ - '& .MuiDataGrid-cell': { - userSelect: 'text', - py: 1, - }, - }} - /> - - ); -} export default function ServerDetails({ setAlertInfo,