]> PHS Git Server - phs-admin.git/commitdiff
Adding a server status dialog.
authorcharleswrayjr <charleswrayjr@gmail.com>
Tue, 9 Sep 2025 18:34:24 +0000 (13:34 -0500)
committercharleswrayjr <charleswrayjr@gmail.com>
Tue, 9 Sep 2025 18:34:24 +0000 (13:34 -0500)
src/app/components/VPN/VPN.helpers.js [new file with mode: 0644]
src/app/components/VPN/VPNContext.jsx
src/app/components/VPN/VPNStatusDialog.jsx [new file with mode: 0644]
src/app/components/index.js
src/app/routes.js
src/app/services/VPN/VPNConfig.js
src/app/services/VPN/VPNService.js
src/app/views/VPN/VPN.jsx
src/app/views/VPN/index.js [deleted file]

diff --git a/src/app/components/VPN/VPN.helpers.js b/src/app/components/VPN/VPN.helpers.js
new file mode 100644 (file)
index 0000000..e69de29
index 66a246f9688ef47b153e7cb27714a8137f3ed250..266f25fff3bf0609a2280fe193fe3c1ba809e7b1 100644 (file)
@@ -1,6 +1,6 @@
-import React, { createContext, useState, useContext, useEffect } from 'react';
+import React, { createContext, useContext, useEffect, useState } from 'react';
 import { VPNService } from '../../services';
-import { CreateVPNClientDialog, ConfirmRevoke } from '../index';
+import { ConfirmRevoke, CreateVPNClientDialog, VPNStatusDialog } from '../index';
 
 const VPNContext = createContext( undefined );
 
@@ -13,6 +13,14 @@ export const VPNProvider = ( { children } ) => {
   const [availableClients, setAvailableClients] = useState( [] );
   const [message, setMessage] = useState( '' );
   const [createOpen, setCreateOpen] = useState( false );
+  const [statusOpen, setStatusOpen] = useState( false );
+  const [serverStatus, setServerStatus] = useState( {} );
+
+  const fetchServerStatus = async () => {
+    await VPNService.getServerStatus()
+      .then( res => setServerStatus( res ) )
+      .catch( err => setMessage( err ) );
+  };
 
   const fetchClients = async () => {
     await VPNService.fetchClients()
@@ -43,10 +51,12 @@ export const VPNProvider = ( { children } ) => {
   useEffect( () => {
     fetchClients().catch( e => setMessage( e ) );
     fetchAvailableClients().catch( e => setMessage( e ) );
+    fetchServerStatus().catch( e => setMessage( e ) );
 
     const interval = setInterval( () => {
       fetchClients().catch( e => setMessage( e ) );
       fetchAvailableClients().catch( e => setMessage( e ) );
+      fetchServerStatus().catch( e => setMessage( e ) );
     }, 10000 * 120 );
 
     return () => clearInterval( interval );
@@ -64,11 +74,22 @@ export const VPNProvider = ( { children } ) => {
     createOpen,
     setCreateOpen,
     handleCreateClientSubmit,
-    handleRevokeClientSubmit
+    handleRevokeClientSubmit,
+    statusOpen,
+    setStatusOpen,
+    serverStatus,
+    setServerStatus
   };
 
   return <VPNContext.Provider value={ value }>
-    {revokeOpen && <ConfirmRevoke open={revokeOpen} onClose={() => setRevokeOpen(false)} onConfirm={handleRevokeClientSubmit}/>}
-    {createOpen && <CreateVPNClientDialog open={createOpen} onClose={() => setCreateOpen(false)} onCreate={handleCreateClientSubmit}/>}
+    { revokeOpen && <ConfirmRevoke open={ revokeOpen }
+                                   onClose={ () => setRevokeOpen( false ) }
+                                   onConfirm={ handleRevokeClientSubmit }/> }
+    { createOpen && <CreateVPNClientDialog open={ createOpen }
+                                           onClose={ () => setCreateOpen( false ) }
+                                           onCreate={ handleCreateClientSubmit }/> }
+    { statusOpen && <VPNStatusDialog open={ statusOpen }
+                                     onClose={ () => setStatusOpen( false ) }
+                                     status={ serverStatus }/> }
     { children }</VPNContext.Provider>;
 };
diff --git a/src/app/components/VPN/VPNStatusDialog.jsx b/src/app/components/VPN/VPNStatusDialog.jsx
new file mode 100644 (file)
index 0000000..3a25266
--- /dev/null
@@ -0,0 +1,13 @@
+import { Dialog, DialogTitle, DialogContent, DialogActions, Button} from '@mui/material';
+
+export default function VPNStatusDialog( { open, onClose, status } ) {
+       return (
+               <Dialog open={ open } onClose={ onClose } >
+                       <DialogTitle>VPN Status</DialogTitle>
+                       <DialogContent>{ status }</DialogContent>
+                       <DialogActions>
+                               <Button onClick={ onClose }>OK</Button>
+                       </DialogActions>
+               </Dialog>
+       );
+};
\ No newline at end of file
index 9467176ba9941c539d7966784582ad5a08fa5441..7e4e52ed7e16877c7832fae793635ac1760c934d 100644 (file)
@@ -1,4 +1,6 @@
 import ConfirmRevoke from './VPN/ConfirmRevoke';
 import CreateVPNClientDialog from './VPN/CreateVPNClientDialog';
+import VPNStatusDialog from './VPN/VPNStatusDialog';
+export * from './VPN/VPNContext';
 
-export { ConfirmRevoke, CreateVPNClientDialog };
\ No newline at end of file
+export { ConfirmRevoke, CreateVPNClientDialog, VPNStatusDialog };
\ No newline at end of file
index c18771cd7dc00c6cfbaa6f0f5123e1ba438180fe..f31818d2b5468afc491e543188ceb343f0942911 100755 (executable)
@@ -1,16 +1,16 @@
 import { Route, Routes } from 'react-router-dom';
 import { Login, NotFound, Dashboard, Git, VPN, Docker } from './views';
-import { VPNProvider } from './components/VPN/VPNContext';
+import { VPNProvider } from './components/';
 
 export default function AppRoutes() {
   return (
     <Routes>
-      <Route path="/" element={<Dashboard />} />
-      <Route path="/login" element={<Login />} />
-      <Route path="/git" element={<Git />} />
-      <Route path="/vpn" element={ <VPNProvider><VPN/></VPNProvider>} />
-      <Route path="/docker" element={<Docker />} />
-      <Route path="*" element={<NotFound />} />
+      <Route path="/" element={ <Dashboard /> } />
+      <Route path="/login" element={ <Login /> } />
+      <Route path="/git" element={ <Git /> } />
+      <Route path="/vpn" element={ <VPNProvider><VPN/></VPNProvider> } />
+      <Route path="/docker" element={ <Docker /> } />
+      <Route path="*" element={ <NotFound /> } />
     </Routes>
   );
 };
index b398f390fd72d0dd1b271b572a2bcf3e2c9e4d30..17b8750f55962b79464ede404d73e98f3dea115f 100644 (file)
@@ -3,7 +3,10 @@ const VPNConfig = {
   create: `${base}create-client/`,
   delete: `${base}revoke-client/`,
   index: `${base}clients/`,
-  availableClients: `${base}available-clients/`
+  availableClients: `${base}available-clients/`,
+  getStatus: `${base}status/`,
+  disconnect: `${base}disconnect/`,
+  restart: `${base}restart/`
 };
 
 export default VPNConfig;
\ No newline at end of file
index 6b2ffdf4f247217db22dc28093580ab9ed6d6816..11feb3f1547a8511494bb8ed038210298ca64990 100644 (file)
@@ -6,63 +6,96 @@ class VPNService {
   fetchClients = () => {
     return new Promise( async ( resolve ) => {
       try {
-        const response = await axios.get(`${base_url}${VPNConfig.index}`);
-        resolve(response.data.clients);
+        const response = await axios.get( `${ base_url }${ VPNConfig.index }` );
+        resolve( response.data.clients );
       } catch (error) {
-        resolve(`Error: ${error.response?.data?.error || 'Failed to fetch clients'}`);
+        resolve( `Error: ${ error.response?.data?.error || 'Failed to fetch clients' }` );
       }
-    });
+    } );
   };
 
   fetchAvailableClients = () => {
     return new Promise( async ( resolve ) => {
       try {
-        const response = await axios.get(`${base_url}${VPNConfig.availableClients}`);
-        resolve(response.data.clients);
+        const response = await axios.get( `${ base_url }${ VPNConfig.availableClients }` );
+        resolve( response.data.clients );
       } catch (error) {
-        resolve(`Error: ${error.response?.data?.error || 'Failed to fetch available clients'}`);
+        resolve( `Error: ${ error.response?.data?.error || 'Failed to fetch available clients' }` );
       }
-    });
+    } );
   };
 
   createClient = ( data, fetchClients ) => {
     return new Promise( async ( resolve ) => {
       const { clientName, useStaticIp, staticIp } = data;
       try {
-        const response = await axios.post(`${base_url}${VPNConfig.create}`, {
+        const response = await axios.post( `${ base_url }${ VPNConfig.create }`, {
           clientName,
-          staticIp: useStaticIp ? staticIp : undefined,
-        });
+          staticIp:useStaticIp ? staticIp : undefined,
+        } );
         fetchClients();
         if (response.data.ovpn) {
-          const element = document.createElement('a');
-          const file = new Blob([response.data.ovpn], { type: 'text/plain' });
-          element.href = URL.createObjectURL(file);
-          element.download = `${clientName}.ovpn`;
-          document.body.appendChild(element);
+          const element = document.createElement( 'a' );
+          const file = new Blob( [response.data.ovpn], { type:'text/plain' } );
+          element.href = URL.createObjectURL( file );
+          element.download = `${ clientName }.ovpn`;
+          document.body.appendChild( element );
           element.click();
-          document.body.removeChild(element);
+          document.body.removeChild( element );
         }
-        resolve(response.data.message);
+        resolve( response.data.message );
       } catch (error) {
-        resolve(`Error: ${error.response?.data?.error || 'Failed to create client'}`);
+        resolve( `Error: ${ error.response?.data?.error || 'Failed to create client' }` );
       }
-    })
+    } );
   };
 
   revokeClient = ( data, fetchClients ) => {
     return new Promise( async ( resolve ) => {
       const { revokeClientName } = data;
       try {
-        const response = await axios.put(`${base_url}${VPNConfig.delete}`, {
-          clientName: revokeClientName,
-        });
+        const response = await axios.put( `${ base_url }${ VPNConfig.delete }`, {
+          clientName:revokeClientName,
+        } );
         fetchClients();
-        resolve(response.data.message);
+        resolve( response.data.message );
       } catch (error) {
-        resolve(`Error: ${error.response?.data?.error || 'Failed to revoke client'}`);
+        resolve( `Error: ${ error.response?.data?.error || 'Failed to revoke client' }` );
       }
-    });
+    } );
+  };
+
+  getServerStatus = () => {
+    return new Promise( async ( resolve ) => {
+      try {
+        const response = await axios.get( `${ base_url }${ VPNConfig.getStatus }` );
+        resolve( response.data );
+      } catch (error) {
+        resolve( `Error: ${ error.response?.data?.error || 'Failed to fetch server status' }` );
+      }
+    } );
+  };
+
+  disconnect = () => {
+    return new Promise( async ( resolve ) => {
+      try {
+        const response = await axios.put( `${ base_url }${ VPNConfig.disconnect }` );
+        resolve( response.data.message );
+      } catch (error) {
+        resolve( `Error: ${ error.response?.data?.error || 'Failed to disconnect' }` );
+      }
+    } );
+  };
+
+  restart = () => {
+    return new Promise( async ( resolve ) => {
+      try {
+        const response = await axios.put( `${ base_url }${ VPNConfig.restart }` );
+        resolve( response.data.message );
+      } catch (error) {
+        resolve( `Error: ${ error.response?.data?.error || 'Failed to restart' }` );
+      }
+    } );
   };
 
 }
index 959a2eaf47fdea15b692f3739303be8c6d09846c..6fdfefbbfdf3734273078e3b7091e70f8f764d7e 100644 (file)
@@ -1,6 +1,6 @@
 import { Container, Typography, Button, Grid } from '@mui/material';
 import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
-import { useVPN } from '../../components/VPN/VPNContext';
+import { useVPN } from '../../components';
 
 const VPN = () => {
   const { setRevokeOpen,
@@ -8,7 +8,8 @@ const VPN = () => {
     clients,
     availableClients,
     message,
-    setCreateOpen } = useVPN();
+    setCreateOpen,
+    setStatusOpen } = useVPN();
   const clientTable = useMaterialReactTable( {
     columns: [
       { accessorKey: 'name', header: 'Name' },
@@ -62,11 +63,18 @@ const VPN = () => {
     data: availableClients,
     renderTopToolbarCustomActions: () => (
       <>
-        <Button variant="contained"
-                color="primary"
+        <Button variant='contained'
+                color='primary'
+                size='small'
                 onClick={ () => setCreateOpen( true ) }>
           Create Client
         </Button>
+        <Button variant='contained'
+                color='warning'
+                size='small'
+                onClick={ () => setStatusOpen( true ) }>
+          Show VPN Status
+        </Button>
       </>
     )
   });
diff --git a/src/app/views/VPN/index.js b/src/app/views/VPN/index.js
deleted file mode 100644 (file)
index e69de29..0000000