Very basic implemention of frontend logic required to display backups and create a new one
This commit is contained in:
parent
17ec4efd3b
commit
9991989f89
16 changed files with 431 additions and 2 deletions
|
@ -0,0 +1,61 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import getServerBackups, { ServerBackup } from '@/api/server/backups/getServerBackups';
|
||||
import useServer from '@/plugins/useServer';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import { httpErrorToHuman } from '@/api/http';
|
||||
import Can from '@/components/elements/Can';
|
||||
import CreateBackupButton from '@/components/server/backups/CreateBackupButton';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
|
||||
export default () => {
|
||||
const { uuid } = useServer();
|
||||
const { addError, clearFlashes } = useFlash();
|
||||
const [ loading, setLoading ] = useState(true);
|
||||
const [ backups, setBackups ] = useState<ServerBackup[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
clearFlashes('backups');
|
||||
getServerBackups(uuid)
|
||||
.then(data => {
|
||||
setBackups(data.items);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
addError({ key: 'backups', message: httpErrorToHuman(error) });
|
||||
})
|
||||
.then(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Spinner size={'large'} centered={true}/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'mt-10 mb-6'}>
|
||||
<FlashMessageRender byKey={'backups'} className={'mb-4'}/>
|
||||
{!backups.length ?
|
||||
<p className="text-center text-sm text-neutral-400">
|
||||
There are no backups stored for this server.
|
||||
</p>
|
||||
:
|
||||
<div>
|
||||
{
|
||||
backups.map(backup => (
|
||||
<div key={backup.uuid}>
|
||||
{backup.uuid}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<Can action={'backup.create'}>
|
||||
<div className={'mt-6 flex justify-end'}>
|
||||
<CreateBackupButton
|
||||
onBackupGenerated={backup => setBackups(s => [...s, backup])}
|
||||
/>
|
||||
</div>
|
||||
</Can>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,118 @@
|
|||
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({
|
||||
name: string().max(255),
|
||||
ignored: string(),
|
||||
})}
|
||||
>
|
||||
<ModalContent
|
||||
appear={true}
|
||||
visible={visible}
|
||||
onDismissed={() => setVisible(false)}
|
||||
/>
|
||||
</Formik>
|
||||
}
|
||||
<button
|
||||
className={'btn btn-primary btn-sm'}
|
||||
onClick={() => setVisible(true)}
|
||||
>
|
||||
Create backup
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue