Skip to content

Commit b2be067

Browse files
committed
Support deleting an allocation for a server
1 parent 365f5e0 commit b2be067

File tree

8 files changed

+94
-35
lines changed

8 files changed

+94
-35
lines changed

app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,19 @@ public function store(NewAllocationRequest $request, Server $server): array
138138
* @return \Illuminate\Http\JsonResponse
139139
*
140140
* @throws \Pterodactyl\Exceptions\DisplayException
141-
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
142-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
143141
*/
144142
public function delete(DeleteAllocationRequest $request, Server $server, Allocation $allocation)
145143
{
146144
if ($allocation->id === $server->allocation_id) {
147145
throw new DisplayException(
148-
'Cannot delete the primary allocation for a server.'
146+
'You cannot delete the primary allocation for this server.'
149147
);
150148
}
151149

152-
$this->repository->update($allocation->id, ['server_id' => null, 'notes' => null]);
150+
Allocation::query()->where('id', $allocation->id)->update([
151+
'notes' => null,
152+
'server_id' => null,
153+
]);
153154

154155
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
155156
}

app/Services/Allocations/FindAssignableAllocationService.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ protected function createNewAllocation(Server $server): Allocation
108108
throw new NoAutoAllocationSpaceAvailableException;
109109
}
110110

111-
// dd($available, array_rand($available));
112111
// Pick a random port out of the remaining available ports.
113112
/** @var int $port */
114113
$port = $available[array_rand($available)];

resources/scripts/api/server/network/getServerAllocations.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { ServerContext } from '@/state/server';
2+
import useSWR from 'swr';
3+
import http from '@/api/http';
4+
import { rawDataToServerAllocation } from '@/api/transformers';
5+
import { Allocation } from '@/api/server/getServer';
6+
7+
export default (initialData?: Allocation[]) => {
8+
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
9+
10+
return useSWR<Allocation[]>([ 'server:allocations', uuid ], async () => {
11+
const { data } = await http.get(`/api/client/servers/${uuid}/network/allocations`);
12+
13+
return (data.data || []).map(rawDataToServerAllocation);
14+
}, { initialData, revalidateOnFocus: false });
15+
};

resources/scripts/components/elements/ConfirmationModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const ConfirmationModal = ({ title, children, buttonText, onConfirmed }: Props)
2020
<h2 css={tw`text-2xl mb-6`}>{title}</h2>
2121
<p css={tw`text-sm`}>{children}</p>
2222
<div css={tw`flex flex-wrap items-center justify-end mt-8`}>
23-
<Button isSecondary onClick={() => dismiss()} css={tw`w-full sm:w-auto`}>
23+
<Button isSecondary onClick={() => dismiss()} css={tw`w-full sm:w-auto border-transparent`}>
2424
Cancel
2525
</Button>
2626
<Button color={'red'} css={tw`w-full sm:w-auto mt-4 sm:mt-0 sm:ml-4`} onClick={() => onConfirmed()}>

resources/scripts/components/server/network/AllocationRow.tsx

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import setServerAllocationNotes from '@/api/server/network/setServerAllocationNo
1515
import useFlash from '@/plugins/useFlash';
1616
import { ServerContext } from '@/state/server';
1717
import CopyOnClick from '@/components/elements/CopyOnClick';
18+
import DeleteAllocationButton from '@/components/server/network/DeleteAllocationButton';
1819

1920
const Code = styled.code`${tw`font-mono py-1 px-2 bg-neutral-900 rounded text-sm inline-block`}`;
2021
const Label = styled.label`${tw`uppercase text-xs mt-1 text-neutral-400 block px-1 select-none transition-colors duration-150`}`;
@@ -44,10 +45,11 @@ const AllocationRow = ({ allocation, onSetPrimary, onNotesChanged }: Props) => {
4445
<GreyRowBox $hoverable={false} css={tw`flex-wrap md:flex-no-wrap mt-2`}>
4546
<div css={tw`flex items-center w-full md:w-auto`}>
4647
<div css={tw`pl-4 pr-6 text-neutral-400`}>
47-
<FontAwesomeIcon icon={faNetworkWired} />
48+
<FontAwesomeIcon icon={faNetworkWired}/>
4849
</div>
4950
<div css={tw`mr-4 flex-1 md:w-40`}>
50-
{allocation.alias ? <CopyOnClick text={allocation.alias}><Code css={tw`w-40 truncate`}>{allocation.alias}</Code></CopyOnClick> :
51+
{allocation.alias ?
52+
<CopyOnClick text={allocation.alias}><Code css={tw`w-40 truncate`}>{allocation.alias}</Code></CopyOnClick> :
5153
<CopyOnClick text={allocation.ip}><Code>{allocation.ip}</Code></CopyOnClick>}
5254
<Label>{allocation.alias ? 'Hostname' : 'IP Address'}</Label>
5355
</div>
@@ -66,20 +68,25 @@ const AllocationRow = ({ allocation, onSetPrimary, onNotesChanged }: Props) => {
6668
/>
6769
</InputSpinner>
6870
</div>
69-
<div css={tw`w-full md:flex-none md:w-32 md:text-center mt-4 md:mt-0 text-right ml-4`}>
71+
<div css={tw`w-full md:flex-none md:w-40 md:text-center mt-4 md:mt-0 ml-4 flex items-center justify-end`}>
7072
{allocation.isDefault ?
7173
<span css={tw`bg-green-500 py-1 px-2 rounded text-green-50 text-xs`}>Primary</span>
7274
:
73-
<Can action={'allocations.update'}>
74-
<Button
75-
isSecondary
76-
size={'xsmall'}
77-
color={'primary'}
78-
onClick={() => onSetPrimary(allocation.id)}
79-
>
80-
Make Primary
81-
</Button>
82-
</Can>
75+
<>
76+
<Can action={'allocations.delete'}>
77+
<DeleteAllocationButton allocation={allocation.id}/>
78+
</Can>
79+
<Can action={'allocations.update'}>
80+
<Button
81+
isSecondary
82+
size={'xsmall'}
83+
color={'primary'}
84+
onClick={() => onSetPrimary(allocation.id)}
85+
>
86+
Make Primary
87+
</Button>
88+
</Can>
89+
</>
8390
}
8491
</div>
8592
</GreyRowBox>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { useState } from 'react';
2+
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
3+
import tw from 'twin.macro';
4+
import Icon from '@/components/elements/Icon';
5+
import ConfirmationModal from '@/components/elements/ConfirmationModal';
6+
import { ServerContext } from '@/state/server';
7+
import deleteServerAllocation from '@/api/server/network/deleteServerAllocation';
8+
import getServerAllocations from '@/api/swr/getServerAllocations';
9+
import useFlash from '@/plugins/useFlash';
10+
11+
interface Props {
12+
allocation: number;
13+
}
14+
15+
const DeleteAllocationButton = ({ allocation }: Props) => {
16+
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
17+
const [ confirm, setConfirm ] = useState(false);
18+
const { mutate } = getServerAllocations();
19+
const { clearFlashes, clearAndAddHttpError } = useFlash();
20+
21+
const deleteAllocation = () => {
22+
clearFlashes('server:network');
23+
24+
mutate(data => data?.filter(a => a.id !== allocation), false);
25+
deleteServerAllocation(uuid, allocation)
26+
.catch(error => clearAndAddHttpError({ key: 'server:network', error }));
27+
};
28+
29+
return (
30+
<>
31+
<ConfirmationModal
32+
visible={confirm}
33+
title={'Remove this allocation?'}
34+
buttonText={'Delete'}
35+
onConfirmed={deleteAllocation}
36+
onModalDismissed={() => setConfirm(false)}
37+
>
38+
This allocation will be immediately removed from your server. Are you sure you want to continue?
39+
</ConfirmationModal>
40+
<button
41+
css={tw`text-neutral-400 px-2 py-1 mr-2 transition-colors duration-150 hover:text-red-400`}
42+
type={'button'}
43+
onClick={() => setConfirm(true)}
44+
>
45+
<Icon icon={faTrashAlt} css={tw`w-3 h-auto`}/>
46+
</button>
47+
</>
48+
);
49+
};
50+
51+
export default DeleteAllocationButton;

resources/scripts/components/server/network/NetworkContainer.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
import React, { useCallback, useEffect, useState } from 'react';
2-
import useSWR from 'swr';
3-
import getServerAllocations from '@/api/server/network/getServerAllocations';
4-
import { Allocation } from '@/api/server/getServer';
52
import Spinner from '@/components/elements/Spinner';
63
import useFlash from '@/plugins/useFlash';
74
import ServerContentBlock from '@/components/elements/ServerContentBlock';
@@ -14,6 +11,7 @@ import createServerAllocation from '@/api/server/network/createServerAllocation'
1411
import tw from 'twin.macro';
1512
import Can from '@/components/elements/Can';
1613
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
14+
import getServerAllocations from '@/api/swr/getServerAllocations';
1715

1816
const NetworkContainer = () => {
1917
const [ loading, setLoading ] = useState(false);
@@ -22,10 +20,7 @@ const NetworkContainer = () => {
2220
const allocations = useDeepMemoize(ServerContext.useStoreState(state => state.server.data!.allocations));
2321

2422
const { clearFlashes, clearAndAddHttpError } = useFlash();
25-
const { data, error, mutate } = useSWR<Allocation[]>(uuid, key => getServerAllocations(key), {
26-
initialData: allocations,
27-
revalidateOnFocus: false,
28-
});
23+
const { data, error, mutate } = getServerAllocations(allocations);
2924

3025
useEffect(() => {
3126
if (error) {

0 commit comments

Comments
 (0)