import React, { useState, useEffect } from 'react';
import { Container, Typography, Button } from '@mui/material';
-import { MaterialReactTable } from 'material-react-table';
-/*import axios from 'axios';*/
-import 'tailwindcss/tailwind.css';
+import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
import { VPNService } from '../../services';
import { ConfirmRevoke, CreateVPNClientDialog } from '../../components';
const VPN = () => {
- /*const [token, setToken] = useState('');
- const [username, setUsername] = useState('');
- const [password, setPassword] = useState('');*/
- /*const [clientName, setClientName] = useState('');
- const [staticIp, setStaticIp] = useState('');
- const [useStaticIp, setUseStaticIp] = useState(false);*/
const [revokeOpen, setRevokeOpen] = useState( false );
const [revokeClientName, setRevokeClientName] = useState('');
const [clients, setClients] = useState([]);
const [availableClients, setAvailableClients] = useState( [] );
const [message, setMessage] = useState('');
const [createOpen, setCreateOpen] = useState( false );
+ const clientTable = useMaterialReactTable( {
+ columns: [
+ { accessorKey: 'name', header: 'Name' },
+ { accessorKey: 'ip', header: 'IP' },
+ { accessorFn: row => row.virtual_ip, header: 'Virtual IP' },
+ { accessorFn: row => row.connectedSince, header: 'Connected Since' },
+ ],
+ data: clients,
+ } );
+ const availableTable = useMaterialReactTable({
+ columns:[
+ { accessorKey: 'clientName', header: 'Name' },
+ { accessorKey: 'staticIp', header: 'IP' },
+ { accessorFn: row => row.hasCertificate ? 'Yes' : 'No', header: 'Active Certificate' },
+ { accessorFn: row => clients.find( c => c.name === row.clientName ) ? 'Yes' : 'No', header: 'Connected' },
+ { accessorFn: row => row.hasOvpn ? 'Yes' : 'No', header: 'Has Profile' },
+ {
+ header: 'Actions',
+ Cell: ({ row }) => (
+ <Button
+ variant="contained"
+ color="secondary"
+ onClick={() => {
+ setRevokeClientName( row.original.clientName );
+ setRevokeOpen( true );
+ }}
+ >
+ Revoke
+ </Button>
+ ),
+ },
+ ],
+ data: availableClients,
+ createDisplayMode: 'modal',
+ renderCreateRowDialogContent: () => (<CreateVPNClientDialog open={createOpen} onClose={() => setCreateOpen(false)} onCreate={handleCreateClientSubmit} />)
+ });
const fetchClients = async () => {
await VPNService.fetchClients().then( res => setClients( res ) ).catch( err => setMessage( err ) );
fetchAvailableClients().catch( e => setMessage( e ) );
}, [] );
- /*const handleLogin = async (e) => {
- e.preventDefault();
- try {
- const response = await axios.post('http://localhost:3000/login', { username, password });
- setToken(response.data.token);
- setMessage('Logged in successfully');
- } catch (error) {
- setMessage(`Error: ${error.response?.data?.error || 'Login failed'}`);
- }
- };*/
-
const handleCreateClientSubmit = async (e, data) => {
const { clientName, useStaticIp, staticIp } = data;
e.preventDefault();
setRevokeOpen( false );
};
+ setTimeout( () => {
+ fetchClients().catch( e => setMessage( e ) );
+ fetchAvailableClients().catch( e => setMessage( e ) );
+ }, 10000 * 120 );
+
return (
<Container>
{ revokeOpen &&
onClose={() => setRevokeOpen(false)}
onConfirm={handleRevokeClientSubmit}
/>}
- <Button variant="contained" color="primary" onClick={() => setCreateOpen(true)}>Create Client</Button>
- {createOpen && <CreateVPNClientDialog open={createOpen} onClose={() => setCreateOpen(false)} onCreate={handleCreateClientSubmit}/>}
- {/*<Typography variant="h5" className="mt-6">Create OpenVPN Client</Typography>
- <form onSubmit={handleCreateClientSubmit} className="space-y-4">
- <TextField
- label="Client Name"
- value={clientName}
- onChange={(e) => setClientName(e.target.value)}
- fullWidth
- />
- <Select
- value={useStaticIp}
- onChange={(e) => setUseStaticIp(e.target.value)}
- fullWidth
- >
- <MenuItem value={false}>Dynamic IP</MenuItem>
- <MenuItem value={true}>Static IP</MenuItem>
- </Select>
- {useStaticIp && (
- <TextField
- label="Static IP"
- value={staticIp}
- onChange={(e) => setStaticIp(e.target.value)}
- fullWidth
- placeholder="e.g., 10.8.0.x"
- />
- )}
- <Button type="submit" variant="contained" color="primary">Create Client</Button>
- </form>*/}
-
- {/*<Typography variant="h5" className="mt-6">Revoke OpenVPN Client</Typography>
- <form onSubmit={handleRevokeClientSubmit} className="space-y-4">
- <TextField
- label="Client Name"
- value={revokeClientName}
- onChange={(e) => setRevokeClientName(e.target.value)}
- fullWidth
- />
- <Button type="submit" variant="contained" color="secondary">Revoke Client</Button>
- </form>*/}
+ {/*<Button variant="contained" color="primary" onClick={() => setCreateOpen(true)}>Create Client</Button>
+ {createOpen && <CreateVPNClientDialog open={createOpen} onClose={() => setCreateOpen(false)} onCreate={handleCreateClientSubmit}/>}*/}
<Typography variant="h5" className="mt-6">Available OpenVPN Clients</Typography>
- <MaterialReactTable
- columns={[
- { accessorKey: 'clientName', header: 'Name' },
- { accessorKey: 'staticIp', header: 'IP' },
- { accessorFn: row => {
- console.log(row.hasCertificate);
- return row.hasCertificate ? 'Yes' : 'No';
- }, header: 'Active Certificate' },
- { accessorFn: row => clients.find( c => c.name === row.clientName ) ? 'Yes' : 'No', header: 'Connected' },
- { accessorFn: row => row.hasOvpn ? 'Yes' : 'No', header: 'Has Profile' },
- {
- header: 'Actions',
- Cell: ({ row }) => (
- <Button
- variant="contained"
- color="secondary"
- onClick={() => {
- setRevokeClientName( row.original.clientName );
- setRevokeOpen( true );
- }}
- >
- Revoke
- </Button>
- ),
- },
- ]}
- data={availableClients}
- />
+ <MaterialReactTable table={ availableTable } />
<Typography variant="h5" className="mt-6">Connected OpenVPN Clients</Typography>
- <MaterialReactTable
- columns={[
- { accessorKey: 'name', header: 'Name' },
- { accessorKey: 'ip', header: 'IP' },
- { accessorKey: 'virtual_ip', header: 'Virtual IP' },
- { accessorKey: 'connectedSince', header: 'Connected Since' },
- ]}
- data={clients}
- />
+ <MaterialReactTable table={ clientTable } />
{message && <Typography color={message.startsWith('Error') ? 'error' : 'success'}>{message}</Typography>}
</Container>
);
-
- /*return (
- <Container>
- <Typography variant="h4" gutterBottom>PHS Admin Dashboard</Typography>
- {!token ? (
- <form onSubmit={handleLogin} className="space-y-4">
- <TextField
- label="Username"
- value={username}
- onChange={(e) => setUsername(e.target.value)}
- fullWidth
- />
- <TextField
- label="Password"
- type="password"
- value={password}
- onChange={(e) => setPassword(e.target.value)}
- fullWidth
- />
- <Button type="submit" variant="contained" color="primary">Login</Button>
- </form>
- ) : (
- <>
- </>
- )}
- </Container>
- );*/
};
export default VPN;
\ No newline at end of file