fix: TT-69
This commit is contained in:
parent
eabc943452
commit
8fc52d76dc
|
@ -20,7 +20,11 @@ import {
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { FaMinusCircle, FaPlus } from 'react-icons/fa';
|
import { FaMinusCircle, FaPlus } from 'react-icons/fa';
|
||||||
import { useClient } from 'urql';
|
import { useClient } from 'urql';
|
||||||
import { ArrayInputOperations } from '../constants';
|
import {
|
||||||
|
ArrayInputOperations,
|
||||||
|
WebhookInputDataFields,
|
||||||
|
WebhookInputHeaderFields,
|
||||||
|
} from '../constants';
|
||||||
import {
|
import {
|
||||||
capitalizeFirstLetter,
|
capitalizeFirstLetter,
|
||||||
validateEventName,
|
validateEventName,
|
||||||
|
@ -28,62 +32,50 @@ import {
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { AddWebhook } from '../graphql/mutation';
|
import { AddWebhook } from '../graphql/mutation';
|
||||||
|
|
||||||
enum INPUT_FIELDS {
|
|
||||||
EVENT_NAME = 'event_name',
|
|
||||||
ENDPOINT = 'endpoint',
|
|
||||||
ENABLED = 'enabled',
|
|
||||||
HEADERS = 'headers',
|
|
||||||
}
|
|
||||||
|
|
||||||
enum HEADER_FIELDS {
|
|
||||||
KEY = 'key',
|
|
||||||
VALUE = 'value',
|
|
||||||
}
|
|
||||||
|
|
||||||
interface headersDataType {
|
interface headersDataType {
|
||||||
[HEADER_FIELDS.KEY]: string;
|
[WebhookInputHeaderFields.KEY]: string;
|
||||||
[HEADER_FIELDS.VALUE]: string;
|
[WebhookInputHeaderFields.VALUE]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface headersValidatorDataType {
|
interface headersValidatorDataType {
|
||||||
[HEADER_FIELDS.KEY]: boolean;
|
[WebhookInputHeaderFields.KEY]: boolean;
|
||||||
[HEADER_FIELDS.VALUE]: boolean;
|
[WebhookInputHeaderFields.VALUE]: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initHeadersData: headersDataType = {
|
const initHeadersData: headersDataType = {
|
||||||
[HEADER_FIELDS.KEY]: '',
|
[WebhookInputHeaderFields.KEY]: '',
|
||||||
[HEADER_FIELDS.VALUE]: '',
|
[WebhookInputHeaderFields.VALUE]: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const initHeadersValidatorData: headersValidatorDataType = {
|
const initHeadersValidatorData: headersValidatorDataType = {
|
||||||
[HEADER_FIELDS.KEY]: true,
|
[WebhookInputHeaderFields.KEY]: true,
|
||||||
[HEADER_FIELDS.VALUE]: true,
|
[WebhookInputHeaderFields.VALUE]: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
interface webhookDataType {
|
interface webhookDataType {
|
||||||
[INPUT_FIELDS.EVENT_NAME]: string;
|
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||||
[INPUT_FIELDS.ENDPOINT]: string;
|
[WebhookInputDataFields.ENDPOINT]: string;
|
||||||
[INPUT_FIELDS.ENABLED]: boolean;
|
[WebhookInputDataFields.ENABLED]: boolean;
|
||||||
[INPUT_FIELDS.HEADERS]: headersDataType[];
|
[WebhookInputDataFields.HEADERS]: headersDataType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface validatorDataType {
|
interface validatorDataType {
|
||||||
[INPUT_FIELDS.EVENT_NAME]: boolean;
|
[WebhookInputDataFields.EVENT_NAME]: boolean;
|
||||||
[INPUT_FIELDS.ENDPOINT]: boolean;
|
[WebhookInputDataFields.ENDPOINT]: boolean;
|
||||||
[INPUT_FIELDS.HEADERS]: headersValidatorDataType[];
|
[WebhookInputDataFields.HEADERS]: headersValidatorDataType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const initWebhookData: webhookDataType = {
|
const initWebhookData: webhookDataType = {
|
||||||
[INPUT_FIELDS.EVENT_NAME]: '',
|
[WebhookInputDataFields.EVENT_NAME]: '',
|
||||||
[INPUT_FIELDS.ENDPOINT]: '',
|
[WebhookInputDataFields.ENDPOINT]: '',
|
||||||
[INPUT_FIELDS.ENABLED]: false,
|
[WebhookInputDataFields.ENABLED]: false,
|
||||||
[INPUT_FIELDS.HEADERS]: [{ ...initHeadersData }],
|
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
||||||
};
|
};
|
||||||
|
|
||||||
const initWebhookValidatorData: validatorDataType = {
|
const initWebhookValidatorData: validatorDataType = {
|
||||||
[INPUT_FIELDS.EVENT_NAME]: true,
|
[WebhookInputDataFields.EVENT_NAME]: true,
|
||||||
[INPUT_FIELDS.ENDPOINT]: true,
|
[WebhookInputDataFields.ENDPOINT]: true,
|
||||||
[INPUT_FIELDS.HEADERS]: [{ ...initHeadersValidatorData }],
|
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersValidatorData }],
|
||||||
};
|
};
|
||||||
|
|
||||||
const AddWebhookModal = () => {
|
const AddWebhookModal = () => {
|
||||||
|
@ -100,36 +92,38 @@ const AddWebhookModal = () => {
|
||||||
const inputChangehandler = (
|
const inputChangehandler = (
|
||||||
inputType: string,
|
inputType: string,
|
||||||
value: any,
|
value: any,
|
||||||
headerInputType: string = HEADER_FIELDS.KEY,
|
headerInputType: string = WebhookInputHeaderFields.KEY,
|
||||||
headerIndex: number = 0
|
headerIndex: number = 0
|
||||||
) => {
|
) => {
|
||||||
switch (inputType) {
|
switch (inputType) {
|
||||||
case INPUT_FIELDS.EVENT_NAME:
|
case WebhookInputDataFields.EVENT_NAME:
|
||||||
setWebhook({ ...webhook, [inputType]: value });
|
setWebhook({ ...webhook, [inputType]: value });
|
||||||
setValidator({
|
setValidator({
|
||||||
...validator,
|
...validator,
|
||||||
[INPUT_FIELDS.EVENT_NAME]: validateEventName(value),
|
[WebhookInputDataFields.EVENT_NAME]: validateEventName(value),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case INPUT_FIELDS.ENDPOINT:
|
case WebhookInputDataFields.ENDPOINT:
|
||||||
setWebhook({ ...webhook, [inputType]: value });
|
setWebhook({ ...webhook, [inputType]: value });
|
||||||
setValidator({
|
setValidator({
|
||||||
...validator,
|
...validator,
|
||||||
[INPUT_FIELDS.ENDPOINT]: validateURI(value),
|
[WebhookInputDataFields.ENDPOINT]: validateURI(value),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case INPUT_FIELDS.ENABLED:
|
case WebhookInputDataFields.ENABLED:
|
||||||
setWebhook({ ...webhook, [inputType]: value });
|
setWebhook({ ...webhook, [inputType]: value });
|
||||||
break;
|
break;
|
||||||
case INPUT_FIELDS.HEADERS:
|
case WebhookInputDataFields.HEADERS:
|
||||||
const updatedHeaders: any = [...webhook[INPUT_FIELDS.HEADERS]];
|
const updatedHeaders: any = [
|
||||||
|
...webhook[WebhookInputDataFields.HEADERS],
|
||||||
|
];
|
||||||
const updatedHeadersValidatorData: any = [
|
const updatedHeadersValidatorData: any = [
|
||||||
...validator[INPUT_FIELDS.HEADERS],
|
...validator[WebhookInputDataFields.HEADERS],
|
||||||
];
|
];
|
||||||
const otherHeaderInputType =
|
const otherHeaderInputType =
|
||||||
headerInputType === HEADER_FIELDS.KEY
|
headerInputType === WebhookInputHeaderFields.KEY
|
||||||
? HEADER_FIELDS.VALUE
|
? WebhookInputHeaderFields.VALUE
|
||||||
: HEADER_FIELDS.KEY;
|
: WebhookInputHeaderFields.KEY;
|
||||||
updatedHeaders[headerIndex][headerInputType] = value;
|
updatedHeaders[headerIndex][headerInputType] = value;
|
||||||
updatedHeadersValidatorData[headerIndex][headerInputType] =
|
updatedHeadersValidatorData[headerIndex][headerInputType] =
|
||||||
value.length > 0
|
value.length > 0
|
||||||
|
@ -154,34 +148,36 @@ const AddWebhookModal = () => {
|
||||||
case ArrayInputOperations.APPEND:
|
case ArrayInputOperations.APPEND:
|
||||||
setWebhook({
|
setWebhook({
|
||||||
...webhook,
|
...webhook,
|
||||||
[INPUT_FIELDS.HEADERS]: [
|
[WebhookInputDataFields.HEADERS]: [
|
||||||
...(webhook?.[INPUT_FIELDS.HEADERS] || []),
|
...(webhook?.[WebhookInputDataFields.HEADERS] || []),
|
||||||
{ ...initHeadersData },
|
{ ...initHeadersData },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
setValidator({
|
setValidator({
|
||||||
...validator,
|
...validator,
|
||||||
[INPUT_FIELDS.HEADERS]: [
|
[WebhookInputDataFields.HEADERS]: [
|
||||||
...(validator?.[INPUT_FIELDS.HEADERS] || []),
|
...(validator?.[WebhookInputDataFields.HEADERS] || []),
|
||||||
{ ...initHeadersValidatorData },
|
{ ...initHeadersValidatorData },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ArrayInputOperations.REMOVE:
|
case ArrayInputOperations.REMOVE:
|
||||||
if (webhook?.[INPUT_FIELDS.HEADERS]?.length) {
|
if (webhook?.[WebhookInputDataFields.HEADERS]?.length) {
|
||||||
const updatedHeaders = [...webhook[INPUT_FIELDS.HEADERS]];
|
const updatedHeaders = [...webhook[WebhookInputDataFields.HEADERS]];
|
||||||
updatedHeaders.splice(index, 1);
|
updatedHeaders.splice(index, 1);
|
||||||
setWebhook({
|
setWebhook({
|
||||||
...webhook,
|
...webhook,
|
||||||
[INPUT_FIELDS.HEADERS]: updatedHeaders,
|
[WebhookInputDataFields.HEADERS]: updatedHeaders,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (validator?.[INPUT_FIELDS.HEADERS]?.length) {
|
if (validator?.[WebhookInputDataFields.HEADERS]?.length) {
|
||||||
const updatedHeadersData = [...validator[INPUT_FIELDS.HEADERS]];
|
const updatedHeadersData = [
|
||||||
|
...validator[WebhookInputDataFields.HEADERS],
|
||||||
|
];
|
||||||
updatedHeadersData.splice(index, 1);
|
updatedHeadersData.splice(index, 1);
|
||||||
setValidator({
|
setValidator({
|
||||||
...validator,
|
...validator,
|
||||||
[INPUT_FIELDS.HEADERS]: updatedHeadersData,
|
[WebhookInputDataFields.HEADERS]: updatedHeadersData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -192,11 +188,11 @@ const AddWebhookModal = () => {
|
||||||
const validateData = () => {
|
const validateData = () => {
|
||||||
return (
|
return (
|
||||||
!loading &&
|
!loading &&
|
||||||
webhook[INPUT_FIELDS.EVENT_NAME].length > 0 &&
|
webhook[WebhookInputDataFields.EVENT_NAME].length > 0 &&
|
||||||
webhook[INPUT_FIELDS.ENDPOINT].length > 0 &&
|
webhook[WebhookInputDataFields.ENDPOINT].length > 0 &&
|
||||||
validator[INPUT_FIELDS.EVENT_NAME] &&
|
validator[WebhookInputDataFields.EVENT_NAME] &&
|
||||||
validator[INPUT_FIELDS.ENDPOINT] &&
|
validator[WebhookInputDataFields.ENDPOINT] &&
|
||||||
!validator[INPUT_FIELDS.HEADERS].some(
|
!validator[WebhookInputDataFields.HEADERS].some(
|
||||||
(headerData: headersValidatorDataType) =>
|
(headerData: headersValidatorDataType) =>
|
||||||
!headerData.key || !headerData.value
|
!headerData.key || !headerData.value
|
||||||
)
|
)
|
||||||
|
@ -205,15 +201,17 @@ const AddWebhookModal = () => {
|
||||||
const saveData = async () => {
|
const saveData = async () => {
|
||||||
if (!validateData()) return;
|
if (!validateData()) return;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
let { [INPUT_FIELDS.HEADERS]: _, ...params }: any = webhook;
|
let { [WebhookInputDataFields.HEADERS]: _, ...params }: any = webhook;
|
||||||
if (
|
if (webhook[WebhookInputDataFields.HEADERS].length) {
|
||||||
webhook[INPUT_FIELDS.HEADERS].length > 0 &&
|
const headers = webhook[WebhookInputDataFields.HEADERS].reduce(
|
||||||
webhook[INPUT_FIELDS.HEADERS][0][HEADER_FIELDS.KEY]
|
(acc, data) => {
|
||||||
) {
|
return data.key ? { ...acc, [data.key]: data.value } : acc;
|
||||||
const headers = webhook[INPUT_FIELDS.HEADERS].reduce((acc, data) => {
|
},
|
||||||
return { ...acc, [data.key]: data.value };
|
{}
|
||||||
}, {});
|
);
|
||||||
params[INPUT_FIELDS.HEADERS] = headers;
|
if (Object.keys(headers).length) {
|
||||||
|
params[WebhookInputDataFields.HEADERS] = headers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const res = await client.mutation(AddWebhook, { params }).toPromise();
|
const res = await client.mutation(AddWebhook, { params }).toPromise();
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
|
@ -234,7 +232,7 @@ const AddWebhookModal = () => {
|
||||||
});
|
});
|
||||||
setWebhook({
|
setWebhook({
|
||||||
...initWebhookData,
|
...initWebhookData,
|
||||||
[INPUT_FIELDS.HEADERS]: [{ ...initHeadersData }],
|
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
||||||
});
|
});
|
||||||
setValidator({ ...initWebhookValidatorData });
|
setValidator({ ...initWebhookValidatorData });
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -279,11 +277,11 @@ const AddWebhookModal = () => {
|
||||||
pr="4.5rem"
|
pr="4.5rem"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="user.login"
|
placeholder="user.login"
|
||||||
value={webhook[INPUT_FIELDS.EVENT_NAME]}
|
value={webhook[WebhookInputDataFields.EVENT_NAME]}
|
||||||
isInvalid={!validator[INPUT_FIELDS.EVENT_NAME]}
|
isInvalid={!validator[WebhookInputDataFields.EVENT_NAME]}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
inputChangehandler(
|
inputChangehandler(
|
||||||
INPUT_FIELDS.EVENT_NAME,
|
WebhookInputDataFields.EVENT_NAME,
|
||||||
e.currentTarget.value
|
e.currentTarget.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -304,11 +302,11 @@ const AddWebhookModal = () => {
|
||||||
pr="4.5rem"
|
pr="4.5rem"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="https://domain.com/webhook"
|
placeholder="https://domain.com/webhook"
|
||||||
value={webhook[INPUT_FIELDS.ENDPOINT]}
|
value={webhook[WebhookInputDataFields.ENDPOINT]}
|
||||||
isInvalid={!validator[INPUT_FIELDS.ENDPOINT]}
|
isInvalid={!validator[WebhookInputDataFields.ENDPOINT]}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
inputChangehandler(
|
inputChangehandler(
|
||||||
INPUT_FIELDS.ENDPOINT,
|
WebhookInputDataFields.ENDPOINT,
|
||||||
e.currentTarget.value
|
e.currentTarget.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -329,11 +327,11 @@ const AddWebhookModal = () => {
|
||||||
</Text>
|
</Text>
|
||||||
<Switch
|
<Switch
|
||||||
size="md"
|
size="md"
|
||||||
isChecked={webhook[INPUT_FIELDS.ENABLED]}
|
isChecked={webhook[WebhookInputDataFields.ENABLED]}
|
||||||
onChange={() =>
|
onChange={() =>
|
||||||
inputChangehandler(
|
inputChangehandler(
|
||||||
INPUT_FIELDS.ENABLED,
|
WebhookInputDataFields.ENABLED,
|
||||||
!webhook[INPUT_FIELDS.ENABLED]
|
!webhook[WebhookInputDataFields.ENABLED]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -364,7 +362,8 @@ const AddWebhookModal = () => {
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex flexDirection="column" maxH={220} overflowY="scroll">
|
<Flex flexDirection="column" maxH={220} overflowY="scroll">
|
||||||
{webhook[INPUT_FIELDS.HEADERS]?.map((headerData, index) => (
|
{webhook[WebhookInputDataFields.HEADERS]?.map(
|
||||||
|
(headerData, index) => (
|
||||||
<Flex
|
<Flex
|
||||||
key={`header-data-${index}`}
|
key={`header-data-${index}`}
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
|
@ -374,17 +373,17 @@ const AddWebhookModal = () => {
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="key"
|
placeholder="key"
|
||||||
value={headerData[HEADER_FIELDS.KEY]}
|
value={headerData[WebhookInputHeaderFields.KEY]}
|
||||||
isInvalid={
|
isInvalid={
|
||||||
!validator[INPUT_FIELDS.HEADERS][index]?.[
|
!validator[WebhookInputDataFields.HEADERS][index]?.[
|
||||||
HEADER_FIELDS.KEY
|
WebhookInputHeaderFields.KEY
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
inputChangehandler(
|
inputChangehandler(
|
||||||
INPUT_FIELDS.HEADERS,
|
WebhookInputDataFields.HEADERS,
|
||||||
e.target.value,
|
e.target.value,
|
||||||
HEADER_FIELDS.KEY,
|
WebhookInputHeaderFields.KEY,
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -397,17 +396,17 @@ const AddWebhookModal = () => {
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="value"
|
placeholder="value"
|
||||||
value={headerData[HEADER_FIELDS.VALUE]}
|
value={headerData[WebhookInputHeaderFields.VALUE]}
|
||||||
isInvalid={
|
isInvalid={
|
||||||
!validator[INPUT_FIELDS.HEADERS][index]?.[
|
!validator[WebhookInputDataFields.HEADERS][index]?.[
|
||||||
HEADER_FIELDS.VALUE
|
WebhookInputHeaderFields.VALUE
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
inputChangehandler(
|
inputChangehandler(
|
||||||
INPUT_FIELDS.HEADERS,
|
WebhookInputDataFields.HEADERS,
|
||||||
e.target.value,
|
e.target.value,
|
||||||
HEADER_FIELDS.VALUE,
|
WebhookInputHeaderFields.VALUE,
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -428,7 +427,8 @@ const AddWebhookModal = () => {
|
||||||
</InputRightElement>
|
</InputRightElement>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</Flex>
|
</Flex>
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
|
@ -153,3 +153,18 @@ export const envSubViews = {
|
||||||
ADMIN_SECRET: 'admin-secret',
|
ADMIN_SECRET: 'admin-secret',
|
||||||
DB_CRED: 'db-cred',
|
DB_CRED: 'db-cred',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum WebhookInputDataFields {
|
||||||
|
ID = 'id',
|
||||||
|
EVENT_NAME = 'event_name',
|
||||||
|
ENDPOINT = 'endpoint',
|
||||||
|
ENABLED = 'enabled',
|
||||||
|
HEADERS = 'headers',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WebhookInputHeaderFields {
|
||||||
|
KEY = 'key',
|
||||||
|
VALUE = 'value',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pageLimits: number[] = [5, 10, 15];
|
||||||
|
|
|
@ -101,3 +101,23 @@ export const EmailVerificationQuery = `
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const WebhooksDataQuery = `
|
||||||
|
query getWebhooksData {
|
||||||
|
_webhooks{
|
||||||
|
webhooks{
|
||||||
|
id
|
||||||
|
event_name
|
||||||
|
endpoint
|
||||||
|
enabled
|
||||||
|
headers
|
||||||
|
}
|
||||||
|
pagination{
|
||||||
|
limit
|
||||||
|
page
|
||||||
|
offset
|
||||||
|
total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -1,8 +1,109 @@
|
||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Box, Flex, Text } from '@chakra-ui/react';
|
import { useClient } from 'urql';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Center,
|
||||||
|
Flex,
|
||||||
|
IconButton,
|
||||||
|
Menu,
|
||||||
|
MenuButton,
|
||||||
|
MenuItem,
|
||||||
|
MenuList,
|
||||||
|
NumberDecrementStepper,
|
||||||
|
NumberIncrementStepper,
|
||||||
|
NumberInput,
|
||||||
|
NumberInputField,
|
||||||
|
NumberInputStepper,
|
||||||
|
Select,
|
||||||
|
Spinner,
|
||||||
|
Table,
|
||||||
|
TableCaption,
|
||||||
|
Tag,
|
||||||
|
Tbody,
|
||||||
|
Td,
|
||||||
|
Text,
|
||||||
|
Th,
|
||||||
|
Thead,
|
||||||
|
Tooltip,
|
||||||
|
Tr,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import {
|
||||||
|
FaAngleDoubleLeft,
|
||||||
|
FaAngleDoubleRight,
|
||||||
|
FaAngleDown,
|
||||||
|
FaAngleLeft,
|
||||||
|
FaAngleRight,
|
||||||
|
FaExclamationCircle,
|
||||||
|
} from 'react-icons/fa';
|
||||||
import AddWebhookModal from '../components/AddWebhookModal';
|
import AddWebhookModal from '../components/AddWebhookModal';
|
||||||
|
import { pageLimits, WebhookInputDataFields } from '../constants';
|
||||||
|
import { WebhooksDataQuery } from '../graphql/queries';
|
||||||
|
|
||||||
|
interface paginationPropTypes {
|
||||||
|
limit: number;
|
||||||
|
page: number;
|
||||||
|
offset: number;
|
||||||
|
total: number;
|
||||||
|
maxPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface webhookDataTypes {
|
||||||
|
[WebhookInputDataFields.ID]: string;
|
||||||
|
[WebhookInputDataFields.EVENT_NAME]: string;
|
||||||
|
[WebhookInputDataFields.ENDPOINT]: string;
|
||||||
|
[WebhookInputDataFields.ENABLED]: boolean;
|
||||||
|
[WebhookInputDataFields.HEADERS]?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
const Webhooks = () => {
|
const Webhooks = () => {
|
||||||
|
const client = useClient();
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [webhookData, setWebhookData] = useState<webhookDataTypes[]>([]);
|
||||||
|
const [paginationProps, setPaginationProps] = useState<paginationPropTypes>({
|
||||||
|
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 fetchWebookData = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
const res = await client.query(WebhooksDataQuery).toPromise();
|
||||||
|
if (res.data?._webhooks) {
|
||||||
|
const { pagination, webhooks } = res.data?._webhooks;
|
||||||
|
const maxPages = getMaxPages(pagination);
|
||||||
|
if (webhooks?.length) {
|
||||||
|
setWebhookData(webhooks);
|
||||||
|
setPaginationProps({ ...paginationProps, ...pagination, maxPages });
|
||||||
|
} else {
|
||||||
|
if (paginationProps.page !== 1) {
|
||||||
|
setPaginationProps({
|
||||||
|
...paginationProps,
|
||||||
|
...pagination,
|
||||||
|
maxPages,
|
||||||
|
page: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fetchWebookData();
|
||||||
|
}, []);
|
||||||
|
const paginationHandler = (value: Record<string, number>) => {
|
||||||
|
setPaginationProps({ ...paginationProps, ...value });
|
||||||
|
};
|
||||||
|
console.log('webhookData ==>> ', webhookData);
|
||||||
return (
|
return (
|
||||||
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
<Box m="5" py="5" px="10" bg="white" rounded="md">
|
||||||
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
<Flex margin="2% 0" justifyContent="space-between" alignItems="center">
|
||||||
|
@ -11,6 +112,218 @@ const Webhooks = () => {
|
||||||
</Text>
|
</Text>
|
||||||
<AddWebhookModal />
|
<AddWebhookModal />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
{!loading ? (
|
||||||
|
webhookData.length ? (
|
||||||
|
<Table variant="simple">
|
||||||
|
<Thead>
|
||||||
|
<Tr>
|
||||||
|
<Th>Event Name</Th>
|
||||||
|
<Th>Endpoint</Th>
|
||||||
|
<Th>Enabled</Th>
|
||||||
|
<Th>Headers</Th>
|
||||||
|
<Th>Actions</Th>
|
||||||
|
</Tr>
|
||||||
|
</Thead>
|
||||||
|
<Tbody>
|
||||||
|
{webhookData.map((webhook: webhookDataTypes, index: number) => (
|
||||||
|
<Tr
|
||||||
|
key={webhook[WebhookInputDataFields.ID]}
|
||||||
|
style={{ fontSize: 14 }}
|
||||||
|
>
|
||||||
|
<Td maxW="300">
|
||||||
|
{webhook[WebhookInputDataFields.EVENT_NAME]}
|
||||||
|
</Td>
|
||||||
|
<Td>{webhook[WebhookInputDataFields.ENDPOINT]}</Td>
|
||||||
|
<Td>
|
||||||
|
<Tag
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
colorScheme={
|
||||||
|
webhook[WebhookInputDataFields.ENABLED]
|
||||||
|
? 'green'
|
||||||
|
: 'yellow'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{webhook[WebhookInputDataFields.ENABLED].toString()}
|
||||||
|
</Tag>
|
||||||
|
</Td>
|
||||||
|
<Td>
|
||||||
|
{
|
||||||
|
Object.keys(webhook[WebhookInputDataFields.HEADERS] || {})
|
||||||
|
?.length
|
||||||
|
}
|
||||||
|
</Td>
|
||||||
|
<Td>
|
||||||
|
<Menu>
|
||||||
|
<MenuButton as={Button} variant="unstyled" size="sm">
|
||||||
|
<Flex
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
>
|
||||||
|
<Text fontSize="sm" fontWeight="light">
|
||||||
|
Menu
|
||||||
|
</Text>
|
||||||
|
<FaAngleDown style={{ marginLeft: 10 }} />
|
||||||
|
</Flex>
|
||||||
|
</MenuButton>
|
||||||
|
<MenuList>
|
||||||
|
<MenuItem onClick={() => {}}>Edit</MenuItem>
|
||||||
|
<MenuItem onClick={() => {}}>Delete</MenuItem>
|
||||||
|
<MenuItem onClick={() => {}}>View Logs</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Menu>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</Tbody>
|
||||||
|
{(paginationProps.maxPages > 1 || paginationProps.total >= 5) && (
|
||||||
|
<TableCaption>
|
||||||
|
<Flex
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
m="2% 0"
|
||||||
|
>
|
||||||
|
<Flex flex="1">
|
||||||
|
<Tooltip label="First Page">
|
||||||
|
<IconButton
|
||||||
|
aria-label="icon button"
|
||||||
|
onClick={() =>
|
||||||
|
paginationHandler({
|
||||||
|
page: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
isDisabled={paginationProps.page <= 1}
|
||||||
|
mr={4}
|
||||||
|
icon={<FaAngleDoubleLeft />}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip label="Previous Page">
|
||||||
|
<IconButton
|
||||||
|
aria-label="icon button"
|
||||||
|
onClick={() =>
|
||||||
|
paginationHandler({
|
||||||
|
page: paginationProps.page - 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
isDisabled={paginationProps.page <= 1}
|
||||||
|
icon={<FaAngleLeft />}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Flex>
|
||||||
|
<Flex
|
||||||
|
flex="8"
|
||||||
|
justifyContent="space-evenly"
|
||||||
|
alignItems="center"
|
||||||
|
>
|
||||||
|
<Text mr={8}>
|
||||||
|
Page{' '}
|
||||||
|
<Text fontWeight="bold" as="span">
|
||||||
|
{paginationProps.page}
|
||||||
|
</Text>{' '}
|
||||||
|
of{' '}
|
||||||
|
<Text fontWeight="bold" as="span">
|
||||||
|
{paginationProps.maxPages}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
<Flex alignItems="center">
|
||||||
|
<Text flexShrink="0">Go to page:</Text>{' '}
|
||||||
|
<NumberInput
|
||||||
|
ml={2}
|
||||||
|
mr={8}
|
||||||
|
w={28}
|
||||||
|
min={1}
|
||||||
|
max={paginationProps.maxPages}
|
||||||
|
onChange={(value) =>
|
||||||
|
paginationHandler({
|
||||||
|
page: parseInt(value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
value={paginationProps.page}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
<NumberInputStepper>
|
||||||
|
<NumberIncrementStepper />
|
||||||
|
<NumberDecrementStepper />
|
||||||
|
</NumberInputStepper>
|
||||||
|
</NumberInput>
|
||||||
|
</Flex>
|
||||||
|
<Select
|
||||||
|
w={32}
|
||||||
|
value={paginationProps.limit}
|
||||||
|
onChange={(e) =>
|
||||||
|
paginationHandler({
|
||||||
|
page: 1,
|
||||||
|
limit: parseInt(e.target.value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{pageLimits.map((pageSize) => (
|
||||||
|
<option key={pageSize} value={pageSize}>
|
||||||
|
Show {pageSize}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Flex>
|
||||||
|
<Flex flex="1">
|
||||||
|
<Tooltip label="Next Page">
|
||||||
|
<IconButton
|
||||||
|
aria-label="icon button"
|
||||||
|
onClick={() =>
|
||||||
|
paginationHandler({
|
||||||
|
page: paginationProps.page + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
isDisabled={
|
||||||
|
paginationProps.page >= paginationProps.maxPages
|
||||||
|
}
|
||||||
|
icon={<FaAngleRight />}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip label="Last Page">
|
||||||
|
<IconButton
|
||||||
|
aria-label="icon button"
|
||||||
|
onClick={() =>
|
||||||
|
paginationHandler({
|
||||||
|
page: paginationProps.maxPages,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
isDisabled={
|
||||||
|
paginationProps.page >= paginationProps.maxPages
|
||||||
|
}
|
||||||
|
ml={4}
|
||||||
|
icon={<FaAngleDoubleRight />}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</TableCaption>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
) : (
|
||||||
|
<Flex
|
||||||
|
flexDirection="column"
|
||||||
|
minH="25vh"
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
>
|
||||||
|
<Center w="50px" marginRight="1.5%">
|
||||||
|
<FaExclamationCircle style={{ color: '#f0f0f0', fontSize: 70 }} />
|
||||||
|
</Center>
|
||||||
|
<Text
|
||||||
|
fontSize="2xl"
|
||||||
|
paddingRight="1%"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="#d9d9d9"
|
||||||
|
>
|
||||||
|
No Data
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<Center minH="25vh">
|
||||||
|
<Spinner />
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user