Fixed a lot of the weird suborg distribution workflow issues
This commit is contained in:
@@ -1743,15 +1743,6 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
|
||||
Environments: execInfo.Environments,
|
||||
}
|
||||
|
||||
//executionRequestWrapper, err := getWorkflowQueue(ctx, environment)
|
||||
//if err != nil {
|
||||
// executionRequestWrapper = ExecutionRequestWrapper{
|
||||
// Data: []ExecutionRequest{executionRequest},
|
||||
// }
|
||||
//} else {
|
||||
// executionRequestWrapper.Data = append(executionRequestWrapper.Data, executionRequest)
|
||||
//}
|
||||
|
||||
//log.Printf("Execution request: %#v", executionRequest)
|
||||
executionRequest.Priority = workflowExecution.Priority
|
||||
err = shuffle.SetWorkflowQueue(ctx, executionRequest, environment)
|
||||
|
||||
@@ -104,9 +104,10 @@ const EditWorkflow = (props) => {
|
||||
const foundScroll = document.getElementById(scrollTo)
|
||||
if (foundScroll !== null) {
|
||||
// Smooth scroll
|
||||
foundScroll.scrollIntoView({ behavior: "smooth" })
|
||||
foundScroll.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
})
|
||||
}
|
||||
|
||||
}, 200)
|
||||
setScrollDone(true)
|
||||
|
||||
@@ -565,13 +566,12 @@ const EditWorkflow = (props) => {
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<Divider style={{ marginTop: 20, marginBottom: 20, }} />
|
||||
<Divider id="mssp_control" style={{ marginTop: 20, marginBottom: 20, }} />
|
||||
|
||||
<Typography variant="h4" style={{ marginTop: 50, }}>
|
||||
MSSP controls
|
||||
</Typography>
|
||||
|
||||
|
||||
<Typography variant="body1" style={{ marginTop: 50, }}>
|
||||
MSSP Suborg Distribution (<b>beta</b> - contact support@shuffler.io for more info)
|
||||
</Typography>
|
||||
|
||||
@@ -889,7 +889,7 @@ useEffect(() => {
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", width:"100%", height: "100%", overflowY: "auto", overflowX: "hidden",transition: 'display 0.3s ease',paddingTop: 0.5 }} onMouseOver={()=>{!leftSideBarOpenByClick && setExpandLeftNav(true)}} onMouseLeave={()=>{!leftSideBarOpenByClick && setExpandLeftNav(false);setOpenAutocomplete(false)}}>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", width:"100%", height: "100%", overflowY: "auto", overflowX: "hidden",transition: 'display 0.3s ease',paddingTop: 0.5 }} onMouseOver={()=>{(!leftSideBarOpenByClick || window?.location?.pathname?.includes("/workflows/")) && setExpandLeftNav(true)}} onMouseLeave={()=>{(!leftSideBarOpenByClick || window?.location?.pathname?.includes("/workflows/")) && setExpandLeftNav(false);setOpenAutocomplete(false)}}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@@ -1194,7 +1194,7 @@ useEffect(() => {
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
marginTop: 1
|
||||
marginTop: 0
|
||||
}}
|
||||
>
|
||||
<span style={{ display: "inline-block", width: "100%" }}>
|
||||
@@ -1229,7 +1229,7 @@ useEffect(() => {
|
||||
width: 18,
|
||||
height: 18,
|
||||
marginRight: expandLeftNav ? 10 : 0,
|
||||
color: userdata?.support ? "inherit" : "#6F6F6F",
|
||||
color: "inherit",
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
@@ -1527,7 +1527,7 @@ useEffect(() => {
|
||||
</Link>
|
||||
|
||||
|
||||
<Link to="/admin?admin_tab=billingstats" style={hrefStyle}>
|
||||
<Link to={isCloud ? "/admin?admin_tab=billingstats" : "/admin?admin_tab=locations"} style={hrefStyle}>
|
||||
<Button
|
||||
onClick={(event) => {
|
||||
setCurrentOpenTab("admin");
|
||||
|
||||
@@ -177,8 +177,8 @@ const ParsedAction = (props) => {
|
||||
setAiQueryModalOpen,
|
||||
} = props;
|
||||
|
||||
let navigate = useNavigate();
|
||||
const classes = useStyles();
|
||||
let navigate = useNavigate()
|
||||
const classes = useStyles()
|
||||
|
||||
const [hideBody, setHideBody] = React.useState(false)
|
||||
const [activateHidingBodyButton, setActivateHidingBodyButton] = React.useState(false)
|
||||
@@ -200,6 +200,7 @@ const ParsedAction = (props) => {
|
||||
const [menuPosition, setMenuPosition] = useState(null);
|
||||
const [uiBox, setUiBox] = useState(null);
|
||||
const isIntegration = selectedAction.app_id === "integration"
|
||||
const isAgent = selectedAction.app_id === "shuffle_agent"
|
||||
const [distributeAuthToSuborgs, setDistributeAuthToSuborgs] = useState(selectedAction?.selectedAuthentication?.suborg_distributed || false)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -208,7 +209,6 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
}, [expansionModalOpen])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
// Changes the order of params to show in order:
|
||||
// auth, required, optional
|
||||
@@ -244,15 +244,37 @@ const ParsedAction = (props) => {
|
||||
var param = selectedActionParameters[paramkey]
|
||||
keyorder.push(param.name)
|
||||
|
||||
if (param.configuration) {
|
||||
if (param?.configuration === true) {
|
||||
auth.push(param)
|
||||
continue
|
||||
}
|
||||
|
||||
if (param?.value?.toLowerCase().includes("secret. replace")) {
|
||||
param.value = ""
|
||||
if (param?.value === undefined || param?.value === null) {
|
||||
console.log("Invalid value: ", param)
|
||||
continue
|
||||
}
|
||||
|
||||
if (typeof param.value === "array") {
|
||||
param.value = param.value.join(",")
|
||||
}
|
||||
|
||||
if (typeof param.value === "object") {
|
||||
try {
|
||||
// Check if it's an array or object
|
||||
if (param.value.length !== undefined) {
|
||||
param.value = param.value.join(",")
|
||||
} else {
|
||||
param.value = JSON.stringify(param.value)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error parsing JSON for param value: ", param, e)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (param?.value?.toLowerCase()?.includes("secret. replace")) {
|
||||
param.value = ""
|
||||
}
|
||||
|
||||
if (selectedApp?.generated === true && param?.name === "body") {
|
||||
param.required = true
|
||||
@@ -260,11 +282,7 @@ const ParsedAction = (props) => {
|
||||
continue
|
||||
}
|
||||
|
||||
//if (param.name.startsWith("${") && param.name.endsWith("}")) {
|
||||
// console.log("PARAM: ", param)
|
||||
//}
|
||||
|
||||
if (param.required === false && param.name.startsWith("${") && param.name.endsWith("}")) {
|
||||
if (param?.required === false && param?.name?.startsWith("${") && param?.name?.endsWith("}")) {
|
||||
// Check if it's a required param
|
||||
param.autocompleted = true
|
||||
if (selectedAction.required_body_fields !== undefined && selectedAction.required_body_fields !== null && selectedAction.required_body_fields.length > 0) {
|
||||
@@ -280,16 +298,16 @@ const ParsedAction = (props) => {
|
||||
continue
|
||||
}
|
||||
|
||||
if (param.name === "headers" || param.name === "queries") {
|
||||
if (param?.name === "headers" || param?.name === "queries") {
|
||||
special_optional.push(param)
|
||||
continue
|
||||
}
|
||||
|
||||
if (hideBody && param?.description.includes("Generated")) {
|
||||
if (hideBody && param?.description?.includes("Generated")) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (param.field_active === true) {
|
||||
if (param?.field_active === true) {
|
||||
param.autocompleted = true
|
||||
generated_optional.push(param)
|
||||
continue
|
||||
@@ -350,6 +368,17 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix apps with fewer actions
|
||||
if (selectedApp !== undefined && selectedApp !== null && selectedApp.actions !== undefined && selectedApp.actions !== null && selectedApp.actions.length <= 1 && apps !== undefined && apps !== null && apps.length > 0) {
|
||||
// 1. Check local storage (?)
|
||||
// 2. Check the "apps" list
|
||||
const foundApp = apps.find(app => app.id === selectedApp.id)
|
||||
if (foundApp !== undefined && foundApp !== null && foundApp.actions !== undefined && foundApp.actions !== null && foundApp.actions.length > 1) {
|
||||
setSelectedApp(foundApp)
|
||||
}
|
||||
|
||||
}
|
||||
}, [])
|
||||
|
||||
const keywords = [
|
||||
@@ -2040,6 +2069,7 @@ const ParsedAction = (props) => {
|
||||
<div style={{ marginTop: 15, position: "relative", }}>
|
||||
<Typography style={{ color: "rgba(255,255,255,0.7)" }}>Authentication</Typography>
|
||||
<Tooltip
|
||||
arrow
|
||||
title={
|
||||
workflow?.suborg_distribution?.length > 0 && Object.getOwnPropertyNames(selectedAction?.selectedAuthentication).length !== 0 ? (
|
||||
<React.Fragment>
|
||||
@@ -2049,7 +2079,7 @@ const ParsedAction = (props) => {
|
||||
<Checkbox
|
||||
checked={distributeAuthToSuborgs}
|
||||
onChange={(event) => {
|
||||
changeDistribution(selectedAction?.selectedAuthentication)
|
||||
changeDistribution(selectedAction?.selectedAuthentication, "auth")
|
||||
}}
|
||||
name="distributeAuth"
|
||||
color="primary"
|
||||
@@ -2428,6 +2458,7 @@ const ParsedAction = (props) => {
|
||||
{setNewSelectedAction !== undefined ? (
|
||||
<Autocomplete
|
||||
id="action_search"
|
||||
disabled={isAgent || (selectedAction?.parent_controlled === true && workflow?.parentorg_workflow?.length > 0)}
|
||||
autoHighlight
|
||||
value={selectedAction}
|
||||
classes={{ inputRoot: classes.inputRoot }}
|
||||
@@ -2628,6 +2659,7 @@ const ParsedAction = (props) => {
|
||||
label={isIntegration ? "Choose a category" : "Find Actions"}
|
||||
variant="outlined"
|
||||
name={`disable_autocomplete_${Math.random()}`}
|
||||
disabled={isAgent || (selectedAction?.parent_controlled === true && workflow?.parentorg_workflow?.length > 0)}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -2645,7 +2677,7 @@ const ParsedAction = (props) => {
|
||||
> {
|
||||
selectedActionParameters !== undefined && selectedActionParameters !== null && Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0 ?
|
||||
<div style={{ marginTop: hideExtraTypes ? 10 : 30 }}>
|
||||
{isIntegration ?
|
||||
{isIntegration || isAgent ?
|
||||
apps !== undefined && apps !== null && apps.length > 0 ?
|
||||
<div style={{ display: "flex", maxWidth: 335, overflowX: "auto", overflowY: "hidden", }}>
|
||||
<div onClick={() => {
|
||||
@@ -2703,16 +2735,20 @@ const ParsedAction = (props) => {
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
{apps.map((app, appIndex) => {
|
||||
if (app.categories === undefined || app.categories === null || app.categories.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
var newactionname = actionname.toLowerCase()
|
||||
if (isAgent === true) {
|
||||
newactionname = "ai"
|
||||
}
|
||||
|
||||
var found = false
|
||||
|
||||
|
||||
for (var key in app.categories) {
|
||||
if (app.categories[key].toLowerCase() !== actionname) {
|
||||
if (app.categories[key].toLowerCase() !== newactionname) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -2943,10 +2979,17 @@ const ParsedAction = (props) => {
|
||||
data.variant = "STATIC_VALUE";
|
||||
}
|
||||
|
||||
if (isIntegration && data.name === "app_name") {
|
||||
if ((isIntegration || isAgent) && data.name === "app_name") {
|
||||
return null
|
||||
}
|
||||
|
||||
/*
|
||||
// Somehow autogenerate from the app itself
|
||||
if (isAgent && data.name == "model") {
|
||||
//console.log("Options: ", data.options)
|
||||
}
|
||||
*/
|
||||
|
||||
if (data.value === "authgroup controlled") {
|
||||
if (data?.name === "url" && authenticationType?.type === "oauth2-app") {
|
||||
} else {
|
||||
@@ -3891,11 +3934,17 @@ const ParsedAction = (props) => {
|
||||
|
||||
viewed_data = (viewed_data.charAt(0).toUpperCase() + viewed_data.slice(1)).replaceAll("_", " ")
|
||||
|
||||
// Check if it's selected or not and highlight
|
||||
var selected = false
|
||||
if (selectedActionParameters[count].value.includes(data)) {
|
||||
selected = true
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={data}
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
backgroundColor: selected ? theme.palette.backgroundColor : theme.palette.inputColor,
|
||||
color: "white",
|
||||
}}
|
||||
value={data}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
Tooltip,
|
||||
Typography,
|
||||
IconButton,
|
||||
Switch,
|
||||
} from '@mui/material';
|
||||
|
||||
import { toast } from "react-toastify"
|
||||
@@ -36,6 +37,9 @@ import {
|
||||
Insights as InsightsIcon,
|
||||
Replay as ReplayIcon,
|
||||
EditNote as EditNoteIcon,
|
||||
AccountTree as AccountTreeIcon,
|
||||
Cached as CachedIcon,
|
||||
FilterAltOff as FilterAltOffIcon
|
||||
} from '@mui/icons-material';
|
||||
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'
|
||||
@@ -73,6 +77,8 @@ const RuntimeDebugger = (props) => {
|
||||
const [rowsPerPage, setRowsPerPage] = useState(10)
|
||||
const [resultRows, setResultRows] = useState([])
|
||||
const [selectedWorkflowExecutions, setSelectedWorkflowExecutions] = useState([])
|
||||
const [suborgWorkflowRuns, setSuborgWorkflowRuns] = useState(false)
|
||||
const [openWorkflowMenu, setOpenWorkflowMenu] = useState(false)
|
||||
const [workflows, setWorkflows] = useState([
|
||||
{"id": "", "name": "All Workflows",}
|
||||
])
|
||||
@@ -162,7 +168,7 @@ const RuntimeDebugger = (props) => {
|
||||
}, maxworkflows*300)
|
||||
}
|
||||
|
||||
const submitSearch = (workflowId, status, startTime, endTime, cursor, limit) => {
|
||||
const submitSearch = (workflowId, status, startTime, endTime, cursor, limit, suborg_runs) => {
|
||||
handleWorkflowUsageCount(workflows)
|
||||
//setResultRows([])
|
||||
setSearchLoading(true)
|
||||
@@ -175,6 +181,7 @@ const RuntimeDebugger = (props) => {
|
||||
start_time: startTime,
|
||||
end_time: endTime,
|
||||
ignore_org: ignoreOrg,
|
||||
suborg_runs: suborg_runs,
|
||||
}
|
||||
|
||||
fetch(`${globalUrl}/api/v1/workflows/search`, {
|
||||
@@ -344,10 +351,28 @@ const RuntimeDebugger = (props) => {
|
||||
source = "manual"
|
||||
}
|
||||
|
||||
var imageSource = "";
|
||||
if (params?.row?.org?.id?.length > 0) {
|
||||
if (params?.row?.org?.image?.length > 0){
|
||||
imageSource = params.row.org.image
|
||||
}else {
|
||||
imageSource = "/images/no_image.png"
|
||||
}
|
||||
}else {
|
||||
if (userdata.active_org.image?.length > 0){
|
||||
imageSource = userdata.active_org.image
|
||||
}else {
|
||||
imageSource = "/images/no_image.png"
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span style={{}} onClick={() => {
|
||||
//setStatus(params.row.status)
|
||||
}}>
|
||||
{userdata?.active_org?.creator_org?.length === 0 ? (
|
||||
<img src={imageSource} alt={source} style={{borderRadius: theme.palette?.borderRadius, height: imageSize, width: imageSize, }} />
|
||||
) : null}
|
||||
<Tooltip title={source} placement="top">
|
||||
{foundSource}
|
||||
</Tooltip>
|
||||
@@ -372,7 +397,7 @@ const RuntimeDebugger = (props) => {
|
||||
headerName: 'Workflow Name',
|
||||
width: 250,
|
||||
renderCell: (params) => (
|
||||
<span style={{cursor: "pointer", }} onClick={() => {
|
||||
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", cursor: "pointer", }} onClick={() => {
|
||||
setWorkflowId(params.row.workflow.id)
|
||||
|
||||
for (let key in workflows) {
|
||||
@@ -382,8 +407,18 @@ const RuntimeDebugger = (props) => {
|
||||
}
|
||||
}
|
||||
}}>
|
||||
{params.row.workflow.name}
|
||||
</span>
|
||||
<span>{params.row.workflow.name}</span>
|
||||
{params?.row?.org?.id?.length > 0 &&
|
||||
<Tooltip title={(
|
||||
<div style={{display: "flex", }}>
|
||||
<img src={params.row.org.image || "/images/no_image.png"} alt={params.row.org.name} style={{height: 24, width: 24, borderRadius: 12, }} />
|
||||
<Typography variant="body2" style={{marginLeft: 5, }}>{params.row.org.name}</Typography>
|
||||
</div>
|
||||
)} placement="top" arrow>
|
||||
<AccountTreeIcon style={{color: "#B0B0B0", height: "24px", width: "24px", marginLeft: 10}} />
|
||||
</Tooltip>
|
||||
}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -630,7 +665,7 @@ const RuntimeDebugger = (props) => {
|
||||
return
|
||||
}
|
||||
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage)
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage, suborgWorkflowRuns)
|
||||
}, [workflowId, status, startTime, endTime])
|
||||
|
||||
const textfieldStyle = {
|
||||
@@ -679,8 +714,9 @@ const RuntimeDebugger = (props) => {
|
||||
|
||||
setWorkflow(e.target.value)
|
||||
setWorkflowId(e.target.value.id)
|
||||
setSuborgWorkflowRuns(false)
|
||||
|
||||
submitSearch(e.target.value.id, status, startTime, endTime, rowCursor, rowsPerPage)
|
||||
submitSearch(e.target.value.id, status, startTime, endTime, rowCursor, rowsPerPage, false)
|
||||
}
|
||||
|
||||
const executeWorkflow = (execution) => {
|
||||
@@ -773,84 +809,17 @@ const RuntimeDebugger = (props) => {
|
||||
|
||||
return (
|
||||
<div style={{minWidth: 1150, maxWidth: 1150, margin: "auto", }}>
|
||||
<div style={{display: "flex", }}>
|
||||
<div style={{display: "flex", paddingTop: 50, }}>
|
||||
<div style={{display: 'flex', flexDirection: 'column'}}>
|
||||
<h1 style={{flex: 3, }}>Workflow Run Debugger {totalCount !== 0 ? ` (~${totalCount})` : ""}</h1>
|
||||
<div style={{position: 'relative', right: 10, marginBottom: 10}}>
|
||||
<TextField
|
||||
fullWidth
|
||||
value={searchQuery}
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
marginTop: 20,
|
||||
marginLeft: 10,
|
||||
marginRight: 12,
|
||||
width: 693,
|
||||
height: 55,
|
||||
borderRadius: 8,
|
||||
fontSize: 16,
|
||||
marginBottom: 15,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
fontSize: "1em",
|
||||
height: 55,
|
||||
width: 693,
|
||||
borderRadius: 8,
|
||||
},
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon style={{ marginLeft: 5}} />
|
||||
</InputAdornment>
|
||||
),
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{searchQuery.length > 0 && (
|
||||
<ClearIcon
|
||||
style={{
|
||||
color: "white",
|
||||
cursor: "pointer",
|
||||
marginRight: 10
|
||||
}}
|
||||
onClick={() => setSearchQuery('')}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"linear-gradient(to right, rgb(248, 106, 62), rgb(243, 64, 121))",
|
||||
color: "white",
|
||||
border: "none",
|
||||
padding: "10px 20px",
|
||||
width: 100,
|
||||
height: 35,
|
||||
borderRadius: 17.5,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</InputAdornment>
|
||||
),
|
||||
|
||||
}}
|
||||
onChange={(e)=>{handleQueryChange(e)}}
|
||||
color="primary"
|
||||
placeholder="Filter by Workflow Name, Status, Execution Argument, Results.."
|
||||
id="shuffle_search_field"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{selectedWorkflowExecutions.length > 0 ?
|
||||
<div style={{display: "flex", width: "100%", }}>
|
||||
<h1 style={{flex: 3, whiteSpace: "nowrap" }}>Workflow Run Debugger {totalCount !== 0 ? ` (~${totalCount})` : ""}</h1>
|
||||
{selectedWorkflowExecutions.length > 0 ?
|
||||
<ButtonGroup>
|
||||
<Tooltip title="Reruns ALL selected workflows. This will make a new execution for them, and not continue the existing.">
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
style={{maxHeight: 40, marginTop: 25, }}
|
||||
style={{maxHeight: 40, marginTop: 25, marginLeft: 20, }}
|
||||
onClick={() => {
|
||||
|
||||
for (var i = 0; i < selectedWorkflowExecutions.length; i++) {
|
||||
@@ -888,7 +857,7 @@ const RuntimeDebugger = (props) => {
|
||||
} else {
|
||||
toast("Aborted "+aborted+" workflows.")
|
||||
// Research
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage)
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage, suborgWorkflowRuns)
|
||||
|
||||
setSelectedWorkflowExecutions([])
|
||||
}
|
||||
@@ -906,7 +875,7 @@ const RuntimeDebugger = (props) => {
|
||||
<Button
|
||||
variant={ignoreOrg ? "contained" : "outlined"}
|
||||
color="secondary"
|
||||
style={{marginLeft: 100, maxHeight: 40, marginTop: 25, }}
|
||||
style={{marginLeft: 20, maxHeight: 40, marginTop: 25, }}
|
||||
onClick={() => {
|
||||
setIgnoreOrg(!ignoreOrg)
|
||||
}}
|
||||
@@ -914,10 +883,98 @@ const RuntimeDebugger = (props) => {
|
||||
{ignoreOrg ? "Ignoring Org" : "Ignore Org (Support Only)"}
|
||||
</Button>
|
||||
: null}
|
||||
</div>
|
||||
<div style={{display: "flex", justifyContent: "space-between", width: "100%"}}>
|
||||
<div style={{position: 'relative', right: 10, marginBottom: 10}}>
|
||||
<TextField
|
||||
fullWidth
|
||||
value={searchQuery}
|
||||
style={{
|
||||
backgroundColor: "#1a1a1a",
|
||||
marginTop: 20,
|
||||
marginLeft: 10,
|
||||
marginRight: 12,
|
||||
width: 693,
|
||||
height: 51,
|
||||
borderRadius: 4,
|
||||
fontSize: 16,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
backgroundColor: "#1a1a1a",
|
||||
fontSize: "1em",
|
||||
height: 51,
|
||||
width: 693,
|
||||
borderRadius: 4,
|
||||
},
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon style={{ marginLeft: 5}} />
|
||||
</InputAdornment>
|
||||
),
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{searchQuery.length > 0 && (
|
||||
<ClearIcon
|
||||
style={{
|
||||
color: "white",
|
||||
cursor: "pointer",
|
||||
marginRight: 10
|
||||
}}
|
||||
onClick={() => setSearchQuery('')}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
color: "#1A1A1A",
|
||||
border: "none",
|
||||
padding: "10px 20px",
|
||||
width: 100,
|
||||
height: 35,
|
||||
borderRadius: 4,
|
||||
backgroundColor: "#FF8544",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</InputAdornment>
|
||||
),
|
||||
|
||||
}}
|
||||
onChange={(e)=>{handleQueryChange(e)}}
|
||||
color="primary"
|
||||
placeholder="Filter by Workflow Name, Status, Execution Argument, Results.."
|
||||
id="shuffle_search_field"
|
||||
/>
|
||||
</div>
|
||||
{userdata?.active_org?.creator_org?.length === 0 ? (
|
||||
<div style={{display: "flex", margin: 'auto',marginTop: 20,justifyContent: 'center', alignItems: 'center', }}>
|
||||
<Switch
|
||||
checked={suborgWorkflowRuns}
|
||||
onChange={() => {
|
||||
setSuborgWorkflowRuns(!suborgWorkflowRuns);
|
||||
//set selected workflow to all workflows when switching between suborg and all workflows
|
||||
setWorkflowId("")
|
||||
setWorkflow({"id": "", "name": "All Workflows"})
|
||||
setStatus("")
|
||||
setStartTime("")
|
||||
setEndTime("")
|
||||
setSearchQuery("")
|
||||
submitSearch("", "", "", "", rowCursor, rowsPerPage, !suborgWorkflowRuns)}
|
||||
}
|
||||
color="secondary"
|
||||
/>
|
||||
<Typography variant="body2" style={{color: "white", }}>Show workflow runs from suborgs</Typography>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form onSubmit={(e) => {
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage)
|
||||
}} style={{display: "flex", }}>
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage, suborgWorkflowRuns)
|
||||
}} style={{display: "flex", justifyContent: "center", alignItems: "center", }}>
|
||||
<FormControl fullWidth style={{marginTop: 5, }}>
|
||||
<InputLabel id="status-label">Status</InputLabel>
|
||||
<Select
|
||||
@@ -951,10 +1008,13 @@ const RuntimeDebugger = (props) => {
|
||||
<Autocomplete
|
||||
id="workflow_search"
|
||||
value={workflow}
|
||||
open={openWorkflowMenu}
|
||||
onOpen={()=>{setOpenWorkflowMenu(true)}}
|
||||
onClose={() => {setOpenWorkflowMenu(false)}}
|
||||
classes={{ inputRoot: classes.inputRoot }}
|
||||
ListboxProps={{
|
||||
style: {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
backgroundColor: "#1a1a1a",
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
@@ -973,11 +1033,11 @@ const RuntimeDebugger = (props) => {
|
||||
options={workflows}
|
||||
fullWidth
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
backgroundColor: "#1a1a1a",
|
||||
height: 50,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
marginTop: 5,
|
||||
borderRadius: 4,
|
||||
marginLeft: 5,
|
||||
marginBottom: 3,
|
||||
}}
|
||||
onChange={(event, newValue) => {
|
||||
console.log("Found value: ", newValue)
|
||||
@@ -1018,12 +1078,13 @@ const RuntimeDebugger = (props) => {
|
||||
}>
|
||||
<MenuItem
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
backgroundColor: "#1a1a1a",
|
||||
color: data.id === workflow.id ? "red" : "white",
|
||||
}}
|
||||
value={data}
|
||||
onClick={(e) => {
|
||||
var parsedinput = { target: { value: data } }
|
||||
setOpenWorkflowMenu(false)
|
||||
handleWorkflowSelectionUpdate(parsedinput)
|
||||
}}
|
||||
>
|
||||
@@ -1036,8 +1097,8 @@ const RuntimeDebugger = (props) => {
|
||||
return (
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
backgroundColor: "#1a1a1a",
|
||||
borderRadius: 4,
|
||||
}}
|
||||
{...params}
|
||||
label="Workflow"
|
||||
@@ -1050,8 +1111,9 @@ const RuntimeDebugger = (props) => {
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DateTimePicker
|
||||
sx={{
|
||||
marginTop: 1,
|
||||
marginLeft: 1,
|
||||
minHeight: 50,
|
||||
maxHeight: 50,
|
||||
minWidth: 240,
|
||||
maxWidth: 240,
|
||||
}}
|
||||
@@ -1064,10 +1126,11 @@ const RuntimeDebugger = (props) => {
|
||||
/>
|
||||
<DateTimePicker
|
||||
sx={{
|
||||
marginTop: 1,
|
||||
marginLeft: 1,
|
||||
minWidth: 240,
|
||||
maxWidth: 240,
|
||||
minHeight: 50,
|
||||
maxHeight: 50,
|
||||
}}
|
||||
ampm={false}
|
||||
label="Search until"
|
||||
@@ -1078,14 +1141,34 @@ const RuntimeDebugger = (props) => {
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
|
||||
<Tooltip title="Clear all filters and search parameters">
|
||||
<Button
|
||||
style={{ marginLeft: 10, minHeight: 60, marginTop: 10, backgroundColor: "#1a1a1a", border: "1px solid #424242", boxShadow: 'none', borderRadius: 4, width: 81, height: 51, marginRight: 15 }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setWorkflowId("")
|
||||
setWorkflow({"id": "", "name": "All Workflows"})
|
||||
setStatus("")
|
||||
setStartTime("")
|
||||
setEndTime("")
|
||||
setSearchQuery("")
|
||||
setSuborgWorkflowRuns(false)
|
||||
submitSearch("", "", "", "", rowCursor, rowsPerPage, false)
|
||||
}}
|
||||
>
|
||||
<FilterAltOffIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage)
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, rowsPerPage, suborgWorkflowRuns)
|
||||
}}
|
||||
disabled={searchLoading}
|
||||
style={{height: 50, minWidth: 100, marginTop: 15, marginLeft: 10, }}
|
||||
style={{height: 50, minWidth: 100, marginTop: 15, }}
|
||||
>
|
||||
{searchLoading ? <CircularProgress size={30} /> : "Search"}
|
||||
</Button>
|
||||
@@ -1100,7 +1183,7 @@ const RuntimeDebugger = (props) => {
|
||||
disableSelectionOnClick
|
||||
onPageSizeChange={(newPageSize) => {
|
||||
setRowsPerPage(newPageSize)
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, newPageSize)
|
||||
submitSearch(workflowId, status, startTime, endTime, rowCursor, newPageSize, suborgWorkflowRuns)
|
||||
}}
|
||||
// event for when clicking next page
|
||||
// Hide page changer
|
||||
|
||||
@@ -58,7 +58,7 @@ const data = [
|
||||
"curve-style": "unbundled-bezier",
|
||||
label: "data(label)",
|
||||
"text-margin-y": "-15px",
|
||||
width: "3px",
|
||||
width: "2px",
|
||||
color: "white",
|
||||
"line-fill": "linear-gradient",
|
||||
"line-gradient-stop-positions": ["0.0", "100"],
|
||||
|
||||
@@ -12,6 +12,14 @@ const Admin2 = (props) => {
|
||||
const [orgRequest, setOrgRequest] = React.useState(true);
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
|
||||
if (document !== undefined) {
|
||||
if (selectedOrganization?.name !== undefined) {
|
||||
document.title = selectedOrganization?.name + " - Admin - Shuffle"
|
||||
} else {
|
||||
document.title = "Admin - Shuffle"
|
||||
}
|
||||
}
|
||||
|
||||
const handleGetOrg = (orgId) => {
|
||||
|
||||
fetch(`${globalUrl}/api/v1/orgs/${orgId}`, {
|
||||
@@ -103,7 +111,8 @@ const Admin2 = (props) => {
|
||||
setSelectedStatus(leads);
|
||||
}
|
||||
|
||||
setSelectedOrganization(responseJson);
|
||||
|
||||
setSelectedOrganization(responseJson)
|
||||
var lists = {
|
||||
active: {
|
||||
triggers: [],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -276,7 +276,14 @@ export const appCategories = [
|
||||
"color": "#FFC107",
|
||||
"icon": "network",
|
||||
"action_labels": ["Get Rules", "Allow IP", "Block IP",],
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "AI",
|
||||
"color": "#FFC107",
|
||||
"icon": "AI",
|
||||
"action_labels": ["Answer Question", "Run Action"],
|
||||
},
|
||||
{
|
||||
"name": "Other",
|
||||
"color": "#FFC107",
|
||||
"icon": "other",
|
||||
@@ -418,6 +425,7 @@ const AppCreator = (defaultprops) => {
|
||||
const [appBuilding, setAppBuilding] = useState(false);
|
||||
const [fileDownloadEnabled, setFileDownloadEnabled] = useState(false);
|
||||
const [actionAmount, setActionAmount] = useState(increaseAmount);
|
||||
const [newAppGroup, setNewAppGroup] = useState("")
|
||||
|
||||
const [oauth2Scopes, setOauth2Scopes] = useState([]);
|
||||
const [oauth2Type, setOauth2Type] = useState("delegated");
|
||||
@@ -4622,23 +4630,25 @@ const AppCreator = (defaultprops) => {
|
||||
}}
|
||||
/>
|
||||
*/}
|
||||
<h4>Choose a Category</h4>
|
||||
<Select
|
||||
fullWidth
|
||||
SelectDisplayProps={{
|
||||
style: {
|
||||
marginLeft: 10,
|
||||
},
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setNewWorkflowCategories([e.target.value]);
|
||||
setUpdate("added " + e.target.value);
|
||||
}}
|
||||
value={newWorkflowCategories.length === 0 ? "Select a category" : newWorkflowCategories[0]}
|
||||
|
||||
style={{ backgroundColor: inputColor, color: "white", height: "50px" }}
|
||||
>
|
||||
{categories.map((data, index) => {
|
||||
<div style={{display: "flex", }}>
|
||||
<div style={{flex: 2, }}>
|
||||
<h4>Choose a Category</h4>
|
||||
<Select
|
||||
fullWidth
|
||||
SelectDisplayProps={{
|
||||
style: {
|
||||
marginLeft: 10,
|
||||
},
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setNewWorkflowCategories([e.target.value]);
|
||||
setUpdate("added " + e.target.value);
|
||||
}}
|
||||
value={newWorkflowCategories.length === 0 ? "Select a category" : newWorkflowCategories[0]}
|
||||
|
||||
style={{ backgroundColor: inputColor, color: "white", height: "50px" }}
|
||||
>
|
||||
{categories.map((data, index) => {
|
||||
if (data === undefined || data === null || data === "" || data === undefined || data === null || data === "") {
|
||||
return null
|
||||
}
|
||||
@@ -4651,9 +4661,38 @@ const AppCreator = (defaultprops) => {
|
||||
>
|
||||
{data.name}
|
||||
</MenuItem>
|
||||
)
|
||||
)
|
||||
})}
|
||||
</Select>
|
||||
</Select>
|
||||
</div>
|
||||
{/*
|
||||
<div style={{flex: 1, marginLeft: 25, }}>
|
||||
<Tooltip title="Helps when searching for apps. E.g. Google or Microsoft are their own groups." placement="top">
|
||||
<h4 style={{marginBottom: 0, }}>Group</h4>
|
||||
</Tooltip>
|
||||
<TextField
|
||||
style={{
|
||||
}}
|
||||
fullWidth
|
||||
placeholder="Group"
|
||||
type="text"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
defaultValue={newAppGroup}
|
||||
onChange={(e) => {
|
||||
setNewAppGroup(e.target.value)
|
||||
setUpdate("group added "+e.target.value)
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
*/}
|
||||
</div>
|
||||
<h4>Tags</h4>
|
||||
<MuiChipsInput
|
||||
style={{ marginTop: 10 }}
|
||||
|
||||
@@ -136,7 +136,7 @@ export const GetIconInfo = (action) => {
|
||||
{ key: "cache_add", values: ["set_cache"] },
|
||||
{ key: "cache_get", values: ["get_cache"] },
|
||||
{ key: "filter", values: ["filter"] },
|
||||
{ key: "merge", values: ["join", "merge", "route", "router"] },
|
||||
{ key: "merge", values: ["join", "merge", "route", "router", "routing"] },
|
||||
{
|
||||
key: "search",
|
||||
values: ["search", "find", "locate", "index", "analyze", "anal", "match", "check cache", "check", "verify", "validate"],
|
||||
@@ -200,7 +200,7 @@ export const GetIconInfo = (action) => {
|
||||
},
|
||||
{
|
||||
key: "compare",
|
||||
values: ["compare", "convert", "to", "filter", "translate", "parse"],
|
||||
values: ["compare", "convert", "to", "filter", "translate", "parse", "generate", ],
|
||||
},
|
||||
{ key: "close", values: ["close", "stop", "cancel", "block"] },
|
||||
{ key: "communication", values: ["communication", "comms", "email", "mail",] },
|
||||
|
||||
Reference in New Issue
Block a user