From 8b1511a07b7d384e5c54a31fee860b0f096294ea Mon Sep 17 00:00:00 2001 From: anik-ghosh-au7 Date: Sat, 16 Jul 2022 23:10:05 +0530 Subject: [PATCH] update: webhooks --- .../src/components/ViewWebhookLogsModal.tsx | 426 ++++++++++++++++++ dashboard/src/graphql/queries/index.ts | 20 + dashboard/src/pages/Webhooks.tsx | 28 +- 3 files changed, 458 insertions(+), 16 deletions(-) create mode 100644 dashboard/src/components/ViewWebhookLogsModal.tsx diff --git a/dashboard/src/components/ViewWebhookLogsModal.tsx b/dashboard/src/components/ViewWebhookLogsModal.tsx new file mode 100644 index 0000000..e26089f --- /dev/null +++ b/dashboard/src/components/ViewWebhookLogsModal.tsx @@ -0,0 +1,426 @@ +import React, { useEffect, useState } from 'react'; +import dayjs from 'dayjs'; +import { + Button, + Center, + Flex, + MenuItem, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + useDisclosure, + Text, + Spinner, + Table, + Th, + Thead, + Tr, + Tbody, + IconButton, + NumberDecrementStepper, + NumberIncrementStepper, + NumberInput, + NumberInputField, + NumberInputStepper, + Select, + TableCaption, + Tooltip, + Td, + Tag, +} from '@chakra-ui/react'; +import { useClient } from 'urql'; +import { + FaAngleDoubleLeft, + FaAngleDoubleRight, + FaAngleLeft, + FaAngleRight, + FaExclamationCircle, + FaRegClone, +} from 'react-icons/fa'; +import { copyTextToClipboard } from '../utils'; +import { WebhookLogsQuery } from '../graphql/queries'; +import { pageLimits } from '../constants'; + +interface paginationPropTypes { + limit: number; + page: number; + offset: number; + total: number; + maxPages: number; +} + +interface deleteWebhookModalInputPropTypes { + webhookId: string; + eventName: string; +} + +interface webhookLogsDataTypes { + id: string; + http_status: number; + request: string; + response: string; + created_at: number; +} + +const ViewWebhookLogsModal = ({ + webhookId, + eventName, +}: deleteWebhookModalInputPropTypes) => { + const client = useClient(); + const { isOpen, onOpen, onClose } = useDisclosure(); + const [loading, setLoading] = useState(false); + const [webhookLogs, setWebhookLogs] = useState([]); + const [paginationProps, setPaginationProps] = useState({ + limit: 5, + page: 1, + offset: 0, + total: 0, + maxPages: 1, + }); + const getMaxPages = (pagination: paginationPropTypes) => { + const { limit, total } = pagination; + if (total > 1) { + return total % limit === 0 + ? total / limit + : parseInt(`${total / limit}`) + 1; + } else return 1; + }; + const fetchWebhookLogsData = async () => { + setLoading(true); + const res = await client + .query(WebhookLogsQuery, { + params: { + webhook_id: webhookId, + pagination: { + limit: paginationProps.limit, + page: paginationProps.page, + }, + }, + }) + .toPromise(); + if (res.data?._webhook_logs) { + const { pagination, webhook_logs } = res.data?._webhook_logs; + const maxPages = getMaxPages(pagination); + if (webhook_logs?.length) { + setWebhookLogs(webhook_logs); + setPaginationProps({ ...paginationProps, ...pagination, maxPages }); + } else { + if (paginationProps.page !== 1) { + setPaginationProps({ + ...paginationProps, + ...pagination, + maxPages, + page: 1, + }); + } + } + } + setLoading(false); + }; + const paginationHandler = (value: Record) => { + setPaginationProps({ ...paginationProps, ...value }); + }; + useEffect(() => { + isOpen && fetchWebhookLogsData(); + }, [isOpen, paginationProps.page, paginationProps.limit]); + return ( + <> + View Logs + + + + Webhook Logs - {eventName} + + + + {!loading ? ( + webhookLogs.length ? ( + + + + + + + + + + + + {webhookLogs.map((logData: webhookLogsDataTypes) => ( + + + + + + + + ))} + + {(paginationProps.maxPages > 1 || + paginationProps.total >= 5) && ( + + + + + + paginationHandler({ + page: 1, + }) + } + isDisabled={paginationProps.page <= 1} + mr={4} + icon={} + /> + + + + paginationHandler({ + page: paginationProps.page - 1, + }) + } + isDisabled={paginationProps.page <= 1} + icon={} + /> + + + + + Page{' '} + + {paginationProps.page} + {' '} + of{' '} + + {paginationProps.maxPages} + + + + Go to page:{' '} + + paginationHandler({ + page: parseInt(value), + }) + } + value={paginationProps.page} + > + + + + + + + + + + + + + paginationHandler({ + page: paginationProps.page + 1, + }) + } + isDisabled={ + paginationProps.page >= + paginationProps.maxPages + } + icon={} + /> + + + + paginationHandler({ + page: paginationProps.maxPages, + }) + } + isDisabled={ + paginationProps.page >= + paginationProps.maxPages + } + ml={4} + icon={} + /> + + + + + )} +
IDCreated AtHttp StatusRequestResponse
+ {`${logData.id.substring( + 0, + 5 + )}***${logData.id.substring( + logData.id.length - 5, + logData.id.length + )}`} + + {dayjs(logData.created_at * 1000).format( + 'MMM DD, YYYY' + )} + + = 400 ? 'red' : 'green' + } + > + {logData.http_status} + + + + + + {logData.request ? 'Payload' : 'No Data'} + + + {logData.request && ( + + )} + + + + + + {logData.response ? 'Preview' : 'No Data'} + + + {logData.response && ( + + )} + +
+ ) : ( + +
+ +
+ + No Data + +
+ ) + ) : ( +
+ +
+ )} +
+
+ + + +
+
+ + ); +}; + +export default ViewWebhookLogsModal; diff --git a/dashboard/src/graphql/queries/index.ts b/dashboard/src/graphql/queries/index.ts index d22dcca..ac9ba15 100644 --- a/dashboard/src/graphql/queries/index.ts +++ b/dashboard/src/graphql/queries/index.ts @@ -121,3 +121,23 @@ export const WebhooksDataQuery = ` } } `; + +export const WebhookLogsQuery = ` + query getWebhookLogs($params: ListWebhookLogRequest!) { + _webhook_logs(params: $params) { + webhook_logs { + id + http_status + request + response + created_at + } + pagination { + limit + page + offset + total + } + } + } +`; diff --git a/dashboard/src/pages/Webhooks.tsx b/dashboard/src/pages/Webhooks.tsx index ed1f9fa..c233819 100644 --- a/dashboard/src/pages/Webhooks.tsx +++ b/dashboard/src/pages/Webhooks.tsx @@ -44,6 +44,7 @@ import { } from '../constants'; import { WebhooksDataQuery } from '../graphql/queries'; import DeleteWebhookModal from '../components/DeleteWebhookModal'; +import ViewWebhookLogsModal from '../components/ViewWebhookLogsModal'; interface paginationPropTypes { limit: number; @@ -117,7 +118,7 @@ const Webhooks = () => { useEffect(() => { fetchWebookData(); }, []); - React.useEffect(() => { + useEffect(() => { fetchWebookData(); }, [paginationProps.page, paginationProps.limit]); return ( @@ -144,7 +145,7 @@ const Webhooks = () => { - {webhookData.map((webhook: webhookDataTypes, index: number) => ( + {webhookData.map((webhook: webhookDataTypes) => ( { { ' ' )} > -
- - {Object.keys( - webhook[WebhookInputDataFields.HEADERS] || {} - )?.length.toString()} - -
+ + {Object.keys( + webhook[WebhookInputDataFields.HEADERS] || {} + )?.length.toString()} +
@@ -215,7 +208,10 @@ const Webhooks = () => { eventName={webhook[WebhookInputDataFields.EVENT_NAME]} fetchWebookData={fetchWebookData} /> - {}}>View Logs +