From 97cf9bb45a081f1aea21c138409c90c424036be2 Mon Sep 17 00:00:00 2001 From: Phillip Ho Date: Fri, 22 Nov 2024 15:20:42 +0800 Subject: [PATCH 1/4] feat: test webhook and delete wallet --- .../src/@3rdweb-sdk/react/hooks/useEngine.ts | 77 +++++- .../components/backend-wallets-table.tsx | 190 +++++++++++-- .../webhooks/components/webhooks-table.tsx | 256 ++++++++++++------ 3 files changed, 407 insertions(+), 116 deletions(-) diff --git a/apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts b/apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts index 560f8359bed..0b7736c1ae4 100644 --- a/apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts +++ b/apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts @@ -83,7 +83,7 @@ export function useEngineInstances() { export type BackendWallet = { address: string; label?: string; - type: string; + type: EngineBackendWalletType; awsKmsKeyId?: string | null; awsKmsArn?: string | null; gcpKmsKeyId?: string | null; @@ -964,6 +964,39 @@ export function useEngineImportBackendWallet(instance: string) { }); } +interface DeleteBackendWalletInput { + walletAddress: string; +} +export function useEngineDeleteBackendWallet(instance: string) { + const token = useLoggedInUser().user?.jwt ?? null; + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (input: DeleteBackendWalletInput) => { + invariant(instance, "instance is required"); + + const res = await fetch( + `${instance}backend-wallet/${input.walletAddress}`, + { + method: "DELETE", + headers: getEngineRequestHeaders(token), + }, + ); + const json = await res.json(); + + if (json.error) { + throw new Error(json.error.message); + } + return json.result; + }, + onSuccess: () => { + return queryClient.invalidateQueries({ + queryKey: engineKeys.backendWallets(instance), + }); + }, + }); +} + export function useEngineGrantPermissions(instance: string) { const token = useLoggedInUser().user?.jwt ?? null; const queryClient = useQueryClient(); @@ -1161,16 +1194,15 @@ export function useEngineCreateWebhook(instance: string) { }); } -type RevokeWebhookInput = { +type DeleteWebhookInput = { id: number; }; - -export function useEngineRevokeWebhook(instance: string) { +export function useEngineDeleteWebhook(instance: string) { const token = useLoggedInUser().user?.jwt ?? null; const queryClient = useQueryClient(); return useMutation({ - mutationFn: async (input: RevokeWebhookInput) => { + mutationFn: async (input: DeleteWebhookInput) => { invariant(instance, "instance is required"); const res = await fetch(`${instance}webhooks/revoke`, { @@ -1179,11 +1211,44 @@ export function useEngineRevokeWebhook(instance: string) { body: JSON.stringify(input), }); const json = await res.json(); - if (json.error) { throw new Error(json.error.message); } + return json.result; + }, + onSuccess: () => { + return queryClient.invalidateQueries({ + queryKey: engineKeys.webhooks(instance), + }); + }, + }); +} + +interface TestWebhookInput { + id: number; +} +interface TestWebhookResponse { + ok: boolean; + status: number; + body: string; +} +export function useEngineTestWebhook(instance: string) { + const token = useLoggedInUser().user?.jwt ?? null; + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async (input: TestWebhookInput) => { + invariant(instance, "instance is required"); + + const res = await fetch(`${instance}webhooks/${input.id}/test`, { + method: "POST", + headers: getEngineRequestHeaders(token), + body: JSON.stringify({}), + }); + const json = await res.json(); + if (json.error) { + throw new Error(json.error.message); + } return json.result; }, onSuccess: () => { diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx index 45f79dd3902..deb1b3213ec 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx @@ -1,15 +1,19 @@ import { WalletAddress } from "@/components/blocks/wallet-address"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Checkbox, CheckboxWithLabel } from "@/components/ui/checkbox"; +import { FormItem } from "@/components/ui/form"; import { type BackendWallet, useEngineBackendWalletBalance, + useEngineDeleteBackendWallet, useEngineSendTokens, useEngineUpdateBackendWallet, } from "@3rdweb-sdk/react/hooks/useEngine"; import { Flex, FormControl, - Image, Input, InputGroup, InputRightAddon, @@ -30,20 +34,21 @@ import { ChainIcon } from "components/icons/ChainIcon"; import { TWTable } from "components/shared/TWTable"; import { useTrack } from "hooks/analytics/useTrack"; import { useTxNotifications } from "hooks/useTxNotifications"; +import { EngineBackendWalletOptions } from "lib/engine"; import { useActiveChainAsDashboardChain } from "lib/v5-adapter"; -import { DownloadIcon, PencilIcon, UploadIcon } from "lucide-react"; +import { + DownloadIcon, + PencilIcon, + TrashIcon, + TriangleAlertIcon, + UploadIcon, +} from "lucide-react"; import QRCode from "qrcode"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { getAddress } from "thirdweb"; import { shortenAddress } from "thirdweb/utils"; -import { - Button, - FormHelperText, - FormLabel, - LinkButton, - Text, -} from "tw-components"; +import { FormHelperText, FormLabel, LinkButton, Text } from "tw-components"; import { prettyPrintCurrency } from "./utils"; interface BackendWalletsTableProps { @@ -150,6 +155,7 @@ export const BackendWalletsTable: React.FC = ({ const editDisclosure = useDisclosure(); const receiveDisclosure = useDisclosure(); const sendDisclosure = useDisclosure(); + const deleteDisclosure = useDisclosure(); const columns = setColumns(instanceUrl); const [selectedBackendWallet, setSelectedBackendWallet] = useState(); @@ -187,6 +193,15 @@ export const BackendWalletsTable: React.FC = ({ sendDisclosure.onOpen(); }, }, + { + icon: , + text: "Delete", + onClick: (wallet) => { + setSelectedBackendWallet(wallet); + deleteDisclosure.onOpen(); + }, + isDestructive: true, + }, ]} /> @@ -211,6 +226,13 @@ export const BackendWalletsTable: React.FC = ({ instanceUrl={instanceUrl} /> )} + {selectedBackendWallet && deleteDisclosure.isOpen && ( + + )} ); }; @@ -224,18 +246,18 @@ const EditModal = ({ disclosure: UseDisclosureReturn; instanceUrl: string; }) => { - const { mutate: updatePermissions } = + const { mutate: updateBackendWallet } = useEngineUpdateBackendWallet(instanceUrl); const trackEvent = useTrack(); const { onSuccess, onError } = useTxNotifications( - "Successfully updated backend wallet", - "Failed to update backend wallet", + "Successfully updated backend wallet.", + "Failed to update backend wallet.", ); const [label, setLabel] = useState(backendWallet.label ?? ""); const onClick = () => { - updatePermissions( + updateBackendWallet( { walletAddress: backendWallet.address, label, @@ -275,7 +297,10 @@ const EditModal = ({
Wallet Address - {backendWallet.address} + Label @@ -290,10 +315,10 @@ const EditModal = ({ - - @@ -347,11 +372,10 @@ const ReceiveFundsModal = ({ address={backendWallet.address} shortenAddress={false} /> - Receive funds to your backend wallet
@@ -364,7 +388,6 @@ interface SendFundsInput { toAddress: string; amount: number; } - const SendFundsModal = ({ fromWallet, backendWallets, @@ -426,7 +449,10 @@ const SendFundsModal = ({
From - {fromWallet.address} + To @@ -457,7 +483,6 @@ const SendFundsModal = ({ toWalletDisclosure.onToggle(); }} variant="link" - size="xs" > {toWalletDisclosure.isOpen ? "Or send to a backend wallet" @@ -498,18 +523,127 @@ const SendFundsModal = ({ - + + + + + ); +}; + +function DeleteModal({ + backendWallet, + disclosure, + instanceUrl, +}: { + backendWallet: BackendWallet; + disclosure: UseDisclosureReturn; + instanceUrl: string; +}) { + const { mutate: deleteBackendWallet } = + useEngineDeleteBackendWallet(instanceUrl); + const trackEvent = useTrack(); + const { onSuccess, onError } = useTxNotifications( + "Successfully deleted backend wallet.", + "Failed to delete backend wallet.", + ); + + const isLocalWallet = + backendWallet.type === "local" || backendWallet.type === "smart:local"; + const [ackDeletion, setAckDeletion] = useState(false); + + const onClick = () => { + deleteBackendWallet( + { walletAddress: backendWallet.address }, + { + onSuccess: () => { + onSuccess(); + disclosure.onClose(); + trackEvent({ + category: "engine", + action: "delete-backend-wallet", + label: "success", + instance: instanceUrl, + }); + }, + onError: (error) => { + onError(error); + trackEvent({ + category: "engine", + action: "delete-backend-wallet", + label: "error", + instance: instanceUrl, + error, + }); + }, + }, + ); + }; + + return ( + + + + Delete Backend Wallet + + +
+ + Wallet Type +
+ { + EngineBackendWalletOptions.find( + (opt) => opt.key === backendWallet.type, + )?.name + } +
+
+ + Wallet Address + + +
+ + {isLocalWallet && ( + + + This action is irreversible. + + + + setAckDeletion(!!checked)} + /> + I understand that access to this backend wallet and any + remaining funds will be lost. + + + + )} +
+ + +
); -}; +} diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx index 53ba43b5e34..38ac6763f47 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx @@ -1,7 +1,12 @@ import { CopyTextButton } from "@/components/ui/CopyTextButton"; +import { Spinner } from "@/components/ui/Spinner/Spinner"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { FormItem } from "@/components/ui/form"; import { type EngineWebhook, - useEngineRevokeWebhook, + useEngineDeleteWebhook, + useEngineTestWebhook, } from "@3rdweb-sdk/react/hooks/useEngine"; import { Flex, @@ -14,6 +19,7 @@ import { ModalHeader, ModalOverlay, Tooltip, + type UseDisclosureReturn, useDisclosure, } from "@chakra-ui/react"; import { createColumnHelper } from "@tanstack/react-table"; @@ -21,9 +27,9 @@ import { TWTable } from "components/shared/TWTable"; import { format, formatDistanceToNowStrict } from "date-fns"; import { useTrack } from "hooks/analytics/useTrack"; import { useTxNotifications } from "hooks/useTxNotifications"; -import { Trash2Icon } from "lucide-react"; +import { MailQuestion, TrashIcon } from "lucide-react"; import { useState } from "react"; -import { Button, Card, FormLabel, Text } from "tw-components"; +import { Card, FormLabel, Text } from "tw-components"; import { shortenString } from "utils/usedapp-external"; export function beautifyString(str: string): string { @@ -113,36 +119,86 @@ export const WebhooksTable: React.FC = ({ isPending, isFetched, }) => { - const [webhookToRevoke, setWebhookToRevoke] = useState(); - const { isOpen, onOpen, onClose } = useDisclosure(); - const { mutate: revokeWebhook } = useEngineRevokeWebhook(instanceUrl); + const [selectedWebhook, setSelectedWebhook] = useState(); + const deleteDisclosure = useDisclosure(); + const testDisclosure = useDisclosure(); + + const activeWebhooks = webhooks.filter((webhook) => webhook.active); + + return ( + <> + , + text: "Test webhook", + onClick: (row) => { + setSelectedWebhook(row); + testDisclosure.onOpen(); + }, + }, + { + icon: , + text: "Delete", + onClick: (row) => { + setSelectedWebhook(row); + deleteDisclosure.onOpen(); + }, + isDestructive: true, + }, + ]} + /> + + {selectedWebhook && deleteDisclosure.isOpen && ( + + )} + {selectedWebhook && testDisclosure.isOpen && ( + + )} + + ); +}; + +interface DeleteWebhookModalProps { + webhook: EngineWebhook; + disclosure: UseDisclosureReturn; + instanceUrl: string; +} +function DeleteWebhookModal({ + webhook, + disclosure, + instanceUrl, +}: DeleteWebhookModalProps) { + const { mutate: deleteWebhook } = useEngineDeleteWebhook(instanceUrl); const trackEvent = useTrack(); const { onSuccess, onError } = useTxNotifications( - "Successfully deleted webhook", - "Failed to delete webhook", + "Successfully deleted webhook.", + "Failed to delete webhook.", ); - const onDelete = (webhook: EngineWebhook) => { - setWebhookToRevoke(webhook); - onOpen(); - }; - - const onRevoke = () => { - if (!webhookToRevoke) { - return; - } - - revokeWebhook( - { - id: webhookToRevoke.id, - }, + const onDelete = () => { + deleteWebhook( + { id: webhook.id }, { onSuccess: () => { onSuccess(); - onClose(); + disclosure.onClose(); trackEvent({ category: "engine", - action: "revoke-webhook", + action: "delete-webhook", label: "success", instance: instanceUrl, }); @@ -151,7 +207,7 @@ export const WebhooksTable: React.FC = ({ onError(error); trackEvent({ category: "engine", - action: "revoke-webhook", + action: "delete-webhook", label: "error", instance: instanceUrl, error, @@ -161,66 +217,102 @@ export const WebhooksTable: React.FC = ({ ); }; - const activeWebhooks = webhooks.filter((webhook) => webhook.active); + return ( + + + + Delete Webhook + + +
+ Are you sure you want to delete this webook? + + Name + {webhook.name} + + + URL + {webhook.url} + + + Created at + + {format(new Date(webhook.createdAt ?? ""), "PP pp z")} + + +
+
+ + + + + +
+
+ ); +} + +interface TestWebhookModalProps { + webhook: EngineWebhook; + disclosure: UseDisclosureReturn; + instanceUrl: string; +} +function TestWebhookModal({ + webhook, + disclosure, + instanceUrl, +}: TestWebhookModalProps) { + const { mutate: testWebhook, isPending } = useEngineTestWebhook(instanceUrl); + const [status, setStatus] = useState(); + const [body, setBody] = useState(); + + const onTest = () => { + testWebhook( + { id: webhook.id }, + { + onSuccess: (result) => { + setStatus(result.status); + setBody(result.body); + }, + }, + ); + }; return ( - <> - - - - Delete webhook - - - {webhookToRevoke && ( -
- Are you sure you want to delete this webook? - - Name - {webhookToRevoke?.name} - - - URL - {webhookToRevoke?.url} - - - Created at - - {format( - new Date(webhookToRevoke?.createdAt ?? ""), - "PP pp z", - )} - - -
- )} -
+ + + + Test Webhook + + +
+ + URL + {webhook.url} + - - - - - - - , - text: "Delete", - onClick: onDelete, - isDestructive: true, - }, - ]} - /> - + {status && ( +
+ + {status} + +
+ )} +
+ {body ?? "Send a request to see the response."} +
+
+
+
+
); -}; +} From 717a62201eae8abb7fa4e78bf06eec7b20c8038a Mon Sep 17 00:00:00 2001 From: Phillip Ho Date: Sun, 24 Nov 2024 10:45:12 +0800 Subject: [PATCH 2/4] pr comments --- .../components/backend-wallets-table.tsx | 77 +++++++++---------- .../webhooks/components/webhooks-table.tsx | 19 +++-- 2 files changed, 46 insertions(+), 50 deletions(-) diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx index deb1b3213ec..d25c540702f 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx @@ -33,7 +33,6 @@ import { type ColumnDef, createColumnHelper } from "@tanstack/react-table"; import { ChainIcon } from "components/icons/ChainIcon"; import { TWTable } from "components/shared/TWTable"; import { useTrack } from "hooks/analytics/useTrack"; -import { useTxNotifications } from "hooks/useTxNotifications"; import { EngineBackendWalletOptions } from "lib/engine"; import { useActiveChainAsDashboardChain } from "lib/v5-adapter"; import { @@ -46,8 +45,10 @@ import { import QRCode from "qrcode"; import { useState } from "react"; import { useForm } from "react-hook-form"; +import { toast } from "sonner"; import { getAddress } from "thirdweb"; import { shortenAddress } from "thirdweb/utils"; +import invariant from "tiny-invariant"; import { FormHelperText, FormLabel, LinkButton, Text } from "tw-components"; import { prettyPrintCurrency } from "./utils"; @@ -246,25 +247,19 @@ const EditModal = ({ disclosure: UseDisclosureReturn; instanceUrl: string; }) => { - const { mutate: updateBackendWallet } = - useEngineUpdateBackendWallet(instanceUrl); + const updateBackendWallet = useEngineUpdateBackendWallet(instanceUrl); const trackEvent = useTrack(); - const { onSuccess, onError } = useTxNotifications( - "Successfully updated backend wallet.", - "Failed to update backend wallet.", - ); const [label, setLabel] = useState(backendWallet.label ?? ""); - const onClick = () => { - updateBackendWallet( + const onClick = async () => { + const promise = updateBackendWallet.mutateAsync( { walletAddress: backendWallet.address, label, }, { onSuccess: () => { - onSuccess(); disclosure.onClose(); trackEvent({ category: "engine", @@ -274,7 +269,6 @@ const EditModal = ({ }); }, onError: (error) => { - onError(error); trackEvent({ category: "engine", action: "update-backend-wallet", @@ -285,6 +279,11 @@ const EditModal = ({ }, }, ); + + toast.promise(promise, { + success: "Successfully updated backend wallet.", + error: "Failed to update backend wallet.", + }); }; return ( @@ -401,39 +400,39 @@ const SendFundsModal = ({ }) => { const chain = useActiveChainAsDashboardChain(); const form = useForm(); - const { mutate: sendTokens } = useEngineSendTokens(instanceUrl); + const sendTokens = useEngineSendTokens(instanceUrl); const { data: backendWalletBalance } = useEngineBackendWalletBalance( instanceUrl, fromWallet.address, ); - const { onSuccess, onError } = useTxNotifications( - "Successfully sent a request to send funds.", - "Failed to send tokens.", - ); const toWalletDisclosure = useDisclosure(); + if (!backendWalletBalance) { + return null; + } + const onSubmit = async (data: SendFundsInput) => { - if (!chain) { - return; - } + invariant(chain, "chain is required"); - try { - await sendTokens({ + const promise = sendTokens.mutateAsync( + { chainId: chain.chainId, fromAddress: fromWallet.address, toAddress: data.toAddress, amount: data.amount, - }); - onSuccess(); - disclosure.onClose(); - } catch (e) { - onError(e); - } - }; + }, + { + onSuccess: () => { + disclosure.onClose(); + }, + }, + ); - if (!backendWalletBalance) { - return null; - } + toast.promise(promise, { + success: "Successfully sent a request to send funds.", + error: "Failed to send tokens.", + }); + }; return ( @@ -544,24 +543,18 @@ function DeleteModal({ disclosure: UseDisclosureReturn; instanceUrl: string; }) { - const { mutate: deleteBackendWallet } = - useEngineDeleteBackendWallet(instanceUrl); + const deleteBackendWallet = useEngineDeleteBackendWallet(instanceUrl); const trackEvent = useTrack(); - const { onSuccess, onError } = useTxNotifications( - "Successfully deleted backend wallet.", - "Failed to delete backend wallet.", - ); const isLocalWallet = backendWallet.type === "local" || backendWallet.type === "smart:local"; const [ackDeletion, setAckDeletion] = useState(false); const onClick = () => { - deleteBackendWallet( + const promise = deleteBackendWallet.mutateAsync( { walletAddress: backendWallet.address }, { onSuccess: () => { - onSuccess(); disclosure.onClose(); trackEvent({ category: "engine", @@ -571,7 +564,6 @@ function DeleteModal({ }); }, onError: (error) => { - onError(error); trackEvent({ category: "engine", action: "delete-backend-wallet", @@ -582,6 +574,11 @@ function DeleteModal({ }, }, ); + + toast.promise(promise, { + success: "Successfully deleted backend wallet.", + error: "Failed to delete backend wallet.", + }); }; return ( diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx index 38ac6763f47..cb3db509603 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx @@ -26,9 +26,9 @@ import { createColumnHelper } from "@tanstack/react-table"; import { TWTable } from "components/shared/TWTable"; import { format, formatDistanceToNowStrict } from "date-fns"; import { useTrack } from "hooks/analytics/useTrack"; -import { useTxNotifications } from "hooks/useTxNotifications"; import { MailQuestion, TrashIcon } from "lucide-react"; import { useState } from "react"; +import { toast } from "sonner"; import { Card, FormLabel, Text } from "tw-components"; import { shortenString } from "utils/usedapp-external"; @@ -182,19 +182,14 @@ function DeleteWebhookModal({ disclosure, instanceUrl, }: DeleteWebhookModalProps) { - const { mutate: deleteWebhook } = useEngineDeleteWebhook(instanceUrl); + const deleteWebhook = useEngineDeleteWebhook(instanceUrl); const trackEvent = useTrack(); - const { onSuccess, onError } = useTxNotifications( - "Successfully deleted webhook.", - "Failed to delete webhook.", - ); const onDelete = () => { - deleteWebhook( + const promise = deleteWebhook.mutateAsync( { id: webhook.id }, { onSuccess: () => { - onSuccess(); disclosure.onClose(); trackEvent({ category: "engine", @@ -204,7 +199,6 @@ function DeleteWebhookModal({ }); }, onError: (error) => { - onError(error); trackEvent({ category: "engine", action: "delete-webhook", @@ -215,6 +209,11 @@ function DeleteWebhookModal({ }, }, ); + + toast.promise(promise, { + success: "Successfully deleted webhook.", + error: "Failed to delete webhook.", + }); }; return ( @@ -225,7 +224,7 @@ function DeleteWebhookModal({
- Are you sure you want to delete this webook? + Are you sure you want to delete this webhook? Name {webhook.name} From 1e3be375f4e8061d142aab96c68f0b737db3c52f Mon Sep 17 00:00:00 2001 From: Phillip Ho Date: Sun, 24 Nov 2024 10:45:47 +0800 Subject: [PATCH 3/4] footer --- .../(instance)/[engineId]/webhooks/components/webhooks-table.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx index cb3db509603..d59c58f8089 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx @@ -312,6 +312,7 @@ function TestWebhookModal({
+
); } From b020439e8b2dc312642744c980c6f956e4565a8a Mon Sep 17 00:00:00 2001 From: Phillip Ho Date: Tue, 26 Nov 2024 10:45:54 +0800 Subject: [PATCH 4/4] remove footer --- .../[engineId]/webhooks/components/webhooks-table.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx index d59c58f8089..5eea406127e 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/webhooks/components/webhooks-table.tsx @@ -288,7 +288,7 @@ function TestWebhookModal({ Test Webhook -
+
URL {webhook.url} @@ -312,7 +312,6 @@ function TestWebhookModal({
- ); }