Onprem X Cloud sync commit. Large changes to the navbar mechanisms
This commit is contained in:
@@ -18,7 +18,7 @@ require (
|
|||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/h2non/filetype v1.1.3
|
github.com/h2non/filetype v1.1.3
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/shuffle/shuffle-shared v0.7.92
|
github.com/shuffle/shuffle-shared v0.7.95
|
||||||
golang.org/x/crypto v0.32.0
|
golang.org/x/crypto v0.32.0
|
||||||
google.golang.org/api v0.176.1
|
google.golang.org/api v0.176.1
|
||||||
google.golang.org/grpc v1.68.1
|
google.golang.org/grpc v1.68.1
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ const EditWorkflow = (props) => {
|
|||||||
const [inputMarkdown, setInputMarkdown] = React.useState(workflow?.form_control?.input_markdown !== undefined && workflow?.form_control?.input_markdown !== null ? workflow?.form_control?.input_markdown : "")
|
const [inputMarkdown, setInputMarkdown] = React.useState(workflow?.form_control?.input_markdown !== undefined && workflow?.form_control?.input_markdown !== null ? workflow?.form_control?.input_markdown : "")
|
||||||
const [scrollDone, setScrollDone] = React.useState(false)
|
const [scrollDone, setScrollDone] = React.useState(false)
|
||||||
const [selectedYieldActions, setSelectedYieldActions] = React.useState(workflow?.form_control?.output_yields !== undefined && workflow?.form_control?.output_yields !== null ? JSON.parse(JSON.stringify(workflow?.form_control?.output_yields)) : [])
|
const [selectedYieldActions, setSelectedYieldActions] = React.useState(workflow?.form_control?.output_yields !== undefined && workflow?.form_control?.output_yields !== null ? JSON.parse(JSON.stringify(workflow?.form_control?.output_yields)) : [])
|
||||||
|
const [selectedCleanupActions, setSelectedCleanupActions] = React.useState(workflow?.form_control?.cleanup_actions !== undefined && workflow?.form_control?.cleanup_actions !== null ? JSON.parse(JSON.stringify(workflow?.form_control?.cleanup_actions)) : [])
|
||||||
|
|
||||||
const [formWidth, setFormWidth] = React.useState(boxWidth === undefined || boxWidth === null ? 500 : boxWidth)
|
const [formWidth, setFormWidth] = React.useState(boxWidth === undefined || boxWidth === null ? 500 : boxWidth)
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
@@ -323,6 +325,7 @@ const EditWorkflow = (props) => {
|
|||||||
innerWorkflow.form_control.input_markdown = inputMarkdown
|
innerWorkflow.form_control.input_markdown = inputMarkdown
|
||||||
innerWorkflow.form_control.output_yields = selectedYieldActions
|
innerWorkflow.form_control.output_yields = selectedYieldActions
|
||||||
innerWorkflow.form_control.form_width = formWidth
|
innerWorkflow.form_control.form_width = formWidth
|
||||||
|
innerWorkflow.form_control.cleanup_actions = selectedCleanupActions
|
||||||
|
|
||||||
innerWorkflow.name = name
|
innerWorkflow.name = name
|
||||||
innerWorkflow.description = description
|
innerWorkflow.description = description
|
||||||
@@ -568,7 +571,7 @@ 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 & Distribution controls
|
Multi-Tenancy, Backups & Security
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 30, marginBottom: 10, }}>
|
<Typography variant="body2" color="textSecondary" style={{ marginTop: 30, marginBottom: 10, }}>
|
||||||
@@ -678,7 +681,7 @@ const EditWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
<Typography variant="body1" style={{ marginTop: 75, }}>
|
<Typography variant="h6" style={{ marginTop: 75, }}>
|
||||||
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">
|
||||||
@@ -824,6 +827,60 @@ const EditWorkflow = (props) => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<div id="cleanup">
|
||||||
|
<Typography variant="h6" style={{ marginTop: 50, }}>
|
||||||
|
Result cleanup ({selectedCleanupActions.length === 0 ? "No cleanup yet" : selectedCleanupActions.length === 1 ? "Cleaning up 1 node" : `Cleaning up ${selectedCleanupActions.length} nodes`})
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 20, }}>
|
||||||
|
<b>Beta Feature</b>: When a workflow run is done, the data from the selected actions will be removed by replacing it with a default value. This is useful for cleaning up sensitive data, or data that is no longer needed. This is done after a workflow run is finished or aborted, and is not reversible. Data will remain in the workflow run result (last node value) even if the action result itself is cleaned up.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<FormControl style={{ marginTop: 15, }}>
|
||||||
|
<Select
|
||||||
|
defaultValue=""
|
||||||
|
id="result-cleanup-control"
|
||||||
|
label="Cleaned Up nodes"
|
||||||
|
multiple
|
||||||
|
fullWidth
|
||||||
|
style={{ width: 500, }}
|
||||||
|
value={selectedCleanupActions === [] ? ["none"] : selectedCleanupActions}
|
||||||
|
renderValue={(selected) => selected.join(', ')}
|
||||||
|
onChange={(event) => {
|
||||||
|
if (event.target.value.length > 0) {
|
||||||
|
if (event.target.value.includes("none")) {
|
||||||
|
setSelectedCleanupActions([])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newvalue = event?.target?.value
|
||||||
|
if (newvalue === undefined || newvalue === null) {
|
||||||
|
} else {
|
||||||
|
setSelectedCleanupActions(newvalue)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem value="none">
|
||||||
|
<em>None</em>
|
||||||
|
</MenuItem>
|
||||||
|
{workflow?.actions?.map((action, actionIndex) => {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={actionIndex}
|
||||||
|
value={action.id}
|
||||||
|
>
|
||||||
|
<Tooltip title={action.app_name} key={actionIndex}>
|
||||||
|
<img src={action.large_image !== undefined && action.large_image !== null && action.large_image.length > 0 ? action.large_image : theme.palette.defaultImage} style={{ width: 20, height: 20, marginRight: 10, }} />
|
||||||
|
</Tooltip>
|
||||||
|
{action.label}
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Divider style={{ marginTop: 20, marginBottom: 20, }} />
|
<Divider style={{ marginTop: 20, marginBottom: 20, }} />
|
||||||
|
|
||||||
|
|
||||||
@@ -1023,11 +1080,11 @@ const EditWorkflow = (props) => {
|
|||||||
|
|
||||||
<div id="output_control">
|
<div id="output_control">
|
||||||
<Typography variant="h6" style={{ marginTop: 50, }}>
|
<Typography variant="h6" style={{ marginTop: 50, }}>
|
||||||
Output Control ({selectedYieldActions.length === 0 ? "No Returns" : selectedYieldActions.length === 1 ? "Returning 1 node" : `Returning ${selectedYieldActions.length} nodes`})
|
Form Output Control ({selectedYieldActions.length === 0 ? "No Returns" : selectedYieldActions.length === 1 ? "Returning 1 node" : `Returning ${selectedYieldActions.length} nodes`})
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 20, }}>
|
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 20, }}>
|
||||||
When running this workflow, the output will be shown as a Markdown object by default, with JSON objects being rendered. By adding nodes below, they will be shown while the workflow is running as soon as they get a result. Failing/Skipped nodes are not shown. This makes it possible to track progress for more complex usecases.
|
When running this workflow as a form, the output will be shown as a Markdown object by default, with JSON objects being rendered. By adding nodes below, they will be shown while the workflow is running as soon as they get a result. Failing/Skipped nodes are not shown. This makes it possible to track progress for more complex usecases.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<FormControl style={{ marginTop: 15, }}>
|
<FormControl style={{ marginTop: 15, }}>
|
||||||
|
|||||||
@@ -1064,7 +1064,9 @@ const EnvironmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
style={{minWidth:120, display: "table-cell",}}
|
style={{minWidth:120, display: "table-cell",}}
|
||||||
primary={
|
primary={
|
||||||
<Tooltip title={environment.Type !== "cloud"
|
<Tooltip title={
|
||||||
|
<Typography variant="body1" style={{margin: 10, }}>
|
||||||
|
{environment.Type !== "cloud"
|
||||||
? environment.running_ip === undefined ||
|
? environment.running_ip === undefined ||
|
||||||
environment.running_ip === null ||
|
environment.running_ip === null ||
|
||||||
environment.running_ip.length === 0
|
environment.running_ip.length === 0
|
||||||
@@ -1074,6 +1076,13 @@ const EnvironmentTab = memo((props) => {
|
|||||||
<span>IP / label: {environment?.running_ip?.split(":")[0]}. May stay running up to a minute after stopping Orborus.</span>
|
<span>IP / label: {environment?.running_ip?.split(":")[0]}. May stay running up to a minute after stopping Orborus.</span>
|
||||||
:
|
:
|
||||||
"Cloud is automatically configured. Reachout to support@shuffler.io if you have any questions."
|
"Cloud is automatically configured. Reachout to support@shuffler.io if you have any questions."
|
||||||
|
}
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
Last checkin: {environment?.checkin !== undefined && environment.checkin !== null && environment?.checkin > 0 ? new Date(environment?.checkin * 1000).toLocaleString() : "Never"}
|
||||||
|
</Typography>
|
||||||
} placement="top">
|
} placement="top">
|
||||||
<Typography
|
<Typography
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -1263,7 +1263,7 @@ const Files = memo((props) => {
|
|||||||
}
|
}
|
||||||
const isDistributed = file?.suborg_distribution?.length > 0 ? true : false;
|
const isDistributed = file?.suborg_distribution?.length > 0 ? true : false;
|
||||||
const filenamesplit = file.filename.split(".")
|
const filenamesplit = file.filename.split(".")
|
||||||
const iseditable = file.filesize < 2000000 && file.status === "active" && allowedFileTypes.includes(filenamesplit[filenamesplit.length-1])
|
const iseditable = file.filesize < 2000000 && file.status === "active" && (allowedFileTypes.includes(filenamesplit[filenamesplit.length-1]) || !file?.filename.includes("."))
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={index}
|
key={index}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
Fade,
|
Fade,
|
||||||
Portal,
|
Portal,
|
||||||
Collapse,
|
Collapse,
|
||||||
|
Tooltip,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import theme from "../theme.jsx";
|
import theme from "../theme.jsx";
|
||||||
import RecentWorkflow from "../components/RecentWorkflow.jsx";
|
import RecentWorkflow from "../components/RecentWorkflow.jsx";
|
||||||
@@ -524,7 +525,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-rc6
|
Version: 2.0.0-rc7
|
||||||
</Typography>
|
</Typography>
|
||||||
</Menu>
|
</Menu>
|
||||||
</span>
|
</span>
|
||||||
@@ -813,13 +814,35 @@ useEffect(() => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<a href="/" style={{ textDecoration: "none" }}>
|
<Tooltip
|
||||||
|
title="Go to Home"
|
||||||
|
placement="top"
|
||||||
|
arrow
|
||||||
|
componentsProps={{
|
||||||
|
tooltip: {
|
||||||
|
sx: {
|
||||||
|
backgroundColor: "rgba(33, 33, 33, 1)",
|
||||||
|
color: "rgba(241, 241, 241, 1)",
|
||||||
|
fontSize: 12,
|
||||||
|
border: "1px solid rgba(73, 73, 73, 1)",
|
||||||
|
fontFamily: theme?.typography?.fontFamily,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
popper: {
|
||||||
|
sx: {
|
||||||
|
zIndex: 1000019,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Link to="/">
|
||||||
<img
|
<img
|
||||||
src={ShuffleLogo}
|
src={ShuffleLogo}
|
||||||
alt="Shuffle Logo"
|
alt="Shuffle Logo"
|
||||||
style={{ width: 24, height: 24 }}
|
style={{ width: 24, height: 24 }}
|
||||||
/>
|
/>
|
||||||
</a>
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -1454,7 +1477,7 @@ useEffect(() => {
|
|||||||
: "#C8C8C8"
|
: "#C8C8C8"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Shuffle Agent
|
Hybrid Locations
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -688,7 +688,7 @@ const ParsedAction = (props) => {
|
|||||||
if (newActionList.find((item) => item.type === "Shuffle DB") === undefined) {
|
if (newActionList.find((item) => item.type === "Shuffle DB") === undefined) {
|
||||||
let cacheKey = {
|
let cacheKey = {
|
||||||
type: "Shuffle DB",
|
type: "Shuffle DB",
|
||||||
name: "Shuffle DB",
|
name: "Shuffle Datastore",
|
||||||
value: "$shuffle_cache",
|
value: "$shuffle_cache",
|
||||||
highlight: "shuffle_cache",
|
highlight: "shuffle_cache",
|
||||||
autocomplete: "shuffle_cache",
|
autocomplete: "shuffle_cache",
|
||||||
@@ -753,17 +753,54 @@ 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 !== "Runtime Argument" && !labels.includes(parentNode.label)) {
|
if (parentNode.label === "Runtime Argument" || labels.includes(parentNode.label)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
labels.push(parentNode.label);
|
labels.push(parentNode.label);
|
||||||
let exampleData = parentNode.example ?? "";
|
let exampleData = parentNode.example ?? "";
|
||||||
if (!exampleData && workflowExecutions.length > 0) {
|
if (parentNode?.app_name === "http") {
|
||||||
|
exampleData = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflowExecutions.length > 0) {
|
||||||
for (let exec of workflowExecutions) {
|
for (let exec of workflowExecutions) {
|
||||||
const foundResult = exec.results?.find(result => result.action.id === parentNode.id);
|
const foundResult = exec.results?.find(result => result?.action?.id === parentNode?.id);
|
||||||
if (foundResult) {
|
if (foundResult) {
|
||||||
const valid = validateJson(foundResult.result);
|
const valid = validateJson(foundResult.result);
|
||||||
if (valid.valid && valid.result.success !== false) {
|
if (valid.valid && valid.result.success !== false) {
|
||||||
exampleData = valid.result;
|
exampleData = valid.result
|
||||||
break;
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exampleData === "" && apps !== undefined && apps !== null && apps?.length > 0) {
|
||||||
|
// Check apps if it exists, then if it
|
||||||
|
const foundApp = apps?.find(app => app?.id === parentNode?.app_id)
|
||||||
|
if (foundApp !== undefined && foundApp !== null) {
|
||||||
|
if (foundApp?.generated === true || foundApp?.name === "http") {
|
||||||
|
const validationData = validateJson(`{
|
||||||
|
"status": 200,
|
||||||
|
"body": {
|
||||||
|
"example": "json",
|
||||||
|
"values": "json"
|
||||||
|
},
|
||||||
|
"url": "https://example.com",
|
||||||
|
"headers": {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Example-Header": "two"
|
||||||
|
},
|
||||||
|
"cookies": {
|
||||||
|
"example": "session",
|
||||||
|
"__session": "sessionid"
|
||||||
|
},
|
||||||
|
"success": true
|
||||||
|
}`)
|
||||||
|
|
||||||
|
if (validationData.valid) {
|
||||||
|
exampleData = validationData.result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -788,9 +825,6 @@ const ParsedAction = (props) => {
|
|||||||
autocomplete: parentNode.label.split(" ").join("_"),
|
autocomplete: parentNode.label.split(" ").join("_"),
|
||||||
example: exampleData,
|
example: exampleData,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -840,8 +874,8 @@ const ParsedAction = (props) => {
|
|||||||
return { ...param, value: paramvalue, error: message }
|
return { ...param, value: paramvalue, error: message }
|
||||||
});
|
});
|
||||||
|
|
||||||
setSelectedActionParameters(newParameters);
|
setSelectedActionParameters(newParameters)
|
||||||
setActionlist(newActionList);
|
setActionlist(newActionList)
|
||||||
}, [workflow.execution_variables, paramUpdate, workflow.workflow_variables, workflowExecutions, workflow, selectedAction, listCache, getParents, setNewSelectedAction]);
|
}, [workflow.execution_variables, paramUpdate, workflow.workflow_variables, workflowExecutions, workflow, selectedAction, listCache, getParents, setNewSelectedAction]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -2575,7 +2609,8 @@ const ParsedAction = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
{setNewSelectedAction !== undefined ? (
|
{isAgent ? null :
|
||||||
|
setNewSelectedAction !== undefined ? (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
id="action_search"
|
id="action_search"
|
||||||
disabled={isAgent || (selectedAction?.parent_controlled === true && workflow?.parentorg_workflow?.length > 0)}
|
disabled={isAgent || (selectedAction?.parent_controlled === true && workflow?.parentorg_workflow?.length > 0)}
|
||||||
|
|||||||
@@ -276,6 +276,8 @@ const CodeEditor = (props) => {
|
|||||||
parsedPaths = GetParsedPaths(actionlist[i].value, "");
|
parsedPaths = GetParsedPaths(actionlist[i].value, "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
//console.log("EXAMPLE: ", actionlist[i])
|
||||||
|
|
||||||
// Handle regular action results
|
// Handle regular action results
|
||||||
if (typeof actionlist[i].example === "object") {
|
if (typeof actionlist[i].example === "object") {
|
||||||
parsedPaths = GetParsedPaths(actionlist[i].example, "");
|
parsedPaths = GetParsedPaths(actionlist[i].example, "");
|
||||||
@@ -1228,7 +1230,7 @@ const CodeEditor = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const editorLoad = (editor) => {
|
const editorLoad = (editor) => {
|
||||||
console.log("EDITOR: ", editor)
|
//console.log("EDITOR: ", editor)
|
||||||
editor.completers = [customCompleter]
|
editor.completers = [customCompleter]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1526,7 +1528,7 @@ const CodeEditor = (props) => {
|
|||||||
Source Data
|
Source Data
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary">
|
<Typography variant="body2" color="textSecondary">
|
||||||
Drag the data you want into the text editor
|
Drag the data you want into the text editor! <b>PS: Only support users can see this test-section!</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{actionlist?.map((innerdata) => {
|
{actionlist?.map((innerdata) => {
|
||||||
@@ -2246,8 +2248,8 @@ const CodeEditor = (props) => {
|
|||||||
{selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ?
|
{selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ?
|
||||||
"Code to run" :
|
"Code to run" :
|
||||||
triggerId ?
|
triggerId ?
|
||||||
`Output : ${triggerName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + triggerName?.replaceAll("_", " ").slice(1)}(${triggerField})` :
|
`Output: ${triggerName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + triggerName?.replaceAll("_", " ").slice(1)} (${triggerField})` :
|
||||||
`Output : ${appName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + appName?.replaceAll("_", " ").slice(1)}(${fieldName})`
|
`Output: ${appName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + appName?.replaceAll("_", " ").slice(1)} (${fieldName})`
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@@ -2429,7 +2431,10 @@ const CodeEditor = (props) => {
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (isFileEditor !== true) {
|
||||||
navigate("")
|
navigate("")
|
||||||
|
}
|
||||||
|
|
||||||
setExpansionModalOpen(false);
|
setExpansionModalOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -2453,7 +2458,9 @@ const CodeEditor = (props) => {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (isFileEditor !== true) {
|
||||||
navigate("")
|
navigate("")
|
||||||
|
}
|
||||||
// Take localcodedata through the Shuffle JSON parser just in case
|
// Take localcodedata through the Shuffle JSON parser just in case
|
||||||
// This is to make it so we don't need to handle these fixes on the
|
// This is to make it so we don't need to handle these fixes on the
|
||||||
// backend by itself
|
// backend by itself
|
||||||
|
|||||||
@@ -678,7 +678,7 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
}
|
}
|
||||||
{img2 !== undefined && img2 !== "" && dstapp !== undefined && dstapp !== "" ?
|
{img2 !== undefined && img2 !== "" && dstapp !== undefined && dstapp !== "" ?
|
||||||
<Tooltip title={dstapp.replaceAll(":default", "").replaceAll("_", " ").replaceAll(" API", "")} placement="top">
|
<Tooltip title={dstapp.replaceAll(":default", "").replaceAll("_", " ").replaceAll(" API", "")} placement="top">
|
||||||
<div style={{display: "flex", }}>
|
<div style={{display : dstapp === "NA" ? "none" : "flex" }}>
|
||||||
<TrendingFlatIcon style={{ marginTop: 7, }} />
|
<TrendingFlatIcon style={{ marginTop: 7, }} />
|
||||||
<div style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
|
<div style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
|
||||||
<img src={img2} style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleDefault : imagestyle} />
|
<img src={img2} style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleDefault : imagestyle} />
|
||||||
|
|||||||
@@ -50,12 +50,13 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
setIsClicked,
|
setIsClicked,
|
||||||
inputWorkflowId,
|
inputWorkflowId,
|
||||||
inputWorkflow,
|
inputWorkflow,
|
||||||
|
onClose,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [isActive, setIsActive] = useState(workflowBuilt === true || (workflowBuilt !== undefined && workflowBuilt !== null && workflowBuilt?.length > 0) || (inputWorkflow !== undefined && inputWorkflow !== null && inputWorkflow.id !== undefined && inputWorkflow.id !== null && inputWorkflow.id !== "") ? true : false)
|
const [isActive, setIsActive] = useState(workflowBuilt === true || (workflowBuilt !== undefined && workflowBuilt !== null && workflowBuilt?.length > 0) || (inputWorkflow !== undefined && inputWorkflow !== null && inputWorkflow.id !== undefined && inputWorkflow.id !== null && inputWorkflow.id !== "") ? true : false)
|
||||||
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const [modalOpen, setModalOpen] = useState(isModalOpenDefault === true ? true : false)
|
const [modalOpen, setModalOpen] = useState(isModalOpenDefault === true);
|
||||||
const [errorMessage, setErrorMessage] = useState("");
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
const [workflowLoading, setWorkflowLoading] = useState(false)
|
const [workflowLoading, setWorkflowLoading] = useState(false)
|
||||||
const [showLoginButton, setShowLoginButton] = useState(false);
|
const [showLoginButton, setShowLoginButton] = useState(false);
|
||||||
@@ -173,6 +174,12 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
}
|
}
|
||||||
}, [configurationFinished, workflow])
|
}, [configurationFinished, workflow])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isModalOpenDefault === true) {
|
||||||
|
setModalOpen(true);
|
||||||
|
}
|
||||||
|
}, [isModalOpenDefault]);
|
||||||
|
|
||||||
const imageSize = 32
|
const imageSize = 32
|
||||||
const defaultBorder = "1px solid rgba(255,255,255,0.6)"
|
const defaultBorder = "1px solid rgba(255,255,255,0.6)"
|
||||||
const imagestyleWrapper = {
|
const imagestyleWrapper = {
|
||||||
@@ -516,6 +523,18 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setModalOpen(false);
|
||||||
|
|
||||||
|
if (onClose) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setIsClicked !== undefined) {
|
||||||
|
setIsClicked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ModalView = () => {
|
const ModalView = () => {
|
||||||
if (modalOpen === false) {
|
if (modalOpen === false) {
|
||||||
return null
|
return null
|
||||||
@@ -528,13 +547,7 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
<Drawer
|
<Drawer
|
||||||
anchor={"right"}
|
anchor={"right"}
|
||||||
open={modalOpen}
|
open={modalOpen}
|
||||||
onClose={() => {
|
onClose={handleClose}
|
||||||
setModalOpen(false);
|
|
||||||
|
|
||||||
if (setIsClicked !== undefined) {
|
|
||||||
setIsClicked(false)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "black",
|
backgroundColor: "black",
|
||||||
@@ -550,17 +563,15 @@ const WorkflowTemplatePopup = (props) => {
|
|||||||
style={{
|
style={{
|
||||||
zIndex: 5000,
|
zIndex: 5000,
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 14,
|
top: 110,
|
||||||
right: 14,
|
right: 110,
|
||||||
color: "white",
|
color: "white",
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={handleClose}
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<DialogContent style={{marginTop: 0, marginLeft: isHomePage ? null : isMobile ? null : 75, maxWidth: 470, }}>
|
<DialogContent style={{marginTop: 0, marginLeft: isHomePage ? null : isMobile ? null : 75, maxWidth: 470, marginTop: 20 }}>
|
||||||
<Typography variant="h4" style={{ fontSize: isMobile ? 20 : null}}>
|
<Typography variant="h4" style={{ fontSize: isMobile ? 20 : null}}>
|
||||||
<b>Configure Workflow</b>
|
<b>Configure Workflow</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -157,6 +157,38 @@ const data = [
|
|||||||
"background-gradient-stop-colors": "data(fillGradient)",
|
"background-gradient-stop-colors": "data(fillGradient)",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
selector: `node[app_id="shuffle_agent"]`,
|
||||||
|
css: {
|
||||||
|
"height": "74px",
|
||||||
|
"width": "222px",
|
||||||
|
"background-image": "data(large_image)",
|
||||||
|
"label": function(element) {
|
||||||
|
var elementname = element.data("label")
|
||||||
|
if (elementname === null || elementname === undefined) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementname.length > 15) {
|
||||||
|
elementname = elementname.substring(0, 15) + ".."
|
||||||
|
}
|
||||||
|
|
||||||
|
return elementname
|
||||||
|
},
|
||||||
|
"background-width": "65px",
|
||||||
|
"background-height": "65px",
|
||||||
|
"background-position-x": "20px",
|
||||||
|
//"background-position-x": "center", // Crashes
|
||||||
|
"background-repeat": "no-repeat",
|
||||||
|
|
||||||
|
"font-size": "14px",
|
||||||
|
"text-halign": "center",
|
||||||
|
"text-valign": "center",
|
||||||
|
"text-margin-x": "-140px",
|
||||||
|
"text-margin-y": "0px",
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
selector: `node[app_name="Testing"]`,
|
selector: `node[app_name="Testing"]`,
|
||||||
css: {
|
css: {
|
||||||
|
|||||||
+35
-3
@@ -83,6 +83,11 @@ const theme = createTheme(adaptV4Theme({
|
|||||||
typography: {
|
typography: {
|
||||||
fontFamily: `"Roboto", "Helvetica", "Arial", "inter", sans-serif`,
|
fontFamily: `"Roboto", "Helvetica", "Arial", "inter", sans-serif`,
|
||||||
useNextVariants: true,
|
useNextVariants: true,
|
||||||
|
fontWeightLight: 300,
|
||||||
|
fontWeightRegular: 400,
|
||||||
|
fontWeightMedium: 500,
|
||||||
|
fontWeightSemiBold: 600,
|
||||||
|
fontWeightBold: 700,
|
||||||
h1: {
|
h1: {
|
||||||
fontSize: 40,
|
fontSize: 40,
|
||||||
},
|
},
|
||||||
@@ -107,12 +112,39 @@ const theme = createTheme(adaptV4Theme({
|
|||||||
MuiCssBaseline: {
|
MuiCssBaseline: {
|
||||||
styleOverrides: `
|
styleOverrides: `
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('roboto'), local('roboto'), format('truetype');
|
src: local('Roboto Light'), local('Roboto-Light');
|
||||||
unicodeRange: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF;
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 600;
|
||||||
|
src: local('Roboto SemiBold'), local('Roboto-SemiBold');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold');
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1243,25 +1243,28 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedTriggerIndex === undefined || selectedTriggerIndex === null || selectedTriggerIndex < 0) {
|
if (selectedTriggerIndex === undefined || selectedTriggerIndex === null || selectedTriggerIndex < 0) {
|
||||||
console.log("Failed in trigger selection: ", selectedTrigger)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//console.log("Failed in trigger selection: ", selectedTriggerIndex, "Trigger: ", selectedTrigger)
|
||||||
|
|
||||||
var found = null
|
var found = null
|
||||||
/*
|
|
||||||
try {
|
try {
|
||||||
for (var key in workflows) {
|
for (var key in workflows) {
|
||||||
const curworkflow = workflows[key]
|
const curworkflow = workflows[key]
|
||||||
const curtrigger = curworkflow?.triggers[selectedTriggerIndex]
|
const curtrigger = curworkflow?.triggers[selectedTriggerIndex]
|
||||||
if (curtrigger === undefined || curtrigger === null) {
|
if (curtrigger === undefined || curtrigger === null) {
|
||||||
|
console.log("Failed in trigger selection (1): ", curworkflow)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curtrigger?.parameters === undefined || curtrigger?.parameters === null || curtrigger?.parameters.length === 0) {
|
if (curtrigger?.parameters === undefined || curtrigger?.parameters === null || curtrigger?.parameters.length === 0) {
|
||||||
|
console.log("Failed in trigger selection (2): ", curworkflow)
|
||||||
continue
|
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) {
|
||||||
|
console.log("Failed in trigger selection (3): ", curworkflow)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1275,10 +1278,9 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
setSubworkflow(found)
|
setSubworkflow(found)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Failed in trigger selection: ", e)
|
console.log("Failed in trigger selection (4): ", e)
|
||||||
return
|
//return
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
const startNode = found.actions?.find((action) => action.id === workflow?.triggers[selectedTriggerIndex]?.parameters[3]?.value)
|
const startNode = found.actions?.find((action) => action.id === workflow?.triggers[selectedTriggerIndex]?.parameters[3]?.value)
|
||||||
@@ -2725,6 +2727,11 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const monitorUpdates = () => {
|
const monitorUpdates = () => {
|
||||||
|
if (cy === undefined || cy === null) {
|
||||||
|
console.log("No cy found to verify startnode.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
var firstnode = cy.getElementById(workflow.start);
|
var firstnode = cy.getElementById(workflow.start);
|
||||||
if (firstnode.length === 0) {
|
if (firstnode.length === 0) {
|
||||||
var found = false;
|
var found = false;
|
||||||
@@ -2822,10 +2829,12 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cy !== undefined && cy !== null) {
|
||||||
var curelements = cy.elements();
|
var curelements = cy.elements();
|
||||||
for (let i = 0; i < curelements.length; i++) {
|
for (let i = 0; i < curelements.length; i++) {
|
||||||
curelements[i].addClass("not-executing-highlight");
|
curelements[i].addClass("not-executing-highlight");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var headers = {
|
var headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -2836,6 +2845,11 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
headers["Org-Id"] = workflow.org_id
|
headers["Org-Id"] = workflow.org_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (workflow?.id === undefined || workflow?.id === null || workflow?.id?.length === 0) {
|
||||||
|
console.log("No workflow id found during execution")
|
||||||
|
workflow.id = props.match.params.key
|
||||||
|
}
|
||||||
|
|
||||||
const data = { execution_argument: executionArgument, start: startNode };
|
const data = { execution_argument: executionArgument, start: startNode };
|
||||||
// fetch(`${globalUrl}/api/v1/workflows/${props.match.params.key}/execute`,
|
// fetch(`${globalUrl}/api/v1/workflows/${props.match.params.key}/execute`,
|
||||||
fetch(`${globalUrl}/api/v1/workflows/${workflow.id}/execute`,
|
fetch(`${globalUrl}/api/v1/workflows/${workflow.id}/execute`,
|
||||||
@@ -4116,10 +4130,14 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
var execFound = new URLSearchParams(cursearch).get("execution_id");
|
var execFound = new URLSearchParams(cursearch).get("execution_id");
|
||||||
var sessionToken = new URLSearchParams(cursearch).get("session_token");
|
var sessionToken = new URLSearchParams(cursearch).get("session_token");
|
||||||
if (execFound === null && sessionToken === null) {
|
if (execFound === null && sessionToken === null) {
|
||||||
toast(`You don't have access to this workflow or loading failed. Redirecting to workflows in a few seconds..`)
|
|
||||||
|
toast.error(`You don't have access to this workflow or loading failed. Redirecting to workflows in a few seconds. If you recently deleted this workflow, speak with support@shuffler.io to recover it from a revision.`, {
|
||||||
|
autoClose: 10000,
|
||||||
|
})
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.pathname = "/workflows";
|
window.location.pathname = "/workflows";
|
||||||
}, 2000);
|
}, 2500);
|
||||||
|
|
||||||
} else if (sessionToken !== null && workflow_id === "3abdfb21-b40f-4e50-b855-ac0d62f83cbe") {
|
} else if (sessionToken !== null && workflow_id === "3abdfb21-b40f-4e50-b855-ac0d62f83cbe") {
|
||||||
toast(`Injecting session token and reloading workflow..`)
|
toast(`Injecting session token and reloading workflow..`)
|
||||||
@@ -4396,7 +4414,11 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
console.log("Node not found: ", target_id)
|
console.log("Node not found: ", target_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
cy.fit(null, 400);
|
cy.fit(null, 400);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Error in fitting (1): ", e)
|
||||||
|
}
|
||||||
cy.on("add", "node", (e) => onNodeAdded(e));
|
cy.on("add", "node", (e) => onNodeAdded(e));
|
||||||
cy.on("add", "edge", (e) => onEdgeAdded(e));
|
cy.on("add", "edge", (e) => onEdgeAdded(e));
|
||||||
} else {
|
} else {
|
||||||
@@ -4529,12 +4551,12 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
setSelectedApp({});
|
setSelectedApp({});
|
||||||
setSelectedComment({})
|
setSelectedComment({})
|
||||||
setSelectedEdge({})
|
setSelectedEdge({})
|
||||||
//setSelectedActionEnvironment({})
|
|
||||||
setTriggerAuthentication({})
|
setTriggerAuthentication({})
|
||||||
setLocalFirstrequest(true)
|
setLocalFirstrequest(true)
|
||||||
|
|
||||||
setSelectedTrigger({});
|
setSelectedTrigger({});
|
||||||
setSelectedTriggerIndex(-1)
|
setSelectedTriggerIndex(-1)
|
||||||
|
setSubworkflow({})
|
||||||
setUpdate(Math.random())
|
setUpdate(Math.random())
|
||||||
|
|
||||||
// Can be used for right side view
|
// Can be used for right side view
|
||||||
@@ -4635,7 +4657,12 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
console.log("DONE: ", workflow_id);
|
console.log("DONE: ", workflow_id);
|
||||||
getWorkflow(workflow_id.value, nodedata);
|
getWorkflow(workflow_id.value, nodedata);
|
||||||
|
|
||||||
|
try {
|
||||||
cy.fit(null, 300);
|
cy.fit(null, 300);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Error in fitting (2): ", e)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -6856,11 +6883,16 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
var found = false;
|
var found = false;
|
||||||
for (let branchkey in workflow.branches) {
|
for (let branchkey in workflow.branches) {
|
||||||
if (workflow.branches[branchkey].destination_id === edge.source && workflow.branches[branchkey].source_id === edge.target) {
|
if (workflow.branches[branchkey].destination_id === edge.source && workflow.branches[branchkey].source_id === edge.target) {
|
||||||
|
|
||||||
|
// Find the branch as well
|
||||||
|
const foundbranch = cy.getElementById(workflow.branches[branchkey].id)
|
||||||
|
if (foundbranch !== undefined && foundbranch !== null && foundbranch.data() !== undefined && foundbranch.data() !== null) {
|
||||||
toast("A branch in the opposite direction already exists")
|
toast("A branch in the opposite direction already exists")
|
||||||
event.target.remove()
|
event.target.remove()
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (workflow.branches[branchkey].destination_id === edge.target && workflow.branches[branchkey].source_id === edge.source) {
|
if (workflow.branches[branchkey].destination_id === edge.target && workflow.branches[branchkey].source_id === edge.source) {
|
||||||
|
|
||||||
@@ -7657,6 +7689,10 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
//if (nodedata.id === selectedAction.id || nodedata.id === selectedTrigger.id) {
|
//if (nodedata.id === selectedAction.id || nodedata.id === selectedTrigger.id) {
|
||||||
// return
|
// return
|
||||||
//}
|
//}
|
||||||
|
//
|
||||||
|
if (nodedata.name === "switch" || nodedata.app_id === "shuffle_agent") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var parsedStyle = {
|
var parsedStyle = {
|
||||||
"border-width": "1px",
|
"border-width": "1px",
|
||||||
@@ -7883,8 +7919,14 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
var parentNode = cy.$("#" + event.target.data("id"));
|
var parentNode = cy.$("#" + event.target.data("id"));
|
||||||
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
||||||
|
|
||||||
const px = parentNode.position("x") - 65;
|
var xDiff = 0
|
||||||
const py = parentNode.position("y") - 5;
|
var yDiff = 0
|
||||||
|
if (parentNode.data("app_id") === "shuffle_agent") {
|
||||||
|
xDiff = 70
|
||||||
|
}
|
||||||
|
|
||||||
|
const px = parentNode.position("x") - 65 - xDiff
|
||||||
|
const py = parentNode.position("y") - 5 - yDiff
|
||||||
const circleId = (newNodeId = uuidv4());
|
const circleId = (newNodeId = uuidv4());
|
||||||
|
|
||||||
parentNode.data("circleId", circleId);
|
parentNode.data("circleId", circleId);
|
||||||
@@ -8205,8 +8247,14 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
var parentNode = cy.$("#" + event.target.data("id"));
|
var parentNode = cy.$("#" + event.target.data("id"));
|
||||||
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
||||||
|
|
||||||
const px = parentNode.position("x") + 100;
|
var xDiff = 0
|
||||||
const py = parentNode.position("y") + 35;
|
var yDiff = 0
|
||||||
|
if (parentNode.data("app_id") === "shuffle_agent") {
|
||||||
|
xDiff = 70
|
||||||
|
}
|
||||||
|
|
||||||
|
const px = parentNode.position("x") + 100 - xDiff;
|
||||||
|
const py = parentNode.position("y") + 35 - yDiff;
|
||||||
const circleId = (newNodeId = uuidv4());
|
const circleId = (newNodeId = uuidv4());
|
||||||
|
|
||||||
parentNode.data("circleId", circleId);
|
parentNode.data("circleId", circleId);
|
||||||
@@ -8240,8 +8288,14 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
var parentNode = cy.$("#" + event.target.data("id"));
|
var parentNode = cy.$("#" + event.target.data("id"));
|
||||||
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
||||||
|
|
||||||
const px = parentNode.position("x") - 65;
|
var xDiff = 0
|
||||||
const py = parentNode.position("y") + 35;
|
var yDiff = 0
|
||||||
|
if (parentNode.data("app_id") === "shuffle_agent") {
|
||||||
|
xDiff = 70
|
||||||
|
}
|
||||||
|
|
||||||
|
const px = parentNode.position("x") - 65 - xDiff;
|
||||||
|
const py = parentNode.position("y") + 35 - yDiff;
|
||||||
const circleId = (newNodeId = uuidv4());
|
const circleId = (newNodeId = uuidv4());
|
||||||
|
|
||||||
parentNode.data("circleId", circleId);
|
parentNode.data("circleId", circleId);
|
||||||
@@ -8400,8 +8454,11 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
addCopyButton(event);
|
addCopyButton(event);
|
||||||
|
|
||||||
|
if (nodedata.app_id !== "shuffle_agent") {
|
||||||
addStartnodeButton(event);
|
addStartnodeButton(event);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// autocomplete
|
// autocomplete
|
||||||
// right click
|
// right click
|
||||||
@@ -8416,7 +8473,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodedata.name === "switch") {
|
if (nodedata.name === "switch" || nodedata.app_id === "shuffle_agent") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9105,7 +9162,12 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
// Reset view for cytoscape
|
// Reset view for cytoscape
|
||||||
if (cy !== undefined && cy !== null) {
|
if (cy !== undefined && cy !== null) {
|
||||||
cy.add(insertedNodes)
|
cy.add(insertedNodes)
|
||||||
|
|
||||||
|
try {
|
||||||
cy.fit(null, 250)
|
cy.fit(null, 250)
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error fitting cytoscape (3): ", error)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setElements(insertedNodes)
|
setElements(insertedNodes)
|
||||||
}
|
}
|
||||||
@@ -9314,6 +9376,8 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
if (responseJson === null) {
|
if (responseJson === null) {
|
||||||
//console.log("No revisions found")
|
//console.log("No revisions found")
|
||||||
|
|
||||||
|
//toast.warning("No revisions found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9502,7 +9566,11 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
// preview: true,
|
// preview: true,
|
||||||
|
|
||||||
|
try {
|
||||||
cy.fit(null, 400)
|
cy.fit(null, 400)
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error fitting cytoscape (4): ", error)
|
||||||
|
}
|
||||||
|
|
||||||
cy.on("boxselect", "node", (e) => {
|
cy.on("boxselect", "node", (e) => {
|
||||||
if (e.target.data("isButton") || e.target.data("isDescriptor") || e.target.data("isSuggestion")) {
|
if (e.target.data("isButton") || e.target.data("isDescriptor") || e.target.data("isSuggestion")) {
|
||||||
@@ -12210,7 +12278,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
// Add Shuffle DB with cache keys if available
|
// Add Shuffle DB with cache keys if available
|
||||||
let cacheKey = {
|
let cacheKey = {
|
||||||
type: "Shuffle DB",
|
type: "Shuffle DB",
|
||||||
name: "Shuffle DB",
|
name: "Shuffle Datastore",
|
||||||
value: "$shuffle_cache",
|
value: "$shuffle_cache",
|
||||||
highlight: "shuffle_cache",
|
highlight: "shuffle_cache",
|
||||||
autocomplete: "shuffle_cache",
|
autocomplete: "shuffle_cache",
|
||||||
@@ -17643,7 +17711,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
id="suborg-changer"
|
id="suborg-changer"
|
||||||
style={{ color: "rgba(255,255,255,0.7)", }}
|
style={{ color: "rgba(255,255,255,0.7)", }}
|
||||||
>
|
>
|
||||||
Select an Org
|
Select an Org ({originalWorkflow?.suborg_distribution?.length})
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
style={{
|
style={{
|
||||||
@@ -17662,12 +17730,12 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}}
|
}}
|
||||||
labelId="suborg-changer"
|
labelId="suborg-changer"
|
||||||
value={workflow.org_id}
|
value={workflow.org_id}
|
||||||
disabled={savingState !== 0 || suborgWorkflows?.length === 0}
|
disabled={savingState !== 0 || suborgWorkflows?.length === 0 || allTriggers === undefined}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (lastSaved === false && originalWorkflow.id === workflow.id) {
|
if (lastSaved === false && originalWorkflow.id === workflow.id) {
|
||||||
setSuborgWorkflows([])
|
setSuborgWorkflows([])
|
||||||
saveWorkflow(workflow, undefined, undefined, e.target.value)
|
saveWorkflow(workflow, undefined, undefined, e.target.value)
|
||||||
toast.warn("Saving workflow first due to detected changes. Please try to change workflow again when it is finished.", {
|
toast.warn(`Saving workflow first due to detected changes. If more than 10 auth`, {
|
||||||
autoClose: 2000,
|
autoClose: 2000,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -17693,6 +17761,7 @@ const AngularWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.unstable_batchedUpdates(() => {
|
ReactDOM.unstable_batchedUpdates(() => {
|
||||||
|
setAllTriggers(undefined)
|
||||||
setSelectedTriggerIndex(-1)
|
setSelectedTriggerIndex(-1)
|
||||||
getEnvironments(e.target.value)
|
getEnvironments(e.target.value)
|
||||||
getAppAuthentication(undefined, undefined, undefined, e.target.value)
|
getAppAuthentication(undefined, undefined, undefined, e.target.value)
|
||||||
|
|||||||
@@ -663,7 +663,7 @@ const ApiExplorerWrapper = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (validate.result.status === 404) {
|
} else if (validate.result.status === 404) {
|
||||||
toast.error("Page not found. Please try a different URL.")
|
//toast.error("Page not found. Please try a different URL.")
|
||||||
} else if (validate.result.error !== undefined && validate.result.error !== null && validate.result.error.length > 0) {
|
} else if (validate.result.error !== undefined && validate.result.error !== null && validate.result.error.length > 0) {
|
||||||
if (validate.result.error.toLowerCase().includes("max retries")) {
|
if (validate.result.error.toLowerCase().includes("max retries")) {
|
||||||
toast.error("Are you sure the URL is correct? It seems like the server is not responding.")
|
toast.error("Are you sure the URL is correct? It seems like the server is not responding.")
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ export const appCategories = [
|
|||||||
"name": "AI",
|
"name": "AI",
|
||||||
"color": "#FFC107",
|
"color": "#FFC107",
|
||||||
"icon": "AI",
|
"icon": "AI",
|
||||||
"action_labels": ["Answer Question", "Run Action"],
|
"action_labels": ["Answer Question", "Run Action", "Run LLM",],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Other",
|
"name": "Other",
|
||||||
|
|||||||
@@ -1215,7 +1215,7 @@ const DocsWrapper = memo(({isLoggedIn, isLoaded, children })=>{
|
|||||||
minWidth: isMobile ? null : (isLoggedIn && isLoaded) ? leftSideBarOpenByClick ? 800 : 900 : null, margin: "auto",
|
minWidth: isMobile ? null : (isLoggedIn && isLoaded) ? leftSideBarOpenByClick ? 800 : 900 : null, margin: "auto",
|
||||||
position: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? "relative" : "static",
|
position: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? "relative" : "static",
|
||||||
left: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? 120 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0,
|
left: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? 120 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0,
|
||||||
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick && (isLoggedIn && isLoaded) ? 160 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
|
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick && (isLoggedIn && isLoaded) ? 90 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
|
||||||
transition: "left 0.3s ease-in-out, min-width 0.3s ease-in-out, max-width 0.3s ease-in-out, position 0.3s ease-in-out, margin 0.3s ease-in-out, margin-left 0.3s ease"
|
transition: "left 0.3s ease-in-out, min-width 0.3s ease-in-out, max-width 0.3s ease-in-out, position 0.3s ease-in-out, margin 0.3s ease-in-out, margin-left 0.3s ease"
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
Chip,
|
Chip,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Fade,
|
Fade,
|
||||||
|
Skeleton,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -140,12 +141,166 @@ const UsecaseListComponent = (props) => {
|
|||||||
const [firstLoad, setFirstLoad] = useState(true)
|
const [firstLoad, setFirstLoad] = useState(true)
|
||||||
const [apps, setApps] = useState([])
|
const [apps, setApps] = useState([])
|
||||||
|
|
||||||
|
const [autoOpenUsecase, setAutoOpenUsecase] = useState(null);
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
const [mitreTags, setMitreTags] = useState([]);
|
const [mitreTags, setMitreTags] = useState([]);
|
||||||
|
|
||||||
|
// Add loading state
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
// Add this useEffect to handle URL parameters on load
|
||||||
|
useEffect(() => {
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
|
const params = Object.fromEntries(urlSearchParams.entries());
|
||||||
|
|
||||||
|
const selectedUsecase = params["selected_object"];
|
||||||
|
if (selectedUsecase && keys.length > 0) {
|
||||||
|
const usecaseName = selectedUsecase.toLowerCase().replaceAll("_", " ");
|
||||||
|
|
||||||
|
// Find the matching usecase in the keys
|
||||||
|
for (const category of keys) {
|
||||||
|
const foundUsecase = category.list.find(
|
||||||
|
usecase => usecase.name.toLowerCase().replaceAll("_", " ") === usecaseName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (foundUsecase) {
|
||||||
|
setAutoOpenUsecase(foundUsecase);
|
||||||
|
|
||||||
|
// Wait for render then scroll
|
||||||
|
setTimeout(() => {
|
||||||
|
const element = document.getElementById(usecaseName);
|
||||||
|
if (element) {
|
||||||
|
element.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "center",
|
||||||
|
inline: "center"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [keys]);
|
||||||
|
|
||||||
|
// Add useEffect to handle auto-opening
|
||||||
|
useEffect(() => {
|
||||||
|
if (autoOpenUsecase) {
|
||||||
|
getUsecase(autoOpenUsecase, 0, 0);
|
||||||
|
setAutoOpenUsecase(null);
|
||||||
|
}
|
||||||
|
}, [autoOpenUsecase]);
|
||||||
|
|
||||||
|
// Loading skeleton component
|
||||||
|
const LoadingSkeleton = () => (
|
||||||
|
<div style={{paddingTop: 75, minHeight: 1000, textAlign: "left"}}>
|
||||||
|
{/* Header skeleton */}
|
||||||
|
<Skeleton variant="text" width={200} height={40} sx={{ bgcolor: 'grey.800' }} />
|
||||||
|
<Skeleton variant="text" width="60%" height={24} sx={{ marginTop: 3, bgcolor: 'grey.800' }} />
|
||||||
|
|
||||||
|
{/* Apps selection skeleton */}
|
||||||
|
<Skeleton variant="text" width={150} height={24} sx={{ marginTop: 5, marginBottom: 10 }} />
|
||||||
|
<Paper style={{
|
||||||
|
height: 60,
|
||||||
|
width: "97.5%",
|
||||||
|
backgroundColor: theme.palette.platformColor,
|
||||||
|
borderRadius: theme.palette?.borderRadius || 5,
|
||||||
|
display: "flex",
|
||||||
|
padding: "0 25px",
|
||||||
|
}}>
|
||||||
|
{/* App icons skeleton */}
|
||||||
|
<div style={{flex: 10, display: "flex", gap: 25, alignItems: "center"}}>
|
||||||
|
{[1, 2, 3, 4, 5].map((app) => (
|
||||||
|
<Skeleton
|
||||||
|
key={app}
|
||||||
|
variant="circular"
|
||||||
|
width={40}
|
||||||
|
height={40}
|
||||||
|
sx={{ bgcolor: 'grey.800' }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{/* Add more apps button skeleton */}
|
||||||
|
<Skeleton
|
||||||
|
variant="rectangular"
|
||||||
|
width={150}
|
||||||
|
height={40}
|
||||||
|
sx={{
|
||||||
|
marginTop: "10px",
|
||||||
|
borderRadius: 20,
|
||||||
|
bgcolor: 'grey.800'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
{/* Usecase categories skeleton - 3 sections: Collect, Enrich, Detect */}
|
||||||
|
{[1, 2, 3,4,5].map((category) => (
|
||||||
|
<div key={category} style={{marginTop: category === 1 ? 20: 45}}>
|
||||||
|
{/* Category title with color indicator */}
|
||||||
|
<Typography variant="body1" style={{marginBottom: 15}}>
|
||||||
|
<Skeleton
|
||||||
|
variant="text"
|
||||||
|
width={200}
|
||||||
|
height={24}
|
||||||
|
sx={{
|
||||||
|
bgcolor: category === 1 ? '#f85a3e33' :
|
||||||
|
category === 2 ? '#ffb00d33' :
|
||||||
|
category === 3 ? '#2196f333' :
|
||||||
|
category === 4 ? '#4caf5033' :
|
||||||
|
category === 5 ? '#9c27b033' : '#00000033'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
{[1, 2, 3].map((item) => (
|
||||||
|
<Grid item xs={isMobile ? 12 : 4} key={item}>
|
||||||
|
<Paper
|
||||||
|
style={{
|
||||||
|
backgroundColor: theme.palette.platformColor,
|
||||||
|
borderRadius: theme.palette?.borderRadius || 5,
|
||||||
|
padding: "10px 20px",
|
||||||
|
height: 80,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 15
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* App icons container */}
|
||||||
|
<div style={{display: "flex", gap: 5}}>
|
||||||
|
<Skeleton
|
||||||
|
variant="circular"
|
||||||
|
width={30}
|
||||||
|
height={30}
|
||||||
|
sx={{ bgcolor: 'grey.800' }}
|
||||||
|
/>
|
||||||
|
<Skeleton
|
||||||
|
variant="circular"
|
||||||
|
width={30}
|
||||||
|
height={30}
|
||||||
|
sx={{ bgcolor: 'grey.800' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* Usecase title */}
|
||||||
|
<Skeleton
|
||||||
|
variant="text"
|
||||||
|
width="70%"
|
||||||
|
height={24}
|
||||||
|
sx={{ bgcolor: 'grey.800' }}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const parseUsecase = (subcase, inputFramework) => {
|
const parseUsecase = (subcase, inputFramework) => {
|
||||||
var useFramework = frameworkData
|
var useFramework = frameworkData
|
||||||
@@ -187,6 +342,7 @@ const UsecaseListComponent = (props) => {
|
|||||||
}, [frameworkData])
|
}, [frameworkData])
|
||||||
|
|
||||||
const loadApps = () => {
|
const loadApps = () => {
|
||||||
|
setIsLoading(true);
|
||||||
fetch(`${globalUrl}/api/v1/apps`, {
|
fetch(`${globalUrl}/api/v1/apps`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -220,9 +376,11 @@ const UsecaseListComponent = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setApps(responseJson);
|
setApps(responseJson);
|
||||||
|
setIsLoading(false);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log("App loading error: " + error.toString());
|
console.log("App loading error: " + error.toString());
|
||||||
|
setIsLoading(false);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,13 +389,21 @@ const UsecaseListComponent = (props) => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (keys === undefined || keys === null || keys.length === 0) {
|
if (keys === undefined || keys === null || keys.length === 0) {
|
||||||
return null
|
return <LoadingSkeleton />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Timeout 50ms to delay it slightly
|
// Timeout 50ms to delay it slightly
|
||||||
const getUsecase = (subcase, index, subindex) => {
|
const getUsecase = (subcase, index, subindex) => {
|
||||||
|
// Update URL with selected usecase
|
||||||
|
const usecaseName = subcase.name.toLowerCase().replaceAll(" ", "_")
|
||||||
|
const newUrl = `?selected_object=${usecaseName}`
|
||||||
|
|
||||||
|
// Force URL update even if it's the same usecase
|
||||||
|
navigate(newUrl, { replace: true })
|
||||||
|
|
||||||
|
// Parse and fetch usecase data
|
||||||
subcase = parseUsecase(subcase)
|
subcase = parseUsecase(subcase)
|
||||||
setPrevSubcase(subcase)
|
setPrevSubcase(subcase)
|
||||||
|
|
||||||
@@ -415,6 +581,19 @@ const UsecaseListComponent = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then, add a cleanup function for URL params when drawer closes
|
||||||
|
const handleUsecaseClose = () => {
|
||||||
|
// Remove the selected_object parameter from URL
|
||||||
|
navigate("/usecases", { replace: true })
|
||||||
|
|
||||||
|
// Reset relevant state
|
||||||
|
setInputUsecase({})
|
||||||
|
setExpandedIndex(-1)
|
||||||
|
setExpandedItem(-1)
|
||||||
|
setFirstLoad(false)
|
||||||
|
setSelectedWorkflows([])
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{paddingTop: 75, minHeight: 1000, textAlign: "left",}}>
|
<div style={{paddingTop: 75, minHeight: 1000, textAlign: "left",}}>
|
||||||
<Typography variant="h4" style={{color: "white", }}>
|
<Typography variant="h4" style={{color: "white", }}>
|
||||||
@@ -645,10 +824,10 @@ const UsecaseListComponent = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid id={fixedName} item xs={isMobile ? 12 : 4} key={subindex} style={{}} onClick={() => {
|
<Grid id={fixedName} item xs={isMobile ? 12 : 4} key={subindex} style={{}} onClick={() => {
|
||||||
if (fixedName === "reporting") {
|
// if (fixedName === "reporting") {
|
||||||
getUsecase(subcase, index, subindex)
|
// getUsecase(subcase, index, subindex)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
//setSelectedWorkflows([])
|
//setSelectedWorkflows([])
|
||||||
if (selectedItem) {
|
if (selectedItem) {
|
||||||
@@ -678,6 +857,8 @@ const UsecaseListComponent = (props) => {
|
|||||||
workflowBuilt={workflowBuilt}
|
workflowBuilt={workflowBuilt}
|
||||||
inputWorkflowId={workflowBuilt}
|
inputWorkflowId={workflowBuilt}
|
||||||
usecaseDetails={usecaseDetails}
|
usecaseDetails={usecaseDetails}
|
||||||
|
isModalOpenDefault={autoOpenUsecase?.name === subcase.name}
|
||||||
|
onClose={handleUsecaseClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -717,6 +898,7 @@ const Usecases2 = (props) => {
|
|||||||
window.location.host === "localhost:3002" ||
|
window.location.host === "localhost:3002" ||
|
||||||
window.location.host === "shuffler.io";
|
window.location.host === "shuffler.io";
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedUsecaseCategory.length === 0) {
|
if (selectedUsecaseCategory.length === 0) {
|
||||||
@@ -729,71 +911,8 @@ const Usecases2 = (props) => {
|
|||||||
}
|
}
|
||||||
}, [selectedUsecaseCategory])
|
}, [selectedUsecaseCategory])
|
||||||
|
|
||||||
const checkSelectedParams = () => {
|
|
||||||
const urlSearchParams = new URLSearchParams(window.location.search)
|
|
||||||
const params = Object.fromEntries(urlSearchParams.entries())
|
|
||||||
|
|
||||||
const curpath = typeof window === "undefined" || window.location === undefined ? "" : window.location.pathname;
|
|
||||||
const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
|
|
||||||
|
|
||||||
const foundQuery = params["selected"]
|
|
||||||
if (foundQuery !== null && foundQuery !== undefined) {
|
|
||||||
setSelectedUsecaseCategory(foundQuery)
|
|
||||||
|
|
||||||
const newitem = removeParam("selected", cursearch);
|
|
||||||
navigate(curpath + newitem)
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseItem = document.getElementById("reporting")
|
|
||||||
if (baseItem !== undefined && baseItem !== null) {
|
|
||||||
baseItem.click()
|
|
||||||
|
|
||||||
// Find close window button -> go to top
|
|
||||||
const foundButton = document.getElementById("close_selection")
|
|
||||||
if (foundButton !== undefined && foundButton !== null) {
|
|
||||||
foundButton.click()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll back to top
|
|
||||||
window.scrollTo(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const foundQuery2 = params["selected_object"]
|
|
||||||
if (foundQuery2 !== null && foundQuery2 !== undefined) {
|
|
||||||
// Take a random object, quickly click it, then go to this one
|
|
||||||
// Something is weird with loading apps without it
|
|
||||||
|
|
||||||
const queryName = foundQuery2.toLowerCase().replaceAll("_", " ")
|
|
||||||
// Waiting a bit for it to render
|
|
||||||
setTimeout(() => {
|
|
||||||
const foundItem = document.getElementById(queryName)
|
|
||||||
if (foundItem !== undefined && foundItem !== null) {
|
|
||||||
foundItem.click()
|
|
||||||
// Scroll to it
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
foundItem.scrollIntoView({
|
|
||||||
behavior: "smooth",
|
|
||||||
block: "center",
|
|
||||||
inline: "center"
|
|
||||||
})
|
|
||||||
}, 100)
|
|
||||||
} else {
|
|
||||||
//console.log("Couldn't find item with name ", queryName)
|
|
||||||
}
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (usecases.length > 0) {
|
|
||||||
//console.log(usecases)
|
|
||||||
checkSelectedParams()
|
|
||||||
}
|
|
||||||
}, [usecases])
|
|
||||||
|
|
||||||
const getFramework = () => {
|
const getFramework = () => {
|
||||||
|
setIsLoading(true);
|
||||||
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -831,6 +950,7 @@ const Usecases2 = (props) => {
|
|||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast(error.toString());
|
toast(error.toString());
|
||||||
|
setIsLoading(false);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ require (
|
|||||||
github.com/docker/docker v27.5.0+incompatible
|
github.com/docker/docker v27.5.0+incompatible
|
||||||
github.com/docker/go-connections v0.5.0
|
github.com/docker/go-connections v0.5.0
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/shuffle/shuffle-shared v0.7.92
|
github.com/shuffle/shuffle-shared v0.7.95
|
||||||
k8s.io/api v0.30.2
|
k8s.io/api v0.30.2
|
||||||
k8s.io/apimachinery v0.30.2
|
k8s.io/apimachinery v0.30.2
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ require (
|
|||||||
github.com/docker/docker v27.5.0+incompatible
|
github.com/docker/docker v27.5.0+incompatible
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/shuffle/shuffle-shared v0.7.92
|
github.com/shuffle/shuffle-shared v0.7.95
|
||||||
k8s.io/api v0.30.2
|
k8s.io/api v0.30.2
|
||||||
k8s.io/apimachinery v0.30.2
|
k8s.io/apimachinery v0.30.2
|
||||||
k8s.io/client-go v0.30.2
|
k8s.io/client-go v0.30.2
|
||||||
|
|||||||
Reference in New Issue
Block a user