Many fixes for frontend and backend related to Oauth2 and environment control
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"@mui/styles": "^5.14.0",
|
||||
"@mui/x-data-grid": "^5.17.11",
|
||||
"@mui/x-date-pickers": "^6.11.1",
|
||||
"@uiw/codemirror-theme-vscode": "^4.21.20",
|
||||
"@uiw/codemirror-themes": "^4.21.9",
|
||||
"@uiw/react-codemirror": "^4.21.9",
|
||||
"@use-it/interval": "^1.0.0",
|
||||
|
||||
@@ -269,35 +269,8 @@ const EditWorkflow = (props) => {
|
||||
/>
|
||||
</div>
|
||||
<div style={{display: "flex", marginTop: 10, }}>
|
||||
<MuiChipsInput
|
||||
style={{ flex: 1, maxHeight: 40, }}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
placeholder="Tags"
|
||||
color="primary"
|
||||
fullWidth
|
||||
value={newWorkflowTags}
|
||||
onChange={(chip) => {
|
||||
console.log("Chip: ", chip)
|
||||
//newWorkflowTags.push(chip);
|
||||
setNewWorkflowTags(chip);
|
||||
}}
|
||||
onAdd={(chip) => {
|
||||
newWorkflowTags.push(chip);
|
||||
setNewWorkflowTags(newWorkflowTags);
|
||||
}}
|
||||
onDelete={(chip, index) => {
|
||||
console.log("Deleting: ", chip, index)
|
||||
newWorkflowTags.splice(index, 1);
|
||||
setNewWorkflowTags(newWorkflowTags);
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
/>
|
||||
{usecases !== null && usecases !== undefined && usecases.length > 0 ?
|
||||
<FormControl style={{flex: 1, marginLeft: 5, }}>
|
||||
<FormControl style={{flex: 1, marginRight: 5,}}>
|
||||
<InputLabel htmlFor="grouped-select-usecase">Usecases</InputLabel>
|
||||
<Select
|
||||
defaultValue=""
|
||||
@@ -350,6 +323,33 @@ const EditWorkflow = (props) => {
|
||||
</Select>
|
||||
</FormControl>
|
||||
: null}
|
||||
<MuiChipsInput
|
||||
style={{ flex: 1, maxHeight: 120, overflow: "auto",}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
placeholder="Tags"
|
||||
color="primary"
|
||||
fullWidth
|
||||
value={newWorkflowTags}
|
||||
onChange={(chip) => {
|
||||
console.log("Chip: ", chip)
|
||||
//newWorkflowTags.push(chip);
|
||||
setNewWorkflowTags(chip);
|
||||
}}
|
||||
onAdd={(chip) => {
|
||||
newWorkflowTags.push(chip);
|
||||
setNewWorkflowTags(newWorkflowTags);
|
||||
}}
|
||||
onDelete={(chip, index) => {
|
||||
console.log("Deleting: ", chip, index)
|
||||
newWorkflowTags.splice(index, 1);
|
||||
setNewWorkflowTags(newWorkflowTags);
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showMoreClicked === true ?
|
||||
@@ -365,7 +365,8 @@ const EditWorkflow = (props) => {
|
||||
onChange={(e) => {
|
||||
console.log("Data: ", e.target.value)
|
||||
|
||||
innerWorkflow.workflow_type = e.target.value
|
||||
//innerWorkflow.workflow_type = e.target.value
|
||||
innerWorkflow.status = e.target.value
|
||||
setInnerWorkflow(innerWorkflow)
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1352,14 +1352,17 @@ const Header = (props) => {
|
||||
);
|
||||
|
||||
// <Divider style={{height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
|
||||
return !isMobile ?
|
||||
isLoggedIn ?
|
||||
//
|
||||
/*
|
||||
!isLoggedIn ?
|
||||
<div style={{minHeight: 68, maxHeight: 68, backgroundColor: theme.palette.backgroundColor, }}>
|
||||
<BrowserView style={{position: "sticky", top: 0, }}>
|
||||
{loginTextBrowser}
|
||||
</BrowserView>
|
||||
</div>
|
||||
:
|
||||
*/
|
||||
return !isMobile ?
|
||||
<AppBar
|
||||
position="sticky"
|
||||
color="transparent"
|
||||
|
||||
@@ -112,8 +112,6 @@ const AuthenticationOauth2 = (props) => {
|
||||
authenticationType.client_secret.length > 0
|
||||
);
|
||||
|
||||
console.log("AUTH: ", authenticationType)
|
||||
|
||||
const [clientId, setClientId] = React.useState(defaultConfigSet ? authenticationType.client_id : "");
|
||||
const [clientSecret, setClientSecret] = React.useState(defaultConfigSet ? authenticationType.client_secret : "");
|
||||
|
||||
@@ -125,7 +123,7 @@ const AuthenticationOauth2 = (props) => {
|
||||
const [offlineAccess, setOfflineAccess] = React.useState(true);
|
||||
|
||||
const allscopes = authenticationType.scope !== undefined && authenticationType.scope !== null ? authenticationType.scope : [];
|
||||
const [selectedScopes, setSelectedScopes] = React.useState(allscopes !== null && allscopes !== undefined ? allscopes.length > 0 && allscopes.length <= 3 ? [allscopes[0]] : [] : [])
|
||||
const [selectedScopes, setSelectedScopes] = React.useState(allscopes !== null && allscopes !== undefined ? allscopes.length > 0 && allscopes.length <= 3 ? allscopes : [] : [])
|
||||
|
||||
const [manuallyConfigure, setManuallyConfigure] = React.useState(
|
||||
defaultConfigSet ? false : true
|
||||
@@ -303,6 +301,23 @@ const AuthenticationOauth2 = (props) => {
|
||||
if ((authenticationType.redirect_uri === undefined || authenticationType.redirect_uri === null || authenticationType.redirect_uri.length === 0) && (authenticationType.token_uri !== undefined && authenticationType.token_uri !== null && authenticationType.token_uri.length > 0)) {
|
||||
console.log("No redirect URI found, and token URI found. Assuming client credentials flow and saving directly in the database")
|
||||
|
||||
|
||||
var tokenUri = authenticationType.token_uri;
|
||||
if (oauthUrl !== undefined && oauthUrl !== null && oauthUrl.length > 0 && selectedApp !== undefined && selectedApp !== null) {
|
||||
var same = false
|
||||
for (var i = 0; i < selectedApp.authentication.parameters.length; i++) {
|
||||
const param = selectedApp.authentication.parameters[i];
|
||||
if (param.name === "url" && (param.value === oauthUrl || param.example === oauthUrl)) {
|
||||
same = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!same) {
|
||||
tokenUri = oauthUrl
|
||||
}
|
||||
}
|
||||
|
||||
// Find app.configuration=true fields in the app.paramters
|
||||
var parsedFields = [{
|
||||
"key": "client_id",
|
||||
@@ -318,7 +333,7 @@ const AuthenticationOauth2 = (props) => {
|
||||
},
|
||||
{
|
||||
"key": "token_uri",
|
||||
"value": authenticationType.token_uri,
|
||||
"value": tokenUri,
|
||||
}]
|
||||
|
||||
if (authenticationType.grant_type !== undefined && authenticationType.grant_type !== null && authenticationType.grant_type.length > 0) {
|
||||
@@ -360,14 +375,14 @@ const AuthenticationOauth2 = (props) => {
|
||||
"reference_workflow": workflowId,
|
||||
}
|
||||
|
||||
setNewAppAuth(appAuthData)
|
||||
setNewAppAuth(appAuthData, true)
|
||||
|
||||
// Wait 1 second, then get app auth with update
|
||||
//
|
||||
if (getAppAuthentication !== undefined) {
|
||||
setTimeout(() => {
|
||||
getAppAuthentication(true, true, true);
|
||||
}, 1000)
|
||||
}
|
||||
//if (getAppAuthentication !== undefined) {
|
||||
// setTimeout(() => {
|
||||
// getAppAuthentication(true, true, true);
|
||||
// }, 1000)
|
||||
//}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -397,8 +412,6 @@ const AuthenticationOauth2 = (props) => {
|
||||
}
|
||||
|
||||
const authentication_url = authenticationType.token_uri;
|
||||
//console.log("AUTH: ", authenticationType)
|
||||
//console.log("SCOPES2: ", resources)
|
||||
const redirectUri = `${window.location.protocol}//${window.location.host}/set_authentication`;
|
||||
const workflowId = workflow !== undefined ? workflow.id : "";
|
||||
var state = `workflow_id%3D${workflowId}%26reference_action_id%3d${selectedAction.app_id}%26app_name%3d${selectedAction.app_name}%26app_id%3d${selectedAction.app_id}%26app_version%3d${selectedAction.app_version}%26authentication_url%3d${authentication_url}%26scope%3d${resources}%26client_id%3d${client_id}%26client_secret%3d${client_secret}`;
|
||||
@@ -523,7 +536,6 @@ const AuthenticationOauth2 = (props) => {
|
||||
}
|
||||
|
||||
const handleSubmitCheck = () => {
|
||||
console.log("NEW AUTH: ", authenticationOption);
|
||||
if (authenticationOption.label.length === 0) {
|
||||
authenticationOption.label = `Auth for ${selectedApp.name}`;
|
||||
//toast("Label can't be empty")
|
||||
@@ -673,7 +685,7 @@ const AuthenticationOauth2 = (props) => {
|
||||
)}
|
||||
</Button>
|
||||
|
||||
if (authButtonOnly === true && (authenticationType.grant_type === undefined || authenticationType.grant_type === null || authenticationType.grant_type === "")) {
|
||||
if (authButtonOnly === true && (authenticationType.redirect_uri !== undefined && authenticationType.redirect_uri !== null && authenticationType.redirect_uri.length > 0) && (authenticationType.token_uri !== undefined && authenticationType.token_uri !== null && authenticationType.token_uri.length > 0)) {
|
||||
return autoAuthButton
|
||||
}
|
||||
|
||||
@@ -777,10 +789,14 @@ const AuthenticationOauth2 = (props) => {
|
||||
setOauthUrl(data.value);
|
||||
}
|
||||
|
||||
const defaultValue = data.name === "url" && authenticationType.token_uri !== undefined && authenticationType.token_uri !== null && authenticationType.token_uri.length > 0 && (authenticationType.authorizationUrl === undefined || authenticationType.authorizationUrl === null || authenticationType.authorizationUrl.length === 0) ? authenticationType.token_uri : data.value === undefined || data.value === null ? "" : data.value
|
||||
const fieldname = data.name === "url" && authenticationType.grant_type !== undefined && authenticationType.grant_type !== null && authenticationType.grant_type.length > 0 ? "Token URL" : data.name
|
||||
|
||||
return (
|
||||
<div key={index} style={{ marginTop: 10 }}>
|
||||
<LockOpenIcon style={{ marginRight: 10 }} />
|
||||
<b>{data.name}</b>
|
||||
|
||||
<b>{fieldname}</b>
|
||||
|
||||
{data.schema !== undefined &&
|
||||
data.schema !== null &&
|
||||
@@ -793,6 +809,7 @@ const AuthenticationOauth2 = (props) => {
|
||||
}}
|
||||
defaultValue={"false"}
|
||||
fullWidth
|
||||
label={fieldname}
|
||||
onChange={(e) => {
|
||||
console.log("Value: ", e.target.value);
|
||||
authenticationOption.fields[data.name] = e.target.value;
|
||||
@@ -842,16 +859,11 @@ const AuthenticationOauth2 = (props) => {
|
||||
: "text"
|
||||
}
|
||||
color="primary"
|
||||
defaultValue={
|
||||
data.value !== undefined && data.value !== null
|
||||
? data.value
|
||||
: ""
|
||||
}
|
||||
defaultValue={defaultValue}
|
||||
placeholder={data.example}
|
||||
onChange={(event) => {
|
||||
authenticationOption.fields[data.name] =
|
||||
event.target.value;
|
||||
console.log("Setting oauth url");
|
||||
authenticationOption.fields[data.name] = event.target.value;
|
||||
console.log("Setting oauth url: ", event.target.value);
|
||||
setOauthUrl(event.target.value);
|
||||
//const [oauthUrl, setOauthUrl] = React.useState("")
|
||||
}}
|
||||
|
||||
@@ -181,6 +181,8 @@ const ParsedAction = (props) => {
|
||||
const [fieldCount, setFieldCount] = React.useState(0);
|
||||
const [hiddenDescription, setHiddenDescription] = React.useState(true);
|
||||
|
||||
const [autoCompleting, setAutocompleting] = React.useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (setLastSaved !== undefined) {
|
||||
@@ -2909,9 +2911,11 @@ const ParsedAction = (props) => {
|
||||
marginLeft: 15,
|
||||
paddingRight: 0,
|
||||
}}
|
||||
disabled={autoCompleting}
|
||||
onClick={() => {
|
||||
// aiSubmit(aiMsg, undefined, undefined, newSelectedAction)
|
||||
aiSubmit("Fill based on previous values", undefined, undefined, selectedAction)
|
||||
setAutocompleting(true)
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
@@ -2919,7 +2923,11 @@ const ParsedAction = (props) => {
|
||||
title={"Autocompletes fields. Uses NAME of the action and previous values' results."}
|
||||
placement="top"
|
||||
>
|
||||
{autoCompleting ?
|
||||
<CircularProgress style={{height: 20, width: 20, }} />
|
||||
:
|
||||
<AutoFixHighIcon style={{ color: "rgba(255,255,255,0.7)", height: 24, }} />
|
||||
}
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
@@ -315,16 +315,26 @@ const RuntimeDebugger = (props) => {
|
||||
)
|
||||
},
|
||||
},
|
||||
{ field: 'startTimestamp', headerName: 'Start time', width: 160, },
|
||||
{ field: 'endTimestamp', headerName: 'End time', width: 160, },
|
||||
{ field: 'startTimestamp', headerName: 'Start time (UTC)', width: 160, },
|
||||
{ field: 'endTimestamp', headerName: 'End time (UTC)', width: 160, },
|
||||
{
|
||||
field: 'id',
|
||||
headerName: 'Explore',
|
||||
width: 65,
|
||||
renderCell: (params) => (
|
||||
<Link href={`/workflows/${params.row.workflow.id}?execution_id=${params.row.id}`} target="_blank" rel="noopener noreferrer">
|
||||
<OpenInNewIcon fontSize="small" />
|
||||
</Link>
|
||||
<Tooltip arrow placement="right" title={
|
||||
<Typography variant="body2" style={{whiteSpace: "pre-line", }}>
|
||||
{params.row.result !== null && params.row.result !== undefined && params.row.result !== "" ?
|
||||
params.row.result
|
||||
:
|
||||
null
|
||||
}
|
||||
</Typography>
|
||||
} >
|
||||
<Link href={`/workflows/${params.row.workflow.id}?execution_id=${params.row.id}`} target="_blank" rel="noopener noreferrer">
|
||||
<OpenInNewIcon fontSize="small" />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -22,6 +22,7 @@ import { isMobile } from "react-device-detect"
|
||||
import { NestedMenuItem } from "mui-nested-menu"
|
||||
import { GetParsedPaths, FindJsonPath } from "../views/Apps.jsx";
|
||||
import { SetJsonDotnotation } from "../views/AngularWorkflow.jsx";
|
||||
import { vscodeDark, vscodeDarkInit } from '@uiw/codemirror-theme-vscode';
|
||||
|
||||
import {
|
||||
FullscreenExit as FullscreenExitIcon,
|
||||
@@ -82,6 +83,7 @@ const pythonFilters = [
|
||||
{"name": "Handle JSON", "value": `{% python %}\nimport json\njsondata = json.loads(r"""$nodename""")\n{% endpython %}`, "example": ``},
|
||||
]
|
||||
|
||||
/*
|
||||
const shuffleTheme = createTheme({
|
||||
theme: 'dark',
|
||||
settings: {
|
||||
@@ -110,6 +112,7 @@ const shuffleTheme = createTheme({
|
||||
{ tag: t.attributeName, color: '#5c6166' },
|
||||
],
|
||||
});
|
||||
*/
|
||||
|
||||
const CodeEditor = (props) => {
|
||||
const {
|
||||
@@ -547,7 +550,7 @@ const CodeEditor = (props) => {
|
||||
var code_lines = localcodedata.split('\n')
|
||||
for (var i = 0; i < code_lines.length; i++){
|
||||
var current_code_line = code_lines[i]
|
||||
// console.log(current_code_line)
|
||||
console.log("Codeline: ", current_code_line)
|
||||
|
||||
var variable_occurence = current_code_line.match(/[\\]{0,1}[$]{1}([a-zA-Z0-9_-]+\.?){1}([a-zA-Z0-9#_-]+\.?){0,}/g)
|
||||
|
||||
@@ -609,9 +612,10 @@ const CodeEditor = (props) => {
|
||||
const fixedVariable = fixVariable(variable_occurence[occ])
|
||||
var correctVariable = availableVariables.includes(fixedVariable)
|
||||
if(!correctVariable) {
|
||||
console.log("Line: ", i, "ch: ", dollar_occurence[occ])
|
||||
|
||||
value.markText({line:i, ch:dollar_occurence[occ]}, {line:i, ch:dollar_occurence_len[occ]+dollar_occurence[occ]}, {"css": "background-color: rgb(248, 106, 62, 0.9); padding-top: 2px; padding-bottom: 2px; color: white"})
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
value.markText({line:i, ch:dollar_occurence[occ]}, {line:i, ch:dollar_occurence_len[occ]+dollar_occurence[occ]}, {"css": "background-color: #8b8e26; padding-top: 2px; padding-bottom: 2px; color: white"})
|
||||
}
|
||||
// console.log(correctVariables)
|
||||
@@ -674,36 +678,33 @@ const CodeEditor = (props) => {
|
||||
try {
|
||||
for (var i = 0; i < found.length; i++) {
|
||||
try {
|
||||
// For found specifically, should replace .#\d with .# with regex
|
||||
|
||||
|
||||
//found[i] = found[i].toLowerCase()
|
||||
const fixedVariable = fixVariable(found[i])
|
||||
//var correctVariable = availableVariables.includes(fixedVariable)
|
||||
|
||||
//
|
||||
var valuefound = false
|
||||
for (var j = 0; j < actionlist.length; j++) {
|
||||
if(fixedVariable.slice(1,).toLowerCase() === actionlist[j].autocomplete.toLowerCase()){
|
||||
valuefound = true
|
||||
if(fixedVariable.slice(1,).toLowerCase() !== actionlist[j].autocomplete.toLowerCase()){
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof actionlist[j].example === "object") {
|
||||
input = input.replace(found[i], JSON.stringify(actionlist[j].example), -1);
|
||||
valuefound = true
|
||||
|
||||
} else if (actionlist[j].example.trim().startsWith("{") || actionlist[j].example.trim().startsWith("[")) {
|
||||
input = input.replace(found[i], JSON.stringify(actionlist[j].example), -1);
|
||||
} else {
|
||||
input = input.replace(found[i], actionlist[j].example, -1)
|
||||
}
|
||||
} catch (e) {
|
||||
try {
|
||||
if (typeof actionlist[j].example === "object") {
|
||||
input = input.replace(found[i], JSON.stringify(actionlist[j].example), -1);
|
||||
|
||||
} else if (actionlist[j].example.trim().startsWith("{") || actionlist[j].example.trim().startsWith("[")) {
|
||||
input = input.replace(found[i], JSON.stringify(actionlist[j].example), -1);
|
||||
} else {
|
||||
input = input.replace(found[i], actionlist[j].example, -1)
|
||||
}
|
||||
} else {
|
||||
// Couldn't find the correct example value
|
||||
} catch (e) {
|
||||
input = input.replace(found[i], actionlist[j].example, -1)
|
||||
}
|
||||
}
|
||||
|
||||
//if (!valuefound) {
|
||||
// console.log("Couldn't find value "+fixedVariable)
|
||||
//}
|
||||
|
||||
if (!valuefound && availableVariables.includes(fixedVariable)) {
|
||||
var shouldbreak = false
|
||||
for (var k=0; k < actionlist.length; k++){
|
||||
@@ -714,46 +715,48 @@ const CodeEditor = (props) => {
|
||||
|
||||
for (var key in parsedPaths) {
|
||||
const fullpath = "$"+actionlist[k].autocomplete.toLowerCase()+parsedPaths[key].autocomplete
|
||||
if (fullpath === fixedVariable) {
|
||||
//if (actionlist[k].example === undefined) {
|
||||
// actionlist[k].example = "TMP"
|
||||
//}
|
||||
if (fullpath !== fixedVariable) {
|
||||
continue
|
||||
}
|
||||
|
||||
var new_input = ""
|
||||
try {
|
||||
new_input = FindJsonPath(fullpath, actionlist[k].example)
|
||||
} catch (e) {
|
||||
console.log("ERR IN INPUT: ", e)
|
||||
}
|
||||
//if (actionlist[k].example === undefined) {
|
||||
// actionlist[k].example = "TMP"
|
||||
//}
|
||||
|
||||
//console.log("Got output for: ", fullpath, new_input, actionlist[k].example, typeof new_input)
|
||||
var new_input = ""
|
||||
try {
|
||||
new_input = FindJsonPath(fullpath, actionlist[k].example)
|
||||
} catch (e) {
|
||||
console.log("ERR IN INPUT: ", e)
|
||||
}
|
||||
|
||||
if (typeof new_input === "object") {
|
||||
new_input = JSON.stringify(new_input)
|
||||
console.log("Got output for: ", fullpath, new_input, actionlist[k].example, typeof new_input)
|
||||
|
||||
if (typeof new_input === "object") {
|
||||
new_input = JSON.stringify(new_input)
|
||||
} else {
|
||||
if (typeof new_input === "string") {
|
||||
new_input = new_input
|
||||
} else {
|
||||
if (typeof new_input === "string") {
|
||||
new_input = new_input
|
||||
} else {
|
||||
console.log("NO TYPE? ", typeof new_input)
|
||||
try {
|
||||
new_input = new_input.toString()
|
||||
} catch (e) {
|
||||
new_input = ""
|
||||
}
|
||||
console.log("NO TYPE? ", typeof new_input)
|
||||
try {
|
||||
new_input = new_input.toString()
|
||||
} catch (e) {
|
||||
new_input = ""
|
||||
}
|
||||
}
|
||||
|
||||
//console.log("FOUND2: ", fixedVariable, actionlist[j].example)
|
||||
input = input.replace(fixedVariable, new_input, -1)
|
||||
input = input.replace(found[i], new_input, -1)
|
||||
|
||||
//} catch (e) {
|
||||
// input = input.replace(found[i], actionlist[k].example)
|
||||
//}
|
||||
|
||||
shouldbreak = true
|
||||
break
|
||||
}
|
||||
|
||||
//console.log("FOUND2: ", fixedVariable, actionlist[j].example)
|
||||
input = input.replace(fixedVariable, new_input, -1)
|
||||
input = input.replace(found[i], new_input, -1)
|
||||
|
||||
//} catch (e) {
|
||||
// input = input.replace(found[i], actionlist[k].example)
|
||||
//}
|
||||
|
||||
shouldbreak = true
|
||||
break
|
||||
}
|
||||
|
||||
if (shouldbreak) {
|
||||
@@ -766,7 +769,7 @@ const CodeEditor = (props) => {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
//console.log("Outer replace error: ", e)
|
||||
console.log("Outer replace error: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,7 +898,7 @@ const CodeEditor = (props) => {
|
||||
aria-labelledby="draggable-code-modal"
|
||||
disableBackdropClick={true}
|
||||
disableEnforceFocus={true}
|
||||
//style={{ pointerEvents: "none" }}
|
||||
//style={{ pointerEvents: "none" }}
|
||||
hideBackdrop={true}
|
||||
open={expansionModalOpen}
|
||||
onClose={() => {
|
||||
@@ -964,6 +967,7 @@ const CodeEditor = (props) => {
|
||||
}}
|
||||
>
|
||||
<div style={{display: "flex"}}>
|
||||
{/*
|
||||
<DialogTitle
|
||||
id="draggable-dialog-title"
|
||||
style={{
|
||||
@@ -974,59 +978,9 @@ const CodeEditor = (props) => {
|
||||
>
|
||||
Code Editor
|
||||
</DialogTitle>
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: isMobile ? "80%" : 350,
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
onClick={() => {
|
||||
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Test Liquid in the playground"}
|
||||
placement="top"
|
||||
>
|
||||
<a
|
||||
href="https://pwwang.github.io/liquidpy/playground/"
|
||||
rel="norefferer"
|
||||
target="_blank"
|
||||
>
|
||||
<ExtensionIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
style={{
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
disabled={isAiLoading}
|
||||
onClick={() => {
|
||||
autoFormat(localcodedata)
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Auto format data"}
|
||||
placement="top"
|
||||
>
|
||||
{isAiLoading ?
|
||||
<CircularProgress style={{height: 20, width: 20, color: "rgba(255,255,255,0.7)"}}/>
|
||||
:
|
||||
<AutoFixHighIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
}
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
*/}
|
||||
{ isFileEditor ? null :
|
||||
<div style={{display: "flex"}}>
|
||||
<div style={{display: "flex", maxHeight: 40, }}>
|
||||
<Button
|
||||
id="basic-button"
|
||||
aria-haspopup="true"
|
||||
@@ -1035,7 +989,7 @@ const CodeEditor = (props) => {
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
style={{
|
||||
textTransform: "none",
|
||||
textTransform: "none",
|
||||
width: 100,
|
||||
}}
|
||||
onClick={(event) => {
|
||||
@@ -1143,9 +1097,9 @@ const CodeEditor = (props) => {
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
style={{
|
||||
textTransform: "none",
|
||||
textTransform: "none",
|
||||
width: 130,
|
||||
marginLeft: 170,
|
||||
marginLeft: 20,
|
||||
}}
|
||||
onClick={(event) => {
|
||||
setMenuPosition({
|
||||
@@ -1393,28 +1347,86 @@ const CodeEditor = (props) => {
|
||||
</Menu>
|
||||
</div>
|
||||
}
|
||||
<span style={{
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: isMobile ? "80%" : 30,
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
onClick={() => {
|
||||
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Test Liquid in the playground"}
|
||||
placement="top"
|
||||
>
|
||||
<a
|
||||
href="https://pwwang.github.io/liquidpy/playground/"
|
||||
rel="norefferer"
|
||||
target="_blank"
|
||||
>
|
||||
<ExtensionIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
style={{
|
||||
height: 50,
|
||||
width: 50,
|
||||
}}
|
||||
disabled={isAiLoading}
|
||||
onClick={() => {
|
||||
autoFormat(localcodedata)
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={"Auto format data"}
|
||||
placement="top"
|
||||
>
|
||||
{isAiLoading ?
|
||||
<CircularProgress style={{height: 20, width: 20, color: "rgba(255,255,255,0.7)"}}/>
|
||||
:
|
||||
<AutoFixHighIcon style={{color: "rgba(255,255,255,0.7)"}}/>
|
||||
}
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
|
||||
<div style={{
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
position: "relative",
|
||||
paddingTop: 0,
|
||||
minHeight: 548,
|
||||
overflow: "hidden",
|
||||
}}>
|
||||
<CodeMirror
|
||||
theme={vscodeDark}
|
||||
value={localcodedata}
|
||||
height={isFileEditor ? 450 : 525}
|
||||
height={isFileEditor ? 450 : 500}
|
||||
width={isFileEditor ? 650 : 600}
|
||||
style={{
|
||||
maxWidth: isFileEditor ? 450 : 500,
|
||||
maxWidth: isFileEditor ? 450 : 600,
|
||||
maxHeight: 548,
|
||||
minHeight: 548,
|
||||
wordBreak: "break-word",
|
||||
marginTop: 0,
|
||||
paddingTop: 0,
|
||||
backgroundColor: "rgba(40,40,40,1)",
|
||||
minHeight: 470,
|
||||
paddingBottom: 10,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onCursorActivity = {(value) => {
|
||||
// console.log(value.getCursor())
|
||||
console.log("CURSOR: ", value.getCursor())
|
||||
setCurrentCharacter(value.getCursor().ch)
|
||||
setCurrentLine(value.getCursor().line)
|
||||
// console.log(value.getCursor().ch, value.getCursor().line)
|
||||
findIndex(value.getCursor().line, value.getCursor().ch)
|
||||
|
||||
highlight_variables(value)
|
||||
}}
|
||||
onChange={(value, viewUpdate) => {
|
||||
@@ -1422,20 +1434,19 @@ const CodeEditor = (props) => {
|
||||
setlocalcodedata(value)
|
||||
expectedOutput(value)
|
||||
|
||||
highlight_variables(value)
|
||||
|
||||
//if(value.display.input.prevInput.startsWith('$') || value.display.input.prevInput.endsWith('$')){
|
||||
// setEditorPopupOpen(true)
|
||||
//}
|
||||
}}
|
||||
extensions={[]}//indentWithTab]}
|
||||
theme={shuffleTheme}
|
||||
options={{
|
||||
styleSelectedText: true,
|
||||
keyMap: 'sublime',
|
||||
mode: validation === true ? "json" : "python",
|
||||
lineWrapping: linewrap,
|
||||
theme: vscodeDark,
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/*editorPopupOpen ?
|
||||
<Paper
|
||||
@@ -1550,13 +1561,14 @@ const CodeEditor = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{flex: 1, marginLeft: 25, }}>
|
||||
<div style={{flex: 1, marginLeft: 5, borderLeft: "1px solid rgba(255,255,255,0.3)", paddingLeft: 5, }}>
|
||||
{isFileEditor ? null :
|
||||
<div>
|
||||
{isMobile ? null :
|
||||
<DialogTitle
|
||||
style={{
|
||||
paddingLeft: 10,
|
||||
paddingTop: 0,
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
@@ -1564,7 +1576,7 @@ const CodeEditor = (props) => {
|
||||
Expected Output
|
||||
</span>
|
||||
|
||||
<IconButton disabled={executing} color="primary" style={{border: `1px solid ${theme.palette.primary.main}`, marginLeft: 100, padding: 8}} variant="contained" onClick={() => {
|
||||
<IconButton disabled={executing} color="secondary" style={{border: `1px solid ${theme.palette.primary.main}`, marginLeft: 250, padding: 8}} variant="contained" onClick={() => {
|
||||
executeSingleAction(expOutput)
|
||||
}}>
|
||||
<Tooltip title="Try it! This runs the Shuffle Tools 'repeat back to me' or 'execute python' action with what you see in the expected output window. Commonly used to test your Python scripts or Liquid filters, not requiring the full workflow to run again." placement="top">
|
||||
@@ -1613,8 +1625,8 @@ const CodeEditor = (props) => {
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
maxHeight: 500,
|
||||
minHeight: 500,
|
||||
minWidth: 500,
|
||||
maxWidth: 500,
|
||||
minWidth: 580,
|
||||
maxWidth: 580,
|
||||
overflow: "auto",
|
||||
whiteSpace: "pre-wrap",
|
||||
}}
|
||||
|
||||
+108
-54
@@ -16,6 +16,7 @@ import {
|
||||
OutlinedInput,
|
||||
Checkbox,
|
||||
Card,
|
||||
Chip,
|
||||
Tooltip,
|
||||
FormControlLabel,
|
||||
Typography,
|
||||
@@ -485,6 +486,14 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
return `mailto:${admins}?bcc=frikky@shuffler.io,binu@shuffler.io&subject=${subject}&body=${body}`
|
||||
}
|
||||
|
||||
|
||||
const changeDistribution = (data) => {
|
||||
//changeDistributed(data, !isDistributed)
|
||||
console.log("Should change distribution to be shared among suborgs")
|
||||
|
||||
editAuthenticationConfig(data.id, "suborg_distribute")
|
||||
}
|
||||
|
||||
const deleteAuthentication = (data) => {
|
||||
toast("Deleting auth " + data.label);
|
||||
|
||||
@@ -800,10 +809,10 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
});
|
||||
};
|
||||
|
||||
const editAuthenticationConfig = (id) => {
|
||||
const editAuthenticationConfig = (id, parentAction) => {
|
||||
const data = {
|
||||
id: id,
|
||||
action: "assign_everywhere",
|
||||
action: parentAction !== undefined && parentAction !== null ? parentAction : "assign_everywhere",
|
||||
};
|
||||
const url = globalUrl + "/api/v1/apps/authentication/" + id + "/config";
|
||||
|
||||
@@ -821,9 +830,9 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
.then((response) =>
|
||||
response.json().then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
toast("Failed overwriting appauth in workflows");
|
||||
toast("Failed overwriting appauth");
|
||||
} else {
|
||||
toast("Successfully updated auth everywhere!");
|
||||
toast("Successfully updated auth!");
|
||||
setSelectedUserModalOpen(false);
|
||||
setTimeout(() => {
|
||||
getAppAuthentication();
|
||||
@@ -1732,7 +1741,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
const userId = user.id;
|
||||
const data = { user_id: userId };
|
||||
|
||||
console.log(user, userdata)
|
||||
toast("Generating new API key")
|
||||
|
||||
var fetchdata = {
|
||||
method: "POST",
|
||||
@@ -3440,6 +3449,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
style={{ minWidth: 300, maxWidth: 300, overflow: "hidden" }}
|
||||
/>
|
||||
<ListItemText primary="Actions" />
|
||||
<ListItemText primary="Delegation" />
|
||||
</ListItem>
|
||||
{schedules === undefined || schedules === null
|
||||
? null
|
||||
@@ -3658,10 +3668,13 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
style={{ minWidth: 125, maxWidth: 125, overflow: "hidden" }}
|
||||
/>
|
||||
<ListItemText
|
||||
primary="Created"
|
||||
primary="Edited"
|
||||
style={{ minWidth: 230, maxWidth: 230, overflow: "hidden" }}
|
||||
/>
|
||||
<ListItemText primary="Actions" />
|
||||
<ListItemText primary="Actions"
|
||||
style={{ minWidth: 150, maxWidth: 150, }}
|
||||
/>
|
||||
<ListItemText primary="Distribution" />
|
||||
</ListItem>
|
||||
{authentication === undefined || authentication === null
|
||||
? null
|
||||
@@ -3693,6 +3706,8 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
];
|
||||
}
|
||||
|
||||
const isDistributed = data.suborg_distributed === true ? true : false;
|
||||
|
||||
return (
|
||||
<ListItem key={index} style={{ backgroundColor: bgColor }}>
|
||||
<ListItemText
|
||||
@@ -3768,31 +3783,32 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
minWidth: 230,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
primary={new Date(data.created * 1000).toISOString()}
|
||||
primary={new Date(data.edited * 1000).toISOString()}
|
||||
/>
|
||||
<ListItemText>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
updateAppAuthentication(data);
|
||||
}}
|
||||
disabled={data.org_id !== selectedOrganization.id ? true : false}
|
||||
>
|
||||
<EditIcon color="primary" />
|
||||
<EditIcon color="secondary" />
|
||||
</IconButton>
|
||||
{data.defined ? (
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="Set in EVERY workflow"
|
||||
title="Set in EVERY workflow in the organization"
|
||||
placement="top"
|
||||
>
|
||||
<IconButton
|
||||
style={{ marginRight: 10 }}
|
||||
disabled={data.defined === false}
|
||||
disabled={data.defined === false || data.org_id !== selectedOrganization.id ? true : false}
|
||||
onClick={() => {
|
||||
editAuthenticationConfig(data.id);
|
||||
}}
|
||||
>
|
||||
<SelectAllIcon
|
||||
color={data.defined ? "primary" : "secondary"}
|
||||
color={"secondary"}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
@@ -3803,23 +3819,54 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
placement="top"
|
||||
>
|
||||
<IconButton
|
||||
style={{ marginRight: 10 }}
|
||||
style={{}}
|
||||
onClick={() => {}}
|
||||
disabled={data.org_id !== selectedOrganization.id ? true : false}
|
||||
>
|
||||
<SelectAllIcon
|
||||
color={data.defined ? "primary" : "secondary"}
|
||||
color="secondary"
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<IconButton
|
||||
style={{marginLeft: 0, }}
|
||||
disabled={data.org_id !== selectedOrganization.id ? true : false}
|
||||
onClick={() => {
|
||||
deleteAuthentication(data);
|
||||
}}
|
||||
>
|
||||
<DeleteIcon color="primary" />
|
||||
<DeleteIcon color="secondary" />
|
||||
</IconButton>
|
||||
</ListItemText>
|
||||
<ListItemText>
|
||||
{selectedOrganization.id !== undefined && data.org_id !== selectedOrganization.id ?
|
||||
<Tooltip
|
||||
title="Parent organization controlled auth. You can use, but not modify this auth. Contact an admin of your parent organization if you need changes to this."
|
||||
placement="top"
|
||||
>
|
||||
<Chip
|
||||
label={"Parent"}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
/>
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip
|
||||
title="Distributed to sub-organizations. This means the sub organizations can use this authentication, but not modify it."
|
||||
placement="top"
|
||||
>
|
||||
<Checkbox
|
||||
disabled={selectedOrganization.creator_org !== undefined && selectedOrganization.creator_org !== null && selectedOrganization.creator_org !== "" ? true : false}
|
||||
checked={isDistributed}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
changeDistribution(data, !isDistributed)
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
}
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
@@ -4018,49 +4065,56 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
<ListItemText
|
||||
style={{ minWidth: 100, maxWidth: 100 }}
|
||||
primary={
|
||||
<Tooltip
|
||||
title={"Copy Orborus command"}
|
||||
style={{}}
|
||||
aria-label={"Copy orborus command"}
|
||||
>
|
||||
<IconButton
|
||||
style={{}}
|
||||
disabled={environment.Type === "cloud"}
|
||||
onClick={() => {
|
||||
if (environment.Type === "cloud") {
|
||||
toast("No Orborus necessary for environment cloud. Create and use a different environment to run executions on-premises.")
|
||||
return
|
||||
}
|
||||
<Tooltip
|
||||
title={"Copy Orborus command"}
|
||||
style={{}}
|
||||
aria-label={"Copy orborus command"}
|
||||
>
|
||||
<IconButton
|
||||
style={{}}
|
||||
disabled={environment.Type === "cloud"}
|
||||
onClick={() => {
|
||||
if (environment.Type === "cloud") {
|
||||
toast("No Orborus necessary for environment cloud. Create and use a different environment to run executions on-premises.")
|
||||
return
|
||||
}
|
||||
|
||||
const elementName = "copy_element_shuffle";
|
||||
const auth = environment.auth === "" ? 'cb5st3d3Z!3X3zaJ*Pc' : environment.auth
|
||||
const commandData = `docker run --volume "/var/run/docker.sock:/var/run/docker.sock" -e ENVIRONMENT_NAME="${environment.Name}" -e 'AUTH=${auth}' -e ORG="${props.userdata.active_org.id}" -e DOCKER_API_VERSION=1.40 -e BASE_URL="${globalUrl}" --name="shuffle-orborus" -d ghcr.io/shuffle/shuffle-orborus:latest`
|
||||
var copyText = document.getElementById(elementName);
|
||||
if (copyText !== null && copyText !== undefined) {
|
||||
const clipboard = navigator.clipboard;
|
||||
if (clipboard === undefined) {
|
||||
toast("Can only copy over HTTPS (port 3443)");
|
||||
return;
|
||||
}
|
||||
if (props.userdata.active_org === undefined || props.userdata.active_org === null) {
|
||||
toast("No active organization yet. Are you logged in?")
|
||||
return
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(commandData);
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(
|
||||
0,
|
||||
99999
|
||||
); /* For mobile devices */
|
||||
const elementName = "copy_element_shuffle";
|
||||
const auth = environment.auth === "" ? 'cb5st3d3Z!3X3zaJ*Pc' : environment.auth
|
||||
const newUrl = globalUrl === "https://shuffler.io" ? "https://shuffle-backend-stbuwivzoq-nw.a.run.app" : globalUrl
|
||||
|
||||
/* Copy the text inside the text field */
|
||||
document.execCommand("copy");
|
||||
const commandData = `docker run --volume "/var/run/docker.sock:/var/run/docker.sock" -e ENVIRONMENT_NAME="${environment.Name}" -e 'AUTH=${auth}' -e ORG="${props.userdata.active_org.id}" -e DOCKER_API_VERSION=1.40 -e BASE_URL="${newUrl}" --name="shuffle-orborus" -d ghcr.io/shuffle/shuffle-orborus:latest`
|
||||
var copyText = document.getElementById(elementName);
|
||||
if (copyText !== null && copyText !== undefined) {
|
||||
const clipboard = navigator.clipboard;
|
||||
if (clipboard === undefined) {
|
||||
toast("Can only copy over HTTPS (port 3443)");
|
||||
return;
|
||||
}
|
||||
|
||||
toast("Orborus command copied to clipboard");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FileCopyIcon disabled={environment.Type === "cloud"} style={{ color: environment.Type === "cloud" ? "rgba(255,255,255,0.2)" : "rgba(255,255,255,0.8)" }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
}
|
||||
navigator.clipboard.writeText(commandData);
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(
|
||||
0,
|
||||
99999
|
||||
); /* For mobile devices */
|
||||
|
||||
/* Copy the text inside the text field */
|
||||
document.execCommand("copy");
|
||||
|
||||
toast("Orborus command copied to clipboard");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FileCopyIcon disabled={environment.Type === "cloud"} style={{ color: environment.Type === "cloud" ? "rgba(255,255,255,0.2)" : "rgba(255,255,255,0.8)" }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
|
||||
<ListItemText
|
||||
|
||||
@@ -501,6 +501,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const [selectedAction, setSelectedAction] = React.useState({});
|
||||
const [selectedActionEnvironment, setSelectedActionEnvironment] = React.useState({});
|
||||
|
||||
const [streamDisabled, setStreamDisabled] = React.useState(false);
|
||||
const [executionRequest, setExecutionRequest] = React.useState({});
|
||||
|
||||
const [executionRunning, setExecutionRunning] = React.useState(false);
|
||||
@@ -551,10 +552,18 @@ const AngularWorkflow = (defaultprops) => {
|
||||
props.userdata.active_org !== undefined
|
||||
? props.userdata.active_org.cloud_sync === true
|
||||
: false;
|
||||
const isCloud =
|
||||
window.location.host === "localhost:3002" ||
|
||||
window.location.host === "shuffler.io";
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
console.log("UNMOUNTING USER!")
|
||||
sendStreamRequest({
|
||||
"item": "workflow",
|
||||
"type": "leave",
|
||||
"id": workflow.id,
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
/*
|
||||
useEffect(() => {
|
||||
console.log("In useeffect for workflow: ", workflow)
|
||||
@@ -918,7 +927,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
});
|
||||
};
|
||||
|
||||
const setNewAppAuth = (appAuthData) => {
|
||||
const setNewAppAuth = (appAuthData, refresh) => {
|
||||
fetch(globalUrl + "/api/v1/apps/authentication", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
@@ -937,9 +946,14 @@ const AngularWorkflow = (defaultprops) => {
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (!responseJson.success) {
|
||||
toast("Failed to set app auth: " + responseJson.reason);
|
||||
toast("Error: " + responseJson.reason);
|
||||
} else {
|
||||
getAppAuthentication(true, false);
|
||||
if (refresh === true) {
|
||||
getAppAuthentication(true, true, true);
|
||||
} else {
|
||||
getAppAuthentication(true, false);
|
||||
}
|
||||
|
||||
setAuthenticationModalOpen(false);
|
||||
|
||||
// Needs a refresh with the new authentication..
|
||||
@@ -1003,16 +1017,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
setExecutionModalView(1);
|
||||
start();
|
||||
|
||||
setExecutionRequest({
|
||||
execution_id: execution.execution_id,
|
||||
authorization: execution.authorization,
|
||||
});
|
||||
|
||||
const newitem = removeParam("execution_id", cursearch);
|
||||
navigate(curpath + newitem)
|
||||
//props.history.push(curpath + newitem);
|
||||
start();
|
||||
|
||||
//const newitem = removeParam("execution_id", cursearch);
|
||||
//navigate(curpath + newitem)
|
||||
} else {
|
||||
console.log("Couldn't find execution for execution ID. Retrying as user to get ", tmpView)
|
||||
|
||||
@@ -1025,8 +1038,8 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setExecutionRequest(cur_execution);
|
||||
start();
|
||||
|
||||
const newitem = removeParam("execution_id", cursearch);
|
||||
navigate(curpath + newitem)
|
||||
//const newitem = removeParam("execution_id", cursearch);
|
||||
//navigate(curpath + newitem)
|
||||
|
||||
setTimeout(() => {
|
||||
stop()
|
||||
@@ -1310,12 +1323,28 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
const sendStreamRequest = (body) => {
|
||||
//console.log("Stream not activated yet.")
|
||||
return
|
||||
if (!isCloud) {
|
||||
console.log("Stream not activated yet for onprem")
|
||||
return
|
||||
}
|
||||
|
||||
if (streamDisabled) {
|
||||
console.log("Stream disabled")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Session may be important here huh
|
||||
body.user_id = userdata.id
|
||||
|
||||
fetch(`${globalUrl}/api/v1/workflows/${props.match.params.key}/stream`, {
|
||||
//const url = ${globalUrl}/api/v1/workflows/${props.match.params.key}/stream
|
||||
//const streamUrl = "http://localhost:5002"
|
||||
|
||||
console.log("Stream request: ", body)
|
||||
const streamUrl = "https://stream.shuffler.io"
|
||||
const url = `${streamUrl}/api/v1/workflows/${props.match.params.key}/stream`
|
||||
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -1337,7 +1366,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Stream send error: ", error.toString())
|
||||
//toast(error.toString());
|
||||
setStreamDisabled(true)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1872,6 +1901,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setSelectedAction(selectedAction);
|
||||
setWorkflow(workflow);
|
||||
saveWorkflow(workflow);
|
||||
|
||||
toast("Added and updated authentication!");
|
||||
shouldClose = true
|
||||
} else {
|
||||
@@ -2084,7 +2114,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const onChunkedResponseError = (err) => {
|
||||
console.error(err)
|
||||
if (streamDisabled) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2570,14 +2602,30 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const startWorkflowStream = async (workflowId) => {
|
||||
const timeout = 60000
|
||||
if (!isCloud) {
|
||||
console.log("Not cloud, not starting workflow stream")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
if (streamDisabled) {
|
||||
console.log("Stream disabled")
|
||||
return
|
||||
}
|
||||
|
||||
const timeout = 60000
|
||||
//const url = `${globalUrl}/api/v1/workflows/${workflowId}/stream`
|
||||
//const streamUrl = "https://shuffle-streaming-backend-stbuwivzoq-ew.a.run.app"
|
||||
//
|
||||
const streamUrl = "https://stream.shuffler.io"
|
||||
const url = `${streamUrl}/api/v1/workflows/${workflowId}/stream`
|
||||
while (true) {
|
||||
if (streamDisabled) {
|
||||
break
|
||||
}
|
||||
|
||||
// Wait 1 second before next request just in case of timeouts
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
await fetchWithTimeout(`${globalUrl}/api/v1/workflows/${workflowId}/stream`, {
|
||||
await fetchWithTimeout(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -6261,7 +6309,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
insertedNodes = insertedNodes.concat(newedges);
|
||||
|
||||
setWorkflow(inputworkflow);
|
||||
|
||||
// Reset view for cytoscape
|
||||
@@ -6271,6 +6318,8 @@ const AngularWorkflow = (defaultprops) => {
|
||||
} else {
|
||||
setElements(insertedNodes);
|
||||
}
|
||||
|
||||
console.log("Setupgraph done 2!")
|
||||
};
|
||||
|
||||
const removeNode = (nodeId) => {
|
||||
@@ -6576,6 +6625,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
// preview: true,
|
||||
|
||||
console.log("In POST graph setup 2")
|
||||
cy.fit(null, 200);
|
||||
|
||||
cy.on("boxselect", "node", (e) => {
|
||||
@@ -6624,6 +6674,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
document.title = "Workflow - " + workflow.name;
|
||||
|
||||
console.log("In POST graph setup 3")
|
||||
startWorkflowStream(props.match.params.key);
|
||||
|
||||
registerKeys();
|
||||
@@ -7516,14 +7567,30 @@ const AngularWorkflow = (defaultprops) => {
|
||||
description = app.actions[actionIndex].description
|
||||
}
|
||||
|
||||
const parsedEnvironments =
|
||||
var parsedEnvironments =
|
||||
environments === null || environments === []
|
||||
? "cloud"
|
||||
: environments[defaultEnvironmentIndex] === undefined
|
||||
? "cloud"
|
||||
: environments[defaultEnvironmentIndex].Name;
|
||||
|
||||
// activated: app.generated === true ? app.activated === false ? false : true : true,
|
||||
// List other nodes in the workflow and see if they have an environment set. If they do, use that as the default
|
||||
if (cy !== undefined && cy !== null) {
|
||||
const foundnodes = cy.nodes().jsons()
|
||||
if (foundnodes !== undefined && foundnodes !== null && foundnodes.length > 0) {
|
||||
// As they should all be the same, this is just an override
|
||||
for (let nodekey in foundnodes) {
|
||||
const curnode = foundnodes[nodekey]
|
||||
if (curnode.data.environment !== undefined && curnode.data.environment !== null && curnode.data.environment.length > 0) {
|
||||
console.log("Found environment: ", curnode.data.environment)
|
||||
parsedEnvironments = curnode.data.environment
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Discovered environment: ", parsedEnvironments)
|
||||
const newAppData = {
|
||||
name: app.actions[actionIndex].name,
|
||||
label: actionLabel,
|
||||
@@ -8139,6 +8206,25 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{visibleApps.length <= 4 ? (
|
||||
<div
|
||||
style={{ textAlign: "center", width: leftBarSize, marginTop: 40, maxWidth: 340, overflow: "hidden", }}
|
||||
onLoad={() => {
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Click one of the relevant public apps below to Activate it for your organization.
|
||||
</Typography>
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
||||
console.log("CLICKED")
|
||||
}}>
|
||||
<CustomSearchBox />
|
||||
<Index indexName="appsearch">
|
||||
<CustomAppHits />
|
||||
</Index>
|
||||
</InstantSearch>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : apps.length > 0 ? (
|
||||
<div
|
||||
@@ -8148,7 +8234,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Couldn't find the app you're looking for? Searching unactivated apps. Click one of the below apps to Activate it for your organization.
|
||||
Couldn't find the apps you were looking for? Searching unactivated apps. Click one of the below apps to Activate it for your organization.
|
||||
</Typography>
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
||||
console.log("CLICKED")
|
||||
@@ -8364,7 +8450,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("NEW ACTION: ", newSelectedAction);
|
||||
setSelectedAction(newSelectedAction);
|
||||
setUpdate(Math.random());
|
||||
|
||||
@@ -13259,10 +13344,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
"user": "Anonymous",
|
||||
"user_id": "user_id",
|
||||
"color": "blue",
|
||||
}, {
|
||||
"user": "frikky",
|
||||
"user_id": "user_id",
|
||||
"color": "red",
|
||||
}]
|
||||
|
||||
|
||||
@@ -13318,18 +13399,18 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const showErrors = !isMobile && !workflow.public && workflow.errors !== undefined && workflow.errors !== null && workflow.errors.length > 0 ?
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
border: "1px solid rgba(255,255,255,0.1)",
|
||||
position: "absolute",
|
||||
bottom: 130,
|
||||
left: leftBarSize+20,
|
||||
color: "white",
|
||||
padding: 5,
|
||||
padding: 10,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
>
|
||||
<Typography variant="body22">
|
||||
<WarningIcon style={{color: "yellow", marginRight: 5, height: 15, width: 15, }} />
|
||||
<b>{workflow.errors.length} Potential Workflow Issue{workflow.errors.length > 1 ? "s" : ""}</b>
|
||||
<WarningIcon style={{marginRight: 5, height: 15, width: 15, }} />
|
||||
<b>{workflow.errors.length} Workflow Issue{workflow.errors.length > 1 ? "s" : ""}</b>
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
|
||||
@@ -413,7 +413,9 @@ const AppCreator = (defaultprops) => {
|
||||
|
||||
const [oauth2Scopes, setOauth2Scopes] = useState([]);
|
||||
const [oauth2Type, setOauth2Type] = useState("delegated");
|
||||
const [oauth2GrantType, setOauth2GrantType] = useState("client_credentials");
|
||||
|
||||
//client_credentials
|
||||
const [oauth2GrantType, setOauth2GrantType] = useState("");
|
||||
const defaultAuth = {
|
||||
name: "",
|
||||
type: "header",
|
||||
@@ -1757,7 +1759,7 @@ const AppCreator = (defaultprops) => {
|
||||
|
||||
// Kind of fucked up, but it works for now?
|
||||
if (value["x-grant-type"] !== undefined && value["x-grant-type"] !== null && value["x-grant-type"].length !== 0) {
|
||||
setOauth2Type(value["x-grant-type"])
|
||||
setOauth2GrantType(value["x-grant-type"])
|
||||
}
|
||||
|
||||
//console.log("FLOW2: ", value[flowkey][basekey])
|
||||
@@ -5988,6 +5990,10 @@ const AppCreator = (defaultprops) => {
|
||||
fullWidth
|
||||
onChange={(e) => {
|
||||
setOauth2Type(e.target.value);
|
||||
|
||||
if (e.target.value === "application" && oauth2GrantType === "") {
|
||||
setOauth2GrantType("client_credentials")
|
||||
}
|
||||
}}
|
||||
value={oauth2Type}
|
||||
style={{
|
||||
|
||||
@@ -368,14 +368,14 @@ const Docs = (defaultprops) => {
|
||||
}
|
||||
|
||||
const markdownStyle = {
|
||||
color: "rgba(255, 255, 255, 0.65)",
|
||||
color: "rgba(255, 255, 255, 0.90)",
|
||||
overflow: "hidden",
|
||||
paddingBottom: 100,
|
||||
margin: "auto",
|
||||
maxWidth: "100%",
|
||||
minWidth: "100%",
|
||||
overflow: "hidden",
|
||||
fontSize: isMobile ? "1.3rem" : "1.0rem",
|
||||
fontSize: isMobile ? "1.3rem" : "1.1rem",
|
||||
};
|
||||
|
||||
function OuterLink(props) {
|
||||
|
||||
@@ -1982,16 +1982,16 @@ const Workflows = (props) => {
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip arrow title={
|
||||
<span style={{}}>
|
||||
{data.image !== undefined && data.image !== null && data.image.length > 0 ?
|
||||
<img src={data.image} alt={data.name} style={{backgroundColor: theme.palette.surfaceColor, maxHeight: 200, minHeigth: 200, borderRadius: theme.palette.borderRadius, }} />
|
||||
: null}
|
||||
<Typography>
|
||||
Edit {data.name}
|
||||
</Typography>
|
||||
</span>
|
||||
} placement="bottom">
|
||||
<Typography
|
||||
<div style={{width: "100%", minWidth: 250, maxWidth: 310, }}>
|
||||
{data.image !== undefined && data.image !== null && data.image.length > 0 ?
|
||||
<img src={data.image} alt={data.name} style={{backgroundColor: theme.palette.surfaceColor, maxWidth: 300, minWidth: 250, borderRadius: theme.palette.borderRadius, }} />
|
||||
: null}
|
||||
<Typography>
|
||||
Edit {data.name}
|
||||
</Typography>
|
||||
</div>
|
||||
} placement="left">
|
||||
<Typography
|
||||
variant="body1"
|
||||
style={{
|
||||
marginBottom: 0,
|
||||
|
||||
Reference in New Issue
Block a user