Support pagination of server backups, closes #2787
This commit is contained in:
parent
8a97b73a6c
commit
a8d9eccf9c
|
@ -60,7 +60,8 @@ class BackupController extends ClientApiController
|
||||||
*/
|
*/
|
||||||
public function index(GetBackupsRequest $request, Server $server)
|
public function index(GetBackupsRequest $request, Server $server)
|
||||||
{
|
{
|
||||||
return $this->fractal->collection($server->backups()->paginate(20))
|
$limit = min($request->query('per_page') ?? 20, 50);
|
||||||
|
return $this->fractal->collection($server->backups()->paginate($limit))
|
||||||
->transformWith($this->getTransformer(BackupTransformer::class))
|
->transformWith($this->getTransformer(BackupTransformer::class))
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,17 @@ import http, { getPaginationSet, PaginatedResult } from '@/api/http';
|
||||||
import { ServerBackup } from '@/api/server/types';
|
import { ServerBackup } from '@/api/server/types';
|
||||||
import { rawDataToServerBackup } from '@/api/transformers';
|
import { rawDataToServerBackup } from '@/api/transformers';
|
||||||
import { ServerContext } from '@/state/server';
|
import { ServerContext } from '@/state/server';
|
||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
|
||||||
export default (page?: number | string) => {
|
interface ctx {
|
||||||
|
page: number;
|
||||||
|
setPage: (value: number | ((s: number) => number)) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Context = createContext<ctx>({ page: 1, setPage: () => 1 });
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const { page } = useContext(Context);
|
||||||
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
||||||
|
|
||||||
return useSWR<PaginatedResult<ServerBackup>>([ 'server:backups', uuid, page ], async () => {
|
return useSWR<PaginatedResult<ServerBackup>>([ 'server:backups', uuid, page ], async () => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ const ApiKeyModal = ({ apiKey }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3 css={tw`mb-6`}>Your API Key</h3>
|
<h3 css={tw`mb-6 text-2xl`}>Your API Key</h3>
|
||||||
<p css={tw`text-sm mb-6`}>
|
<p css={tw`text-sm mb-6`}>
|
||||||
The API key you have requested is shown below. Please store this in a safe location, it will not be
|
The API key you have requested is shown below. Please store this in a safe location, it will not be
|
||||||
shown again.
|
shown again.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import Spinner from '@/components/elements/Spinner';
|
import Spinner from '@/components/elements/Spinner';
|
||||||
import useFlash from '@/plugins/useFlash';
|
import useFlash from '@/plugins/useFlash';
|
||||||
import Can from '@/components/elements/Can';
|
import Can from '@/components/elements/Can';
|
||||||
|
@ -6,11 +6,13 @@ import CreateBackupButton from '@/components/server/backups/CreateBackupButton';
|
||||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||||
import BackupRow from '@/components/server/backups/BackupRow';
|
import BackupRow from '@/components/server/backups/BackupRow';
|
||||||
import tw from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
import getServerBackups from '@/api/swr/getServerBackups';
|
import getServerBackups, { Context as ServerBackupContext } from '@/api/swr/getServerBackups';
|
||||||
import { ServerContext } from '@/state/server';
|
import { ServerContext } from '@/state/server';
|
||||||
import ServerContentBlock from '@/components/elements/ServerContentBlock';
|
import ServerContentBlock from '@/components/elements/ServerContentBlock';
|
||||||
|
import Pagination from '@/components/elements/Pagination';
|
||||||
|
|
||||||
export default () => {
|
const BackupContainer = () => {
|
||||||
|
const { page, setPage } = useContext(ServerBackupContext);
|
||||||
const { clearFlashes, clearAndAddHttpError } = useFlash();
|
const { clearFlashes, clearAndAddHttpError } = useFlash();
|
||||||
const { data: backups, error, isValidating } = getServerBackups();
|
const { data: backups, error, isValidating } = getServerBackups();
|
||||||
|
|
||||||
|
@ -33,19 +35,29 @@ export default () => {
|
||||||
return (
|
return (
|
||||||
<ServerContentBlock title={'Backups'}>
|
<ServerContentBlock title={'Backups'}>
|
||||||
<FlashMessageRender byKey={'backups'} css={tw`mb-4`}/>
|
<FlashMessageRender byKey={'backups'} css={tw`mb-4`}/>
|
||||||
{!backups.items.length ?
|
<Pagination data={backups} onPageSelect={setPage}>
|
||||||
|
{({ items }) => (
|
||||||
|
!items.length ?
|
||||||
|
// Don't show any error messages if the server has no backups and the user cannot
|
||||||
|
// create additional ones for the server.
|
||||||
|
!backupLimit ?
|
||||||
|
null
|
||||||
|
:
|
||||||
<p css={tw`text-center text-sm text-neutral-300`}>
|
<p css={tw`text-center text-sm text-neutral-300`}>
|
||||||
There are no backups stored for this server.
|
{page > 1 ?
|
||||||
|
'Looks like we\'ve run out of backups to show you, try going back a page.'
|
||||||
|
:
|
||||||
|
'It looks like there are no backups currently stored for this server.'
|
||||||
|
}
|
||||||
</p>
|
</p>
|
||||||
:
|
:
|
||||||
<div>
|
items.map((backup, index) => <BackupRow
|
||||||
{backups.items.map((backup, index) => <BackupRow
|
|
||||||
key={backup.uuid}
|
key={backup.uuid}
|
||||||
backup={backup}
|
backup={backup}
|
||||||
css={index > 0 ? tw`mt-2` : undefined}
|
css={index > 0 ? tw`mt-2` : undefined}
|
||||||
/>)}
|
/>)
|
||||||
</div>
|
)}
|
||||||
}
|
</Pagination>
|
||||||
{backupLimit === 0 &&
|
{backupLimit === 0 &&
|
||||||
<p css={tw`text-center text-sm text-neutral-300`}>
|
<p css={tw`text-center text-sm text-neutral-300`}>
|
||||||
Backups cannot be created for this server.
|
Backups cannot be created for this server.
|
||||||
|
@ -66,3 +78,12 @@ export default () => {
|
||||||
</ServerContentBlock>
|
</ServerContentBlock>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const [ page, setPage ] = useState<number>(1);
|
||||||
|
return (
|
||||||
|
<ServerBackupContext.Provider value={{ page, setPage }}>
|
||||||
|
<BackupContainer/>
|
||||||
|
</ServerBackupContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ import tw from 'twin.macro';
|
||||||
|
|
||||||
const ChecksumModal = ({ checksum, ...props }: RequiredModalProps & { checksum: string }) => (
|
const ChecksumModal = ({ checksum, ...props }: RequiredModalProps & { checksum: string }) => (
|
||||||
<Modal {...props}>
|
<Modal {...props}>
|
||||||
<h3 css={tw`mb-6`}>Verify file checksum</h3>
|
<h3 css={tw`mb-6 text-2xl`}>Verify file checksum</h3>
|
||||||
<p css={tw`text-sm`}>
|
<p css={tw`text-sm`}>
|
||||||
The checksum of this file is:
|
The checksum of this file is:
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -111,7 +111,7 @@ export default ({ database, className }: Props) => {
|
||||||
</Formik>
|
</Formik>
|
||||||
<Modal visible={connectionVisible} onDismissed={() => setConnectionVisible(false)}>
|
<Modal visible={connectionVisible} onDismissed={() => setConnectionVisible(false)}>
|
||||||
<FlashMessageRender byKey={'database-connection-modal'} css={tw`mb-6`}/>
|
<FlashMessageRender byKey={'database-connection-modal'} css={tw`mb-6`}/>
|
||||||
<h3 css={tw`mb-6`}>Database connection details</h3>
|
<h3 css={tw`mb-6 text-2xl`}>Database connection details</h3>
|
||||||
<div>
|
<div>
|
||||||
<Label>Endpoint</Label>
|
<Label>Endpoint</Label>
|
||||||
<CopyOnClick text={database.connectionString}><Input type={'text'} readOnly value={database.connectionString} /></CopyOnClick>
|
<CopyOnClick text={database.connectionString}><Input type={'text'} readOnly value={database.connectionString} /></CopyOnClick>
|
||||||
|
|
Loading…
Reference in New Issue