2020-04-04 17:59:25 +00: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 19:30:45 +00:00
|
|
|
name: string().max(255),
|
2020-04-04 17:59:25 +00: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>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|