Synced 2.0 fixes for RC6

This commit is contained in:
Frikky
2025-02-13 03:46:14 +01:00
parent a8c13fe185
commit b367b4cfb7
10 changed files with 1107 additions and 402 deletions
+11 -30
View File
@@ -71,8 +71,7 @@ const EditWorkflow = (props) => {
const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove
const [submitLoading, setSubmitLoading] = React.useState(false); const [submitLoading, setSubmitLoading] = React.useState(false);
//const [showMoreClicked, setShowMoreClicked] = React.useState(expanded === true ? true : false); const [showMoreClicked, setShowMoreClicked] = React.useState(isEditing !== false ? true : false);
const [showMoreClicked, setShowMoreClicked] = React.useState(true);
const [innerWorkflow, setInnerWorkflow] = React.useState(workflow) const [innerWorkflow, setInnerWorkflow] = React.useState(workflow)
@@ -569,12 +568,13 @@ const EditWorkflow = (props) => {
<Divider id="mssp_control" style={{ marginTop: 20, marginBottom: 20, }} /> <Divider id="mssp_control" style={{ marginTop: 20, marginBottom: 20, }} />
<Typography variant="h4" style={{ marginTop: 50, }}> <Typography variant="h4" style={{ marginTop: 50, }}>
MSSP controls MSSP & Distribution controls
</Typography> </Typography>
<Typography variant="body1" style={{ marginTop: 50, }}> <Typography variant="body2" color="textSecondary" style={{ marginTop: 30, marginBottom: 10, }}>
MSSP Suborg Distribution (<b>beta</b> - contact support@shuffler.io for more info) 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. (<b>late beta</b> - contact support@shuffler.io if you want a demo. Please try it!)
</Typography> </Typography>
{userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 0 ? {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.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 === "" ? userdata.active_org.creator_org === undefined || userdata.active_org.creator_org === null || userdata.active_org.creator_org === "" ?
@@ -677,15 +677,12 @@ const EditWorkflow = (props) => {
</Link> </Link>
} }
{/*<Divider style={{marginTop: 20, marginBottom: 20, }} />*/}
<Typography variant="body1" style={{ marginTop: 75, }}>
<Typography variant="body1" style={{ marginTop: 100, }}>
Git Backup Repository Git Backup Repository
</Typography> </Typography>
<Typography variant="body2" style={{ textAlign: "left", marginTop: 5, }} color="textSecondary"> <Typography variant="body2" style={{ textAlign: "left", marginTop: 5, }} color="textSecondary">
Decide where this workflow is backed up in a Git repository. Will create logs and notifications if upload fails. <b>The repository and branch must already have been initialized</b>. Files will show up in the root folder in the format 'orgid/workflow status/workflow id.json' without images. Overrides your <a href="/admin?admin_tab=org_config" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">default backup repository</a>. <a href="/docs/configuration#environment-variables" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">Credentials are encrypted.</a> Creates <a href="/admin?admin_tab=notifications" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">notifications</a> if it fails. Decide where this workflow is backed up in a Git repository. Will create logs and notifications if upload fails. <b>The repository and branch must already have been initialized</b>. Files will show up in the root folder in the format 'orgid/workflow status/workflow id.json' and be formatted, with removed images, to make diffing easy. Overrides your <a href="/admin?admin_tab=org_config" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">default backup repository</a>. <a href="/docs/configuration#environment-variables" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">Credentials are encrypted.</a> Creates <a href="/admin?admin_tab=notifications" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">notifications</a> if it fails.
</Typography> </Typography>
<Grid container style={{ marginTop: 10, }} spacing={2}> <Grid container style={{ marginTop: 10, }} spacing={2}>
<Grid item xs={6} style={{}}> <Grid item xs={6} style={{}}>
@@ -1078,31 +1075,13 @@ const EditWorkflow = (props) => {
</Select> </Select>
</FormControl> </FormControl>
</div> </div>
</div>
: null}
{/*!isEditing ? <>
<div style={{ marginTop: 20, }}>
<FormControlLabel
control={<Checkbox />}
label="Create workflow as code"
style={{ marginTop: '12px' }}
onChange={(e) => {
setWorkflowAsCode(e.target.checked)
workflow.workflow_as_code = e.target.checked
setWorkflow(workflow)
setInnerWorkflow(workflow)
}}
/>
</div>
</> : null*/}
<Typography variant="h4" style={{ marginTop: 100, }}> <Typography variant="h4" style={{ marginTop: 100, }}>
Publishing Publishing
</Typography> </Typography>
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10, }}> <Typography variant="body2" color="textSecondary" style={{ marginTop: 10, }}>
Publishing is related to making the workflow itself public. When publishing a workflow, all the details (except sensitive info) become available to everyone. The details below will help a user understand this better. When a workflow is published, you keep the original, and a copy enters the workflow search, and is associated with your <a href="/creators" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">creator account</a>, if you have one. You can always unpublish the workflow after. To publish it, click the three dots next to the workflow. Publishing is related to making the workflow itself public. When publishing a workflow, all the details (except sensitive info) become available to everyone. The details below will help a user understand this better. When a workflow is published, you keep the original, and a copy enters the workflow search, and is associated with your <a href="/creators" style={{ textDecoration: "none", color: "#f86a3e" }} target="_blank">creator account</a>, if you have one. You can always unpublish the workflow after. When ready to publish, click the three dots next to a workflow on the main workflow screen. After publishing, you can find it in the Shuffle search engine.
</Typography> </Typography>
<LocalizationProvider style={{marginLeft: 0, }} dateAdapter={AdapterDayjs}> <LocalizationProvider style={{marginLeft: 0, }} dateAdapter={AdapterDayjs}>
@@ -1194,6 +1173,8 @@ const EditWorkflow = (props) => {
</Button> </Button>
</Tooltip> </Tooltip>
</div>
: null}
</div> </div>
+1 -1
View File
@@ -524,7 +524,7 @@ useEffect(() => {
<Divider style={{ marginBottom: 10, }} /> <Divider style={{ marginBottom: 10, }} />
<Typography color="textSecondary" align="center" style={{ marginTop: 5, marginBottom: 5, fontSize: 18 }}> <Typography color="textSecondary" align="center" style={{ marginTop: 5, marginBottom: 5, fontSize: 18 }}>
Version: 2.0.0-rc5 Version: 2.0.0-rc6
</Typography> </Typography>
</Menu> </Menu>
</span> </span>
+32 -10
View File
@@ -222,6 +222,10 @@ const ParsedAction = (props) => {
return return
} }
if (selectedApp !== undefined && selectedApp !== null && selectedApp.generated !== true) {
return
}
// Fixing required fields with a shitty structure :) // Fixing required fields with a shitty structure :)
if (selectedApp !== undefined && selectedApp !== null && selectedApp.generated === true && selectedAction !== undefined && selectedAction !== null && selectedAction.name !== undefined && selectedAction.name !== null && selectedApp.actions !== undefined && selectedApp.actions !== null && selectedApp.actions.length > 0 && (selectedAction.required_body_fields === undefined || selectedAction.required_body_fields === null || selectedAction.required_body_fields.length === 0)) { if (selectedApp !== undefined && selectedApp !== null && selectedApp.generated === true && selectedAction !== undefined && selectedAction !== null && selectedAction.name !== undefined && selectedAction.name !== null && selectedApp.actions !== undefined && selectedApp.actions !== null && selectedApp.actions.length > 0 && (selectedAction.required_body_fields === undefined || selectedAction.required_body_fields === null || selectedAction.required_body_fields.length === 0)) {
// Check for required fields // Check for required fields
@@ -654,8 +658,8 @@ const ParsedAction = (props) => {
const valid = validateJson(execArg); const valid = validateJson(execArg);
if (valid.valid) { if (valid.valid) {
newActionList.push({ newActionList.push({
type: "Execution Argument", type: "Runtime Argument",
name: "Execution Argument", name: "Runtime Argument",
value: "$exec", value: "$exec",
highlight: "exec", highlight: "exec",
autocomplete: "exec", autocomplete: "exec",
@@ -668,11 +672,11 @@ const ParsedAction = (props) => {
} }
} }
// Add default Execution Argument if none were added // Add default Runtime Argument if none were added
if (newActionList.length === 0) { if (newActionList.length === 0) {
newActionList.push({ newActionList.push({
type: "Execution Argument", type: "Runtime Argument",
name: "Execution Argument", name: "Runtime Argument",
value: "$exec", value: "$exec",
highlight: "exec", highlight: "exec",
autocomplete: "exec", autocomplete: "exec",
@@ -749,7 +753,7 @@ const ParsedAction = (props) => {
if (parents.length > 1) { if (parents.length > 1) {
const labels = []; const labels = [];
for (let parentNode of parents) { for (let parentNode of parents) {
if (parentNode.label !== "Execution Argument" && !labels.includes(parentNode.label)) { if (parentNode.label !== "Runtime Argument" && !labels.includes(parentNode.label)) {
labels.push(parentNode.label); labels.push(parentNode.label);
let exampleData = parentNode.example ?? ""; let exampleData = parentNode.example ?? "";
if (!exampleData && workflowExecutions.length > 0) { if (!exampleData && workflowExecutions.length > 0) {
@@ -1625,7 +1629,8 @@ const ParsedAction = (props) => {
//window.open("/apps/${selectedAction.app_id}", "_blank") //window.open("/apps/${selectedAction.app_id}", "_blank")
}} }}
> >
<Tooltip title={"App: " + selectedAction.app_name} placement="top"> <Tooltip title={"App: " + selectedAction.app_name + ". Click to open in new tab"} placement="top">
<a href={"/apps/" + selectedAction?.app_id} target="_blank" style={{ textDecoration: "none", color: "white", }}>
<img src={selectedAppIcon} style={{ <img src={selectedAppIcon} style={{
width: 30, width: 30,
height: 30, height: 30,
@@ -1634,6 +1639,7 @@ const ParsedAction = (props) => {
marginTop: 13, marginTop: 13,
border: "2px solid rgba(255,255,255,0.3)", border: "2px solid rgba(255,255,255,0.3)",
}} /> }} />
</a>
</Tooltip> </Tooltip>
<h3 style={{}}> <h3 style={{}}>
@@ -1754,7 +1760,7 @@ const ParsedAction = (props) => {
</Tooltip> </Tooltip>
</IconButton> </IconButton>
{selectedAction?.generated === true && selectedAction?.app_version === "1.0.0" ? {(selectedAction?.generated === true && selectedAction?.app_version === "1.0.0") || (selectedAction?.app_name === "Shuffle Tools" && selectedAction?.app_version !== "1.2.0") ?
<Button <Button
variant="contained" variant="contained"
color="secondary" color="secondary"
@@ -1857,6 +1863,7 @@ const ParsedAction = (props) => {
}} }}
fullWidth fullWidth
color="primary" color="primary"
disabled={selectedAction?.parent_controlled === true && workflow?.parentorg_workflow?.length > 0}
placeholder={selectedAction.label} placeholder={selectedAction.label}
value={appActionName} value={appActionName}
onChange={(event) => { onChange={(event) => {
@@ -2077,6 +2084,7 @@ const ParsedAction = (props) => {
style: theme.palette.innerTextfieldStyle, style: theme.palette.innerTextfieldStyle,
disableUnderline: true, disableUnderline: true,
}} }}
disabled={selectedAction?.parent_controlled === true && workflow?.parentorg_workflow?.length > 0}
placeholder={selectedAction.execution_delay} placeholder={selectedAction.execution_delay}
value={delay} value={delay}
onChange={(event) => { onChange={(event) => {
@@ -2779,6 +2787,20 @@ const ParsedAction = (props) => {
/> />
) : null} ) : null}
{selectedAction?.app_name === "Shuffle AI" && selectedAction?.name === "run_llm" ?
selectedAction?.environment === "Cloud" && isCloud ? (
<Typography color="textSecondary" variant="body2" style={{ paddingTop: 25, }}>
Info: Cloud Inference processing runs with Shuffle's GPUs in EU, Netherlands, and may be unstable. Your data is NOT stored there.
</Typography>
)
:
<Typography color="textSecondary" variant="body2" style={{ paddingTop: 25, color: red, }}>
This action is slow without GPU's. Use Shuffle's Cloud Runtime location for faster processing.
</Typography>
:
null
}
<div <div
style={{ style={{
marginTop: "10px", marginTop: "10px",
@@ -4251,7 +4273,7 @@ const ParsedAction = (props) => {
}; };
const handleMouseover = () => { const handleMouseover = () => {
if (innerdata.type === "Execution Argument") { if (innerdata.type === "Runtime Argument") {
handleExecArgumentHover(true); handleExecArgumentHover(true);
} else if (innerdata.type === "action") { } else if (innerdata.type === "action") {
handleActionHover(true, innerdata.id); handleActionHover(true, innerdata.id);
@@ -4259,7 +4281,7 @@ const ParsedAction = (props) => {
}; };
const handleMouseOut = () => { const handleMouseOut = () => {
if (innerdata.type === "Execution Argument") { if (innerdata.type === "Runtime Argument") {
handleExecArgumentHover(false); handleExecArgumentHover(false);
} else if (innerdata.type === "action") { } else if (innerdata.type === "action") {
handleActionHover(false, innerdata.id); handleActionHover(false, innerdata.id);
+61
View File
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useContext, memo } from "react";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import theme from "../theme.jsx"; import theme from "../theme.jsx";
import { v4 as uuidv4, v5 as uuidv5, validate as isUUID, } from "uuid";
import { import {
Paper, Paper,
Tooltip, Tooltip,
@@ -16,7 +17,13 @@ import {
Autocomplete, Autocomplete,
TextField, TextField,
MenuItem, MenuItem,
IconButton,
} from "@mui/material"; } from "@mui/material";
import {
OpenInNew as OpenInNewIcon,
} from "@mui/icons-material";
import { makeStyles } from "@mui/styles"; import { makeStyles } from "@mui/styles";
import { Context } from "../context/ContextApi.jsx"; import { Context } from "../context/ContextApi.jsx";
@@ -355,6 +362,7 @@ const Priorities = memo((props) => {
<Typography style={{ color: "rgba(158, 158, 158, 1)", fontSize: 16, fontWeight: 400, marginTop: 5, }}> <Typography style={{ color: "rgba(158, 158, 158, 1)", fontSize: 16, fontWeight: 400, marginTop: 5, }}>
The notification workflow triggers when an error occurs in one of your workflows. Each individual one will only start a workflow once every 2 minutes. <b>You can point child org notifications into the parent org notification by choosing it in the list.</b> The notification workflow triggers when an error occurs in one of your workflows. Each individual one will only start a workflow once every 2 minutes. <b>You can point child org notifications into the parent org notification by choosing it in the list.</b>
</Typography> </Typography>
<div style={{ display: "flex", flexDirection: "row", alignItems: "center", }}> <div style={{ display: "flex", flexDirection: "row", alignItems: "center", }}>
{workflows !== undefined && workflows !== null && workflows.length > 0 ? {workflows !== undefined && workflows !== null && workflows.length > 0 ?
@@ -538,6 +546,59 @@ const Priorities = memo((props) => {
</div> */} </div> */}
</div> </div>
{notificationWorkflow === undefined || notificationWorkflow === null || notificationWorkflow.length === 0 ? null :
<div>
<Button variant="outlined" color="secondary" style={{marginTop: 5, textTransform: "none", }} onClick={() => {
if (notificationWorkflow === "parent") {
toast.error("Can't send test notifications to the parent org's notification workflow.")
return
}
fetch(`${globalUrl}/api/v1/workflows/${notificationWorkflow}/execute`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
credentials: "include",
body: JSON.stringify({
"title": "Test Notification",
"description": "This is a test notification to check if the notification workflow is working correctly.",
"org_id": selectedOrganization.id,
"id": uuidv4(),
"reference_url": "/admin?type=test&admin_tab=notifications",
"created_at": Math.floor(new Date().getTime() / 1000),
"updated_at": Math.floor(new Date().getTime() / 1000),
})
})
.then((response) => {
if (response.status === 200) {
toast.success("Test notification sent successfully.")
} else {
toast.error("Failed to send test notification. Please contact support if this persists")
}
}).catch((error) => {
toast.error("Failed to send test notification (2). Please contact support if this persists")
})
}}>
Send test notification
</Button>
<IconButton
style={{marginLeft: 10, }}
onClick={() => {
if (notificationWorkflow === "parent") {
toast.error("Can't open parent org's notification workflow from here.")
return
}
window.open(`/workflows/${notificationWorkflow}?view=executions`, "_blank")
}}
>
<OpenInNewIcon color="primary" />
</IconButton>
</div>
}
<Typography style={{marginTop: 50, fontSize: 24, fontWeight: 'bold', display: clickedFromOrgTab?null:"inline", marginBottom: clickedFromOrgTab? 8:null, color: clickedFromOrgTab?"#ffffff":null }}>Notifications ({ <Typography style={{marginTop: 50, fontSize: 24, fontWeight: 'bold', display: clickedFromOrgTab?null:"inline", marginBottom: clickedFromOrgTab? 8:null, color: clickedFromOrgTab?"#ffffff":null }}>Notifications ({
notifications?.filter((notification) => showRead === true || notification.read === false).length notifications?.filter((notification) => showRead === true || notification.read === false).length
})</Typography> })</Typography>
+114 -27
View File
@@ -44,6 +44,7 @@ import {
Close as CloseIcon, Close as CloseIcon,
DragIndicator as DragIndicatorIcon, DragIndicator as DragIndicatorIcon,
RestartAlt as RestartAltIcon, RestartAlt as RestartAltIcon,
ArrowForward as ArrowForwardIcon,
} from '@mui/icons-material'; } from '@mui/icons-material';
@@ -100,6 +101,7 @@ const pythonFilters = [
const extensions = [] const extensions = []
const CodeEditor = (props) => { const CodeEditor = (props) => {
const { const {
cy,
workflow, workflow,
globalUrl, globalUrl,
fieldCount, fieldCount,
@@ -116,6 +118,7 @@ const CodeEditor = (props) => {
parameterName, parameterName,
// selectedAction, // selectedAction,
// selectedTrigger, // selectedTrigger,
selectedEdge,
workflowExecutions, workflowExecutions,
getParents, getParents,
activeDialog, activeDialog,
@@ -128,6 +131,8 @@ const CodeEditor = (props) => {
fullScreenMode, fullScreenMode,
environment, environment,
fixExample, fixExample,
userdata,
handleConditionFieldChange,
} = props } = props
const [localcodedata, setlocalcodedata] = React.useState(codedata === undefined || codedata === null || codedata.length === 0 ? "" : codedata); const [localcodedata, setlocalcodedata] = React.useState(codedata === undefined || codedata === null || codedata.length === 0 ? "" : codedata);
@@ -149,6 +154,7 @@ const CodeEditor = (props) => {
const [currentLine, setCurrentLine] = React.useState(-1); const [currentLine, setCurrentLine] = React.useState(-1);
const [selectedAction, setSelectedAction] = React.useState({}); const [selectedAction, setSelectedAction] = React.useState({});
const [selectedTrigger, setSelectedTrigger] = React.useState({}); const [selectedTrigger, setSelectedTrigger] = React.useState({});
const [selectedCondition, setSelectedCondition] = React.useState({});
const [variableOccurences, setVariableOccurences] = React.useState([]); const [variableOccurences, setVariableOccurences] = React.useState([]);
const [currentLocation, setCurrentLocation] = React.useState([]); const [currentLocation, setCurrentLocation] = React.useState([]);
const [currentVariable, setCurrentVariable] = React.useState(""); const [currentVariable, setCurrentVariable] = React.useState("");
@@ -197,6 +203,8 @@ const CodeEditor = (props) => {
const triggerId = searchParams.get('trigger_id'); const triggerId = searchParams.get('trigger_id');
const triggerField = searchParams.get('trigger_field'); const triggerField = searchParams.get('trigger_field');
const triggerName = searchParams.get('trigger_name'); const triggerName = searchParams.get('trigger_name');
const conditionId = searchParams.get('condition_id');
const conditionField = searchParams.get('field');
useEffect(() => { useEffect(() => {
if (actionId === undefined || actionId === null) { if (actionId === undefined || actionId === null) {
@@ -206,6 +214,9 @@ const CodeEditor = (props) => {
const action = workflow?.actions?.find(action => action.id === actionId); const action = workflow?.actions?.find(action => action.id === actionId);
setlocalcodedata(editorData?.value); setlocalcodedata(editorData?.value);
setSelectedAction(action); setSelectedAction(action);
// Update available variables when action changes
updateAvailableVariables(actionlist);
}, [actionId, fieldName]) }, [actionId, fieldName])
useEffect(() => { useEffect(() => {
@@ -216,16 +227,33 @@ const CodeEditor = (props) => {
const trigger = workflow?.triggers?.find(trigger => trigger.id === triggerId); const trigger = workflow?.triggers?.find(trigger => trigger.id === triggerId);
setlocalcodedata(editorData?.value); setlocalcodedata(editorData?.value);
setSelectedTrigger(trigger); setSelectedTrigger(trigger);
// Update available variables when trigger changes
updateAvailableVariables(actionlist);
}, [triggerId]) }, [triggerId])
useEffect(() => {
var allVariables = []
var tmpVariables = []
useEffect(() => {
if (conditionId === undefined || conditionId === null) {
return;
}
const condition = selectedEdge?.conditions?.find(condition => condition.id === conditionId);
setlocalcodedata(editorData?.value);
setSelectedCondition(condition);
// Update available variables when condition changes
updateAvailableVariables(actionlist);
}, [conditionId, fieldName])
// Extract variable updating logic into a separate function
const updateAvailableVariables = (actionlist) => {
if (actionlist === undefined || actionlist === null) { if (actionlist === undefined || actionlist === null) {
return return
} }
var allVariables = []
var tmpVariables = []
for (var i = 0; i < actionlist.length; i++) { for (var i = 0; i < actionlist.length; i++) {
allVariables.push('$' + actionlist[i].autocomplete.toLowerCase()) allVariables.push('$' + actionlist[i].autocomplete.toLowerCase())
tmpVariables.push('$' + actionlist[i].autocomplete.toLowerCase()) tmpVariables.push('$' + actionlist[i].autocomplete.toLowerCase())
@@ -265,7 +293,11 @@ const CodeEditor = (props) => {
setAvailableVariables(allVariables) setAvailableVariables(allVariables)
setMainVariables(tmpVariables) setMainVariables(tmpVariables)
expectedOutput(localcodedata) }
// Remove the original useEffect for actionlist since we'll update on action/trigger changes
useEffect(() => {
updateAvailableVariables(actionlist)
}, []) }, [])
useEffect(() => { useEffect(() => {
@@ -1378,6 +1410,18 @@ const CodeEditor = (props) => {
) )
} }
var sourceAction = ""
var targetAction = ""
var sourceImage = ""
var targetImage = ""
if (cy !== undefined && cy !== null) {
sourceAction = cy.getElementById(selectedEdge?.source)
targetAction = cy.getElementById(selectedEdge?.target)
sourceImage = sourceAction?.data()?.large_image
targetImage = targetAction?.data()?.large_image
}
return ( return (
<Dialog <Dialog
aria-labelledby="draggable-dialog-title" aria-labelledby="draggable-dialog-title"
@@ -1601,7 +1645,7 @@ const CodeEditor = (props) => {
{isFileEditor ? null : {isFileEditor ? null :
<div style={{ display: "flex", maxHeight: 40, }}> <div style={{ display: "flex", maxHeight: 40, }}>
<ButtonGroup style={{ borderRadius: theme.palette.borderRadius, }}> <ButtonGroup style={{ borderRadius: theme.palette.borderRadius, }}>
{/* {userdata !== undefined && userdata !== null && userdata.support === true ?
<Button <Button
id="basic-button" id="basic-button"
aria-haspopup="true" aria-haspopup="true"
@@ -1619,7 +1663,7 @@ const CodeEditor = (props) => {
> >
<AddIcon /> Show Source Data <AddIcon /> Show Source Data
</Button> </Button>
*/} : null}
<Button <Button
id="basic-button" id="basic-button"
@@ -2149,9 +2193,64 @@ const CodeEditor = (props) => {
}} }}
> >
<div> <div>
{actionId === null && triggerId === null ?
<div style={{display: "flex", alignItems: "center"}}>
{`Condition ${selectedEdge?.conditions?.findIndex(cond => cond.condition.id === conditionId) + 1 || "0"}`}
{/* Source node image */}
{selectedEdge?.source ?
<img
src={sourceImage || ""}
alt="Source"
style={{
width: 30,
height: 30,
marginRight: 10,
borderRadius: "50%",
marginLeft: 10,
border: conditionField === "source" ? `3px solid #FF8544` : null,
}}
/>
: null
}
{/* Add arrow icon */}
{
selectedEdge && Object.keys(selectedEdge).length > 0 ?
<ArrowForwardIcon style={{
color: "rgba(255,255,255,0.7)",
fontSize: 18,
marginLeft: -5,
marginRight: -5,
}} />
: null
}
{/* Destination node image */}
{selectedEdge?.target ?
<img
src={targetImage || ""}
alt="Destination"
style={{
width: 30,
height: 30,
marginLeft: 10,
borderRadius: "50%",
border: conditionField === "destination" ? `3px solid #FF8544` : null,
}}
/>
: null
}
</div>
:
<span style={{ color: "white" }}> <span style={{ color: "white" }}>
{actionId === null ? `Output : ${triggerName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + triggerName?.replaceAll("_", " ").slice(1)}` : selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ? "Code to run" : `Output : ${appName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + appName?.replaceAll("_", " ").slice(1)}(${fieldName})`} {selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ?
"Code to run" :
triggerId ?
`Output : ${triggerName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + triggerName?.replaceAll("_", " ").slice(1)}(${triggerField})` :
`Output : ${appName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + appName?.replaceAll("_", " ").slice(1)}(${fieldName})`
}
</span> </span>
}
</div> </div>
</DialogTitle> </DialogTitle>
@@ -2369,34 +2468,22 @@ const CodeEditor = (props) => {
if (isFileEditor === true) { if (isFileEditor === true) {
runUpdateText(fixedcodedata); runUpdateText(fixedcodedata);
setcodedata(fixedcodedata); setcodedata(fixedcodedata);
setExpansionModalOpen(false)
} else if (changeActionParameterCodeMirror !== undefined) { } else if (changeActionParameterCodeMirror !== undefined) {
//changeActionParameterCodeMirror(event, fieldCount, fixedcodedata) //changeActionParameterCodeMirror(event, fieldCount, fixedcodedata)
changeActionParameterCodeMirror(event, fieldCount, fixedcodedata, actionlist, parameterName, selectedAction, setSelectedAction) changeActionParameterCodeMirror(event, fieldCount, fixedcodedata, actionlist, parameterName, selectedAction, setSelectedAction)
setExpansionModalOpen(false)
setcodedata(fixedcodedata) setcodedata(fixedcodedata)
} }
// console.log("fieldname", fieldname) // Handle condition fields
// // Check if fieldname is set, and try to find and inject the text if (conditionField !== null && handleConditionFieldChange !== undefined) {
// if (fieldname !== undefined && fieldname !== null && fieldname.length > 0) { handleConditionFieldChange(conditionField, fieldName, fixedcodedata);
// const foundfield = document.getElementById(fieldname) }
// console.log("foundfield", foundfield) // Handle action fields
// if (foundfield !== undefined && foundfield !== null) { else if (actionId !== undefined && actionId !== null && actionId.length > 0) {
// foundfield.value = fixedcodedata
// if(selectedTrigger !== undefined && selectedTrigger !== null && selectedTrigger.name === "Shuffle Workflow") {
// handleSubflowParamChange(fixedcodedata)
// }
// }
// } else {
// //toast("No fieldname found: " + fieldname)
// }
if(actionId !== undefined && actionId !== null && actionId.length > 0) {
handleActionParamChange(actionId, fieldName, fixedcodedata) handleActionParamChange(actionId, fieldName, fixedcodedata)
} }
// Handle trigger fields
if(triggerId !== undefined && triggerId !== null && triggerId.length > 0) { else if (triggerId !== undefined && triggerId !== null && triggerId.length > 0) {
handleSubflowParamChange(triggerId, triggerField, fixedcodedata) handleSubflowParamChange(triggerId, triggerField, fixedcodedata)
} }
+1 -1
View File
@@ -14,7 +14,7 @@ const theme = createTheme(adaptV4Theme({
contrastText: "#000000", contrastText: "#000000",
}, },
text: { text: {
secondary: "rgba(255,255,255,0.7)", secondary: "rgba(255,255,255,0.8)",
}, },
type: "dark", type: "dark",
//inputColor: "#383B40", //inputColor: "#383B40",
File diff suppressed because it is too large Load Diff
-1
View File
@@ -59,7 +59,6 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
(userdata?.admin === "true" && userdata?.active_org?.id === data?.reference_org) || (userdata?.admin === "true" && userdata?.active_org?.id === data?.reference_org) ||
data?.contributors?.includes(userdata?.id) data?.contributors?.includes(userdata?.id)
console.log("appdata", data)
const paperStyle = { const paperStyle = {
backgroundColor: mouseHoverIndex === index ? "rgba(26, 26, 26, 1)" : "#212121", backgroundColor: mouseHoverIndex === index ? "rgba(26, 26, 26, 1)" : "#212121",
color: "rgba(241, 241, 241, 1)", color: "rgba(241, 241, 241, 1)",
+8 -8
View File
@@ -184,15 +184,15 @@ export const CodeHandler = (props) => {
if (validate.valid === false) { if (validate.valid === false) {
// Check if https://shuffler.io in the url // Check if https://shuffler.io in the url
// if so, then we change it for the current url // if so, then we change it for the current url
if (propvalue.includes("https://shuffler.io")) { if (propvalue.includes("https://shuffler.io/api")) {
newprop = propvalue.replace("https://shuffler.io", window.location.origin) newprop = propvalue.replace("https://shuffler.io/api", window.location.origin+"/api")
}
// Check if it contains Bearer APIKEY
// If so, replace apikey const foundurl = localStorage.getItem("globalUrl")
//if (newprop.includes("Bearer APIKEY")) { if (foundurl !== undefined && foundurl !== null && foundurl !== "") {
// newprop = newprop.replace("Bearer APIKEY", "Bearer API newprop = propvalue.replace("https://shuffler.io/api", foundurl+"/api")
//} }
}
} }
// Need to check if it's singletick or multi // Need to check if it's singletick or multi
+1
View File
@@ -2875,6 +2875,7 @@ const Workflows2 = (props) => {
if (editingWorkflow.id !== undefined) { if (editingWorkflow.id !== undefined) {
console.log("Building original workflow"); console.log("Building original workflow");
method = "PUT"; method = "PUT";
//extraData = "/" + editingWorkflow.id + "?skip_save=true";
extraData = "/" + editingWorkflow.id + "?skip_save=true"; extraData = "/" + editingWorkflow.id + "?skip_save=true";
workflowdata = editingWorkflow; workflowdata = editingWorkflow;