import React, { useEffect, useState } from 'react';
-import { Button, Container, TextField, Typography } from '@mui/material';
+import { Button, Container, Tab, Tabs, TextField, Typography } from '@mui/material';
import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
import { DockerService } from '../../services';
const [images, setImages] = useState( [] );
const [composeFile, setComposeFile] = useState( '' );
const [message, setMessage] = useState( '' );
+ const [activeTab, setActiveTab] = useState( 0 );
+
+ useEffect( () => {
+ fetchImages().catch();
+ fetchContainers().catch();
+ }, [] );
const fetchContainers = async () => {
try {
setMessage( error );
}
};
-
const fetchImages = async () => {
try {
const imagesData = await DockerService.fetchImages(); // Assuming you have a service to fetch images
setMessage( error );
}
};
-
- useEffect( () => {
- fetchImages().catch();
- fetchContainers().catch();
- }, [] );
-
const handleContainerAction = async ( action, containerId ) => {
await DockerService.containerAction( action, containerId );
await fetchContainers();
};
-
const handleComposeSubmit = async ( event ) => {
event.preventDefault();
setMessage( await DockerService.composeDown( composeFile ) );
};
-
const containerTable = useMaterialReactTable( {
columns:[
{ accessorKey:'id', header:'ID' },
),
},
],
- data:containers
+ data:containers,
+ renderTopToolbarCustomActions:() => (<Typography variant="h5"
+ className="mt-6">Docker Containers</Typography>)
} );
-
const imageTable = useMaterialReactTable( {
columns:[
{ accessorKey:'id', header:'ID' },
{ accessorKey:'tags', header:'Tags', Cell:( { cell } ) => cell.getValue().join( ', ' ) },
{ accessorKey:'created', header:'Created' },
],
- data:images
+ data:images,
+ renderTopToolbarCustomActions:() => (<Typography variant="h5"
+ className="mt-6">Docker Images</Typography>)
} );
return (
- <Container>
- <Typography variant="h5"
- className="mt-6">Docker Containers</Typography>
- <MaterialReactTable table={ containerTable }/>
-
- <Typography variant="h5"
- className="mt-6">Docker Images</Typography>
- <MaterialReactTable table={ imageTable }/>
-
- <Typography variant="h5"
- className="mt-6">Stop Docker Compose Services</Typography>
- <form onSubmit={ handleComposeSubmit }
- className="space-y-4">
- <TextField label="Compose File Path"
- value={ composeFile }
- onChange={ ( e ) => setComposeFile( e.target.value ) }
- fullWidth/>
- <Button type="submit"
- variant="contained"
- color="secondary">Stop Compose Services</Button>
- </form>
-
+ <Container maxWidth="xxl">
+ <Tabs value={ activeTab }>
+ <Tab label="Containers"
+ onClick={ () => setActiveTab( 0 ) }/>
+ <Tab label="Images"
+ onClick={ () => setActiveTab( 1 ) }/>
+ <Tab label="Compose"
+ onClick={ () => setActiveTab( 2 ) }/>
+ </Tabs>
+ { activeTab === 0 && <MaterialReactTable table={ containerTable }/> }
+ { activeTab === 1 && <MaterialReactTable table={ imageTable }/> }
+ { activeTab === 2 &&
+ <>
+ <Typography variant="h5"
+ className="mt-6">Stop Docker Compose Services</Typography>
+ <form onSubmit={ handleComposeSubmit }
+ className="space-y-4">
+ <TextField label="Compose File Path"
+ value={ composeFile }
+ onChange={ ( e ) => setComposeFile( e.target.value ) }
+ fullWidth/>
+ <Button type="submit"
+ variant="contained"
+ color="secondary">Stop Compose Services</Button>
+ </form>
+ </> }
{ message && <Typography color={ message?.startsWith( 'Error' ) ? 'error' : 'success' }>{ message }</Typography> }
</Container>
);
-import React, { useState, useEffect } from 'react';
-
-import { Container, Typography, TextField, Button, Select, MenuItem } from '@mui/material';
-import { MaterialReactTable } from 'material-react-table';
+import React, { useEffect, useState } from 'react';
+import {
+ Button,
+ Card,
+ CardActions,
+ CardContent,
+ CardHeader,
+ Container,
+ Grid,
+ MenuItem,
+ Select,
+ TextField,
+ Typography
+} from '@mui/material';
+import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
import { GitService } from '../../services';
const Git = () => {
- const [repoName, setRepoName] = useState('');
- const [repoType, setRepoType] = useState('global');
- const [repoUser, setRepoUser] = useState('');
- const [message, setMessage] = useState('');
+ const [repoName, setRepoName] = useState( '' );
+ const [repoType, setRepoType] = useState( 'global' );
+ const [repoUser, setRepoUser] = useState( '' );
+ const [message, setMessage] = useState( '' );
const [repos, setRepos] = useState( [] );
- const [deployRepoName, setDeployRepoName] = useState('');
- const [deployPath, setDeployPath] = useState('');
- const [deployUser, setDeployUser] = useState('');
+ const [deployRepoName, setDeployRepoName] = useState( '' );
+ const [deployPath, setDeployPath] = useState( '' );
+ const [deployUser, setDeployUser] = useState( '' );
const fetchRepos = async () => {
await GitService.fetchRepos().then( res => setRepos( res ) ).catch( err => setMessage( err ) );
};
- useEffect(() => {
+ useEffect( () => {
fetchRepos().catch( e => setMessage( e ) );
}, [] );
- const handleRepoSubmit = async (e) => {
+ const handleRepoSubmit = async ( e ) => {
e.preventDefault();
- setMessage( await GitService.createRepo({repoName, repoType, repoUser}, fetchRepos ) );
+ setMessage( await GitService.createRepo( { repoName, repoType, repoUser }, fetchRepos ) );
};
- const handleDeleteRepo = async (name) => {
- setMessage( await GitService.deleteRepo( name, fetchRepos ) );
+ const handleDeleteRepo = async ( name ) => {
+ setMessage( await GitService.deleteRepo( name, fetchRepos ) );
};
- const handleCloneSubmit = async (e) => {
+ const handleCloneSubmit = async ( e ) => {
e.preventDefault();
setMessage( await GitService.cloneRepo( { deployRepoName, deployPath, deployUser } ) );
};
- return(
- <Container>
- <Typography variant="h5">Create Git Repository</Typography>
- <form onSubmit={handleRepoSubmit} className="space-y-4">
- <TextField
- label="Repository Name"
- value={repoName}
- onChange={(e) => setRepoName(e.target.value)}
- fullWidth
- />
- <Select
- value={repoType}
- onChange={(e) => setRepoType(e.target.value)}
- fullWidth
- >
- <MenuItem value="global">Global (Group-Shared)</MenuItem>
- <MenuItem value="private">Private (User-Specific)</MenuItem>
- </Select>
- <TextField
- label="Username"
- value={repoUser}
- onChange={(e) => setRepoUser(e.target.value)}
- fullWidth
- />
- <Button type="submit" variant="contained" color="primary">Create Repository</Button>
- </form>
+ const gitTable = useMaterialReactTable( {
+ columns:[
+ { accessorKey:'name', header:'Name' },
+ { accessorKey:'cloneUrl', header:'Clone URL' },
+ {
+ header:'Actions',
+ Cell:( { row } ) => (
+ <Button variant="contained"
+ color="secondary"
+ onClick={ () => handleDeleteRepo( row.original.name ) }>
+ Delete
+ </Button>
+ ),
+ },
+ ],
+ data:repos,
+ enableRowActions:true,
+ renderRowActions:( { row } ) => (
+ <Button onClick={ () => navigator.clipboard.writeText( row.original.cloneUrl ) }>
+ Copy Clone URL
+ </Button>
+ ),
+ renderTopToolbarCustomActions:() => (<Typography variant="h5"
+ className="mt-6">Repositories</Typography>)
+ } );
- <Typography variant="h5" className="mt-6">Clone Repository Locally</Typography>
- <form onSubmit={handleCloneSubmit} className="space-y-4">
- <TextField
- label="Repository Name"
- value={deployRepoName}
- onChange={(e) => setDeployRepoName(e.target.value)}
- fullWidth
- />
- <TextField
- label="Deployment Path"
- value={deployPath}
- onChange={(e) => setDeployPath(e.target.value)}
- fullWidth
- />
- <TextField
- label="Username"
- value={deployUser}
- onChange={(e) => setDeployUser(e.target.value)}
- fullWidth
- />
- <Button type="submit" variant="contained" color="primary">Clone Repository</Button>
- </form>
+ return (
+ <Container maxWidth="xxl">
+ <Grid container
+ spacing={ 2 }>
+ <Grid item
+ size={ { xs:12, sm:6 } }>
+ <Card className="mt-6">
+ <CardHeader title="Create Git Repository"
+ component="h5"
+ className="!pt-0 !pb-0"/>
+ <form onSubmit={ handleRepoSubmit }
+ className="space-y-4">
+ <CardContent>
+ <TextField label="Repository Name"
+ value={ repoName }
+ onChange={ ( e ) => setRepoName( e.target.value ) }
+ fullWidth/>
+ <Select variant="outlined"
+ value={ repoType }
+ onChange={ ( e ) => setRepoType( e.target.value ) }
+ fullWidth>
+ <MenuItem value="global">Global (Group-Shared)</MenuItem>
+ <MenuItem value="private">Private (User-Specific)</MenuItem>
+ </Select>
+ <TextField label="Username"
+ value={ repoUser }
+ onChange={ ( e ) => setRepoUser( e.target.value ) }
+ fullWidth/>
+ </CardContent>
+ <CardActions>
+ <Button type="submit"
+ variant="contained"
+ color="primary">Create Repository</Button>
+ </CardActions>
+ </form>
+ </Card>
+ </Grid>
+ <Grid item
+ size={ { xs:12, sm:6 } }>
+ <Card className="mt-6">
+ <CardHeader title="Clone Repository Locally"
+ component="h5"
+ className="!pt-0 !pb-0"/>
+ <form onSubmit={ handleCloneSubmit }
+ className="space-y-4">
+ <CardContent>
+ <TextField label="Repository Name"
+ value={ deployRepoName }
+ onChange={ ( e ) => setDeployRepoName( e.target.value ) }
+ fullWidth/>
+ <TextField label="Deployment Path"
+ value={ deployPath }
+ onChange={ ( e ) => setDeployPath( e.target.value ) }
+ fullWidth/>
+ <TextField label="Username"
+ value={ deployUser }
+ onChange={ ( e ) => setDeployUser( e.target.value ) }
+ fullWidth/>
+ </CardContent>
+ <CardActions>
+ <Button type="submit"
+ variant="contained"
+ color="primary">Clone Repository</Button>
+ </CardActions>
+ </form>
+ </Card>
+ </Grid>
+ </Grid>
+ <br/>
- <Typography variant="h5" className="mt-6">Repositories</Typography>
- <MaterialReactTable
- columns={[
- { accessorKey: 'name', header: 'Name' },
- { accessorKey: 'cloneUrl', header: 'Clone URL' },
- {
- header: 'Actions',
- Cell: ({ row }) => (
- <Button
- variant="contained"
- color="secondary"
- onClick={() => handleDeleteRepo(row.original.name)}
- >
- Delete
- </Button>
- ),
- },
- ]}
- data={repos}
- enableRowActions
- renderRowActions={({ row }) => (
- <Button
- onClick={() => navigator.clipboard.writeText(row.original.cloneUrl)}
- >
- Copy Clone URL
- </Button>
- )}
- />
+ <MaterialReactTable table={ gitTable }/>
- {message && <Typography color={message.startsWith('Error') ? 'error' : 'success'}>{message}</Typography>}
+ { message && <Typography color={ message.startsWith( 'Error' ) ? 'error' : 'success' }>{ message }</Typography> }
</Container>
);
};