From ce5e89e292133647c9d1a7930e7f7154c7e4a357 Mon Sep 17 00:00:00 2001 From: dhaval055 Date: Sat, 17 Feb 2024 10:15:54 +0000 Subject: [PATCH 1/3] added notification workflow stuff --- frontend/src/components/OrgHeaderexpanded.jsx | 465 +++++++++++++++++- 1 file changed, 464 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/OrgHeaderexpanded.jsx b/frontend/src/components/OrgHeaderexpanded.jsx index 268350a2..7729057d 100644 --- a/frontend/src/components/OrgHeaderexpanded.jsx +++ b/frontend/src/components/OrgHeaderexpanded.jsx @@ -2,7 +2,9 @@ import React, { useEffect } from "react"; import { makeStyles } from "@mui/styles"; import theme from '../theme.jsx'; -import { toast } from "react-toastify" +import { toast } from "react-toastify" +import Chip from '@mui/material/Chip'; +import Stack from '@mui/material/Stack'; import { FormControl, @@ -25,6 +27,11 @@ import { Grid, IconButton, Autocomplete, + Dialog, + DialogTitle, + DialogActions, + DialogContent, + Box } from "@mui/material"; import { @@ -158,6 +165,19 @@ const OrgHeaderexpanded = (props) => { const [workflows, setWorkflows] = React.useState([]) const [workflow, setWorkflow] = React.useState({}) + // notification workflow + const [notificationApp, setNotificationApp] = React.useState("") + const [notificationWorkflowModal, setNotificationWorkflowModal] = React.useState(false); + const [selectedAppDetails, setSelectedAppDetails] = React.useState({}); + const [notificationWorkflowTestModal, setNotificationWorkflowTestModal] = React.useState(false); + const [webhookInputValue, setWebhookInputValue] = React.useState(""); + const [authOptions, setAuthOptions] = React.useState([]); + const [selectedAuth, setSelectedAuth] = React.useState(''); + + // for jira modal + const [jiraIssueType, setJiraIssueType] = React.useState(""); + const [jiraProjectKey, setJiraProjectKey] = React.useState(""); + const getAvailableWorkflows = (trigger_index) => { fetch(globalUrl + "/api/v1/workflows", { method: "GET", @@ -295,12 +315,455 @@ const OrgHeaderexpanded = (props) => { ); + const executeTestWorkflow = async (workflowid) => { + const data = { "execution_argument": '{"title":"THIS IS TEST ALERT","description":"TEST ALERT FROM SHUFFLE","reference_url": "shuffler.io"}' } + fetch(globalUrl + `/api/v1/workflows/${workflowid}/execute`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify(data), + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + toast("Failed setting notification workflow: ", response.reason); + console.log("Status not 200 for workflows :O!"); + return; + } + toast("Notification workflow ran successfully"); + return response.json(); + }).catch((error) => { + console.log("Error getting workflows: " + error); + }) +} + +const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId,issuetype) => { + //currently only supports JIRA figure out a way to support more apps + var workflowName = `[GENARATED] ${appname} notification workflow` + var workflowDescription = "Generated by Shuffle for sending error notifications." + var data = { + "name": workflowName, + "description": workflowDescription, + } + + fetch(globalUrl + "/api/v1/workflows", { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify(data), + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + toast("Failed setting notification workflow: ", response.reason); + console.log("Status not 200 for workflows :O!"); + return; + } + return response.json(); + }).then((responseJson)=>{ + if (responseJson !== undefined) { + console.log("Notification workflow created successfully") + var workflow_id = responseJson.id + if (appname.toLowerCase() === "jira"){ + console.log("updating workflow for JIRA") + var workflowBody = { + "name": workflowName, + "Description": workflowDescription, + "id": workflow_id, + "actions": [ + { + "app_name": "Jira", + "name": "post_create_issue", + "authentication_id":appAuthId, + "large_image":appImage, + "isStartNode": true, + "label": "create_issue", + "app_version": "1.1.0", + "parameters": [ + { + "name": "body", + "value": `{"fields": { "project": {"key": "${projectId}"},"summary": "$exec.title","issuetype": {"name": "${issuetype}"},"description": {"content": [{"content":[{"type":"text","text":"$exec.description"}],"type": "paragraph"}],"type": "doc","version": 1}}}` + }, + { + "name": "username_basic", + "value": "" + }, + { + "name": "password_basic", + "value": "" + }, + { + "name": "url", + "value": "" + }, + { + "name": "headers", + "value": "Content-type=application/json \nAccept=application/json" + }, + { + "name": "queries", + "value": "" + }, + { + "name": "ssl_verify", + "value": "False" + } + ] + } + ] + } + } + fetch(globalUrl + `/api/v1/workflows/${workflow_id}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify(workflowBody), + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + toast("Failed setting notification workflow: ", response.reason); + console.log("Status not 200 for workflows :O!"); + return; + } + return response.json(); + }).then((responseJson)=>{ + if (responseJson !== undefined) { + handleEditOrg( + orgName, + orgDescription, + selectedOrganization.id, + selectedOrganization.image, + { + app_download_repo: appDownloadUrl, + app_download_branch: appDownloadBranch, + workflow_download_repo: workflowDownloadUrl, + workflow_download_branch: workflowDownloadBranch, + notification_workflow: workflow_id, + documentation_reference: documentationReference, + }, + { + sso_entrypoint: ssoEntrypoint, + sso_certificate: ssoCertificate, + client_id: openidClientId, + client_secret: openidClientSecret, + openid_authorization: openidAuthorization, + openid_token: openidToken, + } + ) + console.log("Notification workflow updated successfully") + toast("Notification workflow updated successfully") + } + }) + } + }).catch((error) => { + console.log("Error setting workflows: " + error); + }) +} + +const getAppAuth = async (appName) => { + fetch(globalUrl + "/api/v1/apps/authentication", { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + toast(`Failed getting auth for ${appName}: `, response.reason); + console.log("Status not 200 for app auth :O!"); + return; + } + return response.json(); + }).then((responseJson) => { + if (!responseJson.success) { + console.log("Could not get app auth") + return; + } + var authList = responseJson.data.filter(entry => entry.app.name === appName) + console.log("authList: ", authList) + setAuthOptions(authList); + + }).catch((error) => { + console.log("Error getting app auth: " + error); + }) +} + +const testWorkflowModal = notificationWorkflowTestModal ? + ( { + setNotificationWorkflowTestModal(false); + }} + > + + {/* +
+ Notification workflow +
+
*/} + + We have updated the Notification workflow. Do you want to test it? + + + + + +
+
) : null + +const notificationWorkflowModalValid = () => { +return selectedAuth && webhookInputValue; +}; + +const modalView = notificationWorkflowModal ? ( + { + setNotificationWorkflowModal(false); + }} + > + + +
+ {`Configure ${selectedAppDetails.name} workflow`} +
+
+ + + + {authOptions.length > 0 ? + <> + + + Pick an authentication method from the list + + + Available authentications + + + + + + Provide additional required details: + + { + setJiraProjectKey(e.target.value) + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} /> + { + setJiraIssueType(e.target.value) + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} /> + + : <> + + {`No ${selectedAppDetails.name} auth found. Click below to set one up.`} + + + + } + + + + + +
+
+) : null + +// getting comms & cases app from app framework +var notificationAppList = []; +if (selectedOrganization.security_framework.cases && selectedOrganization.security_framework.cases.name.length > 0) { +notificationAppList = notificationAppList.concat(selectedOrganization.security_framework.cases); +} +if (selectedOrganization.security_framework.communication && selectedOrganization.security_framework.communication.name.length > 0) { +notificationAppList = notificationAppList.concat(selectedOrganization.security_framework.communication); +} + +const renderChips = (apps) => { +if (!apps || apps.length === 0) { + return ( + { + console.log(`Clicked EMAIL`) + setNotificationWorkflowModal(true) + }} + avatar={{"email} + /> + ) +} + +return ( + + {apps.map((app) => ( + { + console.log(`Clicked ${app.name}`) + setSelectedAppDetails(app) + setNotificationWorkflowModal(true) + getAppAuth(app.name) + console.log(selectedAppDetails) + }} + avatar={{app.name}} + /> + ))} + +); +}; + + return (
Notification Workflow + {modalView} + {/*{testWorkflowModal} */} +
+ {renderChips(notificationAppList)}
{/* Add a Workflow that receives notifications from Shuffle when an error occurs in one of your workflows From b2a126e6b174526c2b3911eab468ba5ca0832c4f Mon Sep 17 00:00:00 2001 From: dhaval055 Date: Tue, 5 Mar 2024 05:46:46 +0000 Subject: [PATCH 2/3] dynamic app loading for notification workflow --- frontend/src/components/OrgHeaderexpanded.jsx | 389 +++++++++++++++--- 1 file changed, 342 insertions(+), 47 deletions(-) diff --git a/frontend/src/components/OrgHeaderexpanded.jsx b/frontend/src/components/OrgHeaderexpanded.jsx index 7729057d..350b456c 100644 --- a/frontend/src/components/OrgHeaderexpanded.jsx +++ b/frontend/src/components/OrgHeaderexpanded.jsx @@ -5,6 +5,7 @@ import theme from '../theme.jsx'; import { toast } from "react-toastify" import Chip from '@mui/material/Chip'; import Stack from '@mui/material/Stack'; +import AuthenticationData from "./AuthenticationWindow"; import { FormControl, @@ -173,10 +174,32 @@ const OrgHeaderexpanded = (props) => { const [webhookInputValue, setWebhookInputValue] = React.useState(""); const [authOptions, setAuthOptions] = React.useState([]); const [selectedAuth, setSelectedAuth] = React.useState(''); + // const [selectedAppAuth, setSelectedAppAuth] = React.useState({}); // for getting selected app auth parameters + const [authenticationModal, setAuthenticationModal] = React.useState(false); - // for jira modal - const [jiraIssueType, setJiraIssueType] = React.useState(""); - const [jiraProjectKey, setJiraProjectKey] = React.useState(""); + const [notificationAppDetails, setNotificationAppDetails] = React.useState([]); + + // const [tempResult, setTempResult] = React.useState([]) + + // useEffect(() => { + // if (authOptions.length < 1) { + // {getAppConfig(selectedAppDetails.id)} + // } + // }, [authOptions.length]); // not using this now + + useEffect(() => { + if (notificationAppList.length > 0) { + (async () => { + const nameList = notificationAppList.map(item => item.name); + await prepareNotificationAppList(nameList); + })(); + } + }, [notificationAppList]); + + + // for jira & email modal + const [textFieldValue, setTextFieldValue] = React.useState(""); + const [textFieldOneValue, setTextFieldOneValue] = React.useState(""); const getAvailableWorkflows = (trigger_index) => { fetch(globalUrl + "/api/v1/workflows", { @@ -315,6 +338,146 @@ const OrgHeaderexpanded = (props) => { ); + const getAppIDs = async (appList) => { + fetch(globalUrl + "/api/v1/apps", { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }).then((response) => { + if (response.status !== 200) { + toast("Failed getting app ids: ", response.reason); + console.log("Status not 200 for app ids :O!"); + return; + } + return response.json(); + }).then((responseJson) => { + if (responseJson !== undefined) { + // console.log("App ids: ", responseJson) + // console.log("App list: ", appList) + const filteredApps = responseJson.filter(app => appList.includes(app.name)); + const appDetails = filteredApps.map(app => ({ name: app.name, id: app.id })); + return appDetails + // console.log("App IDs: ", appDetails) + } + }).catch((error) => { + console.log("Error getting app ids: " + error); + }) +} + + // getting comms & cases app from app framework + var notificationAppList = []; + if (selectedOrganization.security_framework.cases && selectedOrganization.security_framework.cases.name.length > 0) { + notificationAppList = notificationAppList.concat(selectedOrganization.security_framework.cases); + } + if (selectedOrganization.security_framework.communication && selectedOrganization.security_framework.communication.name.length > 0) { + notificationAppList = notificationAppList.concat(selectedOrganization.security_framework.communication); + } + + const mergeAuthData = (result, responseJson) => { + const updatedResult = result.map(item => { + const matches = responseJson.filter(authItem => authItem.app.name === item.name); + return { + ...item, + authentication_data: matches.length > 0 ? matches : null + }; + }); + return updatedResult; + }; + + const prepareNotificationAppList = async (appList) => { + // getting App ID,Authentication fields and saved auths for each app + var result = [] + if (appList.length > 0) { + fetch(globalUrl + "/api/v1/apps", { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }).then((response) => { + if (response.status !== 200) { + toast("Failed getting app ids: ", response.reason); + console.log("Status not 200 for app ids :O!"); + return; + } + return response.json(); + }).then((responseJson) => { + if (responseJson !== undefined) { + const filteredApps = responseJson.filter(app => appList.includes(app.name)); + const appDetails = filteredApps.map(app => ({ name: app.name, id: app.id })); //mapped apps with IDs as sometime Ids were not correct in security framework + // console.log("appDetails: ", appDetails) + // result = appDetails + + fetch(globalUrl + "/api/v1/apps/authentication", { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + toast(`Failed getting auth for : `, response.reason); + console.log("Status not 200 for app auth :O!"); + return; + } + return response.json(); + }).then(async (responseJson) => { + if (!responseJson.success) { + console.log("Could not get app auth") + return; + } + // console.log("responseJson of auth: ", responseJson.data) + result = await mergeAuthData(appDetails, responseJson.data) + console.log("merged auth data: ", result) + // console.log("result", result) + result.map(item => { + fetch(globalUrl + `/api/v1/apps/${item.id}/config`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }).then((response) => { + if (response.status !== 200) { + toast(`Failed getting config for ${item.id}: `, response.reason); + console.log("Status not 200 for app config :O!"); + return; + } + return response.json(); + }).then((responseJson) => { + if (!responseJson.success) { + console.log("Could not get app config") + return; + } + var decodedString = JSON.parse(atob(responseJson.app)); + // console.log("dcodedString: ",decodedString) + item.auth_config = decodedString.authentication + item.large_image = decodedString.large_image + setNotificationAppDetails(result) + console.log("notificationAppDetails: ", notificationAppDetails) + // setSelectedAppAuth(decodedString.authentication) + }).catch((error) => { + console.log("Error getting app config: " + error); + toast("Error getting app config: " + error); + }) + }) + // get auth config for each app as it is required to render the modal when auth is not available + }) + } + }).catch((error) => { + console.log("Error getting app ids: " + error); + }) + } + } + + const executeTestWorkflow = async (workflowid) => { const data = { "execution_argument": '{"title":"THIS IS TEST ALERT","description":"TEST ALERT FROM SHUFFLE","reference_url": "shuffler.io"}' } fetch(globalUrl + `/api/v1/workflows/${workflowid}/execute`, { @@ -342,7 +505,7 @@ const OrgHeaderexpanded = (props) => { const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId,issuetype) => { //currently only supports JIRA figure out a way to support more apps var workflowName = `[GENARATED] ${appname} notification workflow` - var workflowDescription = "Generated by Shuffle for sending error notifications." + var workflowDescription = "Generated by Shuffle for sending info/error notifications." var data = { "name": workflowName, "description": workflowDescription, @@ -467,6 +630,121 @@ const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId }) } +const generateEmailNotificationWorkflow = async (appname,appImage,shuffleAPIKey,recepients) => { + //currently only supports figure out a way to support more apps + var workflowName = `[GENARATED] ${appname} notification workflow` + var workflowDescription = "Generated by Shuffle for sending info/error notifications." + var data = { + "name": workflowName, + "description": workflowDescription, + } + + fetch(globalUrl + "/api/v1/workflows", { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify(data), + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + toast("Failed setting notification workflow: ", response.reason); + console.log("Status not 200 for workflows :O!"); + return; + } + return response.json(); + }).then((responseJson)=>{ + if (responseJson !== undefined) { + console.log("Notification workflow created successfully") + var workflow_id = responseJson.id + if (appname.toLowerCase() === "email"){ + console.log("updating workflow for email") + var workflowBody = { + "name": workflowName, + "Description": workflowDescription, + "id": workflow_id, + "actions": [ + { + "app_name": "email", + "name": "send_email_shuffle", + "large_image":appImage, + "isStartNode": true, + "label": "send_email_shuffle", + "app_version": "1.3.0", + "parameters": [ + { + "name": "apikey", + "value": shuffleAPIKey + }, + { + "name": "recipients", + "value": recepients + }, + { + "name": "subject", + "value": "$exec.title" + }, + { + "name":"body", + "value":"$exec.description" + } + ] + } + ] + } + } + fetch(globalUrl + `/api/v1/workflows/${workflow_id}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify(workflowBody), + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + toast("Failed setting notification workflow: ", response.reason); + console.log("Status not 200 for workflows :O!"); + return; + } + return response.json(); + }).then((responseJson)=>{ + if (responseJson !== undefined) { + handleEditOrg( + orgName, + orgDescription, + selectedOrganization.id, + selectedOrganization.image, + { + app_download_repo: appDownloadUrl, + app_download_branch: appDownloadBranch, + workflow_download_repo: workflowDownloadUrl, + workflow_download_branch: workflowDownloadBranch, + notification_workflow: workflow_id, + documentation_reference: documentationReference, + }, + { + sso_entrypoint: ssoEntrypoint, + sso_certificate: ssoCertificate, + client_id: openidClientId, + client_secret: openidClientSecret, + openid_authorization: openidAuthorization, + openid_token: openidToken, + } + ) + console.log("Notification workflow updated successfully") + toast("Notification workflow updated successfully") + } + }) + } + }).catch((error) => { + console.log("Error setting workflows: " + error); + }) +} + const getAppAuth = async (appName) => { fetch(globalUrl + "/api/v1/apps/authentication", { method: "GET", @@ -497,6 +775,35 @@ const getAppAuth = async (appName) => { }) } +const getAppConfig = async (appId) => { + fetch(globalUrl + `/api/v1/apps/${appId}/config`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }).then((response) => { + if (response.status !== 200) { + toast(`Failed getting config for ${appId}: `, response.reason); + console.log("Status not 200 for app config :O!"); + return; + } + return response.json(); + }).then((responseJson) => { + if (!responseJson.success) { + console.log("Could not get app config") + return; + } + var decodedString = JSON.parse(atob(responseJson.app)); + console.log("dcodedString: ",decodedString) + return decodedString.authentication + // setSelectedAppAuth(decodedString.authentication) + }).catch((error) => { + console.log("Error getting app config: " + error); + }) +} + const testWorkflowModal = notificationWorkflowTestModal ? ( - - {authOptions.length > 0 ? + {console.log("len Selected app details: ", selectedAppDetails)} + {(selectedAppDetails.authentication_data || selectedAppDetails.auth_config.required == false) ? <> + {selectedAppDetails.auth_config.required == false ? "No authentication required": + <> Pick an authentication method from the list @@ -582,14 +891,15 @@ const modalView = notificationWorkflowModal ? ( - + } @@ -616,10 +926,10 @@ const modalView = notificationWorkflowModal ? ( id="outlined-with-placeholder" margin="normal" variant="outlined" - placeholder="Project key" + placeholder={ selectedAppDetails.name.toLowerCase() === "jira" ? "Project key" : "Shuffle API key"} // value={webhookInputValue} onChange={(e) => { - setJiraProjectKey(e.target.value) + setTextFieldOneValue(e.target.value) }} InputProps={{ classes: { @@ -642,10 +952,10 @@ const modalView = notificationWorkflowModal ? ( id="outlined-with-placeholder" margin="normal" variant="outlined" - placeholder="Issue type" + placeholder={selectedAppDetails.name.toLowerCase() === "jira" ? "Issue type" : "Recepients (comma separated)"} // value={webhookInputValue} onChange={(e) => { - setJiraIssueType(e.target.value) + setTextFieldValue(e.target.value) }} InputProps={{ classes: { @@ -654,28 +964,18 @@ const modalView = notificationWorkflowModal ? ( style: { color: "white", }, - }} /> + }} /> - : <> - - {`No ${selectedAppDetails.name} auth found. Click below to set one up.`} - - + : + <> + 0) ? false : true} + // // setAuthenticationModalOpen={false} + selectedApp={{...selectedAppDetails,authentication: selectedAppDetails.auth_config}} + // getAppAuthentication={selectedAppDetails.name} + /> } @@ -692,11 +992,12 @@ const modalView = notificationWorkflowModal ? ( ) : null -// getting comms & cases app from app framework -var notificationAppList = []; -if (selectedOrganization.security_framework.cases && selectedOrganization.security_framework.cases.name.length > 0) { -notificationAppList = notificationAppList.concat(selectedOrganization.security_framework.cases); -} -if (selectedOrganization.security_framework.communication && selectedOrganization.security_framework.communication.name.length > 0) { -notificationAppList = notificationAppList.concat(selectedOrganization.security_framework.communication); -} const renderChips = (apps) => { if (!apps || apps.length === 0) { @@ -725,7 +1018,9 @@ if (!apps || apps.length === 0) { variant="outlined" onClick={() => { console.log(`Clicked EMAIL`) + setSelectedAppDetails("email") setNotificationWorkflowModal(true) + // setNotificationWorkflowModal(true) }} avatar={{"email} /> @@ -743,8 +1038,8 @@ return ( console.log(`Clicked ${app.name}`) setSelectedAppDetails(app) setNotificationWorkflowModal(true) - getAppAuth(app.name) - console.log(selectedAppDetails) + // getAppAuth(app.name) + console.log("selectedAppDEtails",selectedAppDetails) }} avatar={{app.name}} /> @@ -763,7 +1058,7 @@ return ( {modalView} {/*{testWorkflowModal} */}
- {renderChips(notificationAppList)}
+ {renderChips(notificationAppDetails)}
{/* Add a Workflow that receives notifications from Shuffle when an error occurs in one of your workflows From 7eda67bc443c16b4fdfa46a087da407113a6c615 Mon Sep 17 00:00:00 2001 From: dhaval055 Date: Tue, 12 Mar 2024 12:29:50 +0000 Subject: [PATCH 3/3] added highlighting to app chips --- frontend/src/components/OrgHeaderexpanded.jsx | 214 ++++++------------ 1 file changed, 75 insertions(+), 139 deletions(-) diff --git a/frontend/src/components/OrgHeaderexpanded.jsx b/frontend/src/components/OrgHeaderexpanded.jsx index 350b456c..6946de94 100644 --- a/frontend/src/components/OrgHeaderexpanded.jsx +++ b/frontend/src/components/OrgHeaderexpanded.jsx @@ -167,41 +167,25 @@ const OrgHeaderexpanded = (props) => { const [workflow, setWorkflow] = React.useState({}) // notification workflow - const [notificationApp, setNotificationApp] = React.useState("") const [notificationWorkflowModal, setNotificationWorkflowModal] = React.useState(false); const [selectedAppDetails, setSelectedAppDetails] = React.useState({}); const [notificationWorkflowTestModal, setNotificationWorkflowTestModal] = React.useState(false); - const [webhookInputValue, setWebhookInputValue] = React.useState(""); - const [authOptions, setAuthOptions] = React.useState([]); const [selectedAuth, setSelectedAuth] = React.useState(''); - // const [selectedAppAuth, setSelectedAppAuth] = React.useState({}); // for getting selected app auth parameters - const [authenticationModal, setAuthenticationModal] = React.useState(false); - + const [emailData,setEmailData] = React.useState([]); const [notificationAppDetails, setNotificationAppDetails] = React.useState([]); + const [generatedWorkflow, setGeneatedWorkflow] = React.useState({}); - // const [tempResult, setTempResult] = React.useState([]) - - // useEffect(() => { - // if (authOptions.length < 1) { - // {getAppConfig(selectedAppDetails.id)} - // } - // }, [authOptions.length]); // not using this now - - useEffect(() => { - if (notificationAppList.length > 0) { - (async () => { - const nameList = notificationAppList.map(item => item.name); - await prepareNotificationAppList(nameList); - })(); - } - }, [notificationAppList]); - // for jira & email modal const [textFieldValue, setTextFieldValue] = React.useState(""); const [textFieldOneValue, setTextFieldOneValue] = React.useState(""); - const getAvailableWorkflows = (trigger_index) => { + useEffect(() => { + let nameList = notificationAppList.length > 0? notificationAppList.map(item => item.name): ["email"]; + prepareNotificationAppList(nameList) + }, [notificationAppList,workflows]); + + const getAvailableWorkflows = (trigger_index) => { fetch(globalUrl + "/api/v1/workflows", { method: "GET", headers: { @@ -390,7 +374,6 @@ const OrgHeaderexpanded = (props) => { const prepareNotificationAppList = async (appList) => { // getting App ID,Authentication fields and saved auths for each app var result = [] - if (appList.length > 0) { fetch(globalUrl + "/api/v1/apps", { method: "GET", headers: { @@ -408,6 +391,8 @@ const OrgHeaderexpanded = (props) => { }).then((responseJson) => { if (responseJson !== undefined) { const filteredApps = responseJson.filter(app => appList.includes(app.name)); + const emailData = responseJson.filter(app => app.name === "email") + setEmailData(emailData) const appDetails = filteredApps.map(app => ({ name: app.name, id: app.id })); //mapped apps with IDs as sometime Ids were not correct in security framework // console.log("appDetails: ", appDetails) // result = appDetails @@ -434,7 +419,7 @@ const OrgHeaderexpanded = (props) => { } // console.log("responseJson of auth: ", responseJson.data) result = await mergeAuthData(appDetails, responseJson.data) - console.log("merged auth data: ", result) + // console.log("merged auth data: ", result) // console.log("result", result) result.map(item => { fetch(globalUrl + `/api/v1/apps/${item.id}/config`, { @@ -462,19 +447,19 @@ const OrgHeaderexpanded = (props) => { item.large_image = decodedString.large_image setNotificationAppDetails(result) console.log("notificationAppDetails: ", notificationAppDetails) - // setSelectedAppAuth(decodedString.authentication) + }).then(async()=>{ + await checkIfAlreadyGenerated(appList,workflows); + }).catch((error) => { console.log("Error getting app config: " + error); toast("Error getting app config: " + error); }) }) - // get auth config for each app as it is required to render the modal when auth is not available }) } }).catch((error) => { console.log("Error getting app ids: " + error); - }) - } + }) } @@ -504,7 +489,7 @@ const OrgHeaderexpanded = (props) => { const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId,issuetype) => { //currently only supports JIRA figure out a way to support more apps - var workflowName = `[GENARATED] ${appname} notification workflow` + var workflowName = `[GENERATED] ${appname} notification workflow` var workflowDescription = "Generated by Shuffle for sending info/error notifications." var data = { "name": workflowName, @@ -632,7 +617,7 @@ const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId const generateEmailNotificationWorkflow = async (appname,appImage,shuffleAPIKey,recepients) => { //currently only supports figure out a way to support more apps - var workflowName = `[GENARATED] ${appname} notification workflow` + var workflowName = `[GENERATED] ${appname} notification workflow` var workflowDescription = "Generated by Shuffle for sending info/error notifications." var data = { "name": workflowName, @@ -745,64 +730,6 @@ const generateEmailNotificationWorkflow = async (appname,appImage,shuffleAPIKey, }) } -const getAppAuth = async (appName) => { - fetch(globalUrl + "/api/v1/apps/authentication", { - method: "GET", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - credentials: "include", - }) - .then((response) => { - if (response.status !== 200) { - toast(`Failed getting auth for ${appName}: `, response.reason); - console.log("Status not 200 for app auth :O!"); - return; - } - return response.json(); - }).then((responseJson) => { - if (!responseJson.success) { - console.log("Could not get app auth") - return; - } - var authList = responseJson.data.filter(entry => entry.app.name === appName) - console.log("authList: ", authList) - setAuthOptions(authList); - - }).catch((error) => { - console.log("Error getting app auth: " + error); - }) -} - -const getAppConfig = async (appId) => { - fetch(globalUrl + `/api/v1/apps/${appId}/config`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - credentials: "include", - }).then((response) => { - if (response.status !== 200) { - toast(`Failed getting config for ${appId}: `, response.reason); - console.log("Status not 200 for app config :O!"); - return; - } - return response.json(); - }).then((responseJson) => { - if (!responseJson.success) { - console.log("Could not get app config") - return; - } - var decodedString = JSON.parse(atob(responseJson.app)); - console.log("dcodedString: ",decodedString) - return decodedString.authentication - // setSelectedAppAuth(decodedString.authentication) - }).catch((error) => { - console.log("Error getting app config: " + error); - }) -} const testWorkflowModal = notificationWorkflowTestModal ? ( ) : null -const notificationWorkflowModalValid = () => { -return selectedAuth && webhookInputValue; -}; - const modalView = notificationWorkflowModal ? ( {console.log("len Selected app details: ", selectedAppDetails)} - {(selectedAppDetails.authentication_data || selectedAppDetails.auth_config.required == false) ? + {(selectedAppDetails.authentication_data || (selectedAppDetails.auth_config && selectedAppDetails.auth_config.required == false) || (selectedAppDetails.authentication && selectedAppDetails.authentication.required == false)) ? <> - {selectedAppDetails.auth_config.required == false ? "No authentication required": + {(selectedAppDetails.auth_config && selectedAppDetails.auth_config.required == false || (selectedAppDetails.authentication && selectedAppDetails.authentication.required == false)) ? "No authentication required": <> Pick an authentication method from the list @@ -892,14 +815,15 @@ const modalView = notificationWorkflowModal ? ( labelId="demo-simple-select-label" id="demo-simple-select" value={selectedAuth} - disabled = {selectedAppDetails.auth_config.required == false ? true : false} + disabled = {(selectedAppDetails.auth_config && selectedAppDetails.auth_config.required == false || (selectedAppDetails.authentication && selectedAppDetails.authentication.required == false))} onChange={(event) => {setSelectedAuth(event.target.value) + console.log("event.target.value: ",event.target.value) console.log("Selected auth: ", selectedAuth) }} label="Available authentications" required={true} > - {selectedAppDetails.auth_config.required == false ? "No authentication required" : selectedAppDetails.authentication_data.map((option) => ( + {(selectedAppDetails.auth_config && selectedAppDetails.auth_config.required == false || (selectedAppDetails.authentication && selectedAppDetails.authentication.required == false)) ? "No authentication required" : selectedAppDetails.authentication_data.map((option) => (
@@ -1010,45 +934,61 @@ const modalView = notificationWorkflowModal ? ( ) : null + const checkIfAlreadyGenerated = async (appList, workflows) => { // fixxxxxxxxxxxxxxxxxxxxx + + var workflowName = workflows.find(workflow => workflow.id === notificationWorkflow) + if (workflowName) { + workflowName = workflowName.name + } + else { + console.log("no workflow set") + return + } + if (workflowName) { + const parts = workflowName.split(' '); + console.log("parts", parts) + if (parts[0].toString() === "[GENERATED]" && parts.length > 1) { + console.log("parts1", parts[1]) + if ((appList.includes(parts[1]))) { + console.log("workflow already generated") + setGeneatedWorkflow({"app_name": parts[1]}) + } + } + } + else { + return + } + } + const renderChips = (apps) => { -if (!apps || apps.length === 0) { - return ( - { - console.log(`Clicked EMAIL`) - setSelectedAppDetails("email") - setNotificationWorkflowModal(true) - // setNotificationWorkflowModal(true) - }} - avatar={{"email} - /> - ) -} + return ( + + {apps.map((app) => ( + { + console.log(`Clicked ${app.name}`) + console.log("app: ",app) + setSelectedAppDetails(app) + if (app.authentication_data && app.authentication_data.length > 0){ //fixxxxxxxx + console.log("authdata: ",app.authentication_data[0]) + setSelectedAuth(app.authentication_data[app.authentication_data.length-1].id) + } + setNotificationWorkflowModal(true) + // getAppAuth(app.name) + console.log("selectedAppDEtails",selectedAppDetails) + }} + avatar={{app.name}} -return ( - - {apps.map((app) => ( - { - console.log(`Clicked ${app.name}`) - setSelectedAppDetails(app) - setNotificationWorkflowModal(true) - // getAppAuth(app.name) - console.log("selectedAppDEtails",selectedAppDetails) - }} - avatar={{app.name}} - /> - ))} - -); + /> + ))} + + ); }; - return (
@@ -1058,12 +998,8 @@ return ( {modalView} {/*{testWorkflowModal} */}
- {renderChips(notificationAppDetails)}
- {/* - - Add a Workflow that receives notifications from Shuffle when an error occurs in one of your workflows - - */} + {renderChips(notificationAppDetails.length > 0 ? notificationAppDetails : emailData)} +
{workflows !== undefined && workflows !== null && workflows.length > 0 ?