From 9b18946e84fcc53075d70b70e148ef7722ec0032 Mon Sep 17 00:00:00 2001 From: Matt Fancher <142915944+FancMa01@users.noreply.github.com> Date: Fri, 2 Feb 2024 09:24:31 -0700 Subject: [PATCH 1/4] Adjust Orbit Plugin name to ASR Adjusted orbit integration name to ASR to better encompass the scope of the integration --- .../src/components/admin/Integrations.js | 27 +++++++++++-------- .../src/components/layout/LeftNav.js | 6 ++--- server/job-scheduler.js | 9 ++++--- server/jobs/integrationCreation.js | 9 +++---- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/client-reactjs/src/components/admin/Integrations.js b/client-reactjs/src/components/admin/Integrations.js index 4b7174995..9c73ed006 100644 --- a/client-reactjs/src/components/admin/Integrations.js +++ b/client-reactjs/src/components/admin/Integrations.js @@ -159,6 +159,18 @@ const Integrations = () => { footer={saveBtn} title="Integration Settings">
+

General Settings

+ + setNotifications({ ...notifications, notificationEmailsSev3: e.target.value })}> + +

Megaphone Notification Settings

{ style={{ width: '100%' }} name="notificationEmails" initialValue={selectedIntegration.metaData?.notificationEmails} - validateTrigger={['onChange', 'onBlur']}> + validateTrigger={['onChange', 'onBlur']} + rules={[{ max: 256, message: 'Maximum of 256 characters allowed' }]}> setNotifications({ ...notifications, notificationEmails: e.target.value })}> { style={{ width: '100%' }} name="notificationWebhooks" initialValue={selectedIntegration.metaData?.notificationWebhooks} - validateTrigger={['onChange', 'onBlur']}> + validateTrigger={['onChange', 'onBlur']} + rules={[{ max: 256, message: 'Maximum of 256 characters allowed' }]}> setNotifications({ ...notifications, notificationWebhooks: e.target.value })}> - - setNotifications({ ...notifications, notificationEmailsSev3: e.target.value })}> -
diff --git a/client-reactjs/src/components/layout/LeftNav.js b/client-reactjs/src/components/layout/LeftNav.js index 9ed30fe14..3ac5a6993 100644 --- a/client-reactjs/src/components/layout/LeftNav.js +++ b/client-reactjs/src/components/layout/LeftNav.js @@ -63,7 +63,7 @@ class LeftNav extends Component { const applicationId = this.props?.applicationId || ''; const integrations = this.props?.integrations || []; - const orbitActive = integrations.find((i) => i.name === 'Orbit')?.active; + const asrActive = integrations.find((i) => i.name === 'ASR')?.active; if (!this.props.loggedIn || !this.props.user || Object.getOwnPropertyNames(this.props.user).length == 0) { return null; @@ -124,7 +124,7 @@ class LeftNav extends Component { {} - {orbitActive ? ( + {asrActive ? ( }> {} @@ -139,7 +139,7 @@ class LeftNav extends Component { {} - {orbitActive ? ( + {asrActive ? ( }> {} diff --git a/server/job-scheduler.js b/server/job-scheduler.js index cdaaf3082..94137675e 100644 --- a/server/job-scheduler.js +++ b/server/job-scheduler.js @@ -40,7 +40,10 @@ const { scheduleFileMonitoring, } = require("./jobSchedularMethods/hpccFiles.js"); const { scheduleKeyCheck } = require("./jobSchedularMethods/apiKeys.js"); -const {scheduleEmailNotificationProcessing, scheduleTeamsNotificationProcessing} = require("./jobSchedularMethods/notificationJobs.js"); +const { + scheduleEmailNotificationProcessing, + scheduleTeamsNotificationProcessing, +} = require("./jobSchedularMethods/notificationJobs.js"); const { createOrbitMegaphoneJob, @@ -48,8 +51,6 @@ const { scheduleOrbitMonitoringOnServerStart, } = require("./jobSchedularMethods/orbitJobs.js"); -const { scheduleKeyCheck } = require("./jobSchedularMethods/apiKeys.js"); - //import job directly to run it only once on server start const { createIntegrations } = require("./jobs/integrationCreation.js"); @@ -329,7 +330,7 @@ class JobScheduler { scheduleEmailNotificationProcessing() { return scheduleEmailNotificationProcessing.call(this); } - scheduleTeamsNotificationProcessing(){ + scheduleTeamsNotificationProcessing() { return scheduleTeamsNotificationProcessing.call(this); } //orbit jobs diff --git a/server/jobs/integrationCreation.js b/server/jobs/integrationCreation.js index eebb00ee4..9bf34c1e7 100644 --- a/server/jobs/integrationCreation.js +++ b/server/jobs/integrationCreation.js @@ -19,14 +19,13 @@ async function createIntegrations() { if (process.env.ASR === "true") { integrationList.push({ application_id: application.id, - name: "Orbit", + name: "ASR", description: - "Enabling this integration will allow Tombolo to collect data from HPCCs Orbit system and provide dashboard information for it", + "Enabling this integration will allow Tombolo to collect data from Orbit, FIDO, and other ASR sources in order to provide monitoring and alerting functionality. Additional fields will be made available in certain monitoring types as well.", active: "false", metaData: { - notificationEmails: "matthew.fancher@lexisnexisrisk.com", - notificationWebhooks: - "https://reedelsevier.webhook.office.com/webhookb2/81c072d6-6b47-4eca-9434-73944c464876@9274ee3f-9425-4109-a27f-9fb15c10675d/IncomingWebhook/60019c7653734064b4c225a02b1da597/af40e12f-e839-4801-91e9-e61a20045feb", + notificationEmails: "", + notificationWebhooks: "", }, }); } From 1796d6c112f67d66cbf6b97d83e3cc15ddfdb409 Mon Sep 17 00:00:00 2001 From: Matt Fancher <142915944+FancMa01@users.noreply.github.com> Date: Fri, 2 Feb 2024 10:57:32 -0700 Subject: [PATCH 2/4] adjust format of integrations screen Change format of integration screen so forms are seperate files, and adjust format of ASR form to include left tabs --- client-reactjs/src/App.js | 2 +- .../Integrations/IntegrationForms/ASRForm.js | 73 +++++++++++++++++++ .../admin/{ => Integrations}/Integrations.js | 67 +++++------------ 3 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js rename client-reactjs/src/components/admin/{ => Integrations}/Integrations.js (62%) diff --git a/client-reactjs/src/App.js b/client-reactjs/src/App.js index 86c27c402..86530eb2a 100644 --- a/client-reactjs/src/App.js +++ b/client-reactjs/src/App.js @@ -57,7 +57,7 @@ const Regulations = React.lazy(() => import('./components/admin/ControlsAndRegul const GitHubSettings = React.lazy(() => import('./components/admin/GitHubSettings/GitHubSettings')); const ScheduledJobsPage = React.lazy(() => import('./components/admin/ScheduledJobsPage')); const Compliance = React.lazy(() => import('./components/admin/Compliance/Compliance')); -const Integrations = React.lazy(() => import('./components/admin/Integrations')); +const Integrations = React.lazy(() => import('./components/admin/Integrations/Integrations')); const TeamsNotification = React.lazy(() => import('./components/admin/notifications/MsTeams/Teams')); // Shared layout, etc. diff --git a/client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js b/client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js new file mode 100644 index 000000000..d1364c53b --- /dev/null +++ b/client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { useEffect } from 'react'; +import { Form, Input, Switch, Tabs } from 'antd'; + +const { TabPane } = Tabs; + +const ASRForm = ({ setNotifications, notifications, setActive, selectedIntegration }) => { + const [notificationForm] = Form.useForm(); + + useEffect(() => { + console.log('setting fields values'); + console.log(selectedIntegration); + + notificationForm.setFieldsValue({ + notificationEmailsSev3: selectedIntegration?.metaData?.notificationEmailsSev3, + megaphone: selectedIntegration?.config?.megaphoneActive, + notificationEmails: selectedIntegration?.metaData?.notificationEmails, + notificationWebhooks: selectedIntegration?.metaData?.notificationWebhooks, + }); + }, [selectedIntegration]); + + return ( + <> +
+ + +

General

+ + + setNotifications({ ...notifications, notificationEmailsSev3: e.target.value }) + }> + +
+ +

Megaphone

+ + { + setActive(e); + }}> + + + setNotifications({ ...notifications, notificationEmails: e.target.value })}> + + + setNotifications({ ...notifications, notificationWebhooks: e.target.value })}> + +
+
+
+ + ); +}; +export default ASRForm; diff --git a/client-reactjs/src/components/admin/Integrations.js b/client-reactjs/src/components/admin/Integrations/Integrations.js similarity index 62% rename from client-reactjs/src/components/admin/Integrations.js rename to client-reactjs/src/components/admin/Integrations/Integrations.js index 9c73ed006..73c83d07e 100644 --- a/client-reactjs/src/components/admin/Integrations.js +++ b/client-reactjs/src/components/admin/Integrations/Integrations.js @@ -1,11 +1,12 @@ import React, { useState, useEffect } from 'react'; -import { Tooltip, Space, Table, Switch, Modal, Form, Input, Button, message } from 'antd'; +import { Tooltip, Space, Table, Switch, Modal, Button, message } from 'antd'; import { EditOutlined } from '@ant-design/icons'; -import BreadCrumbs from '../common/BreadCrumbs.js'; -import { authHeader } from '../common/AuthHeader.js'; +import BreadCrumbs from '../../common/BreadCrumbs.js'; +import { authHeader } from '../../common/AuthHeader.js'; import { useSelector, useDispatch } from 'react-redux'; -import { applicationActions } from '../../redux/actions/Application.js'; -import useWindowSize from '../../hooks/useWindowSize.js'; +import { applicationActions } from '../../../redux/actions/Application.js'; +import useWindowSize from '../../../hooks/useWindowSize.js'; +import ASRForm from './IntegrationForms/ASRForm.js'; const Integrations = () => { const [integrations, setIntegrations] = useState([]); @@ -15,7 +16,7 @@ const Integrations = () => { const [selectedIntegration, setSelectedIntegration] = useState({}); const [notifications, setNotifications] = useState({}); const [active, setActive] = useState(false); - const [notificationForm] = Form.useForm(); + const windowSize = useWindowSize(); // Changes modal size per screen vw @@ -82,7 +83,6 @@ const Integrations = () => { setModalVisible(false); dispatch(applicationActions.getIntegrations(applicationId)); - notificationForm.resetFields(); message.success('Successfully updated Integration'); } else { message.success('An Error Occured, Integration not updated'); @@ -158,48 +158,17 @@ const Integrations = () => { destroyOnClose footer={saveBtn} title="Integration Settings"> -
-

General Settings

- - setNotifications({ ...notifications, notificationEmailsSev3: e.target.value })}> - -
-

Megaphone Notification Settings

- - { - setActive(e); - }}> - - - setNotifications({ ...notifications, notificationEmails: e.target.value })}> - - - setNotifications({ ...notifications, notificationWebhooks: e.target.value })}> - -
+ {selectedIntegration?.name === 'ASR' && ( + <> + + + )} ); From 2392c3a337d8ada02bab9313ce537b55336b26d6 Mon Sep 17 00:00:00 2001 From: Matt Fancher <142915944+FancMa01@users.noreply.github.com> Date: Wed, 7 Feb 2024 08:14:27 -0700 Subject: [PATCH 3/4] Adjustments Visually and to Form --- .../src/components/admin/ClusterDetails.jsx | 2 +- .../Integrations/IntegrationForms/ASRForm.js | 100 ++++++++++++++---- .../admin/Integrations/Integrations.js | 3 + .../application/Dataflow/DataflowDetails.js | 1 + .../components/application/IndexDetails.js | 2 +- .../components/application/Jobs/JobDetails.js | 1 + .../application/Jobs/ManualJobDetail.jsx | 2 +- .../application/VisualizationDetails.js | 2 +- .../application/actions/actions.jsx | 2 +- .../application/clusterMonitoring/index.jsx | 1 + .../dashboard/ExportMenu/DashboardModal.jsx | 2 +- .../application/dashboard/Orbit/Orbit.jsx | 1 + .../dashboard/clusterUsage/index.js | 1 + .../notifications/NotificationsTable.jsx | 2 +- .../dashboard/notifications/index.js | 1 + .../fileMonitoring/FileMonitoringModal.jsx | 1 + .../AddEditJobMonitoringModal.jsx | 2 +- .../application/orbitMonitoring/BasicTab.jsx | 6 -- .../orbitMonitoring/OrbitMonitoringModal.jsx | 4 +- .../application/queries/QueryDetails.js | 2 +- .../SuperFileMonitoringModal.jsx | 1 + .../application/templates/FileTemplate.jsx | 2 +- server/routes/integrations/read.js | 2 + 23 files changed, 108 insertions(+), 35 deletions(-) diff --git a/client-reactjs/src/components/admin/ClusterDetails.jsx b/client-reactjs/src/components/admin/ClusterDetails.jsx index 3891416d5..fb73693b0 100644 --- a/client-reactjs/src/components/admin/ClusterDetails.jsx +++ b/client-reactjs/src/components/admin/ClusterDetails.jsx @@ -60,7 +60,7 @@ function ClusterDetails() { return (
- + {clusterMetaData ? ( <> diff --git a/client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js b/client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js index d1364c53b..a068abbbe 100644 --- a/client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js +++ b/client-reactjs/src/components/admin/Integrations/IntegrationForms/ASRForm.js @@ -1,16 +1,29 @@ import React from 'react'; -import { useEffect } from 'react'; -import { Form, Input, Switch, Tabs } from 'antd'; +import { useEffect, useState } from 'react'; +import { Form, Select, Switch, Tabs, message } from 'antd'; +import { isEmail } from 'validator'; +import { getAllTeamsHook } from '../../../application/jobMonitoring/jobMonitoringUtils'; const { TabPane } = Tabs; +const { Option } = Select; const ASRForm = ({ setNotifications, notifications, setActive, selectedIntegration }) => { const [notificationForm] = Form.useForm(); + const [teamsHooks, setTeamsHook] = useState([]); useEffect(() => { - console.log('setting fields values'); - console.log(selectedIntegration); + //Get all teams hook + (async () => { + try { + const allTeamsHook = await getAllTeamsHook(); + setTeamsHook(allTeamsHook); + } catch (error) { + message.error('Error fetching teams hook'); + } + })(); + }, []); + useEffect(() => { notificationForm.setFieldsValue({ notificationEmailsSev3: selectedIntegration?.metaData?.notificationEmailsSev3, megaphone: selectedIntegration?.config?.megaphoneActive, @@ -22,7 +35,7 @@ const ASRForm = ({ setNotifications, notifications, setActive, selectedIntegrati return ( <>
- +

General

- - setNotifications({ ...notifications, notificationEmailsSev3: e.target.value }) - }> + rules={[ + { + validator: (_, value) => { + if (!value || value.length === 0) { + return Promise.reject(new Error('Please add at least one email!')); + } + if (value.length > 20) { + return Promise.reject(new Error('Too many emails')); + } + if (!value.every((v) => isEmail(v))) { + return Promise.reject(new Error('One or more emails are invalid')); + } + return Promise.resolve(); + }, + }, + ]}> + setNotifications({ ...notifications, notificationEmails: e.target.value })}> + rules={[ + { + validator: (_, value) => { + if (!value || value.length === 0) { + return Promise.reject(new Error('Please add at least one email!')); + } + if (value.length > 20) { + return Promise.reject(new Error('Too many emails')); + } + if (!value.every((v) => isEmail(v))) { + return Promise.reject(new Error('One or more emails are invalid')); + } + return Promise.resolve(); + }, + }, + ]}> + setNotifications({ ...notifications, notificationWebhooks: e.target.value })}> + validateTrigger={['onChange', 'onBlur']}> +
diff --git a/client-reactjs/src/components/admin/Integrations/Integrations.js b/client-reactjs/src/components/admin/Integrations/Integrations.js index 73c83d07e..5dc6d9f09 100644 --- a/client-reactjs/src/components/admin/Integrations/Integrations.js +++ b/client-reactjs/src/components/admin/Integrations/Integrations.js @@ -25,6 +25,7 @@ const Integrations = () => { if (width > 1500) { setModalWidth('40vw'); } else if (width > 1000) { + integrations; setModalWidth('60vw'); } else { setModalWidth('100vw'); @@ -49,6 +50,7 @@ const Integrations = () => { const response = await fetch(`/api/integrations/get/${applicationId}`, payload); const data = await response.json(); + if (data) { setIntegrations(data); } @@ -62,6 +64,7 @@ const Integrations = () => { await setModalVisible(true); await setSelectedIntegration(record); await setNotifications(record.metaData); + await setActive(record.config?.megaphoneActive); }; const handleSave = async () => { diff --git a/client-reactjs/src/components/application/Dataflow/DataflowDetails.js b/client-reactjs/src/components/application/Dataflow/DataflowDetails.js index 8af266379..bc416e988 100644 --- a/client-reactjs/src/components/application/Dataflow/DataflowDetails.js +++ b/client-reactjs/src/components/application/Dataflow/DataflowDetails.js @@ -33,6 +33,7 @@ function DataflowDetails() {
) : null} - + } key="1"> } onChange={(activeKey) => this.setState({ selectedTabPaneKey: activeKey })}> diff --git a/client-reactjs/src/components/application/Jobs/ManualJobDetail.jsx b/client-reactjs/src/components/application/Jobs/ManualJobDetail.jsx index 427d01138..a6022c908 100644 --- a/client-reactjs/src/components/application/Jobs/ManualJobDetail.jsx +++ b/client-reactjs/src/components/application/Jobs/ManualJobDetail.jsx @@ -110,7 +110,7 @@ function ManualJobDetail() {
{}: {jobDetails.name}
- + } key="1"> {jobData.map((item, i) => ( diff --git a/client-reactjs/src/components/application/VisualizationDetails.js b/client-reactjs/src/components/application/VisualizationDetails.js index 87a8b20d9..8d856e92f 100644 --- a/client-reactjs/src/components/application/VisualizationDetails.js +++ b/client-reactjs/src/components/application/VisualizationDetails.js @@ -170,7 +170,7 @@ function VisualizationDetails() { return ( - + } key="1"> diff --git a/client-reactjs/src/components/application/actions/actions.jsx b/client-reactjs/src/components/application/actions/actions.jsx index 52081314a..c726b9dae 100644 --- a/client-reactjs/src/components/application/actions/actions.jsx +++ b/client-reactjs/src/components/application/actions/actions.jsx @@ -12,7 +12,7 @@ function Actions() {
- + } key="1"> diff --git a/client-reactjs/src/components/application/clusterMonitoring/index.jsx b/client-reactjs/src/components/application/clusterMonitoring/index.jsx index a7a9a966b..cddffee76 100644 --- a/client-reactjs/src/components/application/clusterMonitoring/index.jsx +++ b/client-reactjs/src/components/application/clusterMonitoring/index.jsx @@ -307,6 +307,7 @@ function ClusterMonitoring() { initialValues={{ msTeamsGroups: [''], emails: [''] }}> { setActiveTab(record); }}> diff --git a/client-reactjs/src/components/application/dashboard/ExportMenu/DashboardModal.jsx b/client-reactjs/src/components/application/dashboard/ExportMenu/DashboardModal.jsx index 452105069..bfd87b14f 100644 --- a/client-reactjs/src/components/application/dashboard/ExportMenu/DashboardModal.jsx +++ b/client-reactjs/src/components/application/dashboard/ExportMenu/DashboardModal.jsx @@ -131,7 +131,7 @@ const DashboardModal = ({ modalVisible, setModalVisible, applicationId, authRedu } footer={false} style={{ marginTop: '200px' }}> - +
diff --git a/client-reactjs/src/components/application/dashboard/clusterUsage/index.js b/client-reactjs/src/components/application/dashboard/clusterUsage/index.js index cb7612da7..6949e67d5 100644 --- a/client-reactjs/src/components/application/dashboard/clusterUsage/index.js +++ b/client-reactjs/src/components/application/dashboard/clusterUsage/index.js @@ -103,6 +103,7 @@ function ClusterUsage() { } activeKey={activeTab} + type="card" onChange={handleTabSwitching}> }> - + {selectedNotificationDetails.map((item) => ( diff --git a/client-reactjs/src/components/application/dashboard/notifications/index.js b/client-reactjs/src/components/application/dashboard/notifications/index.js index 1982b038b..4fd4d73fc 100644 --- a/client-reactjs/src/components/application/dashboard/notifications/index.js +++ b/client-reactjs/src/components/application/dashboard/notifications/index.js @@ -181,6 +181,7 @@ function Index() { return (