Fixed a lot of the weird suborg distribution workflow issues

This commit is contained in:
Frikky
2025-02-06 02:07:58 +01:00
parent f9e4a86245
commit b430e6c900
10 changed files with 1204 additions and 595 deletions
-9
View File
@@ -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)
+4 -4
View File
@@ -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>
+4 -4
View File
@@ -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");
+70 -21
View File
@@ -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}
+177 -94
View File
@@ -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
+1 -1
View File
@@ -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"],
+10 -1
View File
@@ -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
+59 -20
View File
@@ -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 }}
+2 -2
View File
@@ -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",] },