mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-23 16:38:17 +00:00
fix(ui): webhook event handling with tree structure (#7164)
* fix(ui): webhook event handling with tree structure * Fix layout * minor fix * Fix edit webhook redirection. * Fix tree structure issues Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com>
This commit is contained in:
parent
c729abaa95
commit
00e6996ac0
@ -68,3 +68,11 @@ export const resetAllFilters = async () => {
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getInitialFilters = async () => {
|
||||
const url = `${BASE_URL}/bootstrappedFilters`;
|
||||
|
||||
const response = await axiosClient.get<EventFilter[]>(url);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
@ -14,7 +14,6 @@
|
||||
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Tooltip } from 'antd';
|
||||
import { Store } from 'antd/lib/form/interface';
|
||||
import classNames from 'classnames';
|
||||
import cryptoRandomString from 'crypto-random-string-with-promisify-polyfill';
|
||||
import { cloneDeep, isEmpty, isNil } from 'lodash';
|
||||
@ -26,7 +25,7 @@ import React, {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { ROUTES, TERM_ALL } from '../../constants/constants';
|
||||
import { ROUTES } from '../../constants/constants';
|
||||
import {
|
||||
GlobalSettingOptions,
|
||||
GlobalSettingsMenuCategory,
|
||||
@ -55,7 +54,6 @@ import {
|
||||
import { checkPermission } from '../../utils/PermissionsUtils';
|
||||
import { getSettingPath } from '../../utils/RouterUtils';
|
||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import { getEventFilters } from '../../utils/WebhookUtils';
|
||||
import { Button } from '../buttons/Button/Button';
|
||||
import CopyToClipboardButton from '../buttons/CopyToClipboardButton/CopyToClipboardButton';
|
||||
import CardV1 from '../common/Card/CardV1';
|
||||
@ -67,8 +65,7 @@ import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
|
||||
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
|
||||
import { ResourceEntity } from '../PermissionProvider/PermissionProvider.interface';
|
||||
import { AddWebhookProps } from './AddWebhook.interface';
|
||||
import EventFilterSelect from './EventFilterSelect.component';
|
||||
import { EVENT_FILTER_FORM_INITIAL_VALUE } from './WebhookConstants';
|
||||
import EventFilterTree from './EventFilterTree.component';
|
||||
|
||||
const CONFIGURE_TEXT: { [key: string]: string } = {
|
||||
msteams: CONFIGURE_MS_TEAMS_TEXT,
|
||||
@ -80,26 +77,6 @@ const Field = ({ children }: { children: React.ReactNode }) => {
|
||||
return <div className="tw-mt-4">{children}</div>;
|
||||
};
|
||||
|
||||
const getFormData = (eventFilters: EventFilter[]): Store => {
|
||||
if (eventFilters.length === 1 && eventFilters[0].entityType === TERM_ALL) {
|
||||
return EVENT_FILTER_FORM_INITIAL_VALUE;
|
||||
}
|
||||
|
||||
const formEventFilters = {} as Store;
|
||||
|
||||
eventFilters?.forEach((eventFilter) => {
|
||||
if (eventFilter.entityType === TERM_ALL) {
|
||||
return;
|
||||
}
|
||||
|
||||
formEventFilters[eventFilter.entityType] = true;
|
||||
formEventFilters[`${eventFilter.entityType}-tree`] =
|
||||
eventFilter.filters?.map((filter) => filter.eventType) || [];
|
||||
});
|
||||
|
||||
return formEventFilters;
|
||||
};
|
||||
|
||||
const AddWebhook: FunctionComponent<AddWebhookProps> = ({
|
||||
data,
|
||||
header,
|
||||
@ -113,11 +90,9 @@ const AddWebhook: FunctionComponent<AddWebhookProps> = ({
|
||||
onSave,
|
||||
}: AddWebhookProps) => {
|
||||
const markdownRef = useRef<EditorContentRef>();
|
||||
const [eventFilterFormData, setEventFilterFormData] = useState<Store>(
|
||||
data?.eventFilters
|
||||
? getFormData(data?.eventFilters)
|
||||
: EVENT_FILTER_FORM_INITIAL_VALUE
|
||||
);
|
||||
const [eventFilterFormData, setEventFilterFormData] = useState<
|
||||
EventFilter[] | undefined
|
||||
>(data?.eventFilters);
|
||||
const [name, setName] = useState<string>(data?.name || '');
|
||||
const [endpointUrl, setEndpointUrl] = useState<string>(data?.endpoint || '');
|
||||
const [description] = useState<string>(data?.description || '');
|
||||
@ -250,7 +225,7 @@ const AddWebhook: FunctionComponent<AddWebhookProps> = ({
|
||||
name,
|
||||
description: markdownRef.current?.getEditorContent() || undefined,
|
||||
endpoint: endpointUrl,
|
||||
eventFilters: getEventFilters(eventFilterFormData),
|
||||
eventFilters: eventFilterFormData ?? ([] as EventFilter[]),
|
||||
batchSize,
|
||||
timeout: connectionTimeout,
|
||||
enabled: active,
|
||||
@ -468,9 +443,9 @@ const AddWebhook: FunctionComponent<AddWebhookProps> = ({
|
||||
</span>,
|
||||
'tw-mt-3'
|
||||
)}
|
||||
<EventFilterSelect
|
||||
eventFilterFormData={eventFilterFormData}
|
||||
setEventFilterFormData={(data) => setEventFilterFormData(data)}
|
||||
<EventFilterTree
|
||||
value={eventFilterFormData || []}
|
||||
onChange={setEventFilterFormData}
|
||||
/>
|
||||
<Field>
|
||||
<div className="tw-flex tw-justify-end tw-pt-1">
|
||||
|
@ -1,89 +0,0 @@
|
||||
import { Col, Form, Row, TreeSelect } from 'antd';
|
||||
import Checkbox from 'antd/lib/checkbox/Checkbox';
|
||||
import { Store } from 'antd/lib/form/interface';
|
||||
import { startCase } from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
EventFilter,
|
||||
EventType,
|
||||
} from '../../generated/api/events/createWebhook';
|
||||
import { Entities } from './WebhookConstants';
|
||||
|
||||
export enum EventUpdateTypes {
|
||||
UpdatedFollowers = 'updatedFollowers',
|
||||
UpdatedTags = 'updatedTags',
|
||||
UpdatedOwner = 'updatedOwner',
|
||||
UpdateDescription = 'updateDescription',
|
||||
}
|
||||
|
||||
interface EventFilterSelectProps {
|
||||
eventFilterFormData: Store;
|
||||
setEventFilterFormData: (formData: EventFilter[]) => void;
|
||||
}
|
||||
const EventFilterSelect = ({
|
||||
eventFilterFormData,
|
||||
setEventFilterFormData,
|
||||
}: EventFilterSelectProps) => {
|
||||
const metricsOptions = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: 'All',
|
||||
value: 'all',
|
||||
key: 'all',
|
||||
children: Object.values(EventType).map((metric) => ({
|
||||
title: startCase(metric),
|
||||
value: metric,
|
||||
key: metric,
|
||||
children:
|
||||
metric === EventType.EntityUpdated
|
||||
? Object.values(EventUpdateTypes).map((updateType) => ({
|
||||
title: startCase(updateType),
|
||||
value: `${EventType.EntityUpdated}-${updateType}`,
|
||||
key: `${EventType.EntityUpdated}-${updateType}`,
|
||||
}))
|
||||
: undefined,
|
||||
})),
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<Form
|
||||
autoComplete="off"
|
||||
initialValues={eventFilterFormData}
|
||||
layout="vertical"
|
||||
onValuesChange={(_, data) => {
|
||||
setEventFilterFormData(data);
|
||||
}}>
|
||||
<Row gutter={16}>
|
||||
{Object.keys(Entities).map((key) => {
|
||||
const value = Entities[key];
|
||||
|
||||
return (
|
||||
<Col key={key} span={12}>
|
||||
<Form.Item
|
||||
name={key}
|
||||
style={{ marginBottom: 4 }}
|
||||
valuePropName="checked">
|
||||
<Checkbox>{value}</Checkbox>
|
||||
</Form.Item>
|
||||
<Form.Item name={`${key}-tree`} style={{ marginBottom: 8 }}>
|
||||
<TreeSelect
|
||||
treeCheckable
|
||||
disabled={!eventFilterFormData[key]}
|
||||
maxTagCount={2}
|
||||
placeholder="Please select"
|
||||
showCheckedStrategy="SHOW_PARENT"
|
||||
treeData={metricsOptions}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventFilterSelect;
|
@ -0,0 +1,138 @@
|
||||
import { Divider, Tree } from 'antd';
|
||||
import { cloneDeep, isEmpty, map, startCase } from 'lodash';
|
||||
import React, { Key, useEffect, useMemo, useState } from 'react';
|
||||
import { getInitialFilters } from '../../axiosAPIs/eventFiltersAPI';
|
||||
import { TERM_ALL } from '../../constants/constants';
|
||||
import { EventFilter } from '../../generated/api/events/createWebhook';
|
||||
import { Filters } from '../../generated/settings/settings';
|
||||
import { getEventFilterFromTree } from '../../pages/ActivityFeedSettingsPage/ActivityFeedSettingsPage.utils';
|
||||
import './../../pages/ActivityFeedSettingsPage/ActivityFeedSettingsPage.style.less';
|
||||
|
||||
interface EventFilterTreeProps {
|
||||
value: EventFilter[];
|
||||
onChange: (data: EventFilter[]) => void;
|
||||
}
|
||||
|
||||
const EventFilterTree = ({ value, onChange }: EventFilterTreeProps) => {
|
||||
const [updatedTree, setUpdatedTree] = useState<Record<string, string[]>>();
|
||||
const [initialFilters, setInitialFilters] = useState<EventFilter[]>([]);
|
||||
|
||||
const eventFilters = isEmpty(value) ? initialFilters : value;
|
||||
const fetchInitialFilters = async () => {
|
||||
try {
|
||||
const data = await getInitialFilters();
|
||||
setInitialFilters(data);
|
||||
isEmpty(value) && onChange(getEventFilterFromTree({}, eventFilters));
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`filed to fetch event filters `);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchInitialFilters();
|
||||
}, []);
|
||||
|
||||
const generateTreeData = (entityType: string, data?: Filters[]) => {
|
||||
return [
|
||||
{
|
||||
key: entityType,
|
||||
title: <strong>{startCase(entityType)}</strong>,
|
||||
data: true,
|
||||
children:
|
||||
data?.map(({ eventType, include, exclude }) => {
|
||||
const key = `${entityType}-${eventType}` as string;
|
||||
|
||||
return {
|
||||
key: key,
|
||||
title: startCase(eventType),
|
||||
data: isEmpty(value) ? true : include,
|
||||
children:
|
||||
(include?.length === 1 && include[0] === TERM_ALL) ||
|
||||
(exclude?.length === 1 && exclude[0] === TERM_ALL)
|
||||
? undefined
|
||||
: [
|
||||
...(include?.map((inc) => ({
|
||||
key: `${key}-${inc}`,
|
||||
title: startCase(inc),
|
||||
data: true,
|
||||
})) || []),
|
||||
...(exclude?.map((ex) => ({
|
||||
key: `${key}-${ex}`,
|
||||
title: startCase(ex),
|
||||
data: false,
|
||||
})) || []),
|
||||
],
|
||||
};
|
||||
}) || [],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const handleTreeCheckChange = (keys: Key[], entityType: string) => {
|
||||
const updateData = cloneDeep(updatedTree || {});
|
||||
|
||||
updateData[entityType] = keys as string[];
|
||||
|
||||
onChange(getEventFilterFromTree(cloneDeep(updateData), eventFilters));
|
||||
setUpdatedTree(updateData);
|
||||
};
|
||||
const getCheckedKeys = (eventFilters: EventFilter[]) => {
|
||||
const checkedArray = [] as string[];
|
||||
const clonedFilters = cloneDeep(eventFilters);
|
||||
|
||||
clonedFilters?.map(({ entityType, filters }) => {
|
||||
filters &&
|
||||
filters.map((obj) => {
|
||||
if (
|
||||
obj.include &&
|
||||
obj.include.length === 1 &&
|
||||
obj.include[0] === 'all'
|
||||
) {
|
||||
checkedArray.push(`${entityType}-${obj.eventType}`);
|
||||
} else {
|
||||
obj?.include?.forEach((entityUpdated) => {
|
||||
const name = `${entityType}-${obj.eventType}-${entityUpdated}`;
|
||||
checkedArray.push(name);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return checkedArray;
|
||||
};
|
||||
|
||||
const checkedKeys = useMemo(() => {
|
||||
const checkKeys = getCheckedKeys(eventFilters as EventFilter[]);
|
||||
|
||||
return checkKeys;
|
||||
}, [eventFilters, updatedTree]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{initialFilters &&
|
||||
map(initialFilters, ({ entityType, filters }, index) => (
|
||||
<>
|
||||
{entityType !== TERM_ALL ? (
|
||||
<div className="tw-rounded-border" key={entityType}>
|
||||
<Tree
|
||||
checkable
|
||||
defaultExpandAll
|
||||
className="activity-feed-settings-tree"
|
||||
defaultCheckedKeys={checkedKeys}
|
||||
key={entityType}
|
||||
treeData={generateTreeData(entityType, filters)}
|
||||
onCheck={(keys) =>
|
||||
handleTreeCheckChange(keys as Key[], entityType)
|
||||
}
|
||||
/>
|
||||
{index !== initialFilters.length - 1 && <Divider />}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventFilterTree;
|
@ -129,64 +129,53 @@ const WebhooksV1: FC<WebhooksV1Props> = ({
|
||||
return (
|
||||
<>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col xs={18}>
|
||||
<Select
|
||||
showArrow
|
||||
bordered={false}
|
||||
className="tw-text-body webhook-filter-select cursor-pointer"
|
||||
mode="multiple"
|
||||
options={statuses}
|
||||
placeholder="Filter by status"
|
||||
style={{ minWidth: '148px' }}
|
||||
onChange={onStatusFilter}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={6}>
|
||||
<Space
|
||||
align="center"
|
||||
className="tw-w-full tw-justify-end"
|
||||
size={16}>
|
||||
{filteredData.length > 0 && (
|
||||
<Tooltip
|
||||
placement="left"
|
||||
title={
|
||||
addWebhookPermission
|
||||
? 'Add Webhook'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}>
|
||||
<Button
|
||||
className={classNames('tw-h-8 tw-rounded ')}
|
||||
data-testid="add-webhook-button"
|
||||
disabled={!addWebhookPermission}
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="contained"
|
||||
onClick={onAddWebhook}>
|
||||
Add {WEBHOOKS_INTEGRATION[webhookType]}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Space>
|
||||
</Col>
|
||||
<Col xs={24}>
|
||||
<WebhookTable
|
||||
webhookList={filteredData || []}
|
||||
onDelete={(data) => setWebhook(data)}
|
||||
onEdit={onClickWebhook}
|
||||
/>
|
||||
{Boolean(!isNil(paging.after) || !isNil(paging.before)) && (
|
||||
<NextPrevious
|
||||
currentPage={currentPage}
|
||||
pageSize={PAGE_SIZE}
|
||||
paging={paging}
|
||||
pagingHandler={onPageChange}
|
||||
totalCount={paging.total}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<Col xs={18}>
|
||||
<Select
|
||||
showArrow
|
||||
bordered={false}
|
||||
className="tw-text-body webhook-filter-select cursor-pointer"
|
||||
mode="multiple"
|
||||
options={statuses}
|
||||
placeholder="Filter by status"
|
||||
style={{ minWidth: '148px' }}
|
||||
onChange={onStatusFilter}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={6}>
|
||||
<Space align="center" className="tw-w-full tw-justify-end" size={16}>
|
||||
<Tooltip
|
||||
placement="left"
|
||||
title={
|
||||
addWebhookPermission ? 'Add Webhook' : NO_PERMISSION_FOR_ACTION
|
||||
}>
|
||||
<Button
|
||||
className={classNames('tw-h-8 tw-rounded ')}
|
||||
data-testid="add-webhook-button"
|
||||
disabled={!addWebhookPermission}
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="contained"
|
||||
onClick={onAddWebhook}>
|
||||
Add {WEBHOOKS_INTEGRATION[webhookType]}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col xs={24}>
|
||||
<WebhookTable
|
||||
webhookList={filteredData || []}
|
||||
onDelete={(data) => setWebhook(data)}
|
||||
onEdit={onClickWebhook}
|
||||
/>
|
||||
{Boolean(!isNil(paging.after) || !isNil(paging.before)) && (
|
||||
<NextPrevious
|
||||
currentPage={currentPage}
|
||||
pageSize={PAGE_SIZE}
|
||||
paging={paging}
|
||||
pagingHandler={onPageChange}
|
||||
totalCount={paging.total}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
{selectedWebhook && (
|
||||
|
@ -169,6 +169,7 @@ const jsonData = {
|
||||
|
||||
'update-profile-congif-success': 'Profile config updated successfully!',
|
||||
'update-test-case-success': 'Test case updated successfully!',
|
||||
'update-webhook-success': 'Webhook updated successfully!',
|
||||
},
|
||||
'form-error-messages': {
|
||||
'empty-email': 'Email is required.',
|
||||
|
@ -6,6 +6,8 @@ describe('Test ActivityFeedSettingsPage', () => {
|
||||
it('should render properly', async () => {
|
||||
const { findByText } = render(<ActivityFeedSettingsPage />);
|
||||
|
||||
expect(await findByText(/Activity Feed/)).toBeInTheDocument();
|
||||
expect(
|
||||
await findByText(/No activity feed settings available/)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
resetAllFilters,
|
||||
updateFilters,
|
||||
} from '../../axiosAPIs/eventFiltersAPI';
|
||||
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
import { TERM_ALL } from '../../constants/constants';
|
||||
import {
|
||||
@ -187,51 +188,61 @@ const ActivityFeedSettingsPage: React.FC = () => {
|
||||
<Loader />
|
||||
</Col>
|
||||
) : (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Typography.Title level={5} type="secondary">
|
||||
Activity Feed
|
||||
</Typography.Title>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card size="small">
|
||||
{eventFilters &&
|
||||
map(eventFilters, ({ entityType, filters }, index) => (
|
||||
<>
|
||||
{entityType !== TERM_ALL ? (
|
||||
<div className="tw-rounded-border" key={entityType}>
|
||||
<Tree
|
||||
checkable
|
||||
defaultExpandAll
|
||||
className="activity-feed-settings-tree"
|
||||
defaultCheckedKeys={checkedKeys}
|
||||
icon={null}
|
||||
key={entityType}
|
||||
treeData={generateTreeData(entityType, filters)}
|
||||
onCheck={(keys) =>
|
||||
handleTreeCheckChange(keys as Key[], entityType)
|
||||
}
|
||||
/>
|
||||
{index !== eventFilters?.length - 1 && <Divider />}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
))}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col>
|
||||
<Space direction="horizontal" size={16}>
|
||||
<Button type="primary" onClick={onSave}>
|
||||
Save
|
||||
</Button>
|
||||
<Button type="text" onClick={handleResetClick}>
|
||||
Reset all
|
||||
</Button>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col span={24} />
|
||||
<Col span={24} />
|
||||
</Row>
|
||||
<>
|
||||
{eventFilters ? (
|
||||
<>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Typography.Title level={5} type="secondary">
|
||||
Activity Feed
|
||||
</Typography.Title>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card size="small">
|
||||
{eventFilters &&
|
||||
map(eventFilters, ({ entityType, filters }, index) => (
|
||||
<>
|
||||
{entityType !== TERM_ALL ? (
|
||||
<div className="tw-rounded-border" key={entityType}>
|
||||
<Tree
|
||||
checkable
|
||||
defaultExpandAll
|
||||
className="activity-feed-settings-tree"
|
||||
defaultCheckedKeys={checkedKeys}
|
||||
icon={null}
|
||||
key={entityType}
|
||||
treeData={generateTreeData(entityType, filters)}
|
||||
onCheck={(keys) =>
|
||||
handleTreeCheckChange(keys as Key[], entityType)
|
||||
}
|
||||
/>
|
||||
{index !== eventFilters?.length - 1 && <Divider />}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
))}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col>
|
||||
<Space direction="horizontal" size={16}>
|
||||
<Button type="primary" onClick={onSave}>
|
||||
Save
|
||||
</Button>
|
||||
<Button type="text" onClick={handleResetClick}>
|
||||
Reset all
|
||||
</Button>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col span={24} />
|
||||
<Col span={24} />
|
||||
</Row>
|
||||
</>
|
||||
) : (
|
||||
<ErrorPlaceHolder>
|
||||
<Typography.Text>No activity feed settings available</Typography.Text>
|
||||
</ErrorPlaceHolder>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { intersection, isEmpty, isUndefined, xor } from 'lodash';
|
||||
import { isEmpty, isUndefined, xor } from 'lodash';
|
||||
import {
|
||||
EventFilter,
|
||||
EventType,
|
||||
@ -77,19 +77,30 @@ export const getEventFilterFromTree = (
|
||||
filters: eventFilter.filters?.map((filter) => {
|
||||
let includeList = filter.include;
|
||||
let excludeList = filter.exclude;
|
||||
|
||||
// derive the merge list
|
||||
const mergedList = [
|
||||
...(includeList as string[]),
|
||||
...(excludeList as string[]),
|
||||
];
|
||||
|
||||
// manipulate tree if event type is present
|
||||
if (updatedTree[eventFilter.entityType]) {
|
||||
// Split the value to get list of [eventType, filter, event]
|
||||
const temp = updatedTree[eventFilter.entityType].map((key) =>
|
||||
key.split('-')
|
||||
);
|
||||
|
||||
// grab the list of current eventType
|
||||
const eventList = temp.filter((f) => f[1] === filter.eventType);
|
||||
|
||||
if (eventList.length > 0) {
|
||||
if (filter.eventType === EventType.EntityUpdated) {
|
||||
includeList = intersection(
|
||||
filter.include ?? [],
|
||||
eventList.map((f) => f[2])
|
||||
);
|
||||
excludeList = xor(filter.include, includeList);
|
||||
// derive include list based on selected events
|
||||
includeList = eventList.map((f) => f[2]).filter(Boolean);
|
||||
|
||||
// derive the exclude list by symmetric difference
|
||||
excludeList = xor(mergedList, includeList);
|
||||
} else {
|
||||
includeList = ['all'];
|
||||
excludeList = [];
|
||||
|
@ -30,11 +30,11 @@ import {
|
||||
} from '../../constants/globalSettings.constants';
|
||||
import { FormSubmitType } from '../../enums/form.enum';
|
||||
import { CreateWebhook } from '../../generated/api/events/createWebhook';
|
||||
import { Webhook } from '../../generated/entity/events/webhook';
|
||||
import { Webhook, WebhookType } from '../../generated/entity/events/webhook';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
import jsonData from '../../jsons/en';
|
||||
import { getSettingPath } from '../../utils/RouterUtils';
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
|
||||
|
||||
const EDIT_HEADER_WEBHOOKS_TITLE: { [key: string]: string } = {
|
||||
msteams: 'MS Teams',
|
||||
@ -69,11 +69,23 @@ const EditWebhookPage: FunctionComponent = () => {
|
||||
};
|
||||
|
||||
const goToWebhooks = () => {
|
||||
let type = GlobalSettingOptions.WEBHOOK;
|
||||
switch (webhookData?.webhookType) {
|
||||
case WebhookType.Msteams:
|
||||
type = GlobalSettingOptions.MSTEAMS;
|
||||
|
||||
break;
|
||||
case WebhookType.Slack:
|
||||
type = GlobalSettingOptions.SLACK;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
history.push(
|
||||
getSettingPath(
|
||||
GlobalSettingsMenuCategory.INTEGRATIONS,
|
||||
GlobalSettingOptions.WEBHOOK
|
||||
)
|
||||
`${getSettingPath(GlobalSettingsMenuCategory.INTEGRATIONS, type)}`
|
||||
);
|
||||
};
|
||||
|
||||
@ -92,6 +104,9 @@ const EditWebhookPage: FunctionComponent = () => {
|
||||
setStatus('initial');
|
||||
goToWebhooks();
|
||||
}, 500);
|
||||
showSuccessToast(
|
||||
jsonData['api-success-messages']['update-webhook-success']
|
||||
);
|
||||
} else {
|
||||
throw jsonData['api-error-messages']['unexpected-error'];
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user