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 ?
() : null
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 = useCallback(() => {
const appList = Object.values(notificationAppsDetails);
return (
}
/>
))}