//Lib import classes from './RepoManage.module.css'; import { IconAlertCircle, IconX } from '@tabler/icons-react'; import { useState } from 'react'; import { useRouter } from 'next/router'; import { toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import { useForm, Controller } from 'react-hook-form'; import { SpinnerDotted } from 'spinners-react'; import Select from 'react-select'; import Link from 'next/link'; import { IconExternalLink } from '@tabler/icons-react'; export default function RepoManage(props) { ////Var let targetRepo; const router = useRouter(); const { register, handleSubmit, control, formState: { errors, isSubmitting, isValid }, } = useForm({ mode: 'onChange' }); //List of possible times for alerts const alertOptions = [ { value: 0, label: 'Disabled' }, { value: 3600, label: '1 hour' }, { value: 21600, label: '6 hours' }, { value: 43200, label: '12 hours' }, { value: 90000, label: '1 day' }, { value: 172800, label: '2 days' }, { value: 259200, label: '3 days' }, { value: 345600, label: '4 days' }, { value: 432000, label: '5 days' }, { value: 518400, label: '6 days' }, { value: 604800, label: '7 days' }, { value: 864000, label: '10 days' }, { value: 1209600, label: '14 days' }, { value: 2592000, label: '30 days' }, ]; const toastOptions = { position: 'top-right', autoClose: 5000, hideProgressBar: false, closeOnClick: true, pauseOnHover: true, draggable: true, progress: undefined, }; ////State const [deleteDialog, setDeleteDialog] = useState(false); const [isLoading, setIsLoading] = useState(false); ////Functions //router.query.slug is undefined for few milliseconds on first render for a direct URL access (https://github.com/vercel/next.js/discussions/11484). //If I call repoManage with edit mode (props), i'm firstly waiting that router.query.slug being available before rendering. if (!router.query.slug && props.mode == 'edit') { return ( ); } else if (props.mode == 'edit') { for (let element in props.repoList) { if (props.repoList[element].id == router.query.slug) { targetRepo = props.repoList[element]; } } //If the ID does not exist > 404 if (!targetRepo) { router.push('/404'); return null; } } //Delete a repo const deleteHandler = async () => { //API Call for delete fetch('/api/repo/id/' + router.query.slug + '/delete', { method: 'DELETE', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ toDelete: true }), }) .then((response) => { if (response.ok) { toast.success( '🗑 The repository #' + router.query.slug + ' has been successfully deleted', toastOptions ); router.replace('/'); } else { toast.error('An error has occurred', toastOptions); router.replace('/'); console.log('Fail to delete'); } }) .catch((error) => { toast.error('An error has occurred', toastOptions); router.replace('/'); console.log(error); }); }; //Verify that the SSH key is unique const isSSHKeyUnique = async (sshPublicKey) => { let isUnique = true; // Extract the first two columns of the SSH key in the form const publicKeyPrefix = sshPublicKey.split(' ').slice(0, 2).join(' '); await fetch('/api/repo', { method: 'GET' }) .then((response) => response.json()) .then((data) => { for (let element in data.repoList) { // Extract the first two columns of the SSH key in the repoList const repoPublicKeyPrefix = data.repoList[ element ].sshPublicKey .split(' ') .slice(0, 2) .join(' '); if ( repoPublicKeyPrefix === publicKeyPrefix && // Compare the first two columns of the SSH key (!targetRepo || data.repoList[element].id != targetRepo.id) ) { toast.error( 'The SSH key is already used in repository #' + data.repoList[element].id + '. Please use another key or delete the key from the other repository.', toastOptions ); isUnique = false; break; } } }) .catch((error) => { console.log(error); toast.error('An error has occurred', toastOptions); isUnique = false; }); return isUnique; }; //Form submit Handler for ADD or EDIT a repo const formSubmitHandler = async (dataForm) => { //Loading button on submit to avoid multiple send. setIsLoading(true); //Verify that the SSH key is unique if (!(await isSSHKeyUnique(dataForm.sshkey))) { setIsLoading(false); return; } //ADD a repo if (props.mode == 'add') { const newRepo = { alias: dataForm.alias, size: dataForm.size, sshPublicKey: dataForm.sshkey, comment: dataForm.comment, alert: dataForm.alert.value, lanCommand: dataForm.lanCommand, }; //POST API to send new repo await fetch('/api/repo/add', { method: 'POST', headers: { 'Content-type': 'application/json', }, body: JSON.stringify(newRepo), }) .then(async (response) => { if (response.ok) { toast.success( 'New repository added ! 🥳', toastOptions ); router.replace('/'); } else { const errorMessage = await response.json(); toast.error( `An error has occurred : ${errorMessage.message}`, toastOptions ); router.replace('/'); console.log(`Fail to ${props.mode}`); } }) .catch((error) => { toast.error('An error has occurred', toastOptions); router.replace('/'); console.log(error); }); //EDIT a repo } else if (props.mode == 'edit') { const dataEdited = { alias: dataForm.alias, size: dataForm.size, sshPublicKey: dataForm.sshkey, comment: dataForm.comment, alert: dataForm.alert.value, lanCommand: dataForm.lanCommand, }; await fetch('/api/repo/id/' + router.query.slug + '/edit', { method: 'PUT', headers: { 'Content-type': 'application/json', }, body: JSON.stringify(dataEdited), }) .then(async (response) => { if (response.ok) { toast.success( 'The repository #' + targetRepo.id + ' has been successfully edited !', toastOptions ); router.replace('/'); } else { const errorMessage = await response.json(); toast.error( `An error has occurred : ${errorMessage.message}`, toastOptions ); router.replace('/'); console.log(`Fail to ${props.mode}`); } }) .catch((error) => { toast.error('An error has occurred', toastOptions); router.replace('/'); console.log(error); }); } }; return ( <>
{deleteDialog ? (

Delete the repository{' '} #{targetRepo.id} {' '} ?

You are about to permanently delete the repository #{targetRepo.id} and all the backups it contains.
The data will not be recoverable and it will not be possible to go back.
{isLoading ? ( ) : ( <> )}
) : (
{props.mode == 'edit' && (

Edit the repository{' '} #{targetRepo.id}

)} {props.mode == 'add' &&

Add a repository

}
{/* ALIAS */} {errors.alias && ( {errors.alias.message} )} {/* SSH KEY */}