diff --git a/frontend/src/components/AppModal.jsx b/frontend/src/components/AppModal.jsx index 662ea467..5f33898c 100644 --- a/frontend/src/components/AppModal.jsx +++ b/frontend/src/components/AppModal.jsx @@ -249,6 +249,11 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => { } const getUsecase = (subcase, index, subindex) => { + //console.log("Skipping getUsecase") + // FIXME: Skipping for now as this screws over a lot of the prioritization system + // due to them having "looked at" the usecase. + return + subcase = parseUsecase(subcase) setPrevSubcase(subcase) @@ -490,8 +495,10 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => { } - var canEditApp = userdata !== undefined && (userdata?.admin === "true" || userdata?.id === app?.owner || app?.owner === "" || (userdata?.admin === "true" && userdata?.active_org?.id === app?.reference_org)) || !app?.generated - + var canEditApp = userdata?.support || + userdata?.id === app?.owner || + (userdata?.admin === "true" && userdata?.active_org?.id === app?.reference_org) || + app?.contributors?.includes(userdata?.id) return ( { fontFamily: theme?.typography?.fontFamily }} > + {/* About {app?.name.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase())} + */} @@ -570,9 +584,11 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => { flexDirection: "row", alignItems: "center", }}> - - {newAppname} - + + + {newAppname} + + { ): null} + {(canEditApp && app?.generated) && ( + {canEditApp ? "Edit" : "Fork"} + + )} @@ -812,13 +827,13 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => { marginBottom: "16px", fontWeight: 600 }}> - { + {/* (foundAppUsecase?.srcapp !== undefined && foundAppUsecase?.dstapp !== undefined) ? ( "Connect " + foundAppUsecase?.srcapp?.replaceAll("_", " ") + " to " + foundAppUsecase?.dstapp?.replaceAll("_", " ") ) : ( "Connect " + app?.name.replaceAll("_", " ") + " to any tool" ) - } + */} )} @@ -830,7 +845,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => { alignItems: 'center', mb: 3 }}> - {usecaseLoading ? ( + {/*usecaseLoading ? ( @@ -879,7 +894,7 @@ const AppModal = ({ open, onClose, app, globalUrl, getApps }) => { {foundAppUsecase?.name || "Search for a Usecase"} - )} + )*/} diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 688e265e..a93583f0 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -1467,15 +1467,23 @@ const ParsedAction = (props) => { actionname = "comms" } - if (isIntegration) { - + if (isAgent || isIntegration) { // Check if actionname uppercase is in the parsedDatatypeImages() dictionary - if (parsedDatatypeImages()[actionname.toUpperCase()] !== undefined) { - var newimage = parsedDatatypeImages()[actionname.toUpperCase()] - //newimage = - wrapperapp.large_image = newimage + if (isAgent) { + wrapperapp.large_image = theme.palette.singulBlackWhite + newimage = wrapperapp.large_image + } else if (isIntegration) { + wrapperapp.large_image = theme.palette.singulGreen + newimage = theme.palette.singulGreen } else { - console.log("Couldn't find actionname: ", actionname) + const uppercaseimage = parsedDatatypeImages()[actionname.toUpperCase()] + if (uppercaseimage !== undefined) { + var newimage = uppercaseimage + //newimage = + wrapperapp.large_image = newimage + } else { + console.log("Couldn't find actionname: ", actionname) + } } } @@ -1745,6 +1753,37 @@ const ParsedAction = (props) => { } + + {selectedAction?.generated === true && selectedAction?.app_version === "1.0.0" ? + + : null} +
@@ -2764,6 +2803,7 @@ const ParsedAction = (props) => { } } + /* const iconInfo = GetIconInfo(selectedAction) if (iconInfo !== undefined && iconInfo !== null) { selectedAction.fillGradient = iconInfo.fillGradient @@ -2771,6 +2811,7 @@ const ParsedAction = (props) => { selectedAction.iconBackground = iconInfo.iconBackgroundColor selectedAction.fillstyle = "linear-gradient" } + */ if (paramIndex === -1) { console.log("Couldn't find app_name parameter") @@ -2797,13 +2838,14 @@ const ParsedAction = (props) => { minHeight: 30, maxHeight: 30, - marginRight: 5, + marginRight: 25, + marginTop: isIntegration ? 3 : 0, borderRadius: 5, cursor: "pointer", border: noAppSelected ? "3px solid #86c142" : "2px solid rgba(255,255,255,0.6)", - paddingLeft: 5, - paddingTop: 5, + paddingLeft: isAgent || isIntegration ? 0 : 5, + paddingTop: isAgent || isIntegration ? 0 : 5, }} />
@@ -4579,7 +4621,7 @@ const ParsedAction = (props) => { } //console.log("Required fields: ", selectedActionParameters[count]) - navigate(`?action_id=${selectedAction.id}&field=${data.name}&action_name=${selectedAction.name}`) + navigate(`?action_id=${selectedAction.id}&field=${data.name}&action_name=${selectedAction.name}&app_name=${selectedAction?.label}`) setEditorData({ "name": data.name, "value": fixExample(parsedvalue), diff --git a/frontend/src/components/ShuffleCodeEditor1.jsx b/frontend/src/components/ShuffleCodeEditor1.jsx index 8acc23a8..98b9ba80 100644 --- a/frontend/src/components/ShuffleCodeEditor1.jsx +++ b/frontend/src/components/ShuffleCodeEditor1.jsx @@ -53,7 +53,7 @@ import PaperComponent from "../components/PaperComponent.jsx"; import { padding, textAlign } from '@mui/system'; import data from '../frameworkStyle.jsx'; -import { useNavigate, Link, useParams } from "react-router-dom"; +import { useNavigate, Link, useParams, useSearchParams } from "react-router-dom"; import { tags as t } from '@lezer/highlight'; @@ -100,6 +100,7 @@ const pythonFilters = [ const extensions = [] const CodeEditor = (props) => { const { + workflow, globalUrl, fieldCount, actionlist, @@ -107,13 +108,14 @@ const CodeEditor = (props) => { expansionModalOpen, setExpansionModalOpen, codedata, + handleActionParamChange, setcodedata, isFileEditor, runUpdateText, toolsAppId, parameterName, - selectedAction, - selectedTrigger, + // selectedAction, + // selectedTrigger, workflowExecutions, getParents, activeDialog, @@ -145,7 +147,8 @@ const CodeEditor = (props) => { const [currentCharacter, setCurrentCharacter] = React.useState(-1); const [currentLine, setCurrentLine] = React.useState(-1); - + const [selectedAction, setSelectedAction] = React.useState({}); + const [selectedTrigger, setSelectedTrigger] = React.useState({}); const [variableOccurences, setVariableOccurences] = React.useState([]); const [currentLocation, setCurrentLocation] = React.useState([]); const [currentVariable, setCurrentVariable] = React.useState(""); @@ -187,6 +190,33 @@ const CodeEditor = (props) => { }, [localcodedata]) let navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const actionId = searchParams.get('action_id'); + const appName = searchParams.get('app_name'); + const fieldName = searchParams.get('field'); + const triggerId = searchParams.get('trigger_id'); + const triggerField = searchParams.get('trigger_field'); + const triggerName = searchParams.get('trigger_name'); + + useEffect(() => { + if (actionId === undefined || actionId === null) { + return; + } + + const action = workflow?.actions?.find(action => action.id === actionId); + setlocalcodedata(editorData?.value); + setSelectedAction(action); + }, [actionId, fieldName]) + + useEffect(() => { + if (triggerId === undefined || triggerId === null) { + return; + } + + const trigger = workflow?.triggers?.find(trigger => trigger.id === triggerId); + setlocalcodedata(editorData?.value); + setSelectedTrigger(trigger); + }, [triggerId]) useEffect(() => { var allVariables = [] @@ -1364,7 +1394,7 @@ const CodeEditor = (props) => { console.log("In closer") if (changeActionParameterCodeMirror !== undefined) { - changeActionParameterCodeMirror({ target: { value: "" } }, fieldCount, localcodedata) + changeActionParameterCodeMirror({ target: { value: "" } }, fieldCount, localcodedata, selectedAction, setSelectedAction) } else { console.log("No action called changeActionParameterCodeMirror in code editor") } @@ -2120,7 +2150,7 @@ const CodeEditor = (props) => { >
- {selectedAction === undefined ? "" : selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ? "Code to run" : `Output`} + {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})`}
@@ -2134,12 +2164,28 @@ const CodeEditor = (props) => { disabled={executing} color="primary" style={{ - border: `1px solid ${theme.palette.primary.main}`, + border: `1px solid rgba(255, 255, 255, 0.15)`, position: "absolute", - top: 24, + top: 20, right: 100, maxHeight: 35, minWidth: 70, + zIndex: 1200, + fontWeight: 500, + fontSize: 14, + backgroundColor: "rgba(33, 33, 33, 0.95)", + backdropFilter: "blur(8px)", + boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08)", + transition: "all 0.2s ease", + borderRadius: "4px", + "&:hover": { + backgroundColor: "rgba(45, 45, 45, 0.95)", + transform: "translateY(-1px)", + boxShadow: "0 7px 14px rgba(0, 0, 0, 0.12), 0 3px 6px rgba(0, 0, 0, 0.08)", + }, + "&:active": { + transform: "translateY(1px)", + } }} onClick={() => { executeSingleAction(expOutput) @@ -2148,7 +2194,7 @@ const CodeEditor = (props) => { {executing ? : - {selectedAction === undefined ? "" : selectedAction.name === "execute_python" ? "Run Python Code" : selectedAction.name === "execute_bash" ? "Run Bash" : "Try it"} + {selectedAction === undefined ? "Try it" : selectedAction.name === "execute_python" ? "Run Python Code" : selectedAction.name === "execute_bash" ? "Run Bash" : "Try it"} } @@ -2326,22 +2372,32 @@ const CodeEditor = (props) => { setExpansionModalOpen(false) } else if (changeActionParameterCodeMirror !== undefined) { //changeActionParameterCodeMirror(event, fieldCount, fixedcodedata) - changeActionParameterCodeMirror(event, fieldCount, fixedcodedata, actionlist, parameterName) + changeActionParameterCodeMirror(event, fieldCount, fixedcodedata, actionlist, parameterName, selectedAction, setSelectedAction) setExpansionModalOpen(false) setcodedata(fixedcodedata) } - // Check if fieldname is set, and try to find and inject the text - if (fieldname !== undefined && fieldname !== null && fieldname.length > 0) { - const foundfield = document.getElementById(fieldname) - if (foundfield !== undefined && foundfield !== null) { - foundfield.value = fixedcodedata - if(selectedTrigger !== undefined && selectedTrigger !== null && selectedTrigger.name === "Shuffle Workflow") { - handleSubflowParamChange(fixedcodedata) - } - } - } else { - //toast("No fieldname found: " + fieldname) + // console.log("fieldname", fieldname) + // // Check if fieldname is set, and try to find and inject the text + // if (fieldname !== undefined && fieldname !== null && fieldname.length > 0) { + // const foundfield = document.getElementById(fieldname) + // console.log("foundfield", foundfield) + // if (foundfield !== undefined && foundfield !== null) { + // 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) + } + + if(triggerId !== undefined && triggerId !== null && triggerId.length > 0) { + handleSubflowParamChange(triggerId, triggerField, fixedcodedata) } setExpansionModalOpen(false) diff --git a/frontend/src/defaultCytoscapeStyle.jsx b/frontend/src/defaultCytoscapeStyle.jsx index c3ca37d2..243a6916 100644 --- a/frontend/src/defaultCytoscapeStyle.jsx +++ b/frontend/src/defaultCytoscapeStyle.jsx @@ -131,10 +131,8 @@ const data = [ selector: `node[example="noapp"]`, css: { // Make background image padding on the left side 20px - "background-width": "75%", - "background-height": "75%", - "background-position-x": "17px", - "background-position-y": "17px", + "background-width": "100%", + "background-height": "100%", "background-color": "data(iconBackground)", "background-fill": "data(fillstyle)", diff --git a/frontend/src/theme.jsx b/frontend/src/theme.jsx index eab6230e..e26a8942 100644 --- a/frontend/src/theme.jsx +++ b/frontend/src/theme.jsx @@ -76,6 +76,9 @@ const theme = createTheme(adaptV4Theme({ fontSize: 11, }, defaultImage: "/images/no_image.png", + singulOrange: "/images/singul_orange.png", + singulGreen: "/images/singul_green.png", + singulBlackWhite: "/images/singul_black_white.png", }, typography: { fontFamily: `"Roboto", "Helvetica", "Arial", "inter", sans-serif`, diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 3fe95a25..35781673 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -154,8 +154,6 @@ import ExtraApps from "../components/ExtraApps.jsx" import EditWorkflow from "../components/EditWorkflow.jsx" import { act } from "react"; import { Context } from "../context/ContextApi.jsx"; -// import AppStats from "../components/AppStats.jsx"; -const noImage = "/public/no_image.png"; cytoscape.use(edgehandles); @@ -446,6 +444,7 @@ const AngularWorkflow = (defaultprops) => { const [historyIndex, setHistoryIndex] = React.useState(history.length); const [variableInfo, setVariableInfo] = React.useState({}) const [selectedVersion, setSelectedVersion] = React.useState(null) + const [selectedTriggerValue, setSelectedTriggerValue] = React.useState("") const [appAuthentication, setAppAuthentication] = React.useState(undefined); const [variablesModalOpen, setVariablesModalOpen] = React.useState(false); const [aiQueryModalOpen, setAiQueryModalOpen] = React.useState(false) @@ -572,6 +571,13 @@ const AngularWorkflow = (defaultprops) => { } }, [editWorkflowModalOpen]) + useEffect(() => { + if (selectedTrigger !== undefined && selectedTrigger.parameters !== undefined) { + // Right now just setting for the subflow + setSelectedTriggerValue(selectedTrigger?.parameters[1]?.value) + } + }, [selectedTrigger]) + const dragRef = React.useRef(false); @@ -628,11 +634,13 @@ const AngularWorkflow = (defaultprops) => { "multiselect": true, }, ] - }] + }], + large_image: theme.palette.singulBlackWhite, }, { "id": "integration", "name": "Singul", + "large_image": theme.palette.singulGreen, "type": "ACTION", "app_version": "1.0.0", "loop_versions": ["1.0.0"], @@ -9336,14 +9344,16 @@ const AngularWorkflow = (defaultprops) => { // eslint-disable-next-line react-hooks/exhaustive-deps //useEffect(() => { if (firstrequest) { - setFirstrequest(false); - getWorkflow(props.match.params.key, {}); + setFirstrequest(false) + getWorkflow(props.match.params.key, {}) getChildWorkflows(props.match.params.key) getRevisionHistory(props.match.params.key) loadTriggers() getApps() fetchUsecases() + getWorkflowExecution(props.match.params.key, "", executionFilter) + setLeftSideBarOpenByClick(false) localStorage.setItem("expandLeftNav", false) @@ -14008,23 +14018,25 @@ const AngularWorkflow = (defaultprops) => { } ] - const handleSubflowParamChange = (value) => { + const handleSubflowParamChange = (triggerId, triggerField, newData) => { - if (!workflow?.triggers || !workflow.triggers[selectedTriggerIndex]?.parameters) { - console.log("Required workflow properties are undefined") - return - } - - if (!workflow.triggers[selectedTriggerIndex].parameters[1]) { - workflow.triggers[selectedTriggerIndex].parameters[1] = { - name: "execution_argument", - value: "" + if (workflow !== undefined && workflow !== null) { + // Find the trigger with matching id + const triggerIndex = workflow?.triggers?.findIndex(trigger => trigger.id === triggerId); + if (triggerIndex >= 0) { + // Find the parameter with matching name + const paramIndex = workflow.triggers[triggerIndex].parameters?.findIndex(param => param.name === triggerField); + if (paramIndex >= 0) { + // Update the parameter value + workflow.triggers[triggerIndex].parameters[paramIndex].value = newData; + + // Update workflow state to trigger re-render + setWorkflow({...workflow}); + setSelectedTriggerValue(newData) + setLastSaved(false); + } } } - - workflow.triggers[selectedTriggerIndex].parameters[1].value = value - setWorkflow(workflow) - setLastSaved(false) } const SubflowSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined || selectedTrigger.trigger_type !== "SUBFLOW" ? null : @@ -14482,6 +14494,8 @@ const AngularWorkflow = (defaultprops) => { setActiveDialog("codeeditor") var parsedvalue = workflow?.triggers[selectedTriggerIndex]?.parameters[1]?.value + // Right now Handling subflow only with this + navigate(`?trigger_id=${selectedTrigger.id}&trigger_field=${"argument"}&trigger_name=${selectedTrigger.label}`) setEditorData({ "name": workflow.triggers[selectedTriggerIndex].parameters[1].name, "value": parsedvalue, @@ -14531,13 +14545,16 @@ const AngularWorkflow = (defaultprops) => { fullWidth color="primary" placeholder="Some execution data" - defaultValue={ - workflow?.triggers[selectedTriggerIndex]?.parameters[1]?.value + value={ + selectedTriggerValue } - onChange={(e) => { - workflow.triggers[selectedTriggerIndex].parameters[1].value = e.target.value - setWorkflow(workflow) + onChange={(e) => { setLastSaved(false) + setSelectedTriggerValue(e.target.value) + }} + onBlur={() => { + workflow.triggers[selectedTriggerIndex].parameters[1].value = selectedTriggerValue + setWorkflow(workflow) }} /> {!showDropdown ? null : @@ -16933,7 +16950,11 @@ const AngularWorkflow = (defaultprops) => { setLastSaved(false) }} > - + {workflow.name !== undefined && workflow.name !== null && workflow.name.length > 0 ? + + : + null + } {workflow.name} {workflowAsCode && ( @@ -17055,22 +17076,22 @@ const AngularWorkflow = (defaultprops) => { > Go to parent org workflow - : 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 > 1 && workflow?.id !== undefined && workflow?.id && workflow?.id?.length > 0 ? + : null : @@ -19353,14 +19374,14 @@ const AngularWorkflow = (defaultprops) => { base_node_name = "exec" } - console.log("COPY: ", base_node_name, copy); + //console.log("COPY: ", base_node_name, copy); //var newitem = JSON.parse(base); var newitem = validateJson(base).result // Check if base_node_name has changed if (cy !== undefined && cy !== null) { - console.log("Change name?") + //console.log("Change name?") //const allNodes = cy.nodes().jsons(); //for (var key in allNodes) { //const currentNode = allNodes[key]; @@ -19401,7 +19422,7 @@ const AngularWorkflow = (defaultprops) => { const elementName = "copy_element_shuffle"; var copyText = document.getElementById(elementName); if (copyText !== null && copyText !== undefined) { - console.log("NAVIGATOR: ", navigator); + //console.log("NAVIGATOR: ", navigator); const clipboard = navigator.clipboard; if (clipboard === undefined) { toast("Can only copy over HTTPS (port 3443)"); @@ -19414,7 +19435,7 @@ const AngularWorkflow = (defaultprops) => { /* Copy the text inside the text field */ document.execCommand("copy"); - console.log("COPYING!"); + //console.log("COPYING!"); toast("Copied JSON path to clipboard.") } else { console.log("Couldn't find element ", elementName); @@ -21539,18 +21560,28 @@ const AngularWorkflow = (defaultprops) => { textAlign: "center", }} > - - - Loading Workflow - + {isLoaded && workflowDone ? +
+ + No workflow to load. Workflow runs may still exist. If you think this is wrong, please contact support@shuffler.io + +
+ : +
+ + + Loading Workflow + +
+ } ) : ( @@ -23330,7 +23361,7 @@ const AngularWorkflow = (defaultprops) => { - const changeActionParameterCodeMirror = (event, count, data, actionlist, parametername) => { + const changeActionParameterCodeMirror = (event, count, data, actionlist, parametername, selectedAction, setSelectedAction) => { // FIXME: This exists ONLY to make sure focus + blur actually changes the field value // in fields from ParsedAction.jsx such as rightside_field_2 @@ -23510,6 +23541,25 @@ const AngularWorkflow = (defaultprops) => { //setUpdate(Math.random()) } + const handleActionParamChange = (actionId, fieldName, newData) => { + if (workflow !== undefined) { + // Find the action with matching id + const actionIndex = workflow?.actions.findIndex(action => action.id === actionId); + if (actionIndex >= 0) { + // Find the parameter with matching name + console.log("fieldName", fieldName) + const paramIndex = workflow.actions[actionIndex].parameters.findIndex(param => param.name === fieldName); + if (paramIndex >= 0) { + // Update the parameter value + workflow.actions[actionIndex].parameters[paramIndex].value = newData; + + // Update workflow state to trigger re-render + setWorkflow({...workflow}); + setLastSaved(false); + } + } + } + } /* var foundusecase = {} if (workflow.actions !== undefined && workflow.actions !== null && workflow.actions.length > 0 && userdata !== undefined && userdata !== null && userdata.priorities !== undefined && userdata.priorities !== null && userdata.priorities.length > 0) { @@ -23587,19 +23637,21 @@ const AngularWorkflow = (defaultprops) => { {codeEditorModalOpen ? {/* Deactivate button */} - {currTab === 0 && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && ( + {(currTab === 0 || currTab === 1) && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && (
{ - canEditApp && ( + canEditApp ? ( + ) : ( + ) }