diff --git a/resources/scripts/api/server/backups/index.ts b/resources/scripts/api/server/backups/index.ts new file mode 100644 index 000000000..016836364 --- /dev/null +++ b/resources/scripts/api/server/backups/index.ts @@ -0,0 +1,5 @@ +import http from '@/api/http'; + +export const restoreServerBackup = async (uuid: string, backup: string): Promise => { + await http.post(`/api/client/servers/${uuid}/backups/${backup}/restore`); +}; diff --git a/resources/scripts/assets/images/not_found.svg b/resources/scripts/assets/images/not_found.svg new file mode 100644 index 000000000..222a4152e --- /dev/null +++ b/resources/scripts/assets/images/not_found.svg @@ -0,0 +1 @@ +not found \ No newline at end of file diff --git a/resources/scripts/assets/images/pterodactyl.svg b/resources/scripts/assets/images/pterodactyl.svg new file mode 100755 index 000000000..f3582adf2 --- /dev/null +++ b/resources/scripts/assets/images/pterodactyl.svg @@ -0,0 +1 @@ +Artboard 1 \ No newline at end of file diff --git a/resources/scripts/assets/images/server_error.svg b/resources/scripts/assets/images/server_error.svg new file mode 100644 index 000000000..726fa106d --- /dev/null +++ b/resources/scripts/assets/images/server_error.svg @@ -0,0 +1 @@ +server down \ No newline at end of file diff --git a/resources/scripts/assets/images/server_installing.svg b/resources/scripts/assets/images/server_installing.svg new file mode 100644 index 000000000..d2a0ae48b --- /dev/null +++ b/resources/scripts/assets/images/server_installing.svg @@ -0,0 +1 @@ +uploading \ No newline at end of file diff --git a/resources/scripts/assets/images/server_restore.svg b/resources/scripts/assets/images/server_restore.svg new file mode 100644 index 000000000..ce36a8d44 --- /dev/null +++ b/resources/scripts/assets/images/server_restore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/scripts/components/App.tsx b/resources/scripts/components/App.tsx index ef08fc00c..d733538b0 100644 --- a/resources/scripts/components/App.tsx +++ b/resources/scripts/components/App.tsx @@ -9,7 +9,7 @@ import ServerRouter from '@/routers/ServerRouter'; import AuthenticationRouter from '@/routers/AuthenticationRouter'; import { SiteSettings } from '@/state/settings'; import ProgressBar from '@/components/elements/ProgressBar'; -import NotFound from '@/components/screens/NotFound'; +import { NotFound } from '@/components/elements/ScreenBlock'; import tw, { GlobalStyles as TailwindGlobalStyles } from 'twin.macro'; import GlobalStylesheet from '@/assets/css/GlobalStylesheet'; import { history } from '@/components/history'; diff --git a/resources/scripts/components/screens/ScreenBlock.tsx b/resources/scripts/components/elements/ScreenBlock.tsx similarity index 67% rename from resources/scripts/components/screens/ScreenBlock.tsx rename to resources/scripts/components/elements/ScreenBlock.tsx index 30b0faa7f..7eb665717 100644 --- a/resources/scripts/components/screens/ScreenBlock.tsx +++ b/resources/scripts/components/elements/ScreenBlock.tsx @@ -5,6 +5,8 @@ import { faArrowLeft, faSyncAlt } from '@fortawesome/free-solid-svg-icons'; import styled, { keyframes } from 'styled-components/macro'; import tw from 'twin.macro'; import Button from '@/components/elements/Button'; +import NotFoundSvg from '@/assets/images/not_found.svg'; +import ServerErrorSvg from '@/assets/images/server_error.svg'; interface BaseProps { title: string; @@ -16,15 +18,15 @@ interface BaseProps { interface PropsWithRetry extends BaseProps { onRetry?: () => void; - onBack?: never | undefined; + onBack?: never; } interface PropsWithBack extends BaseProps { onBack?: () => void; - onRetry?: never | undefined; + onRetry?: never; } -type Props = PropsWithBack | PropsWithRetry; +export type ScreenBlockProps = PropsWithBack | PropsWithRetry; const spin = keyframes` to { transform: rotate(360deg) } @@ -38,7 +40,7 @@ const ActionButton = styled(Button)` } `; -export default ({ title, image, message, onBack, onRetry }: Props) => ( +const ScreenBlock = ({ title, image, message, onBack, onRetry }: ScreenBlockProps) => (
@@ -61,3 +63,23 @@ export default ({ title, image, message, onBack, onRetry }: Props) => (
); + +type ServerErrorProps = (Omit | Omit) & { + title?: string; +} + +const ServerError = ({ title, ...props }: ServerErrorProps) => ( + +); + +const NotFound = ({ title, message, onBack }: Partial>) => ( + +); + +export { ServerError, NotFound }; +export default ScreenBlock; diff --git a/resources/scripts/components/screens/NotFound.tsx b/resources/scripts/components/screens/NotFound.tsx deleted file mode 100644 index 4ea11e0bb..000000000 --- a/resources/scripts/components/screens/NotFound.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import ScreenBlock from '@/components/screens/ScreenBlock'; - -interface Props { - title?: string; - message?: string; - onBack?: () => void; -} - -export default ({ title, message, onBack }: Props) => ( - -); diff --git a/resources/scripts/components/screens/ServerError.tsx b/resources/scripts/components/screens/ServerError.tsx deleted file mode 100644 index b05dd3f14..000000000 --- a/resources/scripts/components/screens/ServerError.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import ScreenBlock from '@/components/screens/ScreenBlock'; - -interface Props { - title?: string; - message: string; - onRetry?: () => void; - onBack?: () => void; -} - -export default ({ title, message, onBack, onRetry }: Props) => ( - // @ts-ignore - -); diff --git a/resources/scripts/components/server/backups/BackupContextMenu.tsx b/resources/scripts/components/server/backups/BackupContextMenu.tsx index f687d8abe..33cd327b7 100644 --- a/resources/scripts/components/server/backups/BackupContextMenu.tsx +++ b/resources/scripts/components/server/backups/BackupContextMenu.tsx @@ -14,6 +14,7 @@ import getServerBackups from '@/api/swr/getServerBackups'; import { ServerBackup } from '@/api/server/types'; import { ServerContext } from '@/state/server'; import Input from '@/components/elements/Input'; +import { restoreServerBackup } from '@/api/server/backups'; interface Props { backup: ServerBackup; @@ -21,10 +22,9 @@ interface Props { export default ({ backup }: Props) => { const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); + const setServerFromState = ServerContext.useStoreActions(actions => actions.server.setServerFromState); + const [ modal, setModal ] = useState(''); const [ loading, setLoading ] = useState(false); - const [ visible, setVisible ] = useState(false); - const [ deleteVisible, setDeleteVisible ] = useState(false); - const [ restoreVisible, setRestoreVisible ] = useState(false); const { clearFlashes, clearAndAddHttpError } = useFlash(); const { mutate } = getServerBackups(); @@ -47,36 +47,47 @@ export default ({ backup }: Props) => { setLoading(true); clearFlashes('backups'); deleteBackup(uuid, backup.uuid) - .then(() => { - mutate(data => ({ - ...data, - items: data.items.filter(b => b.uuid !== backup.uuid), - }), false); - }) + .then(() => mutate(data => ({ + ...data, + items: data.items.filter(b => b.uuid !== backup.uuid), + }), false)) .catch(error => { console.error(error); clearAndAddHttpError({ key: 'backups', error }); setLoading(false); - setDeleteVisible(false); + setModal(''); }); }; + const doRestorationAction = () => { + setLoading(true); + clearFlashes('backups'); + restoreServerBackup(uuid, backup.uuid) + .then(() => setServerFromState(s => ({ + ...s, + status: 'restoring_backup', + }))) + .catch(error => { + console.error(error); + clearAndAddHttpError({ key: 'backups', error }); + }) + .then(() => setLoading(false)); + }; + return ( <> - {visible && setVisible(false)} + visible={modal === 'checksum'} + onDismissed={() => setModal('')} checksum={backup.checksum} /> - } null} - onModalDismissed={() => setRestoreVisible(false)} + onConfirmed={() => doRestorationAction()} + onModalDismissed={() => setModal('')} >

This server will be stopped in order to restore the backup. Once the backup has started you will @@ -87,7 +98,10 @@ export default ({ backup }: Props) => { Are you sure you want to continue?

-

doDeletion()} - onModalDismissed={() => setDeleteVisible(false)} + onModalDismissed={() => setModal('')} > Are you sure you wish to delete this backup? This is a permanent operation and the backup cannot be recovered once deleted. @@ -122,23 +136,23 @@ export default ({ backup }: Props) => { >
- doDownload()}> + Download - setRestoreVisible(true)}> + setModal('restore')}> Restore - setVisible(true)}> + setModal('checksum')}> Checksum - setDeleteVisible(true)}> + setModal('delete')}> Delete @@ -147,7 +161,7 @@ export default ({ backup }: Props) => { :