misc_pterodactyl-panel/resources/scripts/components/server/backups/CreateBackupButton.tsx

110 lines
4.1 KiB
TypeScript
Raw Normal View History

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';
2020-04-07 05:25:54 +00:00
import { ServerContext } from '@/state/server';
2020-07-04 23:26:07 +00:00
import Button from '@/components/elements/Button';
import tw from 'twin.macro';
import Input, { Textarea } from '@/components/elements/Input';
interface Values {
name: string;
ignored: string;
}
const ModalContent = ({ ...props }: RequiredModalProps) => {
const { isSubmitting } = useFormikContext<Values>();
return (
<Modal {...props} showSpinnerOverlay={isSubmitting}>
2020-07-04 23:26:07 +00:00
<Form>
<FlashMessageRender byKey={'backups:create'} css={tw`mb-4`}/>
<h2 css={tw`text-2xl mb-6`}>Create server backup</h2>
<div css={tw`mb-6`}>
<Field
name={'name'}
label={'Backup name'}
description={'If provided, the name that should be used to reference this backup.'}
/>
</div>
2020-07-04 23:26:07 +00:00
<div css={tw`mb-6`}>
<FormikFieldWrapper
name={'ignored'}
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.
`}
>
2020-07-04 23:26:07 +00:00
<FormikField as={Textarea} name={'ignored'} css={tw`h-32`}/>
</FormikFieldWrapper>
</div>
2020-07-04 23:26:07 +00:00
<div css={tw`flex justify-end`}>
<Button type={'submit'}>
Start backup
2020-07-04 23:26:07 +00:00
</Button>
</div>
</Form>
</Modal>
);
};
2020-04-07 05:25:54 +00:00
export default () => {
const { uuid } = useServer();
const { addError, clearFlashes } = useFlash();
const [ visible, setVisible ] = useState(false);
2020-04-07 05:25:54 +00:00
const appendBackup = ServerContext.useStoreActions(actions => actions.backups.appendBackup);
useEffect(() => {
clearFlashes('backups:create');
2020-04-07 05:25:54 +00:00
}, [ visible ]);
const submit = ({ name, ignored }: Values, { setSubmitting }: FormikHelpers<Values>) => {
2020-04-07 05:25:54 +00:00
clearFlashes('backups:create');
createServerBackup(uuid, name, ignored)
.then(backup => {
2020-04-07 05:25:54 +00:00
appendBackup(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),
ignored: string(),
})}
>
<ModalContent
2020-07-04 23:26:07 +00:00
appear
visible={visible}
onDismissed={() => setVisible(false)}
/>
</Formik>
}
2020-07-04 23:26:07 +00:00
<Button onClick={() => setVisible(true)}>
Create backup
2020-07-04 23:26:07 +00:00
</Button>
</>
);
};