From b070efce98825d88f93081b3683c6c96292ece36 Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Sun, 3 Oct 2021 16:28:58 -0600 Subject: [PATCH] ui(admin): add allocation delete button --- .../nodes/allocations/deleteAllocation.ts | 9 +++ .../admin/nodes/allocations/getAllocations.ts | 2 +- .../admin/nodes/NodeAllocationContainer.tsx | 4 +- .../nodes/allocations/AllocationTable.tsx | 26 +++++++- .../allocations/CreateAllocationForm.tsx | 2 +- .../allocations/DeleteAllocationButton.tsx | 62 +++++++++++++++++++ .../scripts/components/elements/Button.tsx | 3 +- 7 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 resources/scripts/api/admin/nodes/allocations/deleteAllocation.ts create mode 100644 resources/scripts/components/admin/nodes/allocations/DeleteAllocationButton.tsx diff --git a/resources/scripts/api/admin/nodes/allocations/deleteAllocation.ts b/resources/scripts/api/admin/nodes/allocations/deleteAllocation.ts new file mode 100644 index 000000000..f4a775183 --- /dev/null +++ b/resources/scripts/api/admin/nodes/allocations/deleteAllocation.ts @@ -0,0 +1,9 @@ +import http from '@/api/http'; + +export default (nodeId: number, allocationId: number): Promise => { + return new Promise((resolve, reject) => { + http.delete(`/api/application/nodes/${nodeId}/allocations/${allocationId}`) + .then(() => resolve()) + .catch(reject); + }); +}; diff --git a/resources/scripts/api/admin/nodes/allocations/getAllocations.ts b/resources/scripts/api/admin/nodes/allocations/getAllocations.ts index 55d01152b..14c99c655 100644 --- a/resources/scripts/api/admin/nodes/allocations/getAllocations.ts +++ b/resources/scripts/api/admin/nodes/allocations/getAllocations.ts @@ -12,7 +12,7 @@ export interface Filters { export const Context = createContext(); -export default (id: string | number, include: string[] = []) => { +export default (id: number, include: string[] = []) => { const { page, filters, sort, sortDirection } = useContext(Context); const params = {}; diff --git a/resources/scripts/components/admin/nodes/NodeAllocationContainer.tsx b/resources/scripts/components/admin/nodes/NodeAllocationContainer.tsx index eef598835..9e6c2f494 100644 --- a/resources/scripts/components/admin/nodes/NodeAllocationContainer.tsx +++ b/resources/scripts/components/admin/nodes/NodeAllocationContainer.tsx @@ -13,12 +13,12 @@ export default () => { <>
- +
- +
diff --git a/resources/scripts/components/admin/nodes/allocations/AllocationTable.tsx b/resources/scripts/components/admin/nodes/allocations/AllocationTable.tsx index 57b4132dc..aa93b37bc 100644 --- a/resources/scripts/components/admin/nodes/allocations/AllocationTable.tsx +++ b/resources/scripts/components/admin/nodes/allocations/AllocationTable.tsx @@ -5,6 +5,7 @@ import tw from 'twin.macro'; import getAllocations, { Context as AllocationsContext, Filters } from '@/api/admin/nodes/allocations/getAllocations'; import AdminCheckbox from '@/components/admin/AdminCheckbox'; import AdminTable, { ContentWrapper, Loading, NoItems, Pagination, TableBody, TableHead, TableHeader, useTableHooks } from '@/components/admin/AdminTable'; +import DeleteAllocationButton from '@/components/admin/nodes/allocations/DeleteAllocationButton'; import CopyOnClick from '@/components/elements/CopyOnClick'; import useFlash from '@/plugins/useFlash'; @@ -29,7 +30,7 @@ function RowCheckbox ({ id }: { id: number }) { } interface Props { - nodeId: string; + nodeId: number; filters?: Filters; } @@ -37,7 +38,7 @@ function AllocationsTable ({ nodeId, filters }: Props) { const { clearFlashes, clearAndAddHttpError } = useFlash(); const { page, setPage, setFilters, sort, setSort, sortDirection } = useContext(AllocationsContext); - const { data: allocations, error, isValidating } = getAllocations(nodeId, [ 'server' ]); + const { data: allocations, error, isValidating, mutate } = getAllocations(nodeId, [ 'server' ]); const length = allocations?.items?.length || 0; @@ -49,7 +50,7 @@ function AllocationsTable ({ nodeId, filters }: Props) { }; const onSearch = (query: string): Promise => { - return new Promise((resolve) => { + return new Promise(resolve => { if (query.length < 2) { setFilters(filters || null); } else { @@ -87,6 +88,7 @@ function AllocationsTable ({ nodeId, filters }: Props) { setSort('port')}/> + @@ -128,6 +130,24 @@ function AllocationsTable ({ nodeId, filters }: Props) { : } + + + { + await mutate(allocations => ({ + pagination: allocations!.pagination, + items: allocations!.items.filter(a => a.id === allocation.id), + })); + + // Go back a page if no more items will exist on the current page. + if (allocations?.items.length - 1 % 10 === 0) { + setPage(p => p - 1); + } + }} + /> + )) } diff --git a/resources/scripts/components/admin/nodes/allocations/CreateAllocationForm.tsx b/resources/scripts/components/admin/nodes/allocations/CreateAllocationForm.tsx index dc95d73f1..34b97d128 100644 --- a/resources/scripts/components/admin/nodes/allocations/CreateAllocationForm.tsx +++ b/resources/scripts/components/admin/nodes/allocations/CreateAllocationForm.tsx @@ -19,7 +19,7 @@ const distinct = (value: any, index: any, self: any) => { return self.indexOf(value) === index; }; -function CreateAllocationForm ({ nodeId }: { nodeId: string | number }) { +function CreateAllocationForm ({ nodeId }: { nodeId: number }) { const [ ips, setIPs ] = useState([]); const [ ports ] = useState([]); diff --git a/resources/scripts/components/admin/nodes/allocations/DeleteAllocationButton.tsx b/resources/scripts/components/admin/nodes/allocations/DeleteAllocationButton.tsx new file mode 100644 index 000000000..322def5d1 --- /dev/null +++ b/resources/scripts/components/admin/nodes/allocations/DeleteAllocationButton.tsx @@ -0,0 +1,62 @@ +import React, { useState } from 'react'; +import { Actions, useStoreActions } from 'easy-peasy'; +import { ApplicationStore } from '@/state'; +import tw from 'twin.macro'; +import Button from '@/components/elements/Button'; +import ConfirmationModal from '@/components/elements/ConfirmationModal'; +import deleteAllocation from '@/api/admin/nodes/allocations/deleteAllocation'; + +interface Props { + nodeId: number; + allocationId: number; + onDeleted?: () => void; +} + +export default ({ nodeId, allocationId, onDeleted }: Props) => { + const [ visible, setVisible ] = useState(false); + const [ loading, setLoading ] = useState(false); + + const { clearFlashes, clearAndAddHttpError } = useStoreActions((actions: Actions) => actions.flashes); + + const onDelete = () => { + setLoading(true); + clearFlashes('allocation'); + + deleteAllocation(nodeId, allocationId) + .then(() => { + setLoading(false); + setVisible(false); + if (onDeleted !== undefined) { + onDeleted(); + } + }) + .catch(error => { + console.error(error); + clearAndAddHttpError({ key: 'allocation', error }); + + setLoading(false); + setVisible(false); + }); + }; + + return ( + <> + setVisible(false)} + > + Are you sure you want to delete this allocation? + + + + + ); +}; diff --git a/resources/scripts/components/elements/Button.tsx b/resources/scripts/components/elements/Button.tsx index 3b0b820df..2f2ed2500 100644 --- a/resources/scripts/components/elements/Button.tsx +++ b/resources/scripts/components/elements/Button.tsx @@ -4,7 +4,7 @@ import Spinner from '@/components/elements/Spinner'; interface Props { isLoading?: boolean; - size?: 'xsmall' | 'small' | 'large' | 'xlarge'; + size?: 'inline' | 'xsmall' | 'small' | 'large' | 'xlarge'; color?: 'green' | 'red' | 'primary' | 'grey'; isSecondary?: boolean; } @@ -60,6 +60,7 @@ const ButtonStyle = styled.button>` `}; `}; + ${props => props.size === 'inline' && tw`p-1 text-xs`}; ${props => props.size === 'xsmall' && tw`p-2 text-xs`}; ${props => (!props.size || props.size === 'small') && tw`p-3`}; ${props => props.size === 'large' && tw`p-4 text-sm`};