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, ];