103 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 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 createServerBackup from '@/api/server/backups/createServerBackup';
 | |
| import FlashMessageRender from '@/components/FlashMessageRender';
 | |
| import Button from '@/components/elements/Button';
 | |
| import tw from 'twin.macro';
 | |
| import { Textarea } from '@/components/elements/Input';
 | |
| import getServerBackups from '@/api/swr/getServerBackups';
 | |
| import { ServerContext } from '@/state/server';
 | |
| 
 | |
| interface Values {
 | |
|     name: string;
 | |
|     ignored: string;
 | |
| }
 | |
| 
 | |
| const ModalContent = ({ ...props }: RequiredModalProps) => {
 | |
|     const { isSubmitting } = useFormikContext<Values>();
 | |
| 
 | |
|     return (
 | |
|         <Modal {...props} showSpinnerOverlay={isSubmitting}>
 | |
|             <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>
 | |
|                 <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.
 | |
|                         `}
 | |
|                     >
 | |
|                         <FormikField as={Textarea} name={'ignored'} rows={6}/>
 | |
|                     </FormikFieldWrapper>
 | |
|                 </div>
 | |
|                 <div css={tw`flex justify-end`}>
 | |
|                     <Button type={'submit'} disabled={isSubmitting}>
 | |
|                         Start backup
 | |
|                     </Button>
 | |
|                 </div>
 | |
|             </Form>
 | |
|         </Modal>
 | |
|     );
 | |
| };
 | |
| 
 | |
| export default () => {
 | |
|     const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
 | |
|     const { clearFlashes, clearAndAddHttpError } = useFlash();
 | |
|     const [ visible, setVisible ] = useState(false);
 | |
|     const { mutate } = getServerBackups();
 | |
| 
 | |
|     useEffect(() => {
 | |
|         clearFlashes('backups:create');
 | |
|     }, [ visible ]);
 | |
| 
 | |
|     const submit = ({ name, ignored }: Values, { setSubmitting }: FormikHelpers<Values>) => {
 | |
|         clearFlashes('backups:create');
 | |
|         createServerBackup(uuid, name, ignored)
 | |
|             .then(backup => {
 | |
|                 mutate(data => ({ ...data, items: data.items.concat(backup) }), false);
 | |
|                 setVisible(false);
 | |
|             })
 | |
|             .catch(error => {
 | |
|                 clearAndAddHttpError({ key: 'backups:create', error });
 | |
|                 setSubmitting(false);
 | |
|             });
 | |
|     };
 | |
| 
 | |
|     return (
 | |
|         <>
 | |
|             {visible &&
 | |
|             <Formik
 | |
|                 onSubmit={submit}
 | |
|                 initialValues={{ name: '', ignored: '' }}
 | |
|                 validationSchema={object().shape({
 | |
|                     name: string().max(191),
 | |
|                     ignored: string(),
 | |
|                 })}
 | |
|             >
 | |
|                 <ModalContent appear visible={visible} onDismissed={() => setVisible(false)}/>
 | |
|             </Formik>
 | |
|             }
 | |
|             <Button css={tw`w-full sm:w-auto`} onClick={() => setVisible(true)}>
 | |
|                 Create backup
 | |
|             </Button>
 | |
|         </>
 | |
|     );
 | |
| };
 | 
