Merge branch '2.0.0' of https://github.com/Shuffle/Shuffle into flipBranch
This commit is contained in:
@@ -79,6 +79,7 @@ const AppGrid = (props) => {
|
|||||||
const [formMail, setFormMail] = React.useState("");
|
const [formMail, setFormMail] = React.useState("");
|
||||||
const [message, setMessage] = React.useState("");
|
const [message, setMessage] = React.useState("");
|
||||||
const [formMessage, setFormMessage] = React.useState("");
|
const [formMessage, setFormMessage] = React.useState("");
|
||||||
|
const [deactivatedIndexes, setDeactivatedIndexes] = React.useState([]);
|
||||||
|
|
||||||
const buttonStyle = {
|
const buttonStyle = {
|
||||||
borderRadius: 30,
|
borderRadius: 30,
|
||||||
@@ -352,7 +353,7 @@ const AppGrid = (props) => {
|
|||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
toast.error(responseJson.reason);
|
toast.error(responseJson.reason);
|
||||||
} else {
|
} else {
|
||||||
toast.success(`App ${type}d Successfully!`);
|
//toast.success(`App ${type}d Successfully!`);
|
||||||
if (type === 'activate') {
|
if (type === 'activate') {
|
||||||
setAllActivatedAppIds(prev => [...prev, data.objectID]);
|
setAllActivatedAppIds(prev => [...prev, data.objectID]);
|
||||||
setIsAnyAppActivated(true);
|
setIsAnyAppActivated(true);
|
||||||
@@ -395,7 +396,7 @@ const AppGrid = (props) => {
|
|||||||
{!isLoading ? (
|
{!isLoading ? (
|
||||||
<div>
|
<div>
|
||||||
{hits.length === 0 && searchQuery.length >= 0 && showNoAppFound ? (
|
{hits.length === 0 && searchQuery.length >= 0 && showNoAppFound ? (
|
||||||
<Typography variant="body1" style={{ marginTop: '30%' }}>No App Found</Typography>
|
<Typography variant="body1" style={{ marginTop: '30%' }}>No Apps Found</Typography>
|
||||||
) : (
|
) : (
|
||||||
<Grid item spacing={2} justifyContent="flex-start">
|
<Grid item spacing={2} justifyContent="flex-start">
|
||||||
<div
|
<div
|
||||||
@@ -1551,9 +1552,13 @@ const AppGrid = (props) => {
|
|||||||
<Typography variant="h5" style={{ marginBottom: 30, marginTop: 30, fontWeight: "400", fontSize: 24 }}>
|
<Typography variant="h5" style={{ marginBottom: 30, marginTop: 30, fontWeight: "400", fontSize: 24 }}>
|
||||||
Filter By
|
Filter By
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<FilterUsersAndOrgsAppByCategory selectedCategoryForUsersAndOgsApps={selectedCategoryForUsersAndOgsApps} setselectedCategoryForUsersAndOgsApps={setselectedCategoryForUsersAndOgsApps} />
|
<FilterUsersAndOrgsAppByCategory selectedCategoryForUsersAndOgsApps={selectedCategoryForUsersAndOgsApps} setselectedCategoryForUsersAndOgsApps={setselectedCategoryForUsersAndOgsApps} />
|
||||||
|
|
||||||
<FilterUsersAndOrgsAppByActionLabel selectedTagsForUserAndOrgApps={selectedTagsForUserAndOrgApps} setSelectedTagsForUserAndOrgApps={setSelectedTagsForUserAndOrgApps} />
|
<FilterUsersAndOrgsAppByActionLabel selectedTagsForUserAndOrgApps={selectedTagsForUserAndOrgApps} setSelectedTagsForUserAndOrgApps={setSelectedTagsForUserAndOrgApps} />
|
||||||
|
|
||||||
<FilterUsersAndOrgsAppByCreatedWith selectedOptionOfCreatedWith={selectedOptionOfCreatedWith} setSelectedOptionOfCreatedWith={setSelectedOptionOfCreatedWith} />
|
<FilterUsersAndOrgsAppByCreatedWith selectedOptionOfCreatedWith={selectedOptionOfCreatedWith} setSelectedOptionOfCreatedWith={setSelectedOptionOfCreatedWith} />
|
||||||
|
|
||||||
<FilterUsersAndOrgsAppCreatedBy />
|
<FilterUsersAndOrgsAppCreatedBy />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1722,6 +1727,10 @@ const AppGrid = (props) => {
|
|||||||
? `/apps/${data.id}`
|
? `/apps/${data.id}`
|
||||||
: `https://shuffler.io/apps/${data.id}`;
|
: `https://shuffler.io/apps/${data.id}`;
|
||||||
|
|
||||||
|
if (data.name === "" && data.id === "") {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Zoom
|
<Zoom
|
||||||
key={index}
|
key={index}
|
||||||
@@ -1818,17 +1827,71 @@ const AppGrid = (props) => {
|
|||||||
width: 230,
|
width: 230,
|
||||||
textAlign: 'start',
|
textAlign: 'start',
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
color: "rgba(158, 158, 158, 1)"
|
color: "rgba(158, 158, 158, 1)",
|
||||||
|
display: "flex",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{data.tags &&
|
<div style={{minWidth: 120, overflow: "hidden", }}>
|
||||||
data.tags.map((tag, tagIndex) => (
|
{data.generated !== true ?
|
||||||
<span key={tagIndex}>
|
<div>
|
||||||
{normalizedString(tag)}
|
{data.tags &&
|
||||||
{tagIndex < data.tags.length - 1 ? ", " : ""}
|
data.tags.slice(0,2).map((tag, tagIndex) => (
|
||||||
</span>
|
<span key={tagIndex}>
|
||||||
))}
|
{normalizedString(tag)}
|
||||||
</div>
|
{tagIndex < data.tags.length - 1 ? ", " : ""}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
{currTab === 1 && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true ?
|
||||||
|
<Button style={{
|
||||||
|
marginLeft: 15,
|
||||||
|
width: 102,
|
||||||
|
height: 35,
|
||||||
|
borderRadius: 200,
|
||||||
|
backgroundColor: "rgba(73, 73, 73, 1)",
|
||||||
|
color: "rgba(241, 241, 241, 1)",
|
||||||
|
textTransform: "none",
|
||||||
|
}}
|
||||||
|
onClick={(event) => {
|
||||||
|
//deactivatedIndexes.push(index)
|
||||||
|
//setDeactivatedIndexes(deactivatedIndexes)
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
//handleActivateButton(event, data, "deactivate");
|
||||||
|
// FIXME: Put this in a function lol
|
||||||
|
const url = `${globalUrl}/api/v1/apps/${data.id}/deactivate`;
|
||||||
|
|
||||||
|
fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((responseJson) => {
|
||||||
|
if (responseJson.success === false) {
|
||||||
|
toast.error(responseJson.reason);
|
||||||
|
} else {
|
||||||
|
toast.success("App Deactivated Successfully. Reload UI to see updated changes.")
|
||||||
|
//const updatedIds = allActivatedAppIds.filter(id => id !== data.objectID);
|
||||||
|
//setAllActivatedAppIds(updatedIds);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log("app error: ", error.toString());
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
Deactivate
|
||||||
|
</Button>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* )} */}
|
{/* )} */}
|
||||||
</div>
|
</div>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
@@ -1946,6 +2009,7 @@ const AppGrid = (props) => {
|
|||||||
selectedOptionOfCreatedWith={selectedOptionOfCreatedWith}
|
selectedOptionOfCreatedWith={selectedOptionOfCreatedWith}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<AppTab
|
<AppTab
|
||||||
selectedCategoryForUsersAndOgsApps={selectedCategoryForUsersAndOgsApps}
|
selectedCategoryForUsersAndOgsApps={selectedCategoryForUsersAndOgsApps}
|
||||||
selectedTagsForUserAndOrgApps={selectedTagsForUserAndOrgApps}
|
selectedTagsForUserAndOrgApps={selectedTagsForUserAndOrgApps}
|
||||||
@@ -1954,6 +2018,7 @@ const AppGrid = (props) => {
|
|||||||
setSelectedTagsForUserAndOrgApps={setSelectedTagsForUserAndOrgApps}
|
setSelectedTagsForUserAndOrgApps={setSelectedTagsForUserAndOrgApps}
|
||||||
setSelectedOptionOfCreatedWith={setSelectedOptionOfCreatedWith}
|
setSelectedOptionOfCreatedWith={setSelectedOptionOfCreatedWith}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<Configure clickAnalytics />
|
<Configure clickAnalytics />
|
||||||
</InstantSearch>
|
</InstantSearch>
|
||||||
|
|||||||
@@ -1623,12 +1623,12 @@ const Billing = (props) => {
|
|||||||
{userdata.support === true ?
|
{userdata.support === true ?
|
||||||
<div style={{ marginBottom: 10, marginTop: clickedFromOrgTab ? 16 : null, color: clickedFromOrgTab ? "#F1F1F1" : null }}>
|
<div style={{ marginBottom: 10, marginTop: clickedFromOrgTab ? 16 : null, color: clickedFromOrgTab ? "#F1F1F1" : null }}>
|
||||||
For sales: Create
|
For sales: Create
|
||||||
<a href={"https://docs.google.com/document/d/1OeJSi42812EMg7fUAw1HAj1ymOG8rfp8Ma_DGJKvwgI/copy?usp=sharing&organization=" + selectedOrganization.id} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
<a href={"https://docs.google.com/document/d/1N-ZJNn8lWaqiXITrqYcnTt53oXGLNYFEzc5PU-tdAps/copy" + selectedOrganization.id} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
||||||
New Cloud Contract
|
EU contract
|
||||||
</a>
|
</a>
|
||||||
or
|
or
|
||||||
<a href={"https://docs.google.com/document/d/1IguxpeV4Wwwr9C0MPyUNhhajEu_PxjRfP7f0hYyRYOI/copy?usp=sharing&organization=" + selectedOrganization.id} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
<a href={"https://docs.google.com/document/d/1cF-Cwxt1TcahlLrpl1GH2hFZO4gxppLeYjHW6QB0EzQ/copy" + selectedOrganization.id} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
||||||
New Onprem Contract
|
NOT EU contract
|
||||||
</a>
|
</a>
|
||||||
-
|
-
|
||||||
<a href={"https://drive.google.com/drive/folders/1zVvwwkbQXW3p-DJYa0GBDzFo_ZnV_I_5"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
<a href={"https://drive.google.com/drive/folders/1zVvwwkbQXW3p-DJYa0GBDzFo_ZnV_I_5"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
||||||
@@ -1636,7 +1636,7 @@ const Billing = (props) => {
|
|||||||
</a>
|
</a>
|
||||||
-
|
-
|
||||||
<a href={"https://github.com/Shuffle/Shuffle-docs/tree/master/handbook/Sales"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
<a href={"https://github.com/Shuffle/Shuffle-docs/tree/master/handbook/Sales"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
||||||
Sales Process
|
Sales Process (old)
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import UsecaseSearch from "../components/UsecaseSearch.jsx"
|
|||||||
import WorkflowGrid from "../components/WorkflowGrid.jsx"
|
import WorkflowGrid from "../components/WorkflowGrid.jsx"
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import WorkflowTemplatePopup from "./WorkflowTemplatePopup.jsx";
|
import WorkflowTemplatePopup from "./WorkflowTemplatePopup.jsx";
|
||||||
|
import WorkflowValidationTimeline from "../components/WorkflowValidationTimeline.jsx"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
@@ -206,6 +207,16 @@ const EditWorkflow = (props) => {
|
|||||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 20, maxWidth: 440,}}>
|
<Typography variant="body2" color="textSecondary" style={{marginTop: 20, maxWidth: 440,}}>
|
||||||
Workflows can be built from scratch, or from templates. <a href="/usecases" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Usecases</a> can help you discover next steps, and you can <a href="/search?tab=workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>search</a> for them directly. <a href="/docs/workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Learn more</a>
|
Workflows can be built from scratch, or from templates. <a href="/usecases" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Usecases</a> can help you discover next steps, and you can <a href="/search?tab=workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>search</a> for them directly. <a href="/docs/workflows" rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Learn more</a>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
<div style={{marginTop: 10, marginBottom: 10, marginRight: 50, }}>
|
||||||
|
<WorkflowValidationTimeline
|
||||||
|
originalWorkflow={workflow}
|
||||||
|
|
||||||
|
apps={apps}
|
||||||
|
workflow={workflow}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{showUpload === true ?
|
{showUpload === true ?
|
||||||
<div style={{ float: "right" }}>
|
<div style={{ float: "right" }}>
|
||||||
<Tooltip color="primary" title={"Import manually"} placement="top">
|
<Tooltip color="primary" title={"Import manually"} placement="top">
|
||||||
@@ -957,7 +968,7 @@ const EditWorkflow = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{showMoreClicked ? <ExpandLessIcon /> : <ExpandMoreIcon/>}
|
{showMoreClicked ? <ExpandLessIcon /> : <ExpandMoreIcon/>}
|
||||||
{showMoreClicked ? "Collapse": "Expand"}
|
{showMoreClicked ? "Less Options": "More Options"}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -515,16 +515,16 @@ const LicencePopup = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("New variant: ", shuffleVariant)
|
console.log("New variant: ", shuffleVariant)
|
||||||
|
|
||||||
if (shuffleVariant === 1) {
|
if (shuffleVariant === 1) {
|
||||||
setCalculatedCost("$600")
|
setCalculatedCost("$960")
|
||||||
setSelectedValue(8)
|
setSelectedValue(8)
|
||||||
} else {
|
} else {
|
||||||
setCalculatedCost("$540")
|
setCalculatedCost("$960")
|
||||||
setSelectedValue(300)
|
setSelectedValue(300)
|
||||||
}
|
}
|
||||||
}, [shuffleVariant])
|
}, [shuffleVariant])
|
||||||
|
|
||||||
if (typeof window === 'undefined' || window.location === undefined) {
|
if (typeof window === 'undefined' || window.location === undefined) {
|
||||||
return null
|
return null
|
||||||
@@ -680,7 +680,7 @@ const LicencePopup = (props) => {
|
|||||||
color: "white",
|
color: "white",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("Priceitem: ", shuffleVariant)
|
||||||
const isLoggedInHandler = () => {
|
const isLoggedInHandler = () => {
|
||||||
if (calculatedCost === payasyougo) {
|
if (calculatedCost === payasyougo) {
|
||||||
handlePayasyougo(props.userdata)
|
handlePayasyougo(props.userdata)
|
||||||
@@ -690,7 +690,7 @@ const LicencePopup = (props) => {
|
|||||||
const priceItem = window.location.origin === "https://shuffler.io" ?
|
const priceItem = window.location.origin === "https://shuffler.io" ?
|
||||||
shuffleVariant === 0 ? "app_executions" : "cores"
|
shuffleVariant === 0 ? "app_executions" : "cores"
|
||||||
:
|
:
|
||||||
shuffleVariant === 0 ? "price_1MROFrDzMUgUjxHShcSxgHO1" : "price_1NXjQqDzMUgUjxHSg690R4FP"
|
shuffleVariant === 0 ? "price_1PWI5zDzMUgUjxHSKkz0fGdN" : "price_1NXjQqDzMUgUjxHSg690R4FP"
|
||||||
|
|
||||||
const successUrl = `${window.location.origin}/admin?admin_tab=billing&payment=success`
|
const successUrl = `${window.location.origin}/admin?admin_tab=billing&payment=success`
|
||||||
const failUrl = `${window.location.origin}/pricing?admin_tab=billing&payment=failure`
|
const failUrl = `${window.location.origin}/pricing?admin_tab=billing&payment=failure`
|
||||||
|
|||||||
@@ -517,12 +517,11 @@ const Header = (props) => {
|
|||||||
window.location.href = responseJson["url"]
|
window.location.href = responseJson["url"]
|
||||||
return
|
return
|
||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
}
|
||||||
toast("Successfully changed active organization - refreshing!");
|
toast("Successfully changed active organization - refreshing!");
|
||||||
} else {
|
} else {
|
||||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.length > 0) {
|
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.length > 0) {
|
||||||
@@ -1547,7 +1546,7 @@ const Header = (props) => {
|
|||||||
<div style={{ position: "relative", height: topbarHeight, backgroundImage: "linear-gradient(to right, #f86a3e, #f34079)", overflow: "hidden", }}>
|
<div style={{ position: "relative", height: topbarHeight, backgroundImage: "linear-gradient(to right, #f86a3e, #f34079)", overflow: "hidden", }}>
|
||||||
<Typography variant="body1" style={{ paddingTop: 7, margin: "auto", textAlign: "center", color: "white", }}>
|
<Typography variant="body1" style={{ paddingTop: 7, margin: "auto", textAlign: "center", color: "white", }}>
|
||||||
{/* Shuffle 1.4.0 is out! Read more about */}
|
{/* Shuffle 1.4.0 is out! Read more about */}
|
||||||
Shuffle now offers
|
Early Success! More
|
||||||
{/* <u>
|
{/* <u>
|
||||||
<a href="https://github.com/Shuffle/Shuffle/releases/tag/v1.4.0" target="_blank" style={{ color: "inherit", }} onClick={() => {
|
<a href="https://github.com/Shuffle/Shuffle/releases/tag/v1.4.0" target="_blank" style={{ color: "inherit", }} onClick={() => {
|
||||||
ReactGA.event({
|
ReactGA.event({
|
||||||
@@ -1596,10 +1595,11 @@ const Header = (props) => {
|
|||||||
|
|
||||||
navigate("/training")
|
navigate("/training")
|
||||||
|
|
||||||
}} style={{ cursor: "pointer", textDecoration: "none", color: "rgba(255,255,255,0.8)" }}>
|
}} style={{ cursor: "pointer", textDecoration: "none", fontWeight:600, color: "rgba(255,255,255,0.8)" }}>
|
||||||
Public Training!
|
Public Trainings
|
||||||
</span>
|
</span>
|
||||||
</u>
|
</u>
|
||||||
|
Ahead!
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButton color="secondary" style={{ position: "absolute", top: -3, right: 20, }} onClick={(event) => {
|
<IconButton color="secondary" style={{ position: "absolute", top: -3, right: 20, }} onClick={(event) => {
|
||||||
setShowTopbar(false)
|
setShowTopbar(false)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -307,7 +307,6 @@ const ParsedAction = (props) => {
|
|||||||
(action) =>
|
(action) =>
|
||||||
action.name.toLowerCase() === selectedAction.name.toLowerCase()
|
action.name.toLowerCase() === selectedAction.name.toLowerCase()
|
||||||
);
|
);
|
||||||
console.log("FOUNDACTION: ", foundAction);
|
|
||||||
if (foundAction !== null && foundAction !== undefined) {
|
if (foundAction !== null && foundAction !== undefined) {
|
||||||
var foundparams = [];
|
var foundparams = [];
|
||||||
for (let [paramkey,paramkeyval] in Object.entries(foundAction.parameters)) {
|
for (let [paramkey,paramkeyval] in Object.entries(foundAction.parameters)) {
|
||||||
@@ -549,6 +548,11 @@ const ParsedAction = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parentNode.label === undefined) {
|
||||||
|
parentNode.label = ""
|
||||||
|
}
|
||||||
|
|
||||||
newActionList.push({
|
newActionList.push({
|
||||||
type: "action",
|
type: "action",
|
||||||
id: parentNode.id,
|
id: parentNode.id,
|
||||||
|
|||||||
@@ -0,0 +1,443 @@
|
|||||||
|
import React, { useState, } from "react";
|
||||||
|
import { makeStyles, createStyles } from "@mui/styles";
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
Typography,
|
||||||
|
|
||||||
|
Avatar,
|
||||||
|
AvatarGroup,
|
||||||
|
} from "@mui/material"
|
||||||
|
|
||||||
|
import {
|
||||||
|
green,
|
||||||
|
yellow,
|
||||||
|
red,
|
||||||
|
} from "../views/AngularWorkflow.jsx"
|
||||||
|
|
||||||
|
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
||||||
|
import theme from "../theme.jsx";
|
||||||
|
const itemHeight = 40
|
||||||
|
|
||||||
|
export const getParentNodes = (workflow, action) => {
|
||||||
|
if (action === undefined || action === null) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.actions === undefined || workflow.actions === null) {
|
||||||
|
workflow.actions = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.triggers === undefined || workflow.triggers === null) {
|
||||||
|
workflow.triggers = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.branches === undefined || workflow.branches === null) {
|
||||||
|
workflow.branches = []
|
||||||
|
}
|
||||||
|
|
||||||
|
var allkeys = [action.id];
|
||||||
|
var handled = [];
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
// maxiter = max amount of parent nodes to loop
|
||||||
|
// also handles breaks if there are issues
|
||||||
|
var iterations = 0;
|
||||||
|
var maxiter = 10;
|
||||||
|
while (true) {
|
||||||
|
for (let parentkey in allkeys) {
|
||||||
|
if (allkeys[parentkey] === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentnode = workflow.actions.find((element) => element.id === allkeys[parentkey])
|
||||||
|
if (currentnode === undefined) {
|
||||||
|
currentnode = workflow.triggers.find((element) => element.id === allkeys[parentkey])
|
||||||
|
|
||||||
|
if (currentnode === undefined) {
|
||||||
|
console.log("Could not find parent node for: ", allkeys[parentkey])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled.includes(currentnode.id)) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
handled.push(currentnode.id);
|
||||||
|
results.push(currentnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the name / label here too?
|
||||||
|
if (currentnode.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This part is only handling first level,
|
||||||
|
// but needs to recurse
|
||||||
|
var incomingEdges = []
|
||||||
|
for (var branchkey in workflow.branches) {
|
||||||
|
const branch = workflow.branches[branchkey]
|
||||||
|
if (branch.destination_id !== currentnode.id) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go up in the levels
|
||||||
|
const parents = getParentNodes(workflow, {
|
||||||
|
id: branch.source_id,
|
||||||
|
})
|
||||||
|
if (parents.length > 0) {
|
||||||
|
incomingEdges = incomingEdges.concat(parents)
|
||||||
|
}
|
||||||
|
|
||||||
|
incomingEdges.push(branch)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < incomingEdges.length; i++) {
|
||||||
|
var tmp = incomingEdges[i];
|
||||||
|
if (tmp.decorator === true) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allkeys.includes(tmp.source_id)) {
|
||||||
|
allkeys.push(tmp.source_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.length === allkeys.length || iterations === maxiter) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
iterations += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove on the end as we don't want to remove everything
|
||||||
|
results = results.filter((data) => data.id !== action.id)
|
||||||
|
results = results.filter((data) => data.type === "ACTION" || data.app_name === "Shuffle Workflow" || data.app_name === "User Input" || data.app_name === "shuffle-subflow")
|
||||||
|
results.push({ label: "Execution Argument", type: "INTERNAL" })
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
const WorkflowValidationTimeline = (props) => {
|
||||||
|
const { workflow, originalWorkflow, apps, getParents, execution} = props
|
||||||
|
|
||||||
|
|
||||||
|
if (workflow === undefined || workflow === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.validation === undefined || workflow.validation === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.actions === undefined || workflow.actions === null) {
|
||||||
|
workflow.actions = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.triggers === undefined || workflow.triggers === null) {
|
||||||
|
workflow.triggers = []
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.branches === undefined || workflow.branches === null) {
|
||||||
|
workflow.branches = []
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = []
|
||||||
|
if (execution !== undefined) {
|
||||||
|
results = execution.results
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Find startnode
|
||||||
|
// 2. Map childnodes from it
|
||||||
|
const startnodeId = workflow.start
|
||||||
|
|
||||||
|
// Find parent of startnodeId and if it's a webhook
|
||||||
|
var relevantactions = []
|
||||||
|
for (var key in workflow.branches) {
|
||||||
|
const branch = workflow.branches[key]
|
||||||
|
if (branch.destination_id !== startnodeId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var triggerkey in workflow.triggers) {
|
||||||
|
const trigger = workflow.triggers[triggerkey]
|
||||||
|
if (trigger.trigger_type !== "WEBHOOK") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trigger.id === branch.source_id) {
|
||||||
|
trigger.order = -1
|
||||||
|
relevantactions.push(trigger)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (getParents !== undefined) {
|
||||||
|
for (var key in workflow.actions) {
|
||||||
|
const action = workflow.actions[key]
|
||||||
|
if (action.id === startnodeId) {
|
||||||
|
action.order = 0
|
||||||
|
relevantactions.push(action)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const parents = getParents(action)
|
||||||
|
//const parents = getParentNodes(workflow, action)
|
||||||
|
//console.log("PARENTS", key, parents)
|
||||||
|
if (parents !== undefined && parents !== null) {
|
||||||
|
const parentfound = parents.find((element) => element.id === startnodeId)
|
||||||
|
if (parentfound !== undefined) {
|
||||||
|
|
||||||
|
// FIXME: add order here based on how many steps away from the startnode
|
||||||
|
// This just has the parent count
|
||||||
|
action.order = parents.length
|
||||||
|
|
||||||
|
relevantactions.push(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var key in workflow.triggers) {
|
||||||
|
const trigger = workflow.triggers[key]
|
||||||
|
if (trigger.trigger_type !== "SUBFLOW" && trigger.trigger_type !== "USERINPUT") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.actions.find((element) => element.id === trigger.id) === undefined) {
|
||||||
|
workflow.actions.push(trigger)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relevantactions = workflow.actions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort according to how many parents a node has. MAY be wrong~
|
||||||
|
relevantactions.sort((a, b) => {
|
||||||
|
if (a.order === undefined) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.order === undefined) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.order - b.order
|
||||||
|
})
|
||||||
|
|
||||||
|
// FIXME: Add other relevant items as well from subflows (?)
|
||||||
|
var nodecolor = "grey"
|
||||||
|
var branchcolor = "grey"
|
||||||
|
var skipped = false
|
||||||
|
|
||||||
|
var previousTools = false
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{border: workflow.validation.valid ? `2px solid ${green}` : "1px solid rgba(255,255,255,0.4)", padding: "10px 20px 10px 20px", borderRadius: theme.palette.borderRadius, }}>
|
||||||
|
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||||
|
{relevantactions.map((action, index) => {
|
||||||
|
action.result = {}
|
||||||
|
if (results !== undefined) {
|
||||||
|
const foundResult = results.find((element) => element.action.id === action.id)
|
||||||
|
if (foundResult !== undefined) {
|
||||||
|
action.result = foundResult
|
||||||
|
|
||||||
|
action.status = foundResult.status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastitem = index === relevantactions.length - 1
|
||||||
|
if (!lastitem) {
|
||||||
|
if (action.app_name === "Shuffle Tools") {
|
||||||
|
if (action.status === "SUCCESS") {
|
||||||
|
branchcolor = red
|
||||||
|
|
||||||
|
// Check action.result for the actual status
|
||||||
|
const validate = validateJson(action.result.result)
|
||||||
|
if (validate.valid) {
|
||||||
|
if (validate.result.success === true) {
|
||||||
|
branchcolor = green
|
||||||
|
} else {
|
||||||
|
branchcolor = "grey"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else if (action.status === "SKIPPED") {
|
||||||
|
branchcolor = "grey"
|
||||||
|
} else {
|
||||||
|
if (action.status === undefined) {
|
||||||
|
branchcolor = green
|
||||||
|
} else {
|
||||||
|
branchcolor = red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousTools = true
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
if (action.status === "SUCCESS") {
|
||||||
|
nodecolor = green
|
||||||
|
} else if (action.status === "SKIPPED") {
|
||||||
|
nodecolor = "grey"
|
||||||
|
} else {
|
||||||
|
if (action.status === undefined) {
|
||||||
|
nodecolor = green
|
||||||
|
} else {
|
||||||
|
nodecolor = red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodecolor = "grey"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.status === "SKIPPED") {
|
||||||
|
skipped = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var image = ""
|
||||||
|
if (action.large_image !== undefined && action.large_image !== null && action.large_image !== "") {
|
||||||
|
image = action.large_image
|
||||||
|
} else {
|
||||||
|
if (originalWorkflow !== undefined) {
|
||||||
|
for (var key in originalWorkflow.actions) {
|
||||||
|
if (originalWorkflow.actions[key].id === action.id) {
|
||||||
|
image = originalWorkflow.actions[key].large_image
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image === "") {
|
||||||
|
for (var key in originalWorkflow.triggers) {
|
||||||
|
if (originalWorkflow.triggers[key].id === action.id) {
|
||||||
|
image = originalWorkflow.triggers[key].large_image
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var founderror = ""
|
||||||
|
if (workflow.validation !== undefined && workflow.validation !== null && workflow.validation.errors !== undefined && workflow.validation.errors !== null) {
|
||||||
|
const foundError = workflow.validation.errors.find((element) => element.action_id === action.id)
|
||||||
|
if (foundError !== undefined) {
|
||||||
|
founderror = foundError.error
|
||||||
|
nodecolor = yellow
|
||||||
|
branchcolor = yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipped && !lastitem) {
|
||||||
|
nodecolor = "grey"
|
||||||
|
branchcolor = "grey"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousTools) {
|
||||||
|
previousTools = false
|
||||||
|
} else {
|
||||||
|
branchcolor = nodecolor
|
||||||
|
}
|
||||||
|
|
||||||
|
var appgroup = []
|
||||||
|
if (action.trigger_type === "WEBHOOK") {
|
||||||
|
nodecolor = green
|
||||||
|
branchcolor = green
|
||||||
|
} else if (action.app_name === "shuffle-subflow") {
|
||||||
|
if (action.status === "SUCCESS") {
|
||||||
|
nodecolor = green
|
||||||
|
branchcolor = green
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var subflowkey in workflow.validation.subflow_apps) {
|
||||||
|
const subflowApp = workflow.validation.subflow_apps[subflowkey]
|
||||||
|
if (subflowApp.error === action.id) {
|
||||||
|
appgroup.push(subflowApp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var flex = index !== 0 && index !== relevantactions.length - 1 ? 1 : 3
|
||||||
|
const branchTooltip = branchcolor === yellow ? "Check nodes for errors" : ""
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{display: "flex", flex: flex, justifyContent: "right", }}>
|
||||||
|
{lastitem ?
|
||||||
|
<Tooltip title={branchTooltip}>
|
||||||
|
<div style={{marginLeft: 0, marginRight: 0, marginTop: 20, height: 3, width: "100%", backgroundColor: branchcolor, }} />
|
||||||
|
</Tooltip>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{appgroup.length > 0 ?
|
||||||
|
<AvatarGroup max={4} style={{height: itemHeight+8, }}>
|
||||||
|
{appgroup.map((subflowApp, subflowIndex) => {
|
||||||
|
var appimage = ""
|
||||||
|
if (apps !== undefined && apps !== null && apps.length > 0) {
|
||||||
|
for (var key in apps) {
|
||||||
|
const app = apps[key]
|
||||||
|
if (app.name === subflowApp.app_name) {
|
||||||
|
appimage = apps[key].large_image
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip title={`App: ${subflowApp.app_name} - subflow app`}>
|
||||||
|
<Avatar
|
||||||
|
style={{
|
||||||
|
border: `4px solid ${nodecolor}`,
|
||||||
|
}}
|
||||||
|
src={appimage}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</AvatarGroup>
|
||||||
|
:
|
||||||
|
<Tooltip title={
|
||||||
|
<Typography variant="body1" style={{margin: 5, color: "white", }}>
|
||||||
|
{founderror.length > 0 ? founderror : ``}
|
||||||
|
</Typography>
|
||||||
|
} placement="top">
|
||||||
|
|
||||||
|
<Avatar
|
||||||
|
variant="round"
|
||||||
|
sx={{ backgroundColor: nodecolor, width: itemHeight, height: itemHeight, borderRadius: 50, border: `4px solid ${nodecolor}`,}}
|
||||||
|
>
|
||||||
|
{image !== "" ?
|
||||||
|
<img
|
||||||
|
src={image}
|
||||||
|
style={{
|
||||||
|
width: itemHeight,
|
||||||
|
height: itemHeight,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
: null}
|
||||||
|
</Avatar>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
|
||||||
|
{lastitem ? null :
|
||||||
|
<Tooltip title={branchTooltip}>
|
||||||
|
<div style={{marginLeft: 0, marginRight: 0, marginTop: 20, height: 3, width: "100%", backgroundColor: branchcolor, }} />
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WorkflowValidationTimeline
|
||||||
@@ -5385,13 +5385,17 @@ If you're interested, please let me know a time that works for you, or set up a
|
|||||||
<ListItem key={index} style={{ backgroundColor: bgColor }}>
|
<ListItem key={index} style={{ backgroundColor: bgColor }}>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary=
|
primary=
|
||||||
<Tooltip title={data.validation.valid === true ? "Valid. Click to explore." : "Configuration failed. Click to learn why"} placement="top">
|
<Tooltip title={data.validation !== null && data.validation !== undefined && data.validation.valid === true ? "Valid. Click to explore." : "Configuration failed. Click to learn why"} placement="top">
|
||||||
<IconButton>
|
<IconButton>
|
||||||
{validIcon}
|
{validIcon}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
style={{ minWidth: 65, maxWidth: 65, }}
|
style={{ minWidth: 65, maxWidth: 65, }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (data.validation === null || data.validation === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (data.validation.workflow_id === undefined || data.validation.workflow_id === null || data.validation.workflow_id.length === 0) {
|
if (data.validation.workflow_id === undefined || data.validation.workflow_id === null || data.validation.workflow_id.length === 0) {
|
||||||
toast.warn("No workflow runs found for this auth yet. Check back later.")
|
toast.warn("No workflow runs found for this auth yet. Check back later.")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ import Draggable from "react-draggable";
|
|||||||
import cytoscapestyle from "../defaultCytoscapeStyle.jsx";
|
import cytoscapestyle from "../defaultCytoscapeStyle.jsx";
|
||||||
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
||||||
|
|
||||||
|
import WorkflowValidationTimeline from "../components/WorkflowValidationTimeline.jsx"
|
||||||
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
||||||
import { GetParsedPaths, internalIds, } from "../views/Apps.jsx";
|
import { GetParsedPaths, internalIds, } from "../views/Apps.jsx";
|
||||||
import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
|
import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
|
||||||
@@ -319,6 +320,7 @@ export function SetJsonDotnotation(jsonInput, inputKey) {
|
|||||||
|
|
||||||
export const green = "#86c142";
|
export const green = "#86c142";
|
||||||
export const yellow = "#FECC00";
|
export const yellow = "#FECC00";
|
||||||
|
export const red = "red";
|
||||||
|
|
||||||
export function removeParam(key, sourceURL) {
|
export function removeParam(key, sourceURL) {
|
||||||
if (sourceURL === undefined) {
|
if (sourceURL === undefined) {
|
||||||
@@ -1641,7 +1643,6 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
setExecutionData(responseJson)
|
setExecutionData(responseJson)
|
||||||
} else {
|
} else {
|
||||||
if (responseJson.status === "ABORTED" || responseJson.status === "STOPPED" || responseJson.status === "FAILURE" || responseJson.status === "WAITING" || responseJson.status === "FINISHED") {
|
if (responseJson.status === "ABORTED" || responseJson.status === "STOPPED" || responseJson.status === "FAILURE" || responseJson.status === "WAITING" || responseJson.status === "FINISHED") {
|
||||||
console.log("DONE!")
|
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6732,7 +6733,6 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
const parentlabel = parentNode.data("label").toLowerCase().replace(" ", "_")
|
const parentlabel = parentNode.data("label").toLowerCase().replace(" ", "_")
|
||||||
const parentname = parentNode.data("app_name").toLowerCase().replace(" ", "_")
|
const parentname = parentNode.data("app_name").toLowerCase().replace(" ", "_")
|
||||||
if (!parentlabel.startsWith(parentname)+"_") {
|
if (!parentlabel.startsWith(parentname)+"_") {
|
||||||
console.log("Return 1")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7135,7 +7135,6 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
// Find how many executions it has
|
// Find how many executions it has
|
||||||
var executions = 0
|
var executions = 0
|
||||||
const matchingExecutions = workflowExecutions.filter((execution => execution.execution_source === nodedata.app_name.toLowerCase()))
|
const matchingExecutions = workflowExecutions.filter((execution => execution.execution_source === nodedata.app_name.toLowerCase()))
|
||||||
console.log("Matches: ", matchingExecutions.length)
|
|
||||||
const color = matchingExecutions.length > 0 ? "#34a853" : "#ea4436"
|
const color = matchingExecutions.length > 0 ? "#34a853" : "#ea4436"
|
||||||
const decoratorNode = {
|
const decoratorNode = {
|
||||||
position: {
|
position: {
|
||||||
@@ -10204,6 +10203,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
|
|
||||||
// Starts on current node and climbs UP the tree to the root object.
|
// Starts on current node and climbs UP the tree to the root object.
|
||||||
// Sends back everything in it's path
|
// Sends back everything in it's path
|
||||||
|
// FIXME: Use the GetParentNodes in WorkflowValidationTimeline.jsx instead
|
||||||
const getParents = (action) => {
|
const getParents = (action) => {
|
||||||
if (action === undefined || action === null) {
|
if (action === undefined || action === null) {
|
||||||
return []
|
return []
|
||||||
@@ -18720,6 +18720,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
: null}
|
: null}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{executionData.workflow !== undefined && executionData.workflow !== null && executionData.workflow.actions !== undefined && executionData.workflow.actions !== null && executionData.workflow.actions.length > 0 ?
|
{executionData.workflow !== undefined && executionData.workflow !== null && executionData.workflow.actions !== undefined && executionData.workflow.actions !== null && executionData.workflow.actions.length > 0 ?
|
||||||
<div style={{ display: "flex", marginLeft: 10, }}>
|
<div style={{ display: "flex", marginLeft: 10, }}>
|
||||||
<Typography variant="body1">
|
<Typography variant="body1">
|
||||||
@@ -18831,12 +18832,31 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
{new Date(executionData.completed_at * 1000).toLocaleString("en-GB")}
|
{new Date(executionData.completed_at * 1000).toLocaleString("en-GB")}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
{executionData.workflow !== undefined && executionData.workflow !== null && executionData.status !== "EXECUTING" ?
|
||||||
|
<div style={{marginTop: 5, marginBottom: 5, }}>
|
||||||
|
<WorkflowValidationTimeline
|
||||||
|
originalWorkflow={workflow}
|
||||||
|
|
||||||
|
apps={apps}
|
||||||
|
workflow={executionData.workflow}
|
||||||
|
getParents={getParents}
|
||||||
|
|
||||||
|
execution={executionData}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
<div style={{ marginTop: 10 }} />
|
<div style={{ marginTop: 10 }} />
|
||||||
{executionData.execution_argument !== undefined &&
|
|
||||||
executionData.execution_argument.length > 0
|
{executionData.execution_argument !== undefined && executionData.execution_argument !== null &&
|
||||||
|
executionData.execution_argument.length > 1
|
||||||
? parsedExecutionArgument()
|
? parsedExecutionArgument()
|
||||||
: null}
|
:
|
||||||
|
null}
|
||||||
|
|
||||||
<Divider
|
<Divider
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "rgba(255,255,255,0.6)",
|
backgroundColor: "rgba(255,255,255,0.6)",
|
||||||
@@ -18844,6 +18864,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{executionData.results !== undefined &&
|
{executionData.results !== undefined &&
|
||||||
executionData.results !== null &&
|
executionData.results !== null &&
|
||||||
executionData.results.length > 1 &&
|
executionData.results.length > 1 &&
|
||||||
@@ -19538,7 +19559,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
if (stringjson.includes("\n") && !stringjson.includes("\n")) {
|
if (stringjson.includes("\n") && !stringjson.includes("\n")) {
|
||||||
return "Looks like you have a newline problem. Consider using the | replace: '\n', '\\n' }} filter in Liquid."
|
return "Looks like you have a newline problem. Consider using the | replace: '\n', '\\n' }} filter in Liquid."
|
||||||
} else {
|
} else {
|
||||||
return "The result looks like it should be JSON, but is invalid. Look for potential"
|
return "The result looks like it should be JSON, but is invalid. Look for potential single quotes instead of double quotes, missing commas or newlines"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,6 +178,51 @@ func getThisContainerId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cleanupExistingNodes(ctx context.Context) error {
|
func cleanupExistingNodes(ctx context.Context) error {
|
||||||
|
|
||||||
|
if isKubernetes == "true" {
|
||||||
|
if kubernetesNamespace == "" {
|
||||||
|
kubernetesNamespace = "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
clientset, _, err := shuffle.GetKubernetesClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Error getting kubernetes client:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all pods
|
||||||
|
pods, err := clientset.CoreV1().Pods(kubernetesNamespace).List(context.Background(), metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed listing pods: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pod := range pods.Items {
|
||||||
|
err := clientset.CoreV1().Pods(kubernetesNamespace).Delete(context.Background(), pod.Name, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed deleting pod %s: %s", pod.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all services
|
||||||
|
services, err := clientset.CoreV1().Services(kubernetesNamespace).List(context.Background(), metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed listing services: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, service := range services.Items {
|
||||||
|
err := clientset.CoreV1().Services(kubernetesNamespace).Delete(context.Background(), service.Name, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed deleting service %s: %s", service.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Cleaned up all pods and services in namespace %s", kubernetesNamespace)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
serviceListOptions := types.ServiceListOptions{}
|
serviceListOptions := types.ServiceListOptions{}
|
||||||
services, err := dockercli.ServiceList(
|
services, err := dockercli.ServiceList(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
@@ -1662,11 +1707,12 @@ func main() {
|
|||||||
if swarmConfig == "run" || swarmConfig == "swarm" || isKubernetes == "true" {
|
if swarmConfig == "run" || swarmConfig == "swarm" || isKubernetes == "true" {
|
||||||
if isKubernetes != "true" {
|
if isKubernetes != "true" {
|
||||||
checkSwarmService(ctx)
|
checkSwarmService(ctx)
|
||||||
log.Printf("[DEBUG] Cleaning up containers from previous run")
|
|
||||||
cleanupExistingNodes(ctx)
|
|
||||||
time.Sleep(time.Duration(5) * time.Second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Cleaning up containers from previous run")
|
||||||
|
cleanupExistingNodes(ctx)
|
||||||
|
time.Sleep(time.Duration(5) * time.Second)
|
||||||
|
|
||||||
log.Printf("[DEBUG] Deploying worker image %s to swarm", workerImage)
|
log.Printf("[DEBUG] Deploying worker image %s to swarm", workerImage)
|
||||||
|
|
||||||
runString := "Run: \"docker service ls\" for more info"
|
runString := "Run: \"docker service ls\" for more info"
|
||||||
|
|||||||
Reference in New Issue
Block a user