{/* {hideBodyButton} */}
diff --git a/frontend/src/components/SearchData.jsx b/frontend/src/components/SearchData.jsx
index 89ab2050..6e619652 100644
--- a/frontend/src/components/SearchData.jsx
+++ b/frontend/src/components/SearchData.jsx
@@ -47,7 +47,7 @@ const chipStyle = {
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
const SearchData = props => {
- const { serverside, globalUrl, userdata, setModalOpen, modalOpen } = props
+ const { serverside, globalUrl, userdata, searchBarModalOpen, setSearchBarModalOpen } = props
let navigate = useNavigate();
const borderRadius = 3
const node = useRef()
@@ -56,8 +56,8 @@ const SearchData = props => {
const [value, setValue] = useState("");
const handleLinkClick = () => {
- if (modalOpen) {
- setModalOpen(false); // Assuming setModalOpen is defined correctly
+ if (searchBarModalOpen) {
+ setSearchBarModalOpen(false); // Assuming setModalOpen is defined correctly
} else {
console.log("Condition not met, staying on the same page");
}
@@ -95,7 +95,7 @@ const SearchData = props => {
const trimmedValue = inputValue.trim();
if (trimmedValue !== '') {
navigate(`/search?q=${trimmedValue}`, { state: trimmedValue, replace: true });
- setModalOpen(false);
+ setSearchBarModalOpen(false);
}
}
};
@@ -249,7 +249,7 @@ const SearchData = props => {
{
//console.log("CLICK")
setSearchOpen(true)
- setModalOpen(false)
+ setSearchBarModalOpen(false)
aa('init', {
appId: searchClient.appId,
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
@@ -498,7 +498,7 @@ const SearchData = props => {
return (
{
setSearchOpen(true)
- setModalOpen(false)
+ setSearchBarModalOpen(false)
aa('init', {
appId: searchClient.appId,
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
@@ -702,7 +702,7 @@ const SearchData = props => {
console.log("CLICK")
setSearchOpen(true)
- setModalOpen(false)
+ setSearchBarModalOpen(false)
}}>
{
setMouseHoverIndex(index)
diff --git a/frontend/src/components/Searchfield.jsx b/frontend/src/components/Searchfield.jsx
index 6b3c50ae..83fb7675 100644
--- a/frontend/src/components/Searchfield.jsx
+++ b/frontend/src/components/Searchfield.jsx
@@ -1,9 +1,11 @@
-import React, { useState, useEffect, useRef } from 'react';
+import React, { useState, useEffect, useRef, useContext } from 'react';
import theme from '../theme.jsx';
import { useNavigate, Link, useParams } from "react-router-dom";
import SearchBox from "../components/SearchData.jsx";
+import { Context } from '../Context/contextApi.js';
+
import {
Chip,
IconButton,
@@ -45,20 +47,22 @@ const chipStyle = {
const SearchField = props => {
const { serverside, userdata, isMobile, isLoaded, globalUrl, isHeader, isLoggedIn, small, rounded } = props
+ const {searchBarModalOpen, setSearchBarModalOpen} = useContext(Context);
+
let navigate = useNavigate();
const borderRadius = 3
const node = useRef()
const [searchOpen, setSearchOpen] = useState(false)
- const [modalOpen, setModalOpen] = React.useState(false);
+ // const [modalOpen, setModalOpen] = React.useState(false);
const [oldPath, setOldPath] = useState("")
const [value, setValue] = useState("");
useEffect(() => {
Mousetrap.bind(['command+k', 'ctrl+k'], () => {
- setModalOpen(true);
+ setSearchBarModalOpen(true);
return false; // Prevent the default action
});
Mousetrap.bind(['esc'], () => {
- setModalOpen(false);
+ setSearchBarModalOpen(false);
return false; // Prevent the default action
});
@@ -72,9 +76,9 @@ const SearchField = props => {
// console.log("key:", dataValue.key),
//console.log("value:",dataValue.value),
: null}
+
{
// Check if event.target.value is an array. If it is, split with comma
- console.log("1 - SELECTED ACTION: ", selectedAction)
- console.log("1 - DATA: ", data)
if (data.startsWith("${") && data.endsWith("}")) {
// PARAM FIX - Gonna use the ID field, even though it's a hack
diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx
index 3cbeb077..e05a7d90 100755
--- a/frontend/src/views/Docs.jsx
+++ b/frontend/src/views/Docs.jsx
@@ -152,6 +152,8 @@ export const OuterLink = (props) => {
export const Img = (props) => {
+ // Find parent container and check width
+
var height = "auto"
var width = 750
if (props.height !== undefined && props.height !== null) {
diff --git a/frontend/src/views/RunWorkflow.jsx b/frontend/src/views/RunWorkflow.jsx
index e8f3617d..9d741300 100644
--- a/frontend/src/views/RunWorkflow.jsx
+++ b/frontend/src/views/RunWorkflow.jsx
@@ -6,7 +6,7 @@ import ReactJson from "react-json-view-ssr";
import { green, yellow, red, grey} from "./AngularWorkflow.jsx";
import { CodeHandler, Img, OuterLink, } from "../views/Docs.jsx";
import { useNavigate, Link, useParams } from "react-router-dom";
-import { validateJson, GetIconInfo } from "./Workflows.jsx";
+import { validateJson, collapseField, GetIconInfo } from "./Workflows.jsx";
import EditWorkflow from "../components/EditWorkflow.jsx"
import { toast } from "react-toastify"
import { makeStyles } from '@mui/material/styles';
@@ -15,6 +15,7 @@ import { isMobile } from "react-device-detect";
import Markdown from "react-markdown";
import theme from '../theme.jsx';
import rehypeRaw from "rehype-raw";
+import RecentWorkflow from "../components/RecentWorkflow.jsx";
import {
Tooltip,
@@ -39,6 +40,9 @@ import {
ContentCopy as ContentCopyIcon,
ArrowBack as ArrowBackIcon,
ArrowForward as ArrowForwardIcon,
+ Lock as LockIcon,
+ LockOpen as LockOpenIcon,
+ OpenInNew as OpenInNewIcon,
} from '@mui/icons-material';
const hrefStyle = {
@@ -75,12 +79,30 @@ const RunWorkflow = (defaultprops) => {
const [editWorkflowModalOpen, setEditWorkflowModalOpen] = React.useState(false)
const [sharingOpen, setSharingOpen] = React.useState(false)
const [realtimeMarkdown, setRealtimeMarkdown] = React.useState("")
+ const [forms, setForms] = React.useState([])
+
+ const IframeWrapper = (props) => {
+ var propsCopy = JSON.parse(JSON.stringify(props))
+ propsCopy.width = 400
+ propsCopy.height = 225
+
+ return
+ }
+
+ const ImgWrapper = (props) => {
+ var propsCopy = JSON.parse(JSON.stringify(props))
+ if (propsCopy.width === undefined || propsCopy.width === null) {
+ propsCopy.width = 400
+ propsCopy.height = "auto"
+ }
+
+ return Img(propsCopy)
+ }
const boxStyle = {
color: "white",
padding: "25px 50px 50px 50px",
backgroundColor: theme.palette.surfaceColor,
- marginBottom: 150,
borderRadius: 25,
minHeight: 500,
}
@@ -123,6 +145,39 @@ const RunWorkflow = (defaultprops) => {
return true
}
+ const loadForms = (orgId) => {
+ const url = `${globalUrl}/api/v1/orgs/${orgId}/forms`
+ fetch(url, {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for org forms");
+ }
+
+ return response.json()
+ })
+ .then((responseJson) => {
+ if (responseJson.success === false) {
+ toast.error("Failed saving workflow. Please try again.")
+ } else {
+ if (responseJson?.length > 0) {
+ // Sort them by name
+ responseJson.sort((a, b) => a.name.localeCompare(b.name))
+ setForms(responseJson)
+ }
+ }
+ })
+ .catch((error) => {
+ //toast.error("Load form error: " + error)
+ })
+ }
+
const saveWorkflow = (workflow) => {
const url = `${globalUrl}/api/v1/workflows/${workflow.id}`
fetch(url, {
@@ -198,26 +253,13 @@ const RunWorkflow = (defaultprops) => {
return defaultReturn
}
+ const validate = validateJson(executionData.result)
+
return (
- {/*executionData !== undefined && executionData !== null && executionData !== {} && executionData.status !== undefined && (answer === undefined || answer === null) ?
-
-
- Status
-
-
- {executionData.status}
-
-
- : null*/}
+
- {/*
-
- Results: {executionData.results.length}/{executionData.workflow.actions.length}
-
- */}
-
- {executionData.result !== undefined && executionData.result !== null && executionData.result.length > 0 ?
+ {validate.valid === false ?
{
overflowY: "auto",
}}
>
- {executionData.result}
+ {validate.result}
- : null}
+ :
+
{
+ return collapseField(jsonField)
+ }}
+ displayArrayKey={false}
+ enableClipboard={(copy) => {
+ //handleReactJsonClipboard(copy);
+ }}
+ displayDataTypes={false}
+ onSelect={(select) => {
+ //HandleJsonCopy(validate.result, select, "exec");
+ }}
+ name={false}
+ />
+ }
)
@@ -249,8 +312,6 @@ const RunWorkflow = (defaultprops) => {
event.preventDefault()
}
- console.log("ONSUBMIT: ", event, execution_id, authorization, answer)
-
stop()
setMessage("")
setExecutionLoading(true)
@@ -285,7 +346,7 @@ const RunWorkflow = (defaultprops) => {
*/
}
- var url = `${globalUrl}/api/v1/workflows/${props.match.params.key}/execute`
+ var url = `${globalUrl}/api/v1/workflows/${props.match.params.key}/run`
var fetchBody = {
headers: {
'Content-Type': 'application/json; charset=utf-8',
@@ -319,8 +380,6 @@ const RunWorkflow = (defaultprops) => {
}
// IF there is an execution argument, we should use it
- console.log("FULL URL: ", url)
-
fetch(url, fetchBody)
.then((response) => {
if (response.status !== 200 && response.status !== 201) {
@@ -346,6 +405,10 @@ const RunWorkflow = (defaultprops) => {
})
.then(responseJson => {
setExecutionLoading(false)
+ if (responseJson.execution_id !== undefined && responseJson.execution_id !== null && responseJson.execution_id.length > 0) {
+ navigate(`?execution_id=${responseJson.execution_id}`)
+ }
+
if (responseJson.success === false) {
console.log("Failed sending execution request")
if (responseJson.reason !== undefined && responseJson.reason !== null) {
@@ -372,7 +435,7 @@ const RunWorkflow = (defaultprops) => {
})
.catch(error => {
//setExecutionInfo("Error in workflow startup: " + error)
- toast.warn("Error in workflow startup: " + error)
+ toast.warn("Error submitting form. Please try again.")
stop()
setMessage("")
@@ -383,10 +446,104 @@ const RunWorkflow = (defaultprops) => {
})
}
+ /*
+ useEffect(() => {
+ if (executionRequest === undefined || executionRequest === null || executionRequest.execution_id === undefined || executionRequest.execution_id === null || executionRequest.execution_id.length === 0) {
+ return
+ }
+
+ if (executionRequest.start === true) {
+ start()
+ }
+ }, [executionRequest])
+ */
+
+ const { start, stop } = useInterval({
+ duration: 1500,
+ startImmediate: true,
+ callback: () => {
+ fetchUpdates(executionRequest.execution_id, executionRequest.authorization)
+ },
+ })
+
+ const handleExecutionLoader = () => {
+ if (window === undefined || window === null) {
+ console.log("No window")
+ return
+ }
+
+ const urlParams = new URLSearchParams(window.location.search)
+ if (urlParams === undefined || urlParams === null) {
+ console.log("No search params")
+ return
+ }
+
+ const execution = urlParams.get("execution_id")
+ if (execution === undefined || execution === null || execution.length === 0) {
+ console.log("No execution")
+ }
+
+ // Only works if you're logged in
+ fetchUpdates(execution, "")
+ }
+
+ const loadInputWorkflowData = (workflow_id, inputWorkflow) => {
+
+ const url = `${globalUrl}/api/v1/workflows/${workflow_id}/run`
+ fetch(url, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for workflows :O!");
+ }
+
+ return response.json()
+ })
+ .then((responseJson) => {
+ // Timeout after 5 seconds (max load time)
+ if (responseJson.execution_id !== undefined && responseJson.execution_id !== null && responseJson.execution_id.length > 0 && responseJson.authorization !== undefined && responseJson.authorization !== null && responseJson.authorization.length > 0) {
+
+ //for (var key in responseJson.results) {
+ for (let i = 0; i < 5; i++) {
+ setTimeout(() => {
+ fetchUpdates(responseJson.execution_id, responseJson.authorization, false, true)
+ }, i * 1000)
+ }
+ } else {
+ // Replace the markdown with the result
+ if (realtimeMarkdown !== undefined && realtimeMarkdown !== null && realtimeMarkdown.length > 0) {
+ const newmarkdown = realtimeMarkdown.replace(`{{ ${workflow_id} }}`, "", -1)
+ setRealtimeMarkdown(newmarkdown)
+ } else if (inputWorkflow.input_markdown !== undefined && inputWorkflow.input_markdown !== null && inputWorkflow.input_markdown.length > 0) {
+ const newmarkdown = inputWorkflow.input_markdown.replace(`{{ ${workflow_id} }}`, "", -1)
+ setRealtimeMarkdown(newmarkdown)
+ }
+ }
+
+ })
+ .catch((error) => {
+ console.log("Get workflow error: ", error.toString())
+
+ if (realtimeMarkdown !== undefined && realtimeMarkdown !== null && realtimeMarkdown.length > 0) {
+ const newmarkdown = inputWorkflow.input_markdown.replace(`{{ ${workflow_id} }}`, "", -1)
+ setRealtimeMarkdown(newmarkdown)
+ } else if (inputWorkflow.input_markdown !== undefined && inputWorkflow.input_markdown !== null && inputWorkflow.input_markdown.length > 0) {
+ const newmarkdown = inputWorkflow.input_markdown.replace(`{{ ${workflow_id} }}`, "", -1)
+ setRealtimeMarkdown(newmarkdown)
+ }
+ })
+ }
const getWorkflow = (workflow_id, selectedNode) => {
- const url = `${globalUrl}/api/v1/workflows/${workflow_id}`
+ setRealtimeMarkdown("")
+ const url = `${globalUrl}/api/v1/workflows/${workflow_id}`
fetch(url, {
method: "GET",
headers: {
@@ -404,7 +561,7 @@ const RunWorkflow = (defaultprops) => {
toast("This Form is not available to you. If you think this is an error, please contact support@shuffler.io with the URL.")
}
- return response.json();
+ return response.json()
})
.then((responseJson) => {
// Not sure why this is necessary.
@@ -488,20 +645,57 @@ const RunWorkflow = (defaultprops) => {
if (responseJson.input_markdown !== undefined && responseJson.input_markdown !== null && responseJson.input_markdown.length > 0) {
// Look for {{ uuid }} format, and try to run that workflow with their account
// This is a hack, but a fun one.
+ var newmarkdown = responseJson.input_markdown.replace("", "")
- const uuidRegex = /{{\s*[a-f0-9-]+\s*}}/g
- const found = responseJson.input_markdown.match(uuidRegex)
+ const uuidRegex = /{{\s[a-f0-9-]+\s}}/g
+ const found = newmarkdown.match(uuidRegex)
if (found !== undefined && found !== null && found.length > 0) {
+ var handled = []
for (var foundkey in found) {
const uuid = found[foundkey].replace("{{", "").replace("}}", "").trim()
- // Run the workflow, then replace it.
- // Only run if logged in
- console.log("Found UUID: " + uuid)
- responseJson.input_markdown = responseJson.input_markdown.replace(found[foundkey], "")
+
+ if (handled.includes(uuid)) {
+ continue
+ }
+
+ handled.push(uuid)
+
+ const storageKey = `workflowresult_${uuid}`
+ const value = localStorage.getItem(storageKey)
+
+ var runWorkflow = false
+ if (value !== undefined && value !== null && value.length > 0) {
+ // Check if timestamp with new Date().getTime() is more than 10 minutes ago
+ const parsedValue = JSON.parse(value)
+ if (parsedValue.timestamp !== undefined && parsedValue.timestamp !== null) {
+ // 1 min = 60000ms -> 5 min = 300000ms
+ const now = new Date().getTime()
+ if (now - parsedValue.timestamp > 300000) {
+ localStorage.removeItem(storageKey)
+ runWorkflow = true
+ } else {
+ newmarkdown = newmarkdown.replace(`{{ ${uuid} }}`, parsedValue.result, -1)
+ }
+ } else {
+ runWorkflow = true
+ }
+ } else {
+ runWorkflow = true
+ }
+
+ if (runWorkflow) {
+ loadInputWorkflowData(uuid, responseJson)
+ }
+
}
+
+ setRealtimeMarkdown(newmarkdown)
}
}
+
+ handleExecutionLoader()
+
handleGetOrg(responseJson.org_id)
setWorkflow(responseJson);
})
@@ -510,13 +704,6 @@ const RunWorkflow = (defaultprops) => {
});
};
- const { start, stop } = useInterval({
- duration: 1500,
- startImmediate: true,
- callback: () => {
- fetchUpdates(executionRequest.execution_id, executionRequest.authorization)
- },
- });
const handleUpdateResults = (responseJson, executionRequest) => {
if (responseJson === undefined || responseJson === null || responseJson.success === false) {
@@ -582,13 +769,16 @@ const RunWorkflow = (defaultprops) => {
})
}
- const handleGetOrg = (orgId, execution_id, authorization) => {
- if (orgId.length === 0) {
- return;
+ const handleGetOrg = (orgId, execution_id, authorization) => {
+ if (orgId === undefined || orgId === null || orgId.length === 0) {
+ return
}
// Just use this one?
var url = execution_id !== undefined && authorization !== undefined ? `${globalUrl}/api/v1/orgs/${orgId}?reference_execution=${execution_id}&authorization=${authorization}` : `${globalUrl}/api/v1/orgs/${orgId}`;
+
+ loadForms(orgId)
+
fetch(url, {
method: "GET",
credentials: "include",
@@ -611,6 +801,11 @@ const RunWorkflow = (defaultprops) => {
if (document != undefined && document.title != defaultTitle) {
document.title = responseJson.name + " - " + defaultTitle
}
+
+ if (responseJson.image !== undefined && responseJson.image !== null && responseJson.image.length > 0) {
+ } else {
+ responseJson.image = theme.palette.defaultImage
+ }
setSelectedOrganization(responseJson)
}
})
@@ -619,23 +814,25 @@ const RunWorkflow = (defaultprops) => {
});
};
- const fetchUpdates = (execution_id, authorization, getorg) => {
+ const fetchUpdates = (execution_id, authorization, getorg, replaceMarkdown) => {
if (execution_id === undefined || execution_id === null || execution_id === "") {
+ console.log("No execution id: ", execution_id)
stop()
return
}
const innerRequest = {
"execution_id": execution_id,
- "authorization": authorization
+ "authorization": authorization === undefined || authorization === null ? "" : authorization,
}
- if (executionRequest.execution_id !== innerRequest.execution_id) {
+ if (executionRequest.execution_id !== innerRequest.execution_id && replaceMarkdown !== true) {
setExecutionRequest(innerRequest)
}
- if (execution_id === "" || authorization === "") {
- setExecutionLoading(false)
+ if (execution_id === "") {
+ console.log("No execution id or authorization")
+ setExecutionLoading(false)
setExecutionRunning(false)
stop()
return
@@ -658,11 +855,38 @@ const RunWorkflow = (defaultprops) => {
return response.json();
})
.then((responseJson) => {
- if (getorg === true) {
- handleGetOrg(responseJson.org_id, execution_id, authorization)
+ if (responseJson.success == false) {
+ return
}
- handleUpdateResults(responseJson, executionRequest);
+ if (replaceMarkdown === true) {
+ if (responseJson.result.length > 0) {
+ // Set local storage for the workflow id
+ const storageKey = `workflowresult_${responseJson.workflow.id}`
+ const value = {
+ "timestamp": new Date().getTime(),
+ "result": responseJson.result,
+ }
+
+ localStorage.setItem(storageKey, JSON.stringify(value))
+ }
+
+ if (realtimeMarkdown !== undefined && realtimeMarkdown !== null && realtimeMarkdown.length > 0) {
+ const newmarkdown = realtimeMarkdown.replace(`{{ ${responseJson.workflow.id} }}`, responseJson.result, -1)
+ setRealtimeMarkdown(newmarkdown)
+
+ } else if (workflow.input_markdown !== undefined && workflow.input_markdown !== null && workflow.input_markdown.length > 0) {
+ const newmarkdown = workflow.input_markdown.replace(`{{ ${responseJson.workflow.id} }}`, responseJson.result, -1)
+ setRealtimeMarkdown(newmarkdown)
+ }
+
+ } else {
+ if (getorg === true) {
+ handleGetOrg(responseJson.org_id, execution_id, authorization)
+ }
+
+ handleUpdateResults(responseJson, executionRequest);
+ }
})
.catch((error) => {
console.log("Execution result Error: ", error);
@@ -741,10 +965,8 @@ const RunWorkflow = (defaultprops) => {
const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)"
const buttonStyle = {borderRadius: 25, height: 50, fontSize: 18, backgroundImage: handleValidateForm(executionArgument) || executionLoading ? buttonBackground : "grey", color: "white"}
- const disabledButtons = message.length > 0 || executionData.status === "FINISHED" || executionData.status === "ABORTED"
-
- //{disabledButtons ? null :
-
+ //const disabledButtons = message.length > 0 || executionData.status === "FINISHED" || executionData.status === "ABORTED"
+ const disabledButtons = executionLoading || executionRunning
const organization = selectedOrganization !== undefined && selectedOrganization !== null ? selectedOrganization.name : "Unknown"
const contact = selectedOrganization !== undefined && selectedOrganization !== null && selectedOrganization.org !== undefined && selectedOrganization.org !== null? selectedOrganization.org : "support@shuffler.io"
@@ -786,12 +1008,12 @@ const RunWorkflow = (defaultprops) => {
:
-
{workflow.input_markdown !== undefined && workflow.input_markdown !== null && workflow.input_markdown.length > 0 ?
{
return (
- {question.name}
{multiChoiceOptions.length > 1 ?
-
}
@@ -1048,15 +1279,16 @@ const RunWorkflow = (defaultprops) => {
const validate = validateJson(foundresult.result)
validResults += 1
- console.log("VAlid: ", validate)
-
var appendedDetails = foundresult.result
if (validate.valid) {
appendedDetails = {
+ return collapseField(jsonField)
+ }}
iconStyle={theme.palette.jsonIconStyle}
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
displayArrayKey={false}
@@ -1096,6 +1328,9 @@ const RunWorkflow = (defaultprops) => {
}
+
+ Forms are in Beta. Form submissions data includes your Organization's unique ID while logged in, or a unique identifier for your browser otherwise. Your input will be automatically sanitized.
+
@@ -1185,39 +1420,38 @@ const RunWorkflow = (defaultprops) => {
{isLoggedIn && userdata?.active_org?.id === workflow?.org_id ?
-
{
- navigate(`/workflows`)
- }}
- >
-
- Workflows
-
{
- window.open(`/workflow/${workflow.id}`, "_blank")
+ window.open(`/workflows/${workflow.id}`, "_blank")
}}
>
-
+
Workflow
{
setSharingOpen(true)
}}
>
- Share Form
+ {workflow.sharing === "form" ?
+
+ :
+
+ }
+
+ {workflow.sharing === "form" ?
+ "Unshare"
+ :
+ "Share"
+ }
{
+ // Check width
+ const overlap = window !== undefined && window.innerWidth !== undefined && window.innerWidth < 1300
+ const formSidebar = !isLoaded || overlap || !(forms !== undefined && forms !== null && forms.length > 1) ? null :
+
+ {selectedOrganization !== undefined && selectedOrganization !== null ?
+
+

+
+ {selectedOrganization.name}
+
+
+
+ : null}
+
+ {forms !== undefined && forms !== null && forms.length > 0 ?
+
+ {forms.map((form, formIndex) => {
+ if (form.id === undefined || form.id === null) {
+ return null
+ }
+
+ return (
+
+ {
+ navigate(`/forms/${form.id}`)
+ getWorkflow(form.id, sourceNode)
+ }}
+ currentWorkflowId={workflow.id}
+ />
+
+ {/*
+ {
+ navigate(`/forms/${form.id}`)
+ getWorkflow(form.id, sourceNode)
+ }}
+ >
+ {form.name}
+
+ */}
+
+ )
+ })}
+
+ :
+
+ No forms loaded
+
+ }
+
+
+
return (
-
+
{loadedCheck}
+ {formSidebar}
)
}
diff --git a/frontend/src/views/SetAuthentication.jsx b/frontend/src/views/SetAuthentication.jsx
index 0015deda..cbcda6dd 100755
--- a/frontend/src/views/SetAuthentication.jsx
+++ b/frontend/src/views/SetAuthentication.jsx
@@ -3,6 +3,8 @@ import React, { useState } from "react";
import { Typography, CircularProgress } from "@mui/material";
import theme from '../theme.jsx';
+import { red, } from "../views/AngularWorkflow.jsx"
+
const SetAuthentication = (props) => {
const { globalUrl } = props;
@@ -300,7 +302,7 @@ const SetAuthentication = (props) => {
}
return (
-
+
{
variant="h6"
style={{ marginLeft: "auto", marginRight: "auto", marginTop: 50}}
>
- {!finished ? (
+ {!finished ?
failed ?
null :
- ) : (
- "Done - this window should close within 3 seconds."
- )}
-
- {failed ? "Failed setup. Error: " : ""} {response}
+ :
+ failed ?
+ null
+ :
+ "Done - this window should close within 3 seconds."
+ }
+
+
+ {failed ? "Failed auth. Error: " : ""} {response}
- {failed ? "If the error persists, try to use fewer scopes. Contact our support at support@shuffler.io if you need further assistance. You may close this window." : ""}
+ {failed ? "If the error persists, try to use fewer scopes. Contact support@shuffler.io if you need further assistance, and include the current URL and a screenshot. You may now close this window." : ""}
);
diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx
index a17b08ed..00eca27b 100755
--- a/frontend/src/views/Workflows.jsx
+++ b/frontend/src/views/Workflows.jsx
@@ -417,7 +417,37 @@ const chipStyle = {
color: "white",
};
+export const collapseField = (field) => {
+ if (field === undefined || field === null) {
+ return true
+ }
+
+ if (field.name === "headers" || field.name === "cookies") {
+ return true
+ }
+
+ if (field.type === "array") {
+ return true
+ }
+
+ // If more than 10 keys in object, collapse
+ if (field.type === "object") {
+ if (Object.keys(field.src).length > 7) {
+ return true
+ }
+ }
+
+ return false
+}
+
export const validateJson = (showResult) => {
+ if (showResult === undefined || showResult === null) {
+ return {
+ valid: false,
+ result: "",
+ }
+ }
+
if (typeof showResult === 'string') {
showResult = showResult.split(" False").join(" false")
showResult = showResult.split(" True").join(" true")
@@ -645,24 +675,21 @@ const Workflows = (props) => {
}
setGettingStartedItems(activeFiltered)
- //const doneFiltered = activeFiltered.filter((item) => item.done === true)
- //if (doneFiltered.length > 0) {
- // console.log("DONE: ", doneFiltered)
- //}
-
- const sidebar = localStorage.getItem(sidebarKey);
- if (sidebar === null || sidebar === undefined) {
- console.log("No sidebar defined")
-
- localStorage.setItem(sidebarKey, "open");
- setDrawerOpen(true)
- } else {
+ /*
+ const sidebar = localStorage.getItem(sidebarKey)
+ if (sidebar === null || sidebar === undefined) {
+ console.log("No sidebar defined")
+
+ localStorage.setItem(sidebarKey, "open");
+ setDrawerOpen(true)
+ } else {
if (sidebar === "open") {
- setDrawerOpen(true)
+ setDrawerOpen(true)
} else {
- setDrawerOpen(false)
+ setDrawerOpen(false)
}
}
+ */
}
}
@@ -976,7 +1003,7 @@ const Workflows = (props) => {
onClick={() => {
console.log("Editing: ", editingWorkflow);
if (selectedWorkflowId) {
- deleteWorkflow(selectedWorkflowId);
+ deleteWorkflow(selectedWorkflowId)
setTimeout(() => {
getAvailableWorkflows();
}, 1000);
@@ -1877,7 +1904,7 @@ const Workflows = (props) => {
toast("Failed deleting workflow. Do you have access?");
} else {
if (bulk !== true) {
- toast("Deleted workflow " + id);
+ toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`)
}
}
@@ -2063,6 +2090,8 @@ const Workflows = (props) => {
{"Create Form"}
+
+
-
-
+
+
+
+
+