Bumped public Form running and subflow/user input fixes in multi-tenant workflows

This commit is contained in:
Frikky
2025-02-17 00:50:08 +01:00
parent 1f2e0ed6a3
commit 6719f527e8
11 changed files with 148 additions and 119 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ module shuffle
go 1.22.2
//replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared
replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared
require (
cloud.google.com/go/datastore v1.15.0
+26 -14
View File
@@ -25,7 +25,8 @@ import {
TableRow,
InputAdornment,
Divider,
LinearProgress
LinearProgress,
Tooltip,
} from "@mui/material";
import throttle from "lodash/throttle";
import theme from "../theme.jsx";
@@ -1447,19 +1448,28 @@ const ActionsList = memo(({
<div style={{ borderBottom: '1px solid #494949', paddingTop: 10, paddingBottom: 10}}>
<div>
{info?.title ? (
<div style={{ display: "flex", alignItems: "center" }}>
<img
src={openapi?.info["x-logo"]}
width={48}
height={48}
alt="app logo"
style={{ marginLeft: 20, borderRadius: 8 }}
/>
<Typography style={{ fontSize: 24, fontWeight: 'bold', marginLeft: 20, overflow: 'hidden', color: '#F1F1F1'
}}>
{info.title}
</Typography>
</div>
<a
href={`/apps/${openapi?.id}`}
style={{ textDecoration: 'none', }}
target="_blank"
rel="noreferrer"
>
<Tooltip title="Go to app" placement="right">
<div style={{ display: "flex", alignItems: "center" }}>
<img
src={openapi?.info["x-logo"]}
width={48}
height={48}
alt="app logo"
style={{ marginLeft: 20, borderRadius: 8 }}
/>
<Typography style={{ fontSize: 24, fontWeight: 'bold', marginLeft: 20, overflow: 'hidden', color: '#F1F1F1'
}}>
{info.title}
</Typography>
</div>
</Tooltip>
</a>
) : (
<Typography style={{ fontSize: 24, fontWeight: 'bold', marginLeft: 20, overflow: 'hidden', color: '#F1F1F1'
}}>
@@ -1468,6 +1478,7 @@ const ActionsList = memo(({
)}
</div>
</div>
<TextField
value={searchQuery}
placeholder="Search endpoints"
@@ -1488,6 +1499,7 @@ const ActionsList = memo(({
},
}}
/>
<div
style={{
marginLeft: 20,
+3 -3
View File
@@ -657,8 +657,8 @@ useEffect(() => {
};
const getRegionTag = (region_url) => {
//let regiontag = "UK";
let regiontag = "EU";
let regiontag = "UK";
//let regiontag = "EU";
if (
region_url !== undefined &&
region_url !== null &&
@@ -755,7 +755,7 @@ useEffect(() => {
};
const getRegionFlag = (region_url) => {
var region = "gb";
var region = "UK";
const regionMapping = {
"US": "us",
"EU": "eu",
@@ -1087,11 +1087,11 @@ const RegionChangeModal = memo(({selectedOrganization, setSelectedRegion, userda
"US": "us",
"EU-2": "eu",
"CA": "ca",
"EU": "eu"
"UK": "gb"
};
//let regiontag = "UK";
let regiontag = "EU";
let regiontag = "UK";
let regionCode = "gb";
const regionsplit = selectedOrganization?.region_url?.split(".");
@@ -155,7 +155,6 @@ const OrganizationTab = (props) => {
<Button
key={tabName}
onClick={() => {
console.log("index", index);
setCurIndex(index);
handleTabClick(index === 0 ? "org_config" : tabName.toLowerCase().replace(/[\s&]+/g, ''));
}}
+69 -47
View File
@@ -54,15 +54,15 @@ const TenantsTab = memo((props) => {
const [cloudSyncModalOpen, setCloudSyncModalOpen] = React.useState(false);
const [modalOpen, setModalOpen] = React.useState(false);
const [parentOrg, setParentOrg] = React.useState(null);
const [parentOrgFlag, setParentOrgFlag] = React.useState("eu");
const [parentOrgFlag, setParentOrgFlag] = React.useState(null);
const [loadOrgs, setLoadOrgs] = React.useState(true);
const [, forceUpdate] = React.useState();
const itemColor = "black";
useEffect(() => {
if(parentOrgFlag === null) {
let regiontag = "EU";
let regionCode = "eu";
if(parentOrg !== null && parentOrgFlag === null) {
let regiontag = "UK";
let regionCode = "gb";
if (parentOrg?.region_url?.length > 0) {
const regionsplit = parentOrg?.region_url.split(".");
@@ -71,17 +71,16 @@ const TenantsTab = memo((props) => {
regiontag = namesplit[namesplit.length - 1];
if (regiontag === "california") {
regiontag = "US";
regionCode = "us";
regiontag = "US";
regionCode = "us";
} else if (regiontag === "frankfurt") {
regiontag = "EU-2";
regionCode = "eu";
regiontag = "EU-2";
regionCode = "eu";
} else if (regiontag === "ca") {
regiontag = "CA";
regionCode = "ca";
regiontag = "CA";
regionCode = "ca";
}
}
console.log("did i reach here, region code is: ", regionCode);
setParentOrgFlag(regionCode);
}
}
@@ -145,8 +144,8 @@ const TenantsTab = memo((props) => {
setSubOrgs(subOrgs);
setParentOrg(parentOrg);
let regiontag = "EU";
let regionCode = "eu";
let regiontag = "UK";
let regionCode = "gb";
if (parentOrg?.region_url?.length > 0) {
const regionsplit = parentOrg?.region_url.split(".");
@@ -155,14 +154,14 @@ const TenantsTab = memo((props) => {
regiontag = namesplit[namesplit.length - 1];
if (regiontag === "california") {
regiontag = "US";
regionCode = "us";
regiontag = "US";
regionCode = "us";
} else if (regiontag === "frankfurt") {
regiontag = "EU-2";
regionCode = "eu";
regiontag = "EU-2";
regionCode = "eu";
} else if (regiontag === "ca") {
regiontag = "CA";
regionCode = "ca";
regiontag = "CA";
regionCode = "ca";
}
}
setParentOrgFlag(regionCode);
@@ -1220,7 +1219,29 @@ const TenantsTab = memo((props) => {
}}
/>
</ListItem>
{subOrgs.map((data, index) => (
{subOrgs.map((data, index) => {
let regiontag = "UK";
let regionCode = "gb";
if (data.region_url?.length > 0) {
const regionsplit = data.region_url.split(".");
if (regionsplit.length > 2 && !regionsplit[0].includes("shuffler")) {
const namesplit = regionsplit[0].split("/");
regiontag = namesplit[namesplit.length - 1];
if (regiontag === "california") {
regiontag = "US";
regionCode = "us";
} else if (regiontag === "frankfurt") {
regiontag = "EU-2";
regionCode = "eu";
} else if (regiontag === "ca") {
regiontag = "CA";
regionCode = "ca";
}
}
}
return (
<ListItem key={index} style={{ backgroundColor: index % 2 === 0 ? '#1A1A1A' : '#212121', width: "100%", borderBottomLeftRadius: 8, display:'table-row', borderBottomRightRadius: 8 }}>
<ListItemText primary={<img alt={data?.name} src={data.image || theme.palette.defaultImage} style={imageStyle} />} style={{ width: 100,
minWidth: 100,
@@ -1237,30 +1258,31 @@ const TenantsTab = memo((props) => {
padding: 8,
verticalAlign: "middle",
textAlign: "center", }} />
{isCloud && (
<ListItemText
primary={
<div style={{ display: "flex", alignItems: "center" }}>
<img
alt={parentOrgFlag}
src={`https://flagcdn.com/w20/${parentOrgFlag}.png`}
alt={regiontag}
src={`https://flagcdn.com/w20/${regionCode}.png`}
style={{ width: "30px", height: "20px", marginRight: "5px" }}
/>
<ListItemText primary={parentOrgFlag?.toUpperCase()} />
<ListItemText primary={regiontag?.toUpperCase()} />
</div>
}
style={{ display: "table-cell", padding: 8, verticalAlign: "middle" }}
/>
)}
<ListItemText primary={data.id} style={{ minWidth: 300,
maxWidth: 300,
display: "table-cell",
padding: 8,
verticalAlign: "middle", }} />
maxWidth: 300,
display: "table-cell",
padding: 8,
verticalAlign: "middle", }} />
<ListItemText
primary={
<Tooltip title={data.id === userdata?.active_org?.id ? "You are already in this organization." : ""} disableInteractive>
primary={
<Tooltip title={data.id === userdata?.active_org?.id ? "You are already in this organization." : ""} disableInteractive>
<Button
color="primary"
variant='outlined'
@@ -1284,7 +1306,7 @@ const TenantsTab = memo((props) => {
style={{ display: "table-cell", verticalAlign: "middle" }}
/>
</ListItem>
))}
)})}
</List>
</div>
</div>
@@ -1452,26 +1474,26 @@ const TenantsTab = memo((props) => {
) : (
userdata?.orgs?.length > 0 &&
userdata.orgs.map((data, index) => {
let regiontag = "EU";
let regionCode = "eu";
let regiontag = "UK";
let regionCode = "gb";
if (data.region_url?.length > 0) {
const regionsplit = data.region_url.split(".");
if (regionsplit.length > 2 && !regionsplit[0].includes("shuffler")) {
const namesplit = regionsplit[0].split("/");
regiontag = namesplit[namesplit.length - 1];
const regionsplit = data.region_url.split(".");
if (regionsplit.length > 2 && !regionsplit[0].includes("shuffler")) {
const namesplit = regionsplit[0].split("/");
regiontag = namesplit[namesplit.length - 1];
if (regiontag === "california") {
regiontag = "US";
regionCode = "us";
} else if (regiontag === "frankfurt") {
regiontag = "EU-2";
regionCode = "eu";
} else if (regiontag === "ca") {
regiontag = "CA";
regionCode = "ca";
}
}
if (regiontag === "california") {
regiontag = "US";
regionCode = "us";
} else if (regiontag === "frankfurt") {
regiontag = "EU-2";
regionCode = "eu";
} else if (regiontag === "ca") {
regiontag = "CA";
regionCode = "ca";
}
}
}
return (
+29 -23
View File
@@ -1072,7 +1072,7 @@ const AngularWorkflow = (defaultprops) => {
// Special multi-workflow edgecase handler for events
if (distributedFromParent === "" && suborgWorkflows === []) {
} else {
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
cy.removeListener("select");
cy.removeListener("unselect");
cy.removeListener("add");
@@ -1248,32 +1248,37 @@ const AngularWorkflow = (defaultprops) => {
}
var found = null
/*
try {
for (var key in workflows) {
const curworkflow = workflows[key]
const curtrigger = curworkflow.triggers[selectedTriggerIndex]
const curtrigger = curworkflow?.triggers[selectedTriggerIndex]
if (curtrigger === undefined || curtrigger === null) {
continue
}
if (curtrigger.parameters === undefined || curtrigger.parameters === null || curtrigger.parameters.length === 0) {
if (curtrigger?.parameters === undefined || curtrigger?.parameters === null || curtrigger?.parameters.length === 0) {
continue
}
if (curtrigger.parameters[0] === undefined || curtrigger.parameters[0] === null || curtrigger.parameters[0].value === undefined || curtrigger.parameters[0].value === null) {
if (curtrigger?.parameters[0] === undefined || curtrigger?.parameters[0] === null || curtrigger?.parameters[0].value === undefined || curtrigger?.parameters[0].value === null) {
continue
}
if (curtrigger.parameters[0].value === selectedTrigger?.parameters[0]?.value) {
if (curtrigger?.parameters[0].value === selectedTrigger?.parameters[0]?.value) {
found = curworkflow
setSubworkflow(curworkflow)
}
}
setSubworkflow(found)
if (found !== null) {
setSubworkflow(found)
}
} catch (e) {
console.log("Failed in trigger selection: ", e)
return
}
*/
if (found) {
const startNode = found.actions?.find((action) => action.id === workflow?.triggers[selectedTriggerIndex]?.parameters[3]?.value)
@@ -1292,7 +1297,7 @@ const AngularWorkflow = (defaultprops) => {
// Check if the running state is correct or not according to allTriggers
if (allTriggers !== undefined && allTriggers !== null) {
// Find the active trigger
if (selectedTrigger !== undefined && selectedTrigger !== null && selectedTrigger.id !== undefined && selectedTrigger.id !== null) {
if (selectedTrigger !== undefined && selectedTrigger !== null && selectedTrigger?.id !== undefined && selectedTrigger?.id !== null) {
var useTriggers = allTriggers
if (allTriggers.pipelines === undefined || allTriggers.pipelines === null || allTriggers.pipelines.length === 0) {
@@ -2491,7 +2496,7 @@ const AngularWorkflow = (defaultprops) => {
}
*/
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
// scale: 0.3,
// bg: "#27292d",
const cyImageData = cy.png({
@@ -2987,7 +2992,7 @@ const AngularWorkflow = (defaultprops) => {
setAppAuthentication(newauth);
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
// Remove the old listener for select, run with new one
cy.removeListener("select");
@@ -4136,7 +4141,9 @@ const AngularWorkflow = (defaultprops) => {
.then((responseJson) => {
// Load as JSON
if (responseJson.id !== undefined && responseJson.id !== null && responseJson.id.length > 0 && responseJson.id !== workflow_id) {
toast("Workflow ID mismatch. Redirecting to your workflow")
toast.warning("Workflow ID mismatch. Redirected to your actual workflow. This may happen due to being in the wrong org, where we load the child workflow for you automatically.", {
autoClose: 10000,
})
navigate(`/workflows/${responseJson.id}`)
}
@@ -7325,7 +7332,7 @@ const AngularWorkflow = (defaultprops) => {
}
console.log("CTRL+C");
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
var cydata = cy.$(":selected").jsons();
if (cydata !== undefined && cydata !== null && cydata.length > 0) {
console.log(cydata);
@@ -7638,7 +7645,7 @@ const AngularWorkflow = (defaultprops) => {
// Skipping node editing if it's the selected one
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
const typeIds = cy.elements('node:selected').jsons();
for (var idkey in typeIds) {
const item = typeIds[idkey]
@@ -12660,7 +12667,7 @@ const AngularWorkflow = (defaultprops) => {
}
const handleActionHover = (inside, actionId) => {
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
var node = cy.getElementById(actionId);
if (node.length > 0) {
if (inside) {
@@ -12905,7 +12912,6 @@ const AngularWorkflow = (defaultprops) => {
}
setWorkflow(workflow)
console.log("WF: ", workflow)
setUpdate(Math.random())
}
@@ -15125,7 +15131,7 @@ const AngularWorkflow = (defaultprops) => {
for (let triggerkey in workflow.triggers) {
const item = workflow.triggers[triggerkey];
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
var node = cy.getElementById(item.id);
if (node.length > 0) {
if (inside) {
@@ -15140,7 +15146,7 @@ const AngularWorkflow = (defaultprops) => {
}
const handleActionHover = (inside, actionId) => {
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
var node = cy.getElementById(actionId);
if (node.length > 0) {
if (inside) {
@@ -17585,9 +17591,9 @@ const AngularWorkflow = (defaultprops) => {
null
}
{originalWorkflow.suborg_distribution === undefined || originalWorkflow.suborg_distribution === null || originalWorkflow.suborg_distribution.length === 0 || originalWorkflow.suborg_distribution.includes("none") ?
originalWorkflow?.parentorg_workflow !== undefined && originalWorkflow?.parentorg_workflow !== null && originalWorkflow?.parentorg_workflow.length > 0 ?
{originalWorkflow?.suborg_distribution === undefined || originalWorkflow?.suborg_distribution === null || originalWorkflow?.suborg_distribution?.length === 0 || originalWorkflow?.suborg_distribution.includes("none") ?
originalWorkflow?.parentorg_workflow !== undefined && originalWorkflow?.parentorg_workflow !== null && originalWorkflow?.parentorg_workflow.length > 0 || workflow?.parentorg_workflow !== undefined && workflow?.parentorg_workflow !== null && workflow?.parentorg_workflow.length > 0 ?
<Button
color="secondary"
variant="outlined"
@@ -17598,7 +17604,7 @@ const AngularWorkflow = (defaultprops) => {
marginLeft: 10,
}}
onClick={() => {
navigate(`/workflows/${originalWorkflow.parentorg_workflow}`)
navigate(`/workflows/${workflow.parentorg_workflow}`)
// Reload the page
window.location.reload()
}}
@@ -17914,7 +17920,7 @@ const AngularWorkflow = (defaultprops) => {
}
return (
<li>
<li key={index}>
<Tooltip title={orgDiffAction.label} arrow placement="left">
<img alt={orgDiffAction.label} src={orgDiffAction.large_image} style={{width: 20, height: 20, borderRadius: theme.palette.borderRadius, marginRight: 10, }}/>
</Tooltip>
@@ -18279,7 +18285,7 @@ const AngularWorkflow = (defaultprops) => {
};
const handleActionHover = (inside, actionId) => {
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
var node = cy.getElementById(actionId);
if (node.length > 0) {
if (inside) {
@@ -18719,7 +18725,7 @@ const AngularWorkflow = (defaultprops) => {
setDistributedFromParent("")
}
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
cy.removeListener("select");
cy.removeListener("unselect");
@@ -21287,7 +21293,7 @@ const AngularWorkflow = (defaultprops) => {
width: 30,
}}
onClick={() => {
if (cy !== undefined) {
if (cy !== undefined && cy !== null) {
const oldstartnode = cy.getElementById(data.action.id);
//console.log("FOUND NODe: ", oldstartnode)
if (oldstartnode !== undefined && oldstartnode !== null) {
+5 -19
View File
@@ -3042,9 +3042,11 @@ const AppExplorer = (props) => {
const getDownloadUrl = () => {
const appEnding = app?.public === true ? app?.app_verison : app?.id
console.log("APP: ", app)
return `curl -L \ \\\n "${globalUrl}/api/v1/download_docker_image?image=frikky/shuffle:${app?.name.toLowerCase().replaceAll(' ', '_')}_${appEnding}" \\\n -H \"Authorization: Bearer ${userdata?.apikey}" \\\n -o image.zip; \\\n docker load -i image.zip`
const appEnding = app?.public === true ? app?.app_version : app?.id
return `curl -L \ \\\n "${globalUrl}/api/v1/download_docker_image?image=frikky/shuffle:${app?.name.toLowerCase().replaceAll(' ', '_')}_${appEnding}" \\\n -H \"Authorization: Bearer APIKEY" \\\n -o image.zip; \\\n docker load -i image.zip`
}
const renderedActionOptions = deduplicateByName((
@@ -3231,7 +3233,7 @@ const AppExplorer = (props) => {
<div>
<Typography variant="h4">
Use the App onprem
Use the App onprem (hybrid)
</Typography>
<Typography variant="body2" color="textSecondary" style={{marginTop: 5, }}>
Due to using docker containers with privately uploaded containers, we had to use a custom registry. Use the command below to download the image to the server if it fails to run.
@@ -3583,22 +3585,6 @@ const AppExplorer = (props) => {
extraUrl = descSplit[descSplit.length-1]
}
//for (let [line,lineval] in Object.entries(descSplit)) {
// if (descSplit[line].includes("http") && descSplit[line].includes("://")) {
// const urlsplit = descSplit[line].split("/")
// try {
// extraUrl = "/"+urlsplit.slice(3, urlsplit.length).join("/")
// } catch (e) {
// //console.log("Failed - running with -1")
// extraUrl = "/"+urlsplit.slice(3, urlsplit.length-1).join("/")
// }
// //console.log("NO BASEURL TOO!! Why missing last one in certain scenarios (sevco)?", extraUrl, urlsplit, descSplit[line])
// //break
// }
//}
if (extraUrl.length > 0) {
if (extraUrl.includes(" ")) {
extraUrl = extraUrl.split(" ")[0]
+11 -7
View File
@@ -117,7 +117,7 @@ const RunWorkflow = (defaultprops) => {
props.match = {}
props.match.params = params
const defaultTitle = workflow.name !== undefined ? "Shuffle - Form for " + workflow.name : "Shuffle - Form to Run Workflows"
const defaultTitle = workflow.name !== undefined ? "Form for " + workflow.name : "Shuffle - Form to Run Workflows"
if (document != undefined && document.title != defaultTitle) {
document.title = defaultTitle
}
@@ -152,7 +152,7 @@ const RunWorkflow = (defaultprops) => {
}
}
console.log("EXEC: ", executionArgument)
//console.log("EXEC: ", executionArgument)
for (var key in executionArgument) {
if (executionArgument[key] === undefined || executionArgument[key] === null || executionArgument[key] === "") {
return false
@@ -705,6 +705,8 @@ const RunWorkflow = (defaultprops) => {
break
}
}
} else {
setInputQuestions(responseJson.input_questions)
}
if (responseJson.form_control.input_markdown !== undefined && responseJson.form_control.input_markdown !== null && responseJson.form_control.input_markdown.length > 0) {
@@ -894,7 +896,6 @@ const RunWorkflow = (defaultprops) => {
const fetchUpdates = (execution_id, authorization, getorg, replaceMarkdown) => {
if (execution_id === undefined || execution_id === null || execution_id === "") {
console.log("No execution id: ", execution_id)
stop()
return
}
@@ -1225,9 +1226,9 @@ const RunWorkflow = (defaultprops) => {
</div>
}
{workflow.input_questions !== undefined && workflow.input_questions !== null && workflow.input_questions.length > 0 ?
{workflow?.input_questions !== undefined && workflow?.input_questions !== null && workflow?.input_questions?.length > 0 ?
<div style={{marginBottom: 5, }}>
{inputQuestions.map((question, index) => {
{inputQuestions?.map((question, index) => {
// Multiple choice checks for semicolon-splits
var multiChoiceOptions = question.value !== undefined && question.value !== null && question.value.length > 0 && question.value.includes(";") ? question.value.split(";") : []
@@ -1241,9 +1242,12 @@ const RunWorkflow = (defaultprops) => {
return (
<div style={{marginBottom: 10}} key={index}>
<Typography variant="body2" color="textSecondary">
{question.name}
</Typography>
{multiChoiceOptions.length > 1 ?
<div>
{question.name}
<Select
disabled={disabledButtons}
fullWidth
@@ -1280,7 +1284,7 @@ const RunWorkflow = (defaultprops) => {
backgroundColor: theme.palette.inputColor,
marginTop: 5,
}}
label={question.value.charAt(0).toUpperCase() + question.value.slice(1)}
label={question?.value?.charAt(0)?.toUpperCase() + question?.value?.slice(1)}
required
disabled={disabledButtons}
+1 -1
View File
@@ -10,7 +10,7 @@ require (
github.com/docker/docker v27.5.0+incompatible
github.com/docker/go-connections v0.5.0
github.com/satori/go.uuid v1.2.0
github.com/shuffle/shuffle-shared v0.7.83
github.com/shuffle/shuffle-shared v0.7.91
k8s.io/api v0.30.2
k8s.io/apimachinery v0.30.2
)
+1 -1
View File
@@ -8,7 +8,7 @@ require (
github.com/docker/docker v27.5.0+incompatible
github.com/gorilla/mux v1.8.1
github.com/satori/go.uuid v1.2.0
github.com/shuffle/shuffle-shared v0.7.83
github.com/shuffle/shuffle-shared v0.7.91
k8s.io/api v0.30.2
k8s.io/apimachinery v0.30.2
k8s.io/client-go v0.30.2