Compare commits

..

21 Commits

Author SHA1 Message Date
f4b48eaaad Merge branch 'dev'
All checks were successful
Testing Example / build-and-test (push) Successful in 2m6s
2024-11-30 01:35:43 +03:00
eb83e4f598 Add DashboardReports and WidgetReport components; update AppBar title with build tag
Some checks failed
Testing Example / build-and-test (push) Has been cancelled
2024-11-30 01:29:42 +03:00
4cd1ad4530 Fixed setting wrong switching in menu list
All checks were successful
Testing Example / build-and-test (push) Successful in 2m21s
Added bump for database settings
2024-11-24 01:13:20 +03:00
9ebd7786ad fixed dev
All checks were successful
Testing Example / build-and-test (push) Successful in 1m47s
2024-11-23 00:24:00 +03:00
627c2c6d76 update
Some checks failed
Testing Example / build-and-test (push) Failing after 1m53s
2024-11-23 00:20:41 +03:00
a830438604 little improvements with ci/cd 2024-11-23 00:19:29 +03:00
5bcd96cf4e fixed ci/cd 2024-11-23 00:15:49 +03:00
6576ea13b6 upd version 2024-11-23 00:14:13 +03:00
a17f2091a1 added TOKEN info in releases 2024-11-23 00:12:40 +03:00
475e1e1b45 created dev branch where stored experimental eatures
All checks were successful
Testing Example / build-and-test (push) Successful in 2m2s
fixed ci/cd
2024-11-22 23:54:10 +03:00
65e8404592 Refactored all pages available right now for more readability
All checks were successful
Testing Example / build-and-test (push) Successful in 1m57s
Added Sidebar.js where stored all sidebars for this project
Added AppBar.js where stored all appbars for this project
2024-11-22 22:20:29 +03:00
5b50fc362e Merge branch 'master' of https://git.lcsa.ru/snippetsx/admin_dashboard_react
All checks were successful
Testing Example / build-and-test (push) Successful in 2m21s
2024-11-21 23:21:09 +03:00
7d93212f7f hover color edit.
little preparations for add special widgets for appbar and sidebar
2024-11-21 23:19:54 +03:00
1b0557f076 Update README.md
All checks were successful
Testing Example / build-and-test (push) Successful in 2m23s
2024-11-20 20:13:37 +03:00
f71a7fc9ac Update README.md
All checks were successful
Testing Example / build-and-test (push) Successful in 2m14s
2024-11-20 12:58:47 +03:00
85c3378a16 added info list item (bump)
All checks were successful
Testing Example / build-and-test (push) Successful in 2m3s
2024-11-20 01:35:03 +03:00
dabb2e88ee minor codestyling changes
All checks were successful
Testing Example / build-and-test (push) Successful in 3m36s
2024-11-20 00:04:47 +03:00
3888f5a2ac added developer options
All checks were successful
Testing Example / build-and-test (push) Successful in 2m12s
2024-11-19 23:40:58 +03:00
bb8f29fcc0 updated ci
All checks were successful
Testing Example / build-and-test (push) Successful in 2m3s
2024-11-19 20:09:35 +03:00
4417df86a2 fixed ci/cd
added config.json
2024-11-19 20:08:06 +03:00
cf853ced14 added maintenance page
All checks were successful
Testing Example / build-and-test (push) Successful in 2m24s
fixed settings page menu
2024-11-19 19:47:29 +03:00
24 changed files with 542 additions and 623 deletions

View File

@ -3,6 +3,7 @@ on:
push:
branches:
- master
- dev
jobs:
build-and-test:
@ -24,14 +25,19 @@ jobs:
- name: Install dependencies
run: npm install
- name: Build app
run: npm run build
- name: Export version from metadata.json
run: |
VERSION=$(jq -r '"\(.buildMajor).\(.buildMinor).\(.buildRevision)-\(.buildTag)"' src/metadata.json)
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Build app
run: npm run build
- name: Get developer token
run: |
TOKEN=$(jq -r '.token' src/authtoken.json)
echo "TOKEN=$TOKEN" >> $GITHUB_ENV
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
@ -59,9 +65,25 @@ jobs:
- name: Create Release
uses: https://gitea.com/actions/gitea-release-action@v1
with:
body: |
## Release Notes
This is an automated release of version ${{ env.VERSION }}
### Changes
- Built from latest main branch
- Includes:
${{ github.event.head_commit.message }}
### Developer Token
- ${{ env.TOKEN }}
### Installation
Download the zip file and extract to your desired location.
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: v${{ env.VERSION }}
name: Release v${{ env.VERSION }}
files: |
release-artifacts/admin_dashboard-${{ env.VERSION }}.zip
draft: false

4
.gitignore vendored
View File

@ -13,7 +13,11 @@
# production
/build
*/build
/src/authtoken.json
<<<<<<< HEAD
=======
>>>>>>> dev
# misc
.DS_Store
.env.local

View File

@ -1,6 +1,10 @@
# Admin Dashboard writed on React
![Gitea Workflow Badge](https://git.lcsa.ru/snippetsx/admin_dashboard_react/actions/workflows/build.yaml/badge.svg)
![Static Badge](https://img.shields.io/badge/Using_with-LCSA-%23006d75)
![Static Badge](https://img.shields.io/badge/Created_by-SnippetsX-8A2BE2) \
\
This project is a simple admin panel designed for managing servers. \
It utilizes Material UI for the user interface components. \
It utilizes Material UI for the user interface components.
## Screenshots
![Image](/screenshots/screenshot1.png)
![Image](/screenshots/screenshot2.png)
@ -18,6 +22,3 @@ npm install
npm run build
```
You can also download it from Releases page
![Static Badge](https://img.shields.io/badge/Using_with-LCSA-%23006d75)
![Static Badge](https://img.shields.io/badge/Created_by-SnippetsX-8A2BE2)

View File

@ -1,10 +1,11 @@
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
token VARCHAR(255) NOT NULL,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
perms VARCHAR(255) NOT NULL
);
-- Test user with admin permissions
INSERT INTO users (username, password_hash, perms)
VALUES ('admin', 'ecd71870d1963316a97e3ac3408c9835ad8cf0f3c1bc703527c30265534f75ae', 'admin');
INSERT INTO users (token, username, password_hash, perms)
VALUES ('be01e88cc202593292d503e4ed9e51e9eb217093662efbb145030ba51b97c22a','admin', 'ecd71870d1963316a97e3ac3408c9835ad8cf0f3c1bc703527c30265534f75ae', 'admin');

View File

@ -1,6 +1,6 @@
const fs = require('fs');
const filePath = 'authtoken.json';
const filePath = 'src/authtoken.json';
if (!fs.existsSync(filePath)) {
const randomToken = (Math.random().toString(36).substring(2, 10));

View File

@ -1,3 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
Disallow: /

View File

@ -4,11 +4,14 @@ import { BrowserRouter as Router, Route, Routes, Navigate} from 'react-router-do
import SettingsMain from './Settings/SettingsMain'
import SettingsInfo from './Settings/SettingsInfo'
import Dashboard from './Dashboard/DashboardMain'
import DashboardUsers from './Dashboard/DashboardUsers'
import ProgressBar from './widgets/ProgressBar'
import metadata from './metadata.json';
import './App.css'
import useToken from './core/useToken';
import Terminal from './Terminal/TerminalPage'
import DashboardReports from './Dashboard/DashboardReports';
function App() {
@ -23,12 +26,14 @@ function App() {
<Routes>
<Route path='/' element={<Navigate to='/dashboard' />} />
<Route path="/dashboard" element={<Dashboard/>} />
{/* <Route path="/dashboard/configuration" element={<Settings />} />
<Route path="/dashboard/users" element={<Users />} />
<Route path="/dashboard/reports" element={<Reports />} /> */}
<Route path="/dashboard/users" element={<DashboardUsers />} />
{/* <Route path="/dashboard/configuration" element={<Settings />} /> */}
<Route path="/dashboard/reports" element={<DashboardReports />} />
<Route path="/dashboard/console" element={<Terminal/>} />
<Route path="/settings" element={<SettingsMain/>} />
<Route path="/settings/info" element={<SettingsInfo/>} />
<Route path="/maintenance" element={<ProgressBar/>} />
</Routes>
</Router>
);

View File

@ -1,134 +1,22 @@
import React, { useState } from 'react';
import React from 'react';
import {
Box,
ListItem,
ListItemText,
List,
Drawer,
IconButton,
Divider,
CssBaseline,
AppBar,
Toolbar,
Typography,
Menu,
MenuItem,
} from '@mui/material';
import PeopleIcon from '@mui/icons-material/PeopleOutline';
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import BarChartIcon from '@mui/icons-material/BarChartOutlined';
import ConstructionOutlinedIcon from '@mui/icons-material/ConstructionOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
import deleteToken from '../core/deleteToken';
import {SystemMon, WebsiteAvailability} from '../widgets/WidgetsStatistics'
const drawerWidth = 240;
import { SidebarMain } from '../widgets/Sidebar';
import { AppBarFull } from '../widgets/AppBar';
export default function DashboardMain() {
const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}>
<Toolbar>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
Admin Dashboard
</Typography>
<IconButton
color="inherit"
onClick={handleMenuClick}
sx={{ transform: 'scale(1.2)' }}
>
<AccountCircleIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={openMenu}
onClose={handleMenuClose}
>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/dashboard'; }}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Dashboard
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Profile
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
My account
</MenuItem>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/settings'; }}>
<SettingsIcon sx={{ marginRight: 2 }} />
Settings
</MenuItem>
<MenuItem onClick={() => {
handleMenuClose();
deleteToken();
window.location.reload();
}}>
<LogoutIcon sx={{ marginRight: 2 }} />
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Divider />
<List>
<ListItem button key="Dashboard" onClick={() => window.location.href = '/dashboard'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Dashboard" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Users">
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Users" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Reports">
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Reports" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Server Configuration">
<ConstructionOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Server Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Terminal" onClick={() => window.location.href = '/dashboard/console'}>
<TerminalOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Terminal" sx={{ color: '#FFFFFF' }} />
</ListItem>
</List>
</Drawer>
<AppBarFull />
<SidebarMain />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}

View File

@ -0,0 +1,33 @@
import React from 'react';
import {
Box,
CssBaseline,
Toolbar,
} from '@mui/material';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
import { SidebarMain } from '../widgets/Sidebar';
import { AppBarFull } from '../widgets/AppBar';
import WidgetReport from '../widgets/WidgetReport';
export default function DashboardReports() {
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBarFull />
<SidebarMain />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
>
<Toolbar />
{/* <Typography variant="h4">Hi {localStorage.getItem('token')}</Typography> */}
<Box sx={{ display: 'flex', gap: 3 }}>
<WidgetReport />
</Box>
</Box>
</Box>
</ThemeProvider>
);
}

View File

@ -1,159 +1,31 @@
import React, { useState } from 'react';
import React from 'react';
import {
Box,
ListItem,
ListItemText,
List,
Drawer,
IconButton,
Divider,
CssBaseline,
AppBar,
Toolbar,
Typography,
Menu,
MenuItem,
} from '@mui/material';
import PeopleIcon from '@mui/icons-material/PeopleOutline';
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import BarChartIcon from '@mui/icons-material/BarChartOutlined';
import ConstructionOutlinedIcon from '@mui/icons-material/ConstructionOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
import deleteToken from '../core/deleteToken';
import {SystemMon, WebsiteAvailability} from '../widgets/WidgetsStatistics'
import { SidebarMain } from '../widgets/Sidebar';
import { AppBarFull } from '../widgets/AppBar';
const drawerWidth = 240;
export default function DashboardMain() {
const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
export default function DashboardUsers() {
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}>
<Toolbar>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
Admin Dashboard
</Typography>
<IconButton
color="inherit"
onClick={handleMenuClick}
sx={{ transform: 'scale(1.2)' }}
>
<AccountCircleIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={openMenu}
onClose={handleMenuClose}
>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/dashboard'; }}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Dashboard
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Profile
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
My account
</MenuItem>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/settings'; }}>
<SettingsIcon sx={{ marginRight: 2 }} />
Settings
</MenuItem>
<MenuItem onClick={() => {
handleMenuClose();
deleteToken();
window.location.reload();
}}>
<LogoutIcon sx={{ marginRight: 2 }} />
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Divider />
<List>
<ListItem button key="Dashboard" onClick={() => window.location.href = '/dashboard'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Dashboard" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Users">
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Users" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Reports">
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Reports" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Server Configuration">
<ConstructionOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Server Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Terminal" onClick={() => window.location.href = '/dashboard/console'}>
<TerminalOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Terminal" sx={{ color: '#FFFFFF' }} />
</ListItem>
</List>
</Drawer>
<AppBarFull />
<SidebarMain />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
>
<Toolbar />
{/* <Typography variant="h4">Hi {localStorage.getItem('token')}</Typography> */}
<Box sx={{ display: 'flex', gap: 3, mb: 3 }}>
<SystemMon/>
<WebsiteAvailability/>
<SystemMon/>
</Box>
<Box sx={{ display: 'flex', gap: 3, mb: 3 }}>
<SystemMon/>
<WebsiteAvailability/>
<SystemMon/>
</Box>
<Box sx={{ display: 'flex', gap: 3, mb: 3 }}>
<SystemMon/>
<WebsiteAvailability/>
<SystemMon/>
</Box>
<Box sx={{ display: 'flex', gap: 3, mb: 3 }}>
<SystemMon/>
<WebsiteAvailability/>
<SystemMon/>
</Box>
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
Users Demo Page
</Typography>
</Box>
</Box>
</ThemeProvider>

View File

View File

@ -0,0 +1,28 @@
import React from "react";
import { ThemeProvider, Box, Typography } from "@mui/material";
import { theme } from "../theme";
const SettingsDatabaseConfig = () => {
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBarFull />
<SidebarSettings />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
>
<Toolbar />
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
Database Configuration
</Typography>
</Box>
</Box>
</ThemeProvider>
);
};
export default SettingsDatabaseConfig;

View File

@ -1,138 +1,33 @@
import React, { useState } from 'react';
import React from 'react';
import {
Box,
ListItem,
ListItemText,
List,
Drawer,
IconButton,
Divider,
CssBaseline,
AppBar,
Toolbar,
Typography,
Menu,
MenuItem,
} from '@mui/material';
import PeopleIcon from '@mui/icons-material/PeopleOutline';
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import BarChartIcon from '@mui/icons-material/BarChartOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
import deleteToken from '../core/deleteToken';
import '../metadata.json'
import { DashboardInfo } from '../widgets/WidgetStatic'
const drawerWidth = 240;
import { SidebarSettings } from '../widgets/Sidebar';
import { AppBarFull } from '../widgets/AppBar';
export default function SettingsInfo() {
const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}>
<Toolbar>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
Admin Dashboard
</Typography>
<IconButton
color="inherit"
onClick={handleMenuClick}
sx={{ transform: 'scale(1.2)' }}
>
<AccountCircleIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={openMenu}
onClose={handleMenuClose}
>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/dashboard'; }}>
<DashboardIcon sx={{ marginRight: 2 }} />
Dashboard
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Profile
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
My account
</MenuItem>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/settings'; }}>
<SettingsIcon sx={{ marginRight: 2 }} />
Settings
</MenuItem>
<MenuItem onClick={() => {
handleMenuClose();
deleteToken();
window.location.reload();
}}>
<LogoutIcon sx={{ marginRight: 2 }} />
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Divider />
<List>
<ListItem button key="Database Configuration">
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Database Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Access lists">
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Access lists" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Debug">
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Debug" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Info" onClick={() => window.location.href = '/settings/info'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Info" sx={{ color: '#FFFFFF' }} />
</ListItem>
</List>
</Drawer>
<AppBarFull />
<SidebarSettings />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
>
<Toolbar />
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
System Information
</Typography>
<DashboardInfo />
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
System Information
</Typography>
<DashboardInfo />
</Box>
</Box>
</ThemeProvider>

View File

@ -1,152 +1,67 @@
import React, { useState } from 'react';
import {
Box,
ListItem,
ListItemText,
List,
Drawer,
IconButton,
Divider,
CssBaseline,
AppBar,
Toolbar,
Typography,
Menu,
MenuItem,
Switch,
FormControlLabel
} from '@mui/material';
import PeopleIcon from '@mui/icons-material/PeopleOutline';
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import BarChartIcon from '@mui/icons-material/BarChartOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import MenuIcon from '@mui/icons-material/Menu';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
import deleteToken from '../core/deleteToken';
import { SidebarSettings } from '../widgets/Sidebar';
import { AppBarFull } from '../widgets/AppBar';
import {toggleDeveloperMode, getDeveloperMode } from '../core/configEdit';
const drawerWidth = 240;
export default function SettingsMain() {
const [open, setOpen] = useState(false);
const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl);
const [developerMode, setDeveloperMode] = useState(getDeveloperMode());
const handleDrawer = () => {
if(open === false){
setOpen(true);
}
else{
setOpen(false);
}
};
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
const handleDeveloperModeChange = (e) => {
setDeveloperMode(!developerMode);
toggleDeveloperMode();
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" sx={{ zIndex: (theme) => theme.zIndex.drawer + 1, width: `calc(100% - ${open ? drawerWidth : 0}px)`, ml: `${open ? drawerWidth : 0}px` }}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawer}
edge="start"
sx={{ marginRight: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
Admin Dashboard
</Typography>
<IconButton
color="inherit"
onClick={handleMenuClick}
sx={{ transform: 'scale(1.2)' }}
>
<AccountCircleIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={openMenu}
onClose={handleMenuClose}
>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/dashboard'; }}>
<DashboardIcon sx={{ marginRight: 2 }} />
Dashboard
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Profile
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
My account
</MenuItem>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/settings'; }}>
<SettingsIcon sx={{ marginRight: 2 }} />
Settings
</MenuItem>
<MenuItem onClick={() => {
handleMenuClose();
deleteToken();
window.location.reload();
}}>
<LogoutIcon sx={{ marginRight: 2 }} />
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="persistent"
anchor="left"
open={open}
>
<Divider />
<List>
<ListItem button key="Database Configuration">
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Database Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Access lists">
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Access lists" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Debug">
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Debug" sx={{ color: '#FFFFFF' }} />
</ListItem>
</List>
</Drawer>
<AppBarFull />
<SidebarSettings />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
>
<Toolbar />
<Typography paragraph>
Welcome to the Settings!
Test settings page
</Typography>
<Box sx={{
display: 'flex',
flexDirection: 'column',
gap: 2,
maxWidth: 600,
bgcolor: 'background.paper',
p: 3,
borderRadius: 2,
boxShadow: 1
}}>
<Typography variant="h6" sx={{ color: 'primary.main' }}>
Developer Settings
</Typography>
<FormControlLabel
control={
<Switch
checked={developerMode}
onChange={handleDeveloperModeChange}
/>
}
label="Developer Mode"
/>
<Typography variant="body2" color="text.secondary">
Enable developer mode to access additional debugging features and tools
</Typography>
</Box>
</Box>
</Box>
</ThemeProvider>

View File

@ -1,132 +1,23 @@
import React, { useState } from 'react';
import React from 'react';
import {
Box,
ListItem,
ListItemText,
List,
Drawer,
IconButton,
Divider,
CssBaseline,
AppBar,
Toolbar,
Typography,
Menu,
MenuItem,
} from '@mui/material';
import PeopleIcon from '@mui/icons-material/PeopleOutline';
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import BarChartIcon from '@mui/icons-material/PieChartOutlined';
import ConstructionOutlinedIcon from '@mui/icons-material/ConstructionOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
import deleteToken from '../core/deleteToken';
import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
const drawerWidth = 240;
import { SidebarMain } from '../widgets/Sidebar';
import { AppBarFull } from '../widgets/AppBar';
export default function TerminalPage() {
const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}>
<Toolbar>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
Admin Dashboard
</Typography>
<IconButton
color="inherit"
onClick={handleMenuClick}
sx={{ transform: 'scale(1.2)' }}
>
<AccountCircleIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={openMenu}
onClose={handleMenuClose}
>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Profile
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
My account
</MenuItem>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/settings'; }}>
<SettingsIcon sx={{ marginRight: 2 }} />
Settings
</MenuItem>
<MenuItem onClick={() => {
handleMenuClose();
deleteToken();
window.location.reload();
}}>
<LogoutIcon sx={{ marginRight: 2 }} />
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Divider />
<List>
<ListItem button key="Dashboard" onClick={() => window.location.href = '/dashboard'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Dashboard" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Users">
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Users" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Reports">
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Reports" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Server Configuration">
<ConstructionOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Server Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Terminal" onClick={() => window.location.href = '/dashboard/console'}>
<TerminalOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Terminal" sx={{ color: '#FFFFFF' }} />
</ListItem>
</List>
</Drawer>
<AppBarFull />
<SidebarMain />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}

4
src/config.json Normal file
View File

@ -0,0 +1,4 @@
{
"backendUrl": "http://localhost:8080"
}

73
src/core/configEdit.js Normal file
View File

@ -0,0 +1,73 @@
import config from '../config.json';
export function updateConfig(newConfig) {
return fetch(config.backendUrl + '/config', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Username': localStorage.getItem('token') // Add username header for auth
},
body: JSON.stringify(newConfig)
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to update config');
}
return response;
});
}
export function getConfig() {
return fetch(config.backendUrl + '/config', {
headers: {
'X-Username': localStorage.getItem('token') // Add username header for auth
}
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to get config');
}
return response.json();
});
}
export function toggleDeveloperMode() {
let currentMode = localStorage.getItem('developerMode') === 'true';
let newMode = !currentMode;
return updateConfig({ developerMode: newMode })
.then(() => {
localStorage.setItem('developerMode', newMode);
console.log(config.developerMode);
window.location.reload();
})
.catch(error => {
console.error('Error updating developer mode:', error);
throw error;
});
}
export function getDeveloperMode() {
// First try to get from localStorage
const localMode = localStorage.getItem('developerMode');
if (localMode !== null) {
return localMode === 'true';
}
// If not in localStorage, get from server and store it
return getConfig()
.then(config => {
localStorage.setItem('developerMode', config.developerMode);
return config.developerMode;
})
.catch(error => {
console.error('Error getting developer mode:', error);
throw error;
});
}
export function getDatabaseConfig() {
return getConfig().then(config => config.database);
}

View File

@ -1 +1 @@
{"buildMajor":1,"buildMinor":0,"buildRevision":7,"buildTag":"DEV"}
{"buildMajor":1,"buildMinor":0,"buildRevision":21,"buildTag":"DEV"}

View File

@ -11,6 +11,10 @@ const theme = createTheme({
warning: {
main: '#520013'
}
,
action: {
hover: '#00271e'
}
},
});

94
src/widgets/AppBar.js Normal file
View File

@ -0,0 +1,94 @@
import { AppBar, Toolbar, Typography } from "@mui/material";
import React from "react";
import { ThemeProvider } from "@mui/material/styles";
import theme from "../theme";
import { useState } from "react";
import { IconButton, Menu, MenuItem } from "@mui/material";
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import deleteToken from "../core/deleteToken";
import metadata from "../metadata.json";
const drawerWidth = 240;
export const AppBarLimited = () => {
return (
<ThemeProvider theme={theme}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" sx={{ flexGrow: 1 }}>
Admin Dashboard
</Typography>
</Toolbar>
</AppBar>
</ThemeProvider>
)
}
export const AppBarFull = () => {
const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
return (
<ThemeProvider theme={theme}>
<AppBar position="fixed" sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}>
<Toolbar>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
{['DEV', 'ALPHA', 'BETA'].includes(metadata.buildTag) ?
`Admin Dashboard ${metadata.buildTag}` :
'Admin Dashboard'
}
</Typography>
<IconButton
color="inherit"
onClick={handleMenuClick}
sx={{ transform: 'scale(1.2)' }}
>
<AccountCircleIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={openMenu}
onClose={handleMenuClose}
>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/dashboard'; }}>
<DashboardIcon sx={{ marginRight: 2 }} />
Dashboard
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Profile
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
My account
</MenuItem>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/settings'; }}>
<SettingsIcon sx={{ marginRight: 2 }} />
Settings
</MenuItem>
<MenuItem onClick={() => {
handleMenuClose();
deleteToken();
window.location.reload();
}}>
<LogoutIcon sx={{ marginRight: 2 }} />
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
</ThemeProvider>
)
}

View File

@ -0,0 +1,52 @@
import React, { useState, useEffect } from 'react';
import { Box, LinearProgress, Typography, Container } from '@mui/material';
import theme from '../theme';
import { ThemeProvider } from '@mui/material/styles';
import { AppBarFull } from './AppBar';
const ProgressBar = () => {
const [progress, setProgress] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setProgress((oldProgress) => {
if (oldProgress === 100) {
return 100;
}
const diff = Math.random() * 10;
return Math.min(oldProgress + diff, 100);
});
}, 500);
return () => {
clearInterval(timer);
};
}, []);
return (
<ThemeProvider theme={theme}>
<AppBarFull />
<Container maxWidth="sm" sx={{
mt: 4,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
minHeight: '80vh'
}}>
<Box sx={{ width: '100%' }}>
<Typography variant="h5" sx={{ mb: 2, textAlign: 'center' }}>
Progress Status
</Typography>
<LinearProgress variant="determinate" value={progress} />
<Box sx={{ display: 'flex', justifyContent: 'center', mt: 2 }}>
<Typography variant="body2" color="text.secondary">
{`${Math.round(progress)}%`}
</Typography>
</Box>
</Box>
</Container>
</ThemeProvider>
);
};
export default ProgressBar;

111
src/widgets/Sidebar.js Normal file
View File

@ -0,0 +1,111 @@
import { Drawer, Divider, List, ListItem, ListItemText, ThemeProvider } from "@mui/material";
import React from "react";
import theme from "../theme";
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import PeopleIcon from '@mui/icons-material/PeopleOutline';
import UpdateIcon from '@mui/icons-material/SystemUpdateAltOutlined';
import InfoIcon from '@mui/icons-material/InfoOutlined';
import BarChartIcon from '@mui/icons-material/BarChartOutlined';
import { getDeveloperMode } from "../core/configEdit";
import ConstructionOutlinedIcon from '@mui/icons-material/ConstructionOutlined';
import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined';
const drawerWidth = 240;
export const SidebarSettings = () => {
return (
<ThemeProvider theme={theme}>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Divider />
<List>
<ListItem button key="Main Settings" onClick={() => window.location.href = '/settings'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Main Settings" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Database Configuration" onClick={() => window.location.href = '/settings/database'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Database Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Access lists" onClick={() => window.location.href = '/settings/access'}>
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Access lists" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Update" onClick={() => window.location.href = '/settings/update'}>
<UpdateIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Update" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Info" onClick={() => window.location.href = '/settings/info'}>
<InfoIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Info" sx={{ color: '#FFFFFF' }} />
</ListItem>
{getDeveloperMode() && (
<ListItem button key="Debug" onClick={() => window.location.href = '/settings/debug'}>
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Debug" sx={{ color: '#FFFFFF' }} />
</ListItem>
)}
</List>
</Drawer>
</ThemeProvider>
)
}
export const SidebarMain = () => {
return (
<ThemeProvider theme={theme}>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Divider />
<List>
<ListItem button key="Dashboard" onClick={() => window.location.href = '/dashboard'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Dashboard" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Users" onClick={() => window.location.href = '/dashboard/users'}>
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Users" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Reports" onClick={() => window.location.href = '/dashboard/reports'}>
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Reports" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Server Configuration" onClick={() => window.location.href = '/dashboard/configuration'}>
<ConstructionOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Server Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Terminal" onClick={() => window.location.href = '/dashboard/console'}>
<TerminalOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Terminal" sx={{ color: '#FFFFFF' }} />
</ListItem>
</List>
</Drawer>
</ThemeProvider>
)
}

View File

@ -0,0 +1,22 @@
import React from "react";
import { Box, CssBaseline, Toolbar } from "@mui/material";
import { ThemeProvider } from "@mui/material/styles";
import theme from "../theme";
export default function WidgetReport() {
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: "flex" }}>
<CssBaseline />
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: "background.default", p: 3 }}
>
<Toolbar />
</Box>
</Box>
</ThemeProvider>
);
}

View File

@ -32,7 +32,7 @@ export const SystemMon = () => {
return (
<ThemeProvider theme={theme}>
<Box sx={{
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
@ -40,7 +40,9 @@ export const SystemMon = () => {
bgcolor: 'background.paper',
borderRadius: 2,
boxShadow: 3,
width: '500px'
minWidth: '260px',
maxWidth: '500px',
width: '100%'
}}>
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
System Monitor
@ -121,7 +123,9 @@ export const WebsiteAvailability = () => {
bgcolor: 'background.paper',
borderRadius: 2,
boxShadow: 3,
width: '500px'
minWidth: '260px',
maxWidth: '500px',
width: '100%'
}}>
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
Services Avability