2020-04-04 18:59:25 +01:00
import React , { useEffect , useState } from 'react' ;
import Modal , { RequiredModalProps } from '@/components/elements/Modal' ;
import { Field as FormikField , Form , Formik , FormikHelpers , useFormikContext } from 'formik' ;
import { object , string } from 'yup' ;
import Field from '@/components/elements/Field' ;
import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper' ;
import useFlash from '@/plugins/useFlash' ;
import useServer from '@/plugins/useServer' ;
import createServerBackup from '@/api/server/backups/createServerBackup' ;
import { httpErrorToHuman } from '@/api/http' ;
import FlashMessageRender from '@/components/FlashMessageRender' ;
import { ServerBackup } from '@/api/server/backups/getServerBackups' ;
interface Values {
name : string ;
ignored : string ;
}
interface Props {
onBackupGenerated : ( backup : ServerBackup ) = > void ;
}
const ModalContent = ( { . . . props } : RequiredModalProps ) = > {
const { isSubmitting } = useFormikContext < Values > ( ) ;
return (
< Modal { ...props } showSpinnerOverlay = { isSubmitting } >
< Form className = { 'pb-6' } >
< FlashMessageRender byKey = { 'backups:create' } className = { 'mb-4' } / >
< h3 className = { 'mb-6' } > Create server backup < / h3 >
< div className = { 'mb-6' } >
< Field
name = { 'name' }
label = { 'Backup name' }
description = { 'If provided, the name that should be used to reference this backup.' }
/ >
< / div >
< div className = { 'mb-6' } >
< FormikFieldWrapper
name = { 'ignore' }
label = { 'Ignored Files & Directories' }
description = { `
Enter the files or folders to ignore while generating this backup . Leave blank to use
the contents of the . pteroignore file in the root of the server directory if present .
Wildcard matching of files and folders is supported in addition to negating a rule by
prefixing the path with an exclamation point .
` }
>
< FormikField
name = { 'contents' }
component = { 'textarea' }
className = { 'input-dark h-32' }
/ >
< / FormikFieldWrapper >
< / div >
< div className = { 'flex justify-end' } >
< button
type = { 'submit' }
className = { 'btn btn-primary btn-sm' }
>
Start backup
< / button >
< / div >
< / Form >
< / Modal >
) ;
} ;
export default ( { onBackupGenerated } : Props ) = > {
const { uuid } = useServer ( ) ;
const { addError , clearFlashes } = useFlash ( ) ;
const [ visible , setVisible ] = useState ( false ) ;
useEffect ( ( ) = > {
clearFlashes ( 'backups:create' ) ;
} , [ visible ] ) ;
const submit = ( { name , ignored } : Values , { setSubmitting } : FormikHelpers < Values > ) = > {
clearFlashes ( 'backups:create' )
createServerBackup ( uuid , name , ignored )
. then ( backup = > {
onBackupGenerated ( backup ) ;
setVisible ( false ) ;
} )
. catch ( error = > {
console . error ( error ) ;
addError ( { key : 'backups:create' , message : httpErrorToHuman ( error ) } ) ;
setSubmitting ( false ) ;
} ) ;
} ;
return (
< >
{ visible &&
< Formik
onSubmit = { submit }
initialValues = { { name : '' , ignored : '' } }
validationSchema = { object ( ) . shape ( {
2020-04-04 20:26:39 +01:00
name : string ( ) . required ( )
. matches ( /^[w\][\w\s_.-]*[\w]$/ , 'Backup name must only contain alpha-numeric characters, spaces, underscores, dashes, and periods. The name must start and end with an alpha-numeric character.' )
. max ( 255 ) ,
2020-04-04 18:59:25 +01:00
ignored : string ( ) ,
} ) }
>
< ModalContent
appear = { true }
visible = { visible }
onDismissed = { ( ) = > setVisible ( false ) }
/ >
< / Formik >
}
< button
className = { 'btn btn-primary btn-sm' }
onClick = { ( ) = > setVisible ( true ) }
>
Create backup
< / button >
< / >
) ;
} ;