diff --git a/frontend/src/api/npm/base.ts b/frontend/src/api/npm/base.ts index 47b25cf..a9bcc86 100644 --- a/frontend/src/api/npm/base.ts +++ b/frontend/src/api/npm/base.ts @@ -99,3 +99,21 @@ export async function put( const response = await fetch(apiUrl, { method, headers, body, signal }); return processResponse(response, skipCamelize); } + +interface DeleteArgs { + url: string; +} +export async function del( + { url }: DeleteArgs, + abortController?: AbortController, +) { + const apiUrl = buildUrl({ url }); + const method = "DELETE"; + const headers = { + ...buildAuthHeader(), + [contentTypeHeader]: "application/json", + }; + const signal = abortController?.signal; + const response = await fetch(apiUrl, { method, headers, signal }); + return processResponse(response); +} diff --git a/frontend/src/api/npm/deleteCertificate.ts b/frontend/src/api/npm/deleteCertificate.ts new file mode 100644 index 0000000..75afabe --- /dev/null +++ b/frontend/src/api/npm/deleteCertificate.ts @@ -0,0 +1,14 @@ +import * as api from "./base"; + +export async function deleteCertificate( + id: number, + abortController?: AbortController, +): Promise { + const { result } = await api.del( + { + url: `/certificates/${id}`, + }, + abortController, + ); + return result; +} diff --git a/frontend/src/api/npm/index.ts b/frontend/src/api/npm/index.ts index 23250e5..d554c00 100644 --- a/frontend/src/api/npm/index.ts +++ b/frontend/src/api/npm/index.ts @@ -2,6 +2,7 @@ export * from "./createCertificate"; export * from "./createCertificateAuthority"; export * from "./createDNSProvider"; export * from "./createUser"; +export * from "./deleteCertificate"; export * from "./getAccessLists"; export * from "./getCertificate"; export * from "./getCertificateAuthorities"; diff --git a/frontend/src/components/SiteWrapper.tsx b/frontend/src/components/SiteWrapper.tsx index 65443f2..e2e2e98 100644 --- a/frontend/src/components/SiteWrapper.tsx +++ b/frontend/src/components/SiteWrapper.tsx @@ -2,6 +2,7 @@ import { useEffect, ReactNode } from "react"; import { Box, Container, useToast } from "@chakra-ui/react"; import { useQueryClient } from "@tanstack/react-query"; + import { getSSEToken, SSEMessage } from "src/api/npm"; import { Footer, Navigation } from "src/components"; import { intl } from "src/locale"; diff --git a/frontend/src/locale/src/en.json b/frontend/src/locale/src/en.json index a9daa41..53cf596 100644 --- a/frontend/src/locale/src/en.json +++ b/frontend/src/locale/src/en.json @@ -347,6 +347,9 @@ "certificate.create": { "defaultMessage": "Create Certificate" }, + "certificate.deleted": { + "defaultMessage": "Certificate has been deleted" + }, "certificate.renewal-requested": { "defaultMessage": "Renewal has been queued" }, diff --git a/frontend/src/pages/Certificates/Table.tsx b/frontend/src/pages/Certificates/Table.tsx index b41759a..c0f6658 100644 --- a/frontend/src/pages/Certificates/Table.tsx +++ b/frontend/src/pages/Certificates/Table.tsx @@ -28,6 +28,7 @@ export interface TableProps { filters: TableFilter[]; onTableEvent: any; onRenewal: (id: number) => void; + onDelete: (id: number) => void; } function Table({ data, @@ -36,6 +37,7 @@ function Table({ sortBy, filters, onRenewal, + onDelete, }: TableProps) { const [editId, setEditId] = useState(0); const [columns, tableData] = useMemo(() => { @@ -113,7 +115,7 @@ function Table({ title: intl.formatMessage({ id: "action.delete", }), - onClick: (_: any, { id }: any) => alert(id), + onClick: (_: any, { id }: any) => onDelete(id), icon: , disabled: (data: any) => data.isReadonly, }, diff --git a/frontend/src/pages/Certificates/TableWrapper.tsx b/frontend/src/pages/Certificates/TableWrapper.tsx index 2402c23..584e163 100644 --- a/frontend/src/pages/Certificates/TableWrapper.tsx +++ b/frontend/src/pages/Certificates/TableWrapper.tsx @@ -3,7 +3,7 @@ import { useEffect, useReducer, useState } from "react"; import { Alert, AlertIcon, useToast } from "@chakra-ui/react"; import { useQueryClient } from "@tanstack/react-query"; -import { renewCertificate } from "src/api/npm"; +import { renewCertificate, deleteCertificate } from "src/api/npm"; import { EmptyList, SpinnerPage, tableEventReducer } from "src/components"; import { useCertificates } from "src/hooks"; import { intl } from "src/locale"; @@ -68,6 +68,32 @@ function TableWrapper() { } }; + const deleteCert = async (id: number) => { + try { + await deleteCertificate(id); + toast({ + description: intl.formatMessage({ + id: `certificate.deleted`, + }), + status: "success", + position: "top", + duration: 3000, + isClosable: true, + }); + setTimeout(() => { + queryClient.invalidateQueries({ queryKey: ["certificates"] }); + }, 500); + } catch (err: any) { + toast({ + description: err.message, + status: "error", + position: "top", + duration: 3000, + isClosable: true, + }); + } + }; + if (isFetching || isLoading || !tableData) { return ; } @@ -105,6 +131,7 @@ function TableWrapper() { filters={filters} onTableEvent={dispatch} onRenewal={renewCert} + onDelete={deleteCert} /> ); }