diff --git a/frontend/app/components/Client/Client.tsx b/frontend/app/components/Client/Client.tsx
index be2bfd3cf..58f1aa7da 100644
--- a/frontend/app/components/Client/Client.tsx
+++ b/frontend/app/components/Client/Client.tsx
@@ -14,6 +14,7 @@ import Notifications from './Notifications';
import Roles from './Roles';
import SessionsListingSettings from 'Components/Client/SessionsListingSettings';
import Modules from 'Components/Client/Modules';
+import CustomEventsList from 'Components/Client/CustomEvents/CustomEventsList';
@withRouter
export default class Client extends React.PureComponent {
@@ -38,6 +39,7 @@ export default class Client extends React.PureComponent {
+
);
diff --git a/frontend/app/components/Client/CustomEvents/CustomEventForm.tsx b/frontend/app/components/Client/CustomEvents/CustomEventForm.tsx
new file mode 100644
index 000000000..a532961b1
--- /dev/null
+++ b/frontend/app/components/Client/CustomEvents/CustomEventForm.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { Button, Form, Input } from 'antd';
+import { FormField } from 'semantic-ui-react';
+
+interface Props {
+ event?: any;
+}
+
+function CustomEventForm(props: Props) {
+ return (
+
+
+
+ );
+}
+
+export default CustomEventForm;
diff --git a/frontend/app/components/Client/CustomEvents/CustomEventItem.tsx b/frontend/app/components/Client/CustomEvents/CustomEventItem.tsx
new file mode 100644
index 000000000..4c11820b9
--- /dev/null
+++ b/frontend/app/components/Client/CustomEvents/CustomEventItem.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+
+interface Props {
+ event: any;
+}
+
+function CustomEventItem(props: Props) {
+ return (
+
+
{props.event.name}
+
{props.event.user?.name}
+ {/*
{props.event.created_at}
*/}
+
+ );
+}
+
+export default CustomEventItem;
diff --git a/frontend/app/components/Client/CustomEvents/CustomEventsList.tsx b/frontend/app/components/Client/CustomEvents/CustomEventsList.tsx
new file mode 100644
index 000000000..28b1d087b
--- /dev/null
+++ b/frontend/app/components/Client/CustomEvents/CustomEventsList.tsx
@@ -0,0 +1,78 @@
+import React, { useEffect } from 'react';
+import cn from 'classnames';
+import styles from 'Components/Client/Webhooks/webhooks.module.css';
+import { Button, Divider, Icon, Loader, NoContent } from 'UI';
+import AnimatedSVG from 'Shared/AnimatedSVG';
+import { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
+import CustomEventItem from 'Components/Client/CustomEvents/CustomEventItem';
+import { useStore } from 'App/mstore';
+import { useModal } from 'Components/ModalContext';
+import CustomEventForm from 'Components/Client/CustomEvents/CustomEventForm';
+import { List } from 'antd';
+
+function CustomEventsList() {
+ const [loading, setLoading] = React.useState(false);
+ const { customEventStore: store } = useStore();
+ const { openModal } = useModal();
+
+ // useEffect(() => {
+ // setLoading(true);
+ // store.fetchAll({}).finally(() => {
+ // setLoading(false);
+ // });
+ // setTimeout(() => {
+ // setLoading(false);
+ // }, 2000);
+ // }, []);
+
+ const init = () => {
+ console.log('init');
+ showEvent();
+ };
+
+ const showEvent = (event?: any) => {
+ openModal(, {
+ title: event ? 'Edit Event' : 'Add Event',
+ width: 400
+ });
+ };
+
+ return (
+
+
+
{'Events'}
+
+
+
+
+
+ Leverage webhook notifications on alerts to trigger custom callbacks.
+
+
+
+
+
+ None added yet
+
+ }
+ size="small"
+ show={store.list.length === 0}
+ >
+ (
+
+
+
+ )} />
+
+
+
+ );
+}
+
+const mapStateToProps = (state: any) => ({
+ sites: state.getIn(['site', 'list'])
+});
+
+export default CustomEventsList;
diff --git a/frontend/app/layout/SideMenu.tsx b/frontend/app/layout/SideMenu.tsx
index 476a95296..c2c2ccd5c 100644
--- a/frontend/app/layout/SideMenu.tsx
+++ b/frontend/app/layout/SideMenu.tsx
@@ -124,7 +124,8 @@ function SideMenu(props: Props) {
[PREFERENCES_MENU.TEAM]: () => client(CLIENT_TABS.MANAGE_USERS),
[PREFERENCES_MENU.NOTIFICATIONS]: () => client(CLIENT_TABS.NOTIFICATIONS),
[PREFERENCES_MENU.BILLING]: () => client(CLIENT_TABS.BILLING),
- [PREFERENCES_MENU.MODULES]: () => client(CLIENT_TABS.MODULES)
+ [PREFERENCES_MENU.MODULES]: () => client(CLIENT_TABS.MODULES),
+ [PREFERENCES_MENU.CUSTOM_EVENTS]: () => client(CLIENT_TABS.CUSTOM_EVENTS),
};
const handleClick = (item: any) => {
diff --git a/frontend/app/layout/data.ts b/frontend/app/layout/data.ts
index ea458e3d5..f2b1dcd5d 100644
--- a/frontend/app/layout/data.ts
+++ b/frontend/app/layout/data.ts
@@ -26,6 +26,7 @@ export const enum PREFERENCES_MENU {
INTEGRATIONS = 'integrations',
METADATA = 'metadata',
WEBHOOKS = 'webhooks',
+ CUSTOM_EVENTS = 'custom-events',
MODULES = 'modules',
PROJECTS = 'projects',
ROLES_ACCESS = 'roles-access',
@@ -134,6 +135,7 @@ export const preferences: Category[] = [
{ label: 'Integrations', key: PREFERENCES_MENU.INTEGRATIONS, icon: 'plug' },
{ label: 'Metadata', key: PREFERENCES_MENU.METADATA, icon: 'tags' },
{ label: 'Webhooks', key: PREFERENCES_MENU.WEBHOOKS, icon: 'link-45deg' },
+ { label: 'Custom Events', key: PREFERENCES_MENU.CUSTOM_EVENTS, icon: 'calendar' },
{ label: 'Modules', key: PREFERENCES_MENU.MODULES, icon: 'puzzle' },
{ label: 'Projects', key: PREFERENCES_MENU.PROJECTS, icon: 'folder2' },
{
diff --git a/frontend/app/mstore/customEventsStore.ts b/frontend/app/mstore/customEventsStore.ts
new file mode 100644
index 000000000..6f4fd3293
--- /dev/null
+++ b/frontend/app/mstore/customEventsStore.ts
@@ -0,0 +1,80 @@
+import { makeAutoObservable, runInAction } from 'mobx';
+import { customEventService } from 'App/services';
+import Audit from 'MOBX/types/audit';
+import CustomEvent from 'App/mstore/types/customEvent';
+
+export default class CustomEventsStore {
+ list: CustomEvent[] = [
+ CustomEvent.fromJson({
+ id: '1',
+ name: 'Event 1',
+ description: 'Description 1',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ user: {
+ id: '1',
+ name: 'User 1'
+ }
+ }),
+ CustomEvent.fromJson({
+ id: '2',
+ name: 'Event 2',
+ description: 'Description 2',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ user: {
+ id: '1',
+ name: 'User 1'
+ }
+ }),
+ CustomEvent.fromJson({
+ id: '3',
+ name: 'Event 3',
+ description: 'Description 3',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ user: {
+ id: '1',
+ name: 'User 1'
+ }
+ })
+ ];
+
+
+ constructor() {
+ makeAutoObservable(this);
+ }
+
+ fetchAll = async (params: any = {}) => {
+ return new Promise((resolve, reject) => {
+ customEventService.fetchAll(params).then((response: any) => {
+ runInAction(() => {
+ this.list = response.data.map((item: any) => CustomEvent.fromJson(item));
+ });
+ resolve(this.list);
+ }).catch(error => {
+ reject(error);
+ }).finally(() => {
+ // this.isLoading = false;
+ });
+ });
+ };
+
+ createCustomEvent = async (data: any) => {
+ return new Promise((resolve, reject) => {
+ customEventService.create(data).then(response => {
+ runInAction(() => {
+ this.list.push(CustomEvent.fromJson(response.data));
+ });
+ resolve(response);
+ }).catch(error => {
+ reject(error);
+ });
+ });
+ };
+
+ updateCustomEvent = async (data: any) => {
+
+ };
+
+}
diff --git a/frontend/app/mstore/index.tsx b/frontend/app/mstore/index.tsx
index 0faf86249..0be9f2aba 100644
--- a/frontend/app/mstore/index.tsx
+++ b/frontend/app/mstore/index.tsx
@@ -24,6 +24,7 @@ import AiFiltersStore from "./aiFiltersStore";
import SpotStore from "./spotStore";
import LoginStore from "./loginStore";
import FilterStore from "./filterStore";
+import CustomEventStore from "./customEventsStore"
export class RootStore {
dashboardStore: DashboardStore;
@@ -49,6 +50,7 @@ export class RootStore {
spotStore: SpotStore;
loginStore: LoginStore;
filterStore: FilterStore;
+ customEventStore: CustomEventStore;
constructor() {
this.dashboardStore = new DashboardStore();
@@ -74,6 +76,7 @@ export class RootStore {
this.spotStore = new SpotStore();
this.loginStore = new LoginStore();
this.filterStore = new FilterStore();
+ this.customEventStore = new CustomEventStore();
}
initClient() {
diff --git a/frontend/app/mstore/types/customEvent.ts b/frontend/app/mstore/types/customEvent.ts
new file mode 100644
index 000000000..ef8aedeb1
--- /dev/null
+++ b/frontend/app/mstore/types/customEvent.ts
@@ -0,0 +1,49 @@
+interface User {
+ id: string;
+ name: string;
+}
+
+interface ICustomEvent {
+ id: string;
+ name: string;
+ user: User;
+ created_at: Date;
+}
+
+export default class CustomEvent implements ICustomEvent {
+ id: string;
+ name: string;
+ user: User;
+ created_at: Date;
+
+ constructor(id: string, name: string, user: User, created_at: Date) {
+ this.id = id;
+ this.name = name;
+ this.user = user;
+ this.created_at = created_at;
+ }
+
+ static fromJson(json: any): CustomEvent {
+ return new CustomEvent(
+ json.id,
+ json.name,
+ {
+ id: json.user?.id,
+ name: json.user?.name
+ },
+ new Date(json.created_at)
+ );
+ }
+
+ toJson(): any {
+ return {
+ id: this.id,
+ name: this.name,
+ user: {
+ id: this.user.id,
+ name: this.user.name
+ },
+ created_at: this.created_at.toISOString()
+ };
+ }
+}
diff --git a/frontend/app/routes.ts b/frontend/app/routes.ts
index 8179b27bd..9e16b84a9 100644
--- a/frontend/app/routes.ts
+++ b/frontend/app/routes.ts
@@ -67,6 +67,7 @@ export const CLIENT_TABS = {
SITES: 'projects',
CUSTOM_FIELDS: 'metadata',
WEBHOOKS: 'webhooks',
+ CUSTOM_EVENTS: 'custom-events',
NOTIFICATIONS: 'notifications',
AUDIT: 'audit',
BILLING: 'billing',
diff --git a/frontend/app/services/CustomEventService.ts b/frontend/app/services/CustomEventService.ts
new file mode 100644
index 000000000..fd32b9edb
--- /dev/null
+++ b/frontend/app/services/CustomEventService.ts
@@ -0,0 +1,28 @@
+import BaseService from './BaseService';
+
+export default class CustomEventService extends BaseService {
+ async fetchAll(params: {}): Promise<[]> {
+ return this.client.get('/custom-events', params)
+ .then(r => r.json()).then(j => j.data);
+ }
+
+ async create(data: {}): Promise<{}> {
+ return this.client.post('/custom-events', data)
+ .then(r => r.json()).then(j => j.data);
+ }
+
+ async update(data: {}): Promise<{}> {
+ return this.client.put(`/custom-events/${data.id}`, data)
+ .then(r => r.json()).then(j => j.data);
+ }
+
+ async delete(id: string): Promise<{}> {
+ return this.client.delete(`/custom-events/${id}`)
+ .then(r => r.json()).then(j => j.data);
+ }
+
+ async fetchOne(id: string): Promise<{}> {
+ return this.client.get(`/custom-events/${id}`)
+ .then(r => r.json()).then(j => j.data);
+ }
+}
diff --git a/frontend/app/services/index.ts b/frontend/app/services/index.ts
index 56a343b5d..9770b237b 100644
--- a/frontend/app/services/index.ts
+++ b/frontend/app/services/index.ts
@@ -20,6 +20,7 @@ import WebhookService from './WebhookService';
import SpotService from './spotService';
import LoginService from "./loginService";
import FilterService from "./FilterService";
+import CustomEventService from 'App/services/CustomEventService';
export const dashboardService = new DashboardService();
export const metricService = new MetricService();
@@ -42,6 +43,7 @@ export const aiService = new AiService();
export const spotService = new SpotService();
export const loginService = new LoginService();
export const filterService = new FilterService();
+export const customEventService = new CustomEventService();
export const services = [
dashboardService,
@@ -65,4 +67,5 @@ export const services = [
spotService,
loginService,
filterService,
+ customEventService,
];