import React, { useState, useEffect, useContext, memo, useCallback } from "react"; import { toast } from "react-toastify"; import { getTheme } from "../theme.jsx"; import { v4 as uuidv4, v5 as uuidv5, validate as isUUID, } from "uuid"; import { Paper, Tooltip, Typography, Divider, Button, ButtonGroup, Grid, Card, Switch, Autocomplete, TextField, MenuItem, IconButton, Dialog, FormControl, DialogContent, DialogActions, DialogTitle, InputLabel, Box, Select } from "@mui/material"; import AuthenticationData from "../components/AuthenticationWindow.jsx"; import Stack from "@mui/material/Stack"; import Chip from "@mui/material/Chip"; import { OpenInNew as OpenInNewIcon, Info as InfoIcon, } from "@mui/icons-material"; import { makeStyles } from "@mui/styles"; import { Context } from "../context/ContextApi.jsx"; import { useNavigate, Link } from "react-router-dom"; import Priority from "../components/Priority.jsx"; import { constrainMatrix } from "reaviz"; //import { useAlert const useStyles = makeStyles({ notchedOutline: { borderColor: "#f85a3e !important", }, }); const Priorities = memo((props) => { const { globalUrl, userdata, clickedFromOrgTab, selectedOrganization, handleEditOrg, serverside, billingInfo, stripeKey, checkLogin, setAdminTab, setCurTab, notifications, setNotifications, } = props; const { themeMode, brandColor } = useContext(Context); const theme = getTheme(themeMode, brandColor); const [showDismissed, setShowDismissed] = React.useState(false); const [showRead, setShowRead] = React.useState(false); const [appFramework, setAppFramework] = React.useState({}); const [selectedWorkflow, setSelectedWorkflow] = React.useState("NO HIGHLIGHT"); const [selectedExecutionId, setSelectedExecutionId] = React.useState("NO HIGHLIGHT"); const [highlightKMS, setHighlightKMS] = React.useState(false) const [workflows, setWorkflows] = React.useState([]) const [openNotification, setOpenNotification] = React.useState(false); const [workflow, setWorkflow] = React.useState({}) const [notificationWorkflow, setNotificationWorkflow] = React.useState( selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.notification_workflow === undefined || selectedOrganization.defaults.notification_workflow.length === 0 ? "" : selectedOrganization.defaults.notification_workflow ); // notification workflow const [notificationWorkflowModal, setNotificationWorkflowModal] = React.useState(false); const [selectedAppDetails, setSelectedAppDetails] = React.useState({}); const [notificationWorkflowTestModal, setNotificationWorkflowTestModal] = React.useState(false); const [selectedAuth, setSelectedAuth] = React.useState(''); const [emailData, setEmailData] = React.useState([]); const [notificationAppsDetails, setnotificationAppsDetails] = React.useState({}); const [generatedWorkflow, setGeneatedWorkflow] = React.useState({}); // for jira & email modal const [textFieldValue, setTextFieldValue] = React.useState(""); const [textFieldOneValue, setTextFieldOneValue] = React.useState(""); useEffect(() => { prepareNotificationAppList() if (notifications === undefined || notifications === null || notifications.length === 0) { getNotifications() } }, []); let navigate = useNavigate(); const classes = useStyles(); // getting comms & cases app from app framework var notificationAppList = []; const mergeAuthData = (result, responseJson) => { // result is only getting: Jira AND discord. 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 = () => { // getting App ID,Authentication fields and saved auths for each app var result = [] 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 => app.categories?.includes("Communication") || app.categories?.includes("Cases")); 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 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((responseJson) => { if (!responseJson.success) { console.log("Could not get app auth") return; } // console.log("responseJson of auth: ", responseJson.data) result = 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.error(`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)); // why is auth_config appearing like this? // this is not very clean. item.auth_config = decodedString.authentication item.large_image = decodedString.large_image item.categories = decodedString.categories let newJSON = notificationAppList; // keeping state changes to a minimum if ((newJSON[item.name] === undefined) && (item?.authentication_data !== null)) { newJSON[item.name] = item; setnotificationAppsDetails(newJSON); console.log("notificationAppsDetails: ", newJSON) } }).then(() => { // removing this for now, // checkIfAlreadyGenerated(filteredApps, workflows); }).catch((error) => { console.log("Error getting app config: " + error); //toast.error("Error getting app config: " + error); }) }) }) } }).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`, { 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); }) } useEffect(() => { console.log("Apps: ", notificationAppsDetails); }, [notificationAppsDetails]) const generateCommsNotificationWorkflow = async (app, sender, recepient) => { var appname = app.name var appImage = app.large_image //currently only supports figure out a way to support more apps var workflowName = `[GENERATED] ${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) => { toast("Trying to create notification workflow..") if (responseJson !== undefined) { console.log("Notification workflow created successfully") var commsParameter = [ { "key": "recipient", "value": recepient }, { "key": "sender", "value": sender }, { "key": "subject", "value": "$exec.title" }, { "key": "body", "value": "$exec.description" } ] if (app.name.toLowerCase() === "gmail") { // this is a special case and we know it commsParameter = `[ { "key": "content", "value": {% python %} import base64 # Set your email variables sender = "${sender}" recipient = "${recepient}" subject = "$exec.title" body = "$exec.description" raw_email = f"""FROM: {sender}\\nTO: {recipient}\\nsubject: {subject}\\n{body}""" # Encode for Gmail API encoded = base64.urlsafe_b64encode(raw_email.encode()).decode() print('"' + encoded + '"') {% endpython %}, }, { "key": "userId", "value": "me" }]` } var workflow_id = responseJson.id; var commsAction = { "app_name": "Singul", "app_version": "1.0.0", "description": "Available actions for communication", "app_id": "integration", "errors": [], "is_valid": true, "isStartNode": true, "label": "Send Notification Message", "public": false, "generated": false, "large_image": app.large_image, "environment": "Cloud", "name": "Communication", "parameters": [ { "description": "", "id": "", "name": "action", "example": "", "value": "send_message", "multiline": false, "multiselect": false, "options": [ "list_messages", "get_message", "send_message", "search_messages", "list_attachments", "get_attachment", "create_contact", "get_contact" ], "action_field": "", "variant": "", "required": true, "configuration": false, "tags": null, "schema": { "type": "" }, "skip_multicheck": false, "value_replace": null, "unique_toggled": false, "error": "", "hidden": false }, { "description": "", "id": "", "name": "fields", "example": "", "value": `${commsParameter}`, "multiline": true, "multiselect": false, "options": null, "action_field": "", "variant": "", "required": false, "configuration": false, "tags": null, "schema": { "type": "" }, "skip_multicheck": false, "value_replace": null, "unique_toggled": false, "error": "", "hidden": false }, { "description": "", "id": "", "name": "app_name", "example": "", "value": app.name, "multiline": false, "multiselect": false, "options": null, "action_field": "", "variant": "", "required": false, "configuration": false, "tags": null, "schema": { "type": "" }, "skip_multicheck": false, "value_replace": null, "unique_toggled": false, "error": "", "hidden": false } ], "execution_variable": { "description": "", "id": "", "name": "", "value": "" }, "position": { "x": 67.96428571428578, "y": 263.14385714285714 }, "authentication_id": "", "category": "", "reference_url": "", "sub_action": false, "run_magic_output": false, "run_magic_input": false, "execution_delay": 0, "category_label": null, "suggestion": false, "parent_controlled": false, "source_workflow": "", "source_execution": "" } console.log("updating workflow for email") var workflowBody = { "name": workflowName, "Description": workflowDescription, "id": workflow_id, "actions": [ commsAction, ] } 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) { toast("Saving as notification workflow now..") handleEditOrg( selectedOrganization.name, selectedOrganization.description, selectedOrganization.id, selectedOrganization.image, { documentation_reference: selectedOrganization?.defaults?.documentation_reference, workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo, workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch, workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username, workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token, newsletter: selectedOrganization?.defaults?.newsletter, weekly_recommendations: selectedOrganization?.defaults?.weekly_recommendations, notification_workflow: workflow_id, }, { sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint, sso_certificate: selectedOrganization?.sso_config?.sso_certificate, client_id: selectedOrganization?.sso_config?.client_id, client_secret: selectedOrganization?.sso_config?.client_secret, openid_authorization: selectedOrganization?.sso_config?.openid_authorization, openid_token: selectedOrganization?.sso_config?.openid_token, SSORequired: selectedOrganization?.sso_config?.SSORequired, auto_provision: selectedOrganization?.sso_config?.auto_provision, } ) console.log("Notification workflow updated successfully") toast("Notification workflow updated successfully") } }) } }).catch((error) => { console.log("Error setting workflows: " + error); }) } const generateCasesNotificationWorkflow = async (app, projectId) => { var appname = app.name var appImage = app.large_image //currently only supports figure out a way to support more apps var workflowName = `[GENERATED] ${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) => { toast("Trying to create notification workflow..") if (responseJson !== undefined) { console.log("Notification workflow created successfully") var ticketParameter = [ { "key": "project", "value": projectId, }, { "key": "content", "value": "$exec.title" }, { "key": "title", "value": "$exec.description" } ] // fields = fields.concat(otherFields) var workflow_id = responseJson.id; var commsAction = { "app_name": "Singul", "app_version": "1.0.0", "description": "Available actions for case management", "app_id": "integration", "errors": [ ], "is_valid": true, "isStartNode": true, "label": "create_case_from_notification", "public": false, "generated": false, "large_image": app.large_image, "environment": "Cloud", "name": "Cases", "parameters": [ { "description": "", "id": "", "name": "action", "example": "", "value": "create_ticket", "multiline": false, "multiselect": false, "options": [ "list_tickets", "get_ticket", "create_ticket", "close_ticket", "add_comment", "update_ticket", "search_tickets" ], "action_field": "", "variant": "", "required": true, "configuration": false, "tags": null, "schema": { "type": "" }, "skip_multicheck": false, "value_replace": null, "unique_toggled": false, "error": "", "hidden": false }, { "description": "", "id": "", "name": "fields", "example": "", "value": ticketParameter, "multiline": true, "multiselect": false, "options": null, "action_field": "", "variant": "", "required": false, "configuration": false, "tags": null, "schema": { "type": "" }, "skip_multicheck": false, "value_replace": null, "unique_toggled": false, "error": "", "hidden": false }, { "description": "", "id": "", "name": "app_name", "example": "", "value": app.name, "multiline": false, "multiselect": false, "options": null, "action_field": "", "variant": "", "required": false, "configuration": false, "tags": null, "schema": { "type": "" }, "skip_multicheck": false, "value_replace": null, "unique_toggled": false, "error": "", "hidden": false } ], "execution_variable": { "description": "", "id": "", "name": "", "value": "" }, "position": { "x": -111.59751960534861, "y": 180.34429863506278 }, "authentication_id": "", "category": "", "reference_url": "", "sub_action": false, "run_magic_output": false, "run_magic_input": false, "execution_delay": 0, "category_label": null, "suggestion": false, "parent_controlled": false, "source_workflow": "", "source_execution": "" } console.log("updating workflow for email") var workflowBody = { "name": workflowName, "Description": workflowDescription, "id": workflow_id, "actions": [ commsAction, ] } 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( selectedOrganization.name, selectedOrganization.description, selectedOrganization.id, selectedOrganization.image, { documentation_reference: selectedOrganization?.defaults?.documentation_reference, workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo, workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch, workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username, workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token, newsletter: selectedOrganization?.defaults?.newsletter, weekly_recommendations: selectedOrganization?.defaults?.weekly_recommendations, notification_workflow: workflow_id, }, { sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint, sso_certificate: selectedOrganization?.sso_config?.sso_certificate, client_id: selectedOrganization?.sso_config?.client_id, client_secret: selectedOrganization?.sso_config?.client_secret, openid_authorization: selectedOrganization?.sso_config?.openid_authorization, openid_token: selectedOrganization?.sso_config?.openid_token, SSORequired: selectedOrganization?.sso_config?.SSORequired, auto_provision: selectedOrganization?.sso_config?.auto_provision, } ) console.log("Notification workflow updated successfully") toast("Notification workflow updated successfully") } }) } }).catch((error) => { console.log("Error setting workflows: " + error); }) } const testWorkflowModal = notificationWorkflowTestModal ? ( { setNotificationWorkflowTestModal(false); }} > {/*
Notification workflow
*/} We have updated the Notification workflow. Do you want to test it?
) : null const modalView = notificationWorkflowModal ? ( { setNotificationWorkflowModal(false); }} >
{`Configure ${selectedAppDetails?.name?.replaceAll("_", " ")} workflow`}
{console.log("len Selected app details: ", selectedAppDetails)} {(selectedAppDetails.authentication_data || (selectedAppDetails.auth_config && selectedAppDetails.auth_config.required == false) || (selectedAppDetails.authentication && selectedAppDetails.authentication.required == false)) ? <> {true || (selectedAppDetails.auth_config && selectedAppDetails.auth_config.required == false || (selectedAppDetails.authentication && selectedAppDetails.authentication.required == false)) ? "No authentication required" : <> Pick an authentication method from the list Available authentications } Provide additional required details: { setTextFieldOneValue(e.target.value) }} InputProps={{ classes: { notchedOutline: classes.notchedOutline, }, style: { color: "white", }, }} /> { setTextFieldValue(e.target.value) }} InputProps={{ classes: { notchedOutline: classes.notchedOutline, }, style: { color: "white", }, }} /> : <> 0) ? false : true} // // setAuthenticationModalOpen={false} selectedApp={{ ...selectedAppDetails, authentication: selectedAppDetails.auth_config }} // getAppAuthentication={selectedAppDetails.name} /> }
) : 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 = useCallback(() => { const appList = Object.values(notificationAppsDetails); return ( {appList.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}} /> ))} Want access to more templates? Set up app authentication to show additional workflow options. ); }, [notificationAppsDetails]) useEffect(() => { getFramework() // Check "workflow" and "execution_id" in URL const urlParams = new URLSearchParams(window.location.search) const workflow = urlParams.get("workflow") const execution_id = urlParams.get("execution_id") const kms = urlParams.get("kms") if (kms !== null && kms !== undefined && kms.length > 0 && kms === "true") { toast.info("KMS-related notifications are highlighted.") setHighlightKMS(true) } if (execution_id !== null) { setSelectedExecutionId(execution_id) //toast.info("Execution-related notifications are highlighted.") } if (workflow !== null) { setSelectedWorkflow(workflow) toast.info("Workflow-related notifications are highlighted.") } }, []) useEffect(() => { if (selectedOrganization === undefined || selectedOrganization === null || selectedOrganization?.id === undefined || selectedOrganization?.id === null || selectedOrganization?.id.length === 0) { return } if (workflows?.length === 0) { getAvailableWorkflows() } if (notificationWorkflow !== selectedOrganization?.defaults?.notification_workflow) { setNotificationWorkflow(selectedOrganization?.defaults?.notification_workflow) } }, [selectedOrganization]) if (userdata === undefined || userdata === null) { return } const getFramework = () => { fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for framework!"); } return response.json(); }) .then((responseJson) => { if (responseJson.success === false) { setAppFramework({}) if (responseJson.reason !== undefined) { //toast("Failed loading: " + responseJson.reason) } else { //toast("Failed to load framework for your org.") } } else { setAppFramework(responseJson) } }) .catch((error) => { console.log("err in framework: ", error.toString()); }) } const getNotifications = () => { fetch(`${globalUrl}/api/v1/notifications`, { credentials: "include", method: "GET", headers: { "Content-Type": "application/json", }, }) .then(function (response) { if (response.status !== 200) { console.log("Error in response"); } return response.json(); }) .then(function (responseJson) { if (responseJson?.success !== false && responseJson?.notifications !== undefined && responseJson?.notifications !== null) { setNotifications(responseJson.notifications || []) } else { toast("Failed loading notifications. Please try again later."); } }) .catch((error) => { console.log("error in notification loading: ", error); }); } const clearNotifications = () => { // Don't really care about the logout toast.info("Marking all notifications as read. This may take a while.") fetch(`${globalUrl}/api/v1/notifications/clear`, { credentials: "include", method: "GET", headers: { "Content-Type": "application/json", }, }) .then(function (response) { if (response.status !== 200) { console.log("Error in response"); } return response.json(); }) .then(function (responseJson) { if (responseJson.success === true) { // Reload the UI const newNotifications = notifications.map((notification) => { notification.read = true return notification }) setNotifications(newNotifications) setShowRead(true) } else { toast("Failed dismissing notifications. Please try again later."); } }) .catch((error) => { console.log("error in notification dismissal: ", error); //removeCookie("session_token", {path: "/"}) }); }; const dismissNotification = (alert_id, disabled) => { var notificationurl = `${globalUrl}/api/v1/notifications/${alert_id}/markasread` if (disabled === true) { notificationurl += "?disabled=true" } else if (disabled === false) { notificationurl += "?disabled=false" } fetch(notificationurl, { credentials: "include", method: "GET", headers: { "Content-Type": "application/json", }, }) .then(function (response) { if (response.status !== 200) { console.log("Error in response"); } return response.json(); }) .then(function (responseJson) { if (responseJson.success === true) { // Mark current one as read var newNotifications = notifications.map((notification) => { if (notification.id === alert_id) { notification.read = true } return notification }) if (disabled === true) { toast("Notification disabled, and will not be shown again.") newNotifications = newNotifications.map((notification) => { if (notification.id === alert_id) { notification.ignored = true } return notification }) console.log("NEW NOTIFICATIONS: ", newNotifications); } else if (disabled === false) { toast("Notification re-enabled successfully") newNotifications = newNotifications.map((notification) => { if (notification.id === alert_id) { notification.ignored = false } return notification }) } else { toast("Notification dismissed successfully") } //const newNotifications = notifications.filter( // (data) => data.id !== alert_id //) //console.log("NEW NOTIFICATIONS: ", newNotifications); if (setNotifications !== undefined && newNotifications !== undefined) { setNotifications(newNotifications) } } else { toast("Failed dismissing notification. Please try again later."); } }) .catch((error) => { console.log("error in notification dismissal: ", error); //removeCookie("session_token", {path: "/"}) }) } const notificationWidth = "100%" const imagesize = 22 const boxColor = "#86c142" const getAvailableWorkflows = () => { fetch(globalUrl + "/api/v1/workflows", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for workflows :O!"); return; } return response.json(); }) .then((responseJson) => { if (responseJson !== undefined) { // Add parent notification workflow if it's a child org // selectedOrganization, if (selectedOrganization.creator_org !== undefined && selectedOrganization.creator_org !== null && selectedOrganization.creator_org.length > 0) { // Add to start of the list responseJson.unshift({ "name": "Parent-Org's Notification Workflow", "id": "parent", }) } setWorkflows(responseJson) if (selectedOrganization.defaults !== undefined && selectedOrganization.defaults.notification_workflow !== undefined) { const workflow = responseJson.find((workflow) => workflow.id === selectedOrganization.defaults.notification_workflow) if (workflow !== undefined && workflow !== null) { setWorkflow(workflow) } } } }) .catch((error) => { console.log("Error getting workflows: " + error); }) } const handleWorkflowSelectionUpdate = (e, isUserinput) => { if (e.target.value === undefined || e.target.value === null || e.target.value.id === undefined) { console.log("Returning as there's no id") return null } setOpenNotification(false) setWorkflow(e.target.value) setNotificationWorkflow(e.target.value.id) handleEditOrg( selectedOrganization?.name, selectedOrganization.description, selectedOrganization.id, selectedOrganization.image, { app_download_repo: selectedOrganization?.defaults?.app_download_repo, app_download_branch: selectedOrganization?.defaults?.app_download_branch, workflow_download_repo: selectedOrganization?.defaults?.workflow_download_repo, workflow_download_branch: selectedOrganization?.defaults?.workflow_download_branch, notification_workflow: e.target.value.id, documentation_reference: selectedOrganization?.defaults?.documentation_reference, workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo, workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch, workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username, workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token, newsletter: selectedOrganization?.defaults?.newsletter, weekly_recommendations: selectedOrganization?.defaults?.weekly_recommendations, }, { sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint, sso_certificate: selectedOrganization?.sso_config?.sso_certificate, client_id: selectedOrganization?.sso_config?.client_id, client_secret: selectedOrganization?.sso_config?.client_secret, openid_authorization: selectedOrganization?.sso_config?.openid_authorization, openid_token: selectedOrganization?.sso_config?.openid_token, SSORequired: selectedOrganization?.sso_config?.SSORequired, auto_provision: selectedOrganization?.sso_config?.auto_provision, } ) } return (
Error Workflow The error workflow triggers when an error occurs in one of your workflows. Each individual one will only start a workflow once every 2 minutes. You can point child org errors to a parent org's error workflow by choosing it in the list. {modalView} {/*{testWorkflowModal} */}
{renderChips()}
{workflows !== undefined && workflows !== null && workflows.length > 0 ? { setOpenNotification(true); }} onClose={() => { setOpenNotification(false); }} freeSolo //autoSelect value={workflows?.find(w => w.id === notificationWorkflow) || null} classes={{ inputRoot: classes.inputRoot }} ListboxProps={{ style: { backgroundColor: theme.palette.surfaceColor, color: theme.palette.text.primary, borderRadius: theme.palette.borderRadius, }, }} getOptionLabel={(option) => { if ( option === undefined || option === null || option.name === undefined || option.name === null ) { return "No Workflow Selected"; } const newname = ( option.name.charAt(0).toUpperCase() + option.name.substring(1) ).replaceAll("_", " "); return newname; }} options={workflows} fullWidth style={{ backgroundColor: theme.palette.textFieldStyle.backgroundColor, borderRadius: theme.palette.textFieldStyle.borderRadius, color: theme.palette.textFieldStyle.color, height: 35, marginBottom: 40, }} onChange={(event, newValue) => { console.log("Found value: ", newValue) var parsedinput = { target: { value: newValue } } // For variables if (typeof newValue === 'string' && newValue.startsWith("$")) { parsedinput = { target: { value: { "name": newValue, "id": newValue, "actions": [], "triggers": [], } } } } handleWorkflowSelectionUpdate(parsedinput) }} renderOption={(props, data, state) => { if (data.id === workflow.id) { data = workflow; } return ( {data.image !== undefined && data.image !== null && data.image.length > 0 ? {data.name} : null} Choose {data.name} } placement="bottom"> { props.onMouseDown?.(null); var parsedinput = { target: { value: data } } handleWorkflowSelectionUpdate(parsedinput) }} > {data.name} ) }} renderInput={(params) => { return ( ); }} /> : { setNotificationWorkflow(e.target.value); }} /> } {/*
{orgSaveButton}
*/}
{notificationWorkflow === undefined || notificationWorkflow === null || notificationWorkflow.length === 0 ? null :
{ if (notificationWorkflow === "parent") { toast.error("Can't open parent org's notification workflow from here.") return } window.open(`/workflows/${notificationWorkflow}?view=executions`, "_blank") }} >
} Errors ({ notifications?.filter((notification) => showRead === true || notification.read === false).length }) Error help you find potential problems with your workflows and apps.  Learn more
{ setShowRead(!showRead); }} />  Show read {notifications !== undefined && notifications !== null && notifications.length > 1 ? ( ) : null}
{clickedFromOrgTab ? null : } Suggestions Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company.
These range from simple configurations in Shuffle to Usecases you may have missed.  Learn more
{ setShowDismissed(!showDismissed); }} />  Show dismissed {userdata.priorities === null || userdata.priorities === undefined || userdata.priorities.length === 0 ? No Suggestions found : userdata.priorities.map((priority, index) => { if (showDismissed === false && priority.active === false) { return null } return ( ) }) }
) }) export default Priorities; const NotificationItem = memo((props) => { const { data, selectedExecutionId, selectedWorkflow, highlightKMS, userdata, imagesize, boxColor, clickedFromOrgTab, notificationWidth, dismissNotification } = props var image = ""; var orgName = ""; var orgId = ""; const { themeMode, brandColor } = useContext(Context); const theme = getTheme(themeMode, brandColor); var highlighted = selectedExecutionId === "" && selectedWorkflow === "" ? false : data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0 ? false : data.reference_url.includes(selectedExecutionId) || data.reference_url.includes(selectedWorkflow) if (!highlighted && highlightKMS) { if (data.title !== undefined && data.title !== null && data.title.toLowerCase().includes("kms")) { highlighted = true } else if (data.description !== undefined && data.description !== null && data.description.toLowerCase().includes("kms")) { highlighted = true } } if (userdata.orgs !== undefined) { const foundOrg = userdata.orgs.find((org) => org.id === data["org_id"]); if (foundOrg !== undefined && foundOrg !== null) { //position: "absolute", bottom: 5, right: -5, const imageStyle = { width: imagesize, height: imagesize, pointerEvents: "none", marginLeft: data.creator_org !== undefined && data.creator_org.length > 0 ? 20 : 0, borderRadius: 10, border: foundOrg.id === userdata.active_org.id ? `3px solid ${boxColor}` : null, cursor: "pointer", marginRight: 10, }; image = foundOrg.image === "" ? ( {foundOrg.name} ) : ( {foundOrg.name} { }} /> ); orgName = foundOrg.name; orgId = foundOrg.id; } } return (
{data.amount === 1 && data.read === false ? : null} {data.ignored === true ? : null} {data.read === false ? : } {data.title}
{data.image !== undefined && data.image !== null && data.image.length > 0 ? {data.title} : null } {data.description}
{data.read === false ? ( ) : null} First seen:{" "} {new Date(data.created_at * 1000).toISOString().slice(0, 19)} Last seen:{" "} {new Date(data.updated_at * 1000).toISOString().slice(0, 19)} Times seen: {data.amount}
); }) const NotificationComponent = memo(({ notifications, showRead, selectedExecutionId, selectedWorkflow, highlightKMS, userdata, imagesize, boxColor, clickedFromOrgTab, notificationWidth, dismissNotification }) => { return (
{notifications === null || notifications === undefined || notifications?.length === 0 ? ( null ) :
{notifications?.map((notification, index) => { if (showRead === false && notification.read === true) { return null } return ( ) })}
}
) }) // const PaddingWrapper = memo(({children, clickedFromOrgTab}) => { // const { leftSideBarOpenByClick } = useContext(Context) // return( //
// {children} //
// ) // }) // const Wrapper = memo(({children, clickedFromOrgTab}) => { // return( // // {children} // // ) // })