+// noinspection JSValidateTypes
+
/**
* @file Component for creating a new message
*/
+// noinspection JSValidateTypes
+
/**
* @file Component for creating a new message group
*/
+// noinspection JSValidateTypes
+
/**
* @file Component for adding a message group member
*/
+// noinspection JSValidateTypes
+
/**
* @file Component for creating a new post
*/
import React, { createContext, useContext, useEffect, useState } from 'react';
import { VPNService } from '../../services';
import { ConfirmRevoke, CreateVPNClientDialog, SuspendClient } from '../index';
+import { useSnackbar } from 'notistack';
const VPNContext = createContext( undefined );
const [suspendOpen, setSuspendOpen] = useState( false );
/** TODO: Change the default time to something more reasonable. */
const [duration, setDuration] = useState( 1 );
+ const { enqueueSnackbar } = useSnackbar();
const fetchServerStatus = async () => {
await VPNService.getServerStatus()
setRevokeClientName( '' );
};
+ const handleToggleVPN = (action) => VPNService[action]().then( () => {
+ enqueueSnackbar( `VPN ${action} completed successfully`, { variant: 'success' } );
+ setTimeout( () => fetchServerStatus(), 1000 );
+ } ).catch( e => {
+ enqueueSnackbar( `VPN ${action} failed`, { variant: 'error' } );
+ setMessage( e );
+ });
+
useEffect( () => {
fetchClients().catch( e => setMessage( e ) );
fetchAvailableClients().catch( e => setMessage( e ) );
suspendOpen,
setSuspendOpen,
duration,
- setDuration
+ setDuration,
+ handleToggleVPN
};
return <VPNContext.Provider value={ value }>
availableClients: `${base}available-clients/`,
getStatus: `${base}status/`,
disconnect: `${base}disconnect/`,
+ stop: `${base}stop/`,
+ start: `${base}start/`,
restart: `${base}restart/`
};
} );
};
+ stop = () => {
+ return new Promise( async ( resolve ) => {
+ try {
+ const response = await axios.put( `${ base_url }${ VPNConfig.stop }` );
+ resolve( response.data.message );
+ } catch (error) {
+ resolve( `Error: ${ error.response?.data?.error || 'Failed to stop' }` );
+ }
+ } );
+ };
+
+ start = () => {
+ return new Promise( async ( resolve ) => {
+ try {
+ const response = await axios.put( `${ base_url }${ VPNConfig.start }` );
+ resolve( response.data.message );
+ } catch (error) {
+ resolve( `Error: ${ error.response?.data?.error || 'Failed to start' }` );
+ }
+ } );
+ };
+
restart = () => {
return new Promise( async ( resolve ) => {
try {
-import { Container, Typography, Button, Grid, IconButton } from '@mui/material';
+import { Container, Typography, Button, Grid, IconButton, Card, CardHeader, CardContent } from '@mui/material';
import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
import { useVPN } from '../../components';
import AccessTimeOutlined from '@mui/icons-material/AccessTimeOutlined';
availableClients,
message,
setCreateOpen,
+ handleToggleVPN,
serverStatus,
setSuspendOpen } = useVPN();
const clientTable = useMaterialReactTable( {
{ accessorFn: row => row.connectedSince, header: 'Connected Since' },
],
data: clients,
+ renderTopToolbarCustomActions: () => (
+ <Grid container spacing={4}>
+ <Grid item>
+ <Typography variant="h5">Connected OpenVPN Clients</Typography>
+ </Grid>
+ </Grid>
+ )
} );
const availableTable = useMaterialReactTable({
columns:[
},
],
data: availableClients,
- renderTopToolbarCustomActions: () => (
- <>
- <Button variant='contained'
- color='primary'
- size='small'
- onClick={ () => setCreateOpen( true ) }>
- Create Client
- </Button>
- </>
- )
+ renderTopToolbarCustomActions: () => ( <Typography variant="h5" className="mt-6">Available Clients</Typography> )
});
console.log('serverStatus', serverStatus);
return (
- <Container>
- <Typography variant="h5" className="mt-6">Available OpenVPN Clients<small style={{ float: 'right', marginRight: '1rem' }} >Status: <small style={{ color: serverStatus ? '#00FF00' : '#FF0000' }}>{ serverStatus ? 'Active' : 'Inactive' }</small></small></Typography>
- <MaterialReactTable table={ availableTable } />
-
- <Typography variant="h5" className="mt-6">Connected OpenVPN Clients</Typography>
- <MaterialReactTable table={ clientTable } />
-
+ <Card maxWidth="xxl" className="mt-6">
+ <CardHeader title={(
+ <Grid container spacing={4}>
+ <Grid item>
+ <Typography variant="h5" className="mt-6">OpenVPN Management<small style={{ marginLeft: '1rem' }} >Status: <small style={{ color: serverStatus ? '#00FF00' : '#FF0000' }}>{ serverStatus ? 'Active' : 'Inactive' }</small></small></Typography>
+ </Grid>
+ <Grid item>
+ <Button variant='contained' color='error' size='small' onClick={ () => handleToggleVPN('stop') }>Stop Server</Button>
+ </Grid>
+ <Grid item>
+ <Button variant='contained' color='success' size='small' onClick={ () => handleToggleVPN('start') }>Start Server</Button>
+ </Grid>
+ <Grid item>
+ <Button variant='contained' color='warning' size='small' onClick={ () => handleToggleVPN('restart') }>Restart Server</Button>
+ </Grid>
+ <Grid item>
+ <Button variant='contained'
+ color='primary'
+ size='small'
+ onClick={ () => setCreateOpen( true ) }>
+ Create Client
+ </Button>
+ </Grid>
+ </Grid>
+ )} />
+ <CardContent>
+ <Grid container spacing={2} className="w-full">
+ <Grid item size={{ xs: 12 }} >
+ <MaterialReactTable table={ availableTable } />
+ </Grid>
+ <Grid item size={{ xs: 12 }}>
+ <MaterialReactTable table={ clientTable } />
+ </Grid>
+ </Grid>
+ </CardContent>
{message && <Typography color={message.startsWith('Error') ? 'error' : 'success'}>{message}</Typography>}
- </Container>
+ </Card>
);
};
-export const base_url = 'http://localhost:23601/';
+export const base_url = 'https://api.phasecustomsoft.com/';
/** @type {import('tailwindcss').Config} */
/* eslint-disable import/no-extraneous-dependencies */
-// noinspection SpellCheckingInspection
+// noinspection SpellCheckingInspection,JSUnusedGlobalSymbols
const path = require('path');