From f0c2dfa3d22f12eaa8479a079619bae6b7a367a7 Mon Sep 17 00:00:00 2001 From: Frikky Date: Tue, 11 Mar 2025 01:57:05 +0100 Subject: [PATCH] Multiple diff fixes for multi tenant workflows --- backend/go-app/go.mod | 2 +- backend/go-app/go.sum | 2 + backend/go-app/walkoff.go | 8 +- frontend/src/components/Billing.jsx | 81 ++++++++------ frontend/src/components/EditWorkflow.jsx | 15 ++- frontend/src/components/LicencePopup.jsx | 70 +++++++++--- frontend/src/components/Navbar.jsx | 2 +- frontend/src/views/AngularWorkflow.jsx | 134 +++++++++++++++++------ frontend/src/views/LoginPage.jsx | 20 ++-- frontend/src/views/Workflows.jsx | 5 +- frontend/src/views/Workflows2.jsx | 14 ++- 11 files changed, 247 insertions(+), 106 deletions(-) diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index 8af42425..cf2eb962 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -18,7 +18,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/h2non/filetype v1.1.3 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.8.7 + github.com/shuffle/shuffle-shared v0.8.12 golang.org/x/crypto v0.32.0 google.golang.org/api v0.176.1 google.golang.org/grpc v1.68.1 diff --git a/backend/go-app/go.sum b/backend/go-app/go.sum index f240b4e4..99179e7f 100644 --- a/backend/go-app/go.sum +++ b/backend/go-app/go.sum @@ -356,6 +356,8 @@ github.com/shuffle/shuffle-shared v0.8.5 h1:c98AMOzIrDXmgQrKyf1HJ9wZwAwB02LPRvf9 github.com/shuffle/shuffle-shared v0.8.5/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= github.com/shuffle/shuffle-shared v0.8.6 h1:chnGJRKsO1gR5Vt/8hp5SQg1yP8/DmiK8sRhWVaTgEg= github.com/shuffle/shuffle-shared v0.8.6/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= +github.com/shuffle/shuffle-shared v0.8.12 h1:fg6jGAuevOGLgR7kpoZDJh//tzFjrEqj/bpxRFzxUTw= +github.com/shuffle/shuffle-shared v0.8.12/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 037d6d32..dfdccefe 100755 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -1032,10 +1032,14 @@ func deleteWorkflow(resp http.ResponseWriter, request *http.Request) { log.Printf("[INFO] Should have deleted workflow %s (%s)", workflow.Name, fileId) - cacheKey := fmt.Sprintf("%s_workflows", user.Id) - shuffle.DeleteCache(ctx, cacheKey) + shuffle.DeleteCache(ctx, fmt.Sprintf("%s_workflows", user.Id)) shuffle.DeleteCache(ctx, fmt.Sprintf("%s_workflows", user.ActiveOrg.Id)) + shuffle.DeleteCache(ctx, fmt.Sprintf("%s_%s", user.Username, fileId)) log.Printf("[DEBUG] Cleared workflow cache for %s (%s)", user.Username, user.Id) + shuffle.DeleteCache(ctx, fmt.Sprintf("workflow_%s_childworkflows", workflow.ID)) + if len(workflow.ParentWorkflowId) > 0 { + shuffle.DeleteCache(ctx, fmt.Sprintf("workflow_%s_childworkflows", workflow.ParentWorkflowId)) + } resp.WriteHeader(200) resp.Write([]byte(`{"success": true}`)) diff --git a/frontend/src/components/Billing.jsx b/frontend/src/components/Billing.jsx index 577d249c..39e15706 100644 --- a/frontend/src/components/Billing.jsx +++ b/frontend/src/components/Billing.jsx @@ -77,6 +77,8 @@ const Billing = memo((props) => { const [currentIndex, setCurrentIndex] = useState(0); const [deleteAlertIndex, setDeleteAlertIndex] = useState(-1); const [deleteAlertVerification, setDeleteAlertVerification] = useState(false); + const [isScale, setIsScale] = useState(false); + useEffect(() => { if (userdata.app_execution_limit !== undefined && userdata.app_execution_usage !== undefined) { const percentage = (userdata.app_execution_usage / userdata.app_execution_limit) * 100; @@ -176,11 +178,10 @@ const Billing = memo((props) => { padding: 20, // maxWidth: 400, width: 340, - height: 480, + height: 'auto', // width: "100%", - backgroundColor: theme.palette.backgroundColor, - borderRadius: theme.palette?.borderRadius * 2, - border: "1px solid rgba(255,255,255,0.3)", + backgroundColor: "#1e1e1e", + borderRadius: 10, marginRight: 10, marginTop: 15, } @@ -361,7 +362,7 @@ const Billing = memo((props) => { var showSupport = false if (subscription.name.includes("default")) { top_text = "Custom Contract" - newPaperstyle.border = "1px solid rgba(255,255,255,0.3)" + // newPaperstyle.border = "1px solid rgba(255,255,255,0.3)" showSupport = true } @@ -377,16 +378,17 @@ const Billing = memo((props) => { if (subscription.name.includes("Scale")) { top_text = "Scale access" + setIsScale(true) } if (highlight === true) { // Add an "Upgrade now" button - newPaperstyle.border = "1px solid rgba(255,255,255,0.3)" + // newPaperstyle.border = "1px solid rgba(255,255,255,0.3)" } - if (hovered) { - newPaperstyle.backgroundColor = "#2b2b2b" - } + // if (hovered) { + // newPaperstyle.backgroundColor = "#2b2b2b" + // } const handleClickOpen = () => { setOpenChangeEmailBox(true); @@ -556,6 +558,7 @@ const Billing = memo((props) => { +
{top_text === "Base Cloud Access" && userdata.has_card_available === true ? { { }} @@ -2013,7 +2016,33 @@ const Billing = memo((props) => { : null} -
+
+
+ {isCloud && + selectedOrganization.subscriptions !== undefined && + selectedOrganization.subscriptions !== null && + selectedOrganization.subscriptions.length > 0 && + !isChildOrg ? + selectedOrganization.subscriptions + .reverse() + .map((sub, index) => { + return ( + + ) + }) + : null} + +
{isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ? isChildOrg ? null : { isCloud={isCloud} userdata={userdata} stripeKey={stripeKey} + isScale={isScale} {...props} /> : !isCloud ? @@ -2061,6 +2091,7 @@ const Billing = memo((props) => { isCloud={isCloud} userdata={userdata} stripeKey={stripeKey} + isScale={isScale} /> {/* { /> */} : null} +
+
- {isCloud && - selectedOrganization.subscriptions !== undefined && - selectedOrganization.subscriptions !== null && - selectedOrganization.subscriptions.length > 0 && - !isChildOrg ? - selectedOrganization.subscriptions - .reverse() - .map((sub, index) => { - return ( - - ) - }) - : null} {/* { */}
- {/*isCloud && selectedOrganization.partner_info !== undefined && selectedOrganization.partner_info.reseller === true ? ( diff --git a/frontend/src/components/EditWorkflow.jsx b/frontend/src/components/EditWorkflow.jsx index b67bde93..48574126 100644 --- a/frontend/src/components/EditWorkflow.jsx +++ b/frontend/src/components/EditWorkflow.jsx @@ -577,12 +577,20 @@ const EditWorkflow = (props) => { Multi-Tenancy, Backups & Security - - Multi-Tenant Workflows. Make one workflow, and keep a separate, synced copy in all your tenants. Control distributed auth, runtime locations, files, datastore keys etc. (contact support@shuffler.io if you want a demo. Please try it!) + Control mechanisms for multi-tenancy, backups, and security. - {userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 0 ? + + Multi-Tenant Workflows + + + + Make one workflow, and keep a separate, synced copy in your other tenants. Control distributed auth, runtime locations, files, datastore keys etc. Can only distribute from parent org to child org. Need help trying it? Contact us for a demo + + + {userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 0 ? + userdata.orgs.filter(org => org.creator_org === userdata.active_org.id).length === 0 ? userdata.active_org.creator_org === undefined || userdata.active_org.creator_org === null || userdata.active_org.creator_org === "" ? @@ -600,6 +608,7 @@ const EditWorkflow = (props) => { multiple style={{ marginTop: 10, }} value={innerWorkflow.suborg_distribution === undefined || innerWorkflow.suborg_distribution === null ? ["none"] : innerWorkflow.suborg_distribution} + disabled={workflow?.parentorg_workflow !== undefined && workflow?.parentorg_workflow !== null && workflow?.parentorg_workflow.length > 0} onChange={(e) => { var newvalue = e.target.value if (newvalue.length > 1 && newvalue[0] === "none") { diff --git a/frontend/src/components/LicencePopup.jsx b/frontend/src/components/LicencePopup.jsx index f52ffa45..9492ae99 100644 --- a/frontend/src/components/LicencePopup.jsx +++ b/frontend/src/components/LicencePopup.jsx @@ -46,7 +46,7 @@ import { handlePayasyougo } from "../views/HandlePaymentNew.jsx" import Billing from "./Billing.jsx"; const LicencePopup = (props) => { - const { globalUrl, userdata, serverside, billingInfo, stripeKey, setModalOpen, isLoggedIn, isMobile, selectedOrganization, isCloud } = props; + const { globalUrl, userdata, serverside, billingInfo, stripeKey, setModalOpen, isScale, isLoggedIn, isMobile, selectedOrganization, isCloud } = props; //const alert = useAlert(); let navigate = useNavigate(); const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false); @@ -165,11 +165,25 @@ const LicencePopup = (props) => { ] } + if (userdata?.app_execution_limit >= 300000) { + subscription.name = "Enterprise" + subscription.currency_text = "$" + subscription.price = typecost_single + subscription.limit = userdata?.app_execution_limit + subscription.interval = "app run / month" + subscription.features = [ + "Includes " + (userdata?.app_execution_limit/1000) + "K app runs/month. ", + "Multi-Tenancy and Region-Selection", + "And all other features from /pricing", + ] + } + + var newPaperstyle = JSON.parse(JSON.stringify(paperStyle)) if (subscription.name === "Enterprise" && subscription.active === true) { - top_text = "Current Plan" + top_text = "Enterprise Plan" - newPaperstyle.border = "1px solid #f85a3e" + // newPaperstyle.border = "1px solid #f85a3e" } var showSupport = false @@ -255,7 +269,7 @@ const LicencePopup = (props) => { style={{ borderRadius: theme.palette?.borderRadius, }} placement="bottom" > -
+
setHovered(true)} @@ -343,9 +357,9 @@ const LicencePopup = (props) => {
- + {subscription.active === true && !isScale && }
- {top_text === "Base Cloud Access" && userdata.has_card_available === true ? + {top_text === "Base Cloud Access" && userdata.has_card_available === true && !isScale ? { "While you have a card attached to your account, Shuffle will no longer prevent workflows from running. Billing will occur at the start of each month." : isCloud ? - `You are not subscribed to any plan and are using the free plan with max 10,000 app runs per month. Upgrade to deactivate this limit.` + userdata?.app_execution_limit && userdata?.app_execution_limit >= 300000 ? + "You have subscribed to the Enterprise plan, which includes " + (userdata?.app_execution_limit/1000) + "K app runs/month. You can increase the limit by upgrading current plan. Contact support@shuffler.io for more information." : + `You are not subscribed to any plan and are using the free plan with max 10,000 app runs per month. Upgrade to deactivate this limit.` + : `You are not subscribed to any plan and are using the free, open source plan. This plan has no enforced limits, but scale issues may occur due to CPU congestion.` } @@ -699,8 +716,33 @@ const LicencePopup = (props) => { setCalculatedCost("$960") setSelectedValue(8) } else { - setCalculatedCost("$960") - setSelectedValue(300) + if (userdata && userdata?.app_execution_limit) { + if (userdata.app_execution_limit >= 300000 && userdata.app_execution_limit < 400000) { + setSelectedValue(400) + setCalculatedCost("$1280") + }else if (userdata?.app_execution_limit >= 400000 && userdata?.app_execution_limit < 500000) { + setSelectedValue(500) + setCalculatedCost("$1600") + } else if (userdata?.app_execution_limit >= 500000 && userdata?.app_execution_limit < 600000) { + setSelectedValue(600) + setCalculatedCost("$1920") + } else if (userdata?.app_execution_limit >= 600000 && userdata?.app_execution_limit < 700000) { + setSelectedValue(700) + setCalculatedCost("$2240") + } else if (userdata?.app_execution_limit >= 700000 && userdata?.app_execution_limit < 800000) { + setSelectedValue(800) + setCalculatedCost("$2560") + } else if (userdata?.app_execution_limit >= 800000 && userdata?.app_execution_limit < 900000) { + setSelectedValue(900) + setCalculatedCost("$2880") + }else { + setCalculatedCost("$960") + setSelectedValue(300) + } + }else { + setCalculatedCost("$960") + setSelectedValue(300) + } } }, [shuffleVariant]) @@ -977,7 +1019,7 @@ const LicencePopup = (props) => { : null} - {isCloud && + {/* {isCloud && selectedOrganization.subscriptions !== undefined && selectedOrganization.subscriptions !== null && selectedOrganization.subscriptions.length > 0 ? @@ -998,7 +1040,7 @@ const LicencePopup = (props) => { /> ) }) - : null} + : null} */} @@ -1006,12 +1048,12 @@ const LicencePopup = (props) => {
- + color="primary">Recommended }
{shuffleVariant === 1 ? "Scale" : "Enterprise"} diff --git a/frontend/src/components/Navbar.jsx b/frontend/src/components/Navbar.jsx index ebee1db5..c3cca3f8 100644 --- a/frontend/src/components/Navbar.jsx +++ b/frontend/src/components/Navbar.jsx @@ -47,7 +47,7 @@ const menuData = { title: "Shuffle", description: "The most versatile automation engine with focus on security.", - icon: "images/logos/orange_logo.svg", + icon: "images/icons/shuffleLogo.svg", path: "/docs/about", gaData: { category: "navbar", diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 79a9d98a..374ce85b 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -575,11 +575,17 @@ const AngularWorkflow = (defaultprops) => { }, [editWorkflowModalOpen]) useEffect(() => { - if(selectedTrigger?.trigger_type === "SUBFLOW"){ + // Check if selectedTriggerIndex is a number >= 0 + if (isNaN(selectedTriggerIndex) || selectedTriggerIndex < 0) { + return + } + + if (selectedTrigger?.trigger_type === "SUBFLOW" && selectedTriggerIndex !== undefined && selectedTriggerIndex !== null && workflow?.triggers[selectedTriggerIndex].parameters.length > 1) { setSelectedTriggerValue(workflow.triggers[selectedTriggerIndex].parameters[1].value || "") - } else if(selectedTrigger?.trigger_type === "USERINPUT"){ + } else if (selectedTrigger?.trigger_type === "USERINPUT" && selectedTriggerIndex !== undefined && selectedTriggerIndex !== null && workflow?.triggers[selectedTriggerIndex].parameters.length > 0) { setSelectedTriggerValue(workflow.triggers[selectedTriggerIndex].parameters[0].value || "Do you want to continue the workflow? Start parameters: $exec") } + }, [selectedTriggerIndex, selectedTrigger, workflow]) useEffect(() => { @@ -948,11 +954,15 @@ const AngularWorkflow = (defaultprops) => { } useEffect(() => { - if (workflow.actions?.length == 1) { - if (workflow.actions[0].app_id == "3e320a20966d33c9b7e6790b2705f0bf") { + if (workflow?.actions?.length == 1) { + if (workflow?.actions[0].app_id == "3e320a20966d33c9b7e6790b2705f0bf") { setWorkflowAsCode(true); } } + + if (workflow?.suborg_distribution !== undefined && workflow?.suborg_distribution !== null && workflow?.suborg_distribution.length > 0) { + getChildWorkflows(workflow.id) + } }, [workflow]); // Event for making sure app is correct @@ -1495,6 +1505,8 @@ const AngularWorkflow = (defaultprops) => { if (workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0) { headers["Org-Id"] = workflow.org_id } + + setWorkflows([]) fetch(globalUrl + "/api/v1/workflows?subflow=true", { method: "GET", @@ -1512,7 +1524,7 @@ const AngularWorkflow = (defaultprops) => { if (responseJson !== undefined) { // Sets up subflow trigger with the right info - if (trigger_index > -1) { + if (isNaN(trigger_index) === false && trigger_index > -1) { var baseSubflow = {} const trigger = workflow.triggers[trigger_index]; @@ -2494,15 +2506,19 @@ const AngularWorkflow = (defaultprops) => { if (cy !== undefined && cy !== null) { // scale: 0.3, // bg: "#27292d", - if (cy.png !== undefined && cy.png !== null) { - const cyImageData = cy.png({ - output: "base64uri", - maxWidth: 480, - maxHeight: 270, - }) + if (cy?.png !== undefined && cy?.png !== null) { + try { + const cyImageData = cy.png({ + output: "base64uri", + maxWidth: 480, + maxHeight: 270, + }) - if (cyImageData !== undefined && cyImageData !== null && cyImageData.length > 0) { - useworkflow.image = cyImageData + if (cyImageData !== undefined && cyImageData !== null && cyImageData.length > 0) { + useworkflow.image = cyImageData + } + } catch (e) { + console.log("Failed to get image data: ", e) } } } @@ -3914,6 +3930,10 @@ const AngularWorkflow = (defaultprops) => { } const findWorkflowDiff = (parentWorkflow, childWorkflow) => { + // Ensures new memory is used + parentWorkflow = JSON.parse(JSON.stringify(parentWorkflow)) + childWorkflow = JSON.parse(JSON.stringify(childWorkflow)) + var diff = { "different": false, "environment": false, @@ -3931,9 +3951,13 @@ const AngularWorkflow = (defaultprops) => { return diff } - var parentEnvironment = "" var childEnvironment = "" + + if (parentWorkflow.triggers !== undefined && parentWorkflow.triggers !== null && parentWorkflow.triggers.length > 0) { + parentWorkflow.actions = parentWorkflow.actions.concat(parentWorkflow.triggers) + } + for (var parentKey in parentWorkflow.actions) { const parentAction = parentWorkflow.actions[parentKey] if (parentAction.environment !== undefined && parentAction.environment !== null && parentAction.environment !== "") { @@ -3945,6 +3969,19 @@ const AngularWorkflow = (defaultprops) => { } var found = false + if (childWorkflow.triggers !== undefined && childWorkflow.triggers !== null && childWorkflow.triggers.length > 0) { + for (var triggerKey in childWorkflow.triggers) { + if (childWorkflow.triggers[triggerKey].replacement_for_trigger !== parentAction.id) { + continue + } + + // Rewrapping the ID just in case + childWorkflow.triggers[triggerKey].id = childWorkflow.triggers[triggerKey].replacement_for_trigger + childWorkflow.actions.push(childWorkflow.triggers[triggerKey]) + break + } + } + for (var childKey in childWorkflow.actions) { const childAction = childWorkflow.actions[childKey] if (childAction.environment !== undefined && childAction.environment !== null && childAction.environment !== "") { @@ -3991,6 +4028,10 @@ const AngularWorkflow = (defaultprops) => { continue } + var parentworkflow = "" + var parentstartnode = "" + var childworkflow = "" + var childstartnode = "" for (var parentParamIndex in parentAction.parameters) { const parentParam = parentAction.parameters[parentParamIndex] for (var childParamIndex in childAction.parameters) { @@ -3999,20 +4040,38 @@ const AngularWorkflow = (defaultprops) => { continue } + if (childParam.name === "workflow" || childParam.name === "subflow") { + parentworkflow = parentParam.value + childworkflow = childParam.value + continue + } + + if (childParam.name == "startnode") { + parentstartnode = parentParam.value + childstartnode = childParam.value + continue + } + if (childParam.value !== parentParam.value) { actionDiff.parameters.push(childParam.name) } } } + + if (parentworkflow !== childworkflow && parentstartnode !== childstartnode) { + actionDiff.parameters.push("subflow") + } } if (actionDiff.parameters.length > 0) { actionDiff.params = true } + /* if (!found) { actionDiff.new = true } + */ if (actionDiff !== undefined && actionDiff !== null && Object.keys(actionDiff).length > 1) { actionDiff.label = parentAction.label.replaceAll("_", " ") @@ -6305,11 +6364,15 @@ const AngularWorkflow = (defaultprops) => { if (workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0 && originalWorkflow.org_id !== undefined && originalWorkflow.org_id !== null && originalWorkflow.org_id.length > 0 && workflow.org_id === originalWorkflow.org_id) { // Allows a parent workflow to control the schedule } else if (data.replacement_for_trigger !== undefined && data.replacement_for_trigger !== null && data.replacement_for_trigger.length > 0) { - toast.warning("This schedule is controlled by the parent workflow. If you want additional schedule control, please add a custom schedule to this workflow.", { - autoClose: 30000, - }) - event.target.unselect() - return + + // No custom control on cloud + if (isCloud) { + toast.warning("This schedule is controlled by the parent workflow. If you want additional schedule control, please add a custom schedule to this workflow.", { + autoClose: 30000, + }) + event.target.unselect() + return + } } } else if (data.app_name === "Webhook" && trigger_index >= 0) { @@ -6885,7 +6948,7 @@ const AngularWorkflow = (defaultprops) => { ) if (targetnode !== -1) { if (workflow.triggers[targetnode].app_name === "User Input" || workflow.triggers[targetnode].app_name === "Shuffle Workflow" || workflow.triggers[targetnode].app_name === "Shuffle Subflow") { - console.log("User Input or Shuffle Workflow") + //console.log("User Input or Shuffle Workflow") } else { toast("Can't have triggers as target of branch") event.target.remove() @@ -9217,11 +9280,15 @@ const AngularWorkflow = (defaultprops) => { } insertedNodes = insertedNodes.concat(newedges); - setWorkflow(inputworkflow); + setWorkflow(inputworkflow) // Reset view for cytoscape if (cy !== undefined && cy !== null) { - cy.add(insertedNodes) + try { + cy.add(insertedNodes) + } catch (error) { + console.log("Error adding nodes to cytoscape (6): ", error) + } try { cy.fit(null, 250) @@ -9300,12 +9367,6 @@ const AngularWorkflow = (defaultprops) => { } } - //if (selectedNode.data("id") === selectedAction.id) { - // setSelectedApp({}); - // setSelectedAction({}); - //setSelectedTrigger({}); - //setSelectedTriggerIndex({}); - //} const parsedSelection = cy.$(":selected"); if (selectedNode.data().decorator === true && selectedNode.data("type") !== "COMMENT") { toast("This node can't be deleted."); @@ -9505,7 +9566,6 @@ const AngularWorkflow = (defaultprops) => { if (firstrequest) { setFirstrequest(false) getWorkflow(props.match.params.key, {}) - getChildWorkflows(props.match.params.key) getRevisionHistory(props.match.params.key) loadTriggers() getApps() @@ -14891,12 +14951,15 @@ const AngularWorkflow = (defaultprops) => { }} >
- Select a workflow to execute + Select a workflow to run
+ {workflow.triggers[selectedTriggerIndex].parameters[0].value .length === 0 ? null : workflow.triggers[selectedTriggerIndex] - .parameters[0].value === props.match.params.key ? null : ( + .parameters[0].value === props.match.params.key ? + null + : (
{ {workflows === undefined || workflows === null || - workflows.length === 0 ? null : ( - + workflows.length === 0 ? + + : ( { value={workflow.org_id} disabled={savingState !== 0 || suborgWorkflows?.length === 0 || allTriggers === undefined} onChange={(e) => { + if (cy !== undefined && cy !== null) { + cy.nodes().unselect() + } + if (lastSaved === false && originalWorkflow.id === workflow.id) { setSuborgWorkflows([]) diff --git a/frontend/src/views/LoginPage.jsx b/frontend/src/views/LoginPage.jsx index 385a2d8e..97c8b5cf 100755 --- a/frontend/src/views/LoginPage.jsx +++ b/frontend/src/views/LoginPage.jsx @@ -427,14 +427,14 @@ const LoginPage = props => { window.location.pathname = "/workflows" } - const checkAdmin = () => { - const url = globalUrl + "/api/v1/checkusers"; - fetch(url, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }) + const checkAdmin = () => { + const url = globalUrl + "/api/v1/checkusers"; + fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) .then((response) => response.json().then((responseJson) => { if (responseJson["success"] === false) { @@ -459,7 +459,7 @@ const LoginPage = props => { navigate("/adminsetup") }, 2500) }) - }; + } const onSubmit = (e) => { @@ -952,7 +952,7 @@ const LoginPage = props => {
return ( -
+
{loadedCheck}
) diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index 1eee8317..100eed13 100755 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -1946,7 +1946,10 @@ const Workflows = (props) => { .then((response) => { if (response.status !== 200) { console.log("Status not 200 for setting workflows :O!"); - toast("Failed deleting workflow. Do you have access?"); + + if (bulk !== true) { + toast(`Failed deleting workflow ${id}. Do you have access?`); + } } else { if (bulk !== true) { toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`) diff --git a/frontend/src/views/Workflows2.jsx b/frontend/src/views/Workflows2.jsx index 0b079407..f1e18120 100644 --- a/frontend/src/views/Workflows2.jsx +++ b/frontend/src/views/Workflows2.jsx @@ -2043,7 +2043,10 @@ const Workflows2 = (props) => { .then((response) => { if (response.status !== 200) { console.log("Status not 200 for setting workflows :O!"); - toast("Failed deleting workflow. Do you have access?"); + + if (bulk !== true) { + toast("Failed deleting workflow. Do you have access?"); + } } else { if (bulk !== true) { toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`) @@ -2821,7 +2824,7 @@ const Workflows2 = (props) => { {(data.sharing !== undefined && data.sharing !== null && data.sharing === "form") || (data?.form_control?.input_markdown !== undefined && data?.form_control?.input_markdown !== null && data?.form_control?.input_markdown !== "") && type !== "public" ? -
+
{ : null} {(data?.validation?.validation_ran === true && data?.validation?.valid === false && data?.validation?.errors?.length > 0 ) ? - -
+ +
{
- : null} +
@@ -3235,6 +3238,7 @@ const Workflows2 = (props) => {
} +