cloud frontend sync
This commit is contained in:
+468
-179
@@ -24,6 +24,9 @@ import {
|
||||
TextField,
|
||||
Popover,
|
||||
Divider,
|
||||
|
||||
AvatarGroup,
|
||||
Avatar,
|
||||
} from '@mui/material'
|
||||
|
||||
import {
|
||||
@@ -40,6 +43,7 @@ import {
|
||||
Refresh as RefreshIcon,
|
||||
Add as AddIcon,
|
||||
Warning as WarningIcon,
|
||||
Pause as PauseIcon,
|
||||
} from '@mui/icons-material'
|
||||
|
||||
import {
|
||||
@@ -68,6 +72,27 @@ const AgentUI = (props) => {
|
||||
const [appPickerAnchor, setAppPickerAnchor] = React.useState(null)
|
||||
const [chosenApps, setChosenApps] = useState([])
|
||||
|
||||
const activateApp = (appId) => {
|
||||
if (appId === undefined || appId === null || appId === "") {
|
||||
return
|
||||
}
|
||||
|
||||
const url = `${globalUrl}/api/v1/apps/${appId}/activate`
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json()
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success !== false) {
|
||||
getApps()
|
||||
} else {
|
||||
toast.warn("Failed to activate app: " + responseJson.reason)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (newSelectedApp.objectID === undefined || newSelectedApp.objectID === null || newSelectedApp.objectID === "") {
|
||||
@@ -83,9 +108,76 @@ const AgentUI = (props) => {
|
||||
id: newSelectedApp.objectID,
|
||||
image: newSelectedApp.image_url,
|
||||
}]))
|
||||
|
||||
var found = false
|
||||
if (apps?.length > 0) {
|
||||
for (var key in apps) {
|
||||
const app = apps[key]
|
||||
if (app?.id !== newSelectedApp?.objectID) {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
activateApp(newSelectedApp.objectID)
|
||||
}
|
||||
}
|
||||
}, [newSelectedApp])
|
||||
|
||||
useEffect(() => {
|
||||
if (chosenApps?.length > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (apps?.length === 0) {
|
||||
console.log("No apps loaded yet")
|
||||
return
|
||||
}
|
||||
|
||||
if (data === undefined || data === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (data?.allowed_actions === undefined || data?.allowed_actions === null) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log("HERE!")
|
||||
console.log("Data, apps: ", data, apps)
|
||||
|
||||
var newChosenApps = []
|
||||
for (var key in data?.allowed_actions) {
|
||||
const allowedAction = data?.allowed_actions[key]
|
||||
if (!allowedAction?.startsWith("app:")) {
|
||||
newChosenApps.push({
|
||||
"name": allowedAction,
|
||||
"large_image": "",
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
const appId = allowedAction.split(":")[1]
|
||||
for (var appKey in apps) {
|
||||
const app = apps[appKey]
|
||||
if (app.id !== appId) {
|
||||
continue
|
||||
}
|
||||
|
||||
newChosenApps.push(app)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (newChosenApps.length > 0) {
|
||||
setChosenApps(newChosenApps)
|
||||
}
|
||||
}, [data])
|
||||
|
||||
const {themeMode} = useContext(Context)
|
||||
const theme = getTheme(themeMode)
|
||||
const navigate = useNavigate();
|
||||
@@ -95,12 +187,13 @@ const AgentUI = (props) => {
|
||||
}
|
||||
|
||||
const agentWrapperStyle = {
|
||||
width: 1000,
|
||||
height: 1000,
|
||||
width: "100%",
|
||||
maxHeight: "100vh",
|
||||
margin: "auto",
|
||||
paddingTop: 100,
|
||||
paddingBottom: 1000,
|
||||
backgroundColor: theme.palette.backgroundColor,
|
||||
|
||||
paddingBottom: showAgentStarter ? 0 : 1500,
|
||||
|
||||
}
|
||||
|
||||
if (data.input === undefined || data.input === null) {
|
||||
@@ -412,9 +505,7 @@ const AgentUI = (props) => {
|
||||
} else {
|
||||
for (var key in questionAnswers) {
|
||||
const answer = questionAnswers[key]
|
||||
if (isContinuation === true) {
|
||||
newArgument["question_"+(answer.index)] = answer.value
|
||||
}
|
||||
newArgument["question_"+(answer.index)] = answer.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,8 +769,8 @@ const AgentUI = (props) => {
|
||||
</Tooltip>
|
||||
|
||||
|
||||
const rerunButton =
|
||||
<Tooltip title="Rerun FROM this decision. This can be used if an agent decision action somehow stopped and didn't get a result. Clears out all decisions AFTER this one." placement="right">
|
||||
const rerunButton = item?.type === "processing" ? null :
|
||||
<Tooltip title={item?.type === "decision" ? "Rerun FROM this decision. This can be used if an agent decision action somehow stopped and didn't get a result. Clears out all decisions AFTER this one." : ""} placement="right">
|
||||
<span>
|
||||
<IconButton
|
||||
disabled={item.type !== "decision" || disableButtons}
|
||||
@@ -698,6 +789,11 @@ const AgentUI = (props) => {
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
var itemLabel = item?.label?.replaceAll("_", " ") || ""
|
||||
if (item?.details?.reason !== undefined && item?.details?.reason !== null && item?.details?.reason !== "") {
|
||||
itemLabel = item?.details?.reason
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -778,10 +874,22 @@ const AgentUI = (props) => {
|
||||
paddingTop: defaultTopPadding,
|
||||
paddingBottom: defaultTopPadding,
|
||||
}}>
|
||||
{item.label}
|
||||
{itemLabel}
|
||||
</div>
|
||||
|
||||
<Tooltip title={`Time taken: ${currentDuration} seconds. Started: ${new Date(itemStartTime * 1000).toLocaleString()}\nFinished: ${new Date(itemEndTime * 1000).toLocaleString()}`} placement="right">
|
||||
<Tooltip title={`Time taken: ${currentDuration} seconds. Started: ${new Date(itemStartTime * 1000).toLocaleString()}\nFinished: ${new Date(itemEndTime * 1000).toLocaleString()}`} placement="right"
|
||||
PopperProps={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 130], // [skid, distance]
|
||||
},
|
||||
},
|
||||
],
|
||||
}}
|
||||
style={theme.palette.tooltip}
|
||||
>
|
||||
<div style={{
|
||||
minWidth: maxTimelineWidth,
|
||||
maxWidth: maxTimelineWidth,
|
||||
@@ -874,7 +982,7 @@ const AgentUI = (props) => {
|
||||
item?.type === "decision" ?
|
||||
<div style={{display: "flex", }}>
|
||||
{rerunButton}
|
||||
<Tooltip title="Explore/debug execution" placement="left">
|
||||
<Tooltip title="Explore/debug app run" placement="left">
|
||||
<span>
|
||||
<IconButton
|
||||
disabled={item?.details?.run_details?.debug_url === undefined || item?.details?.run_details?.debug_url === null || item?.details?.run_details?.debug_url === ""}
|
||||
@@ -895,21 +1003,24 @@ const AgentUI = (props) => {
|
||||
:
|
||||
rerunButton
|
||||
}
|
||||
<Tooltip title="Explore results" placement="right">
|
||||
<span>
|
||||
<IconButton
|
||||
disabled={item.details === undefined || item.details === null || item.details === ""}
|
||||
style={{marginLeft: 10, }}
|
||||
>
|
||||
{open ?
|
||||
<ExpandLessIcon />
|
||||
:
|
||||
<ExpandMoreIcon />
|
||||
}
|
||||
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
{item?.type === "processing" ? null :
|
||||
<Tooltip title="Explore results" placement="right">
|
||||
<span>
|
||||
<IconButton
|
||||
disabled={item.details === undefined || item.details === null || item.details === ""}
|
||||
style={{marginLeft: 10, }}
|
||||
>
|
||||
{open ?
|
||||
<ExpandLessIcon />
|
||||
:
|
||||
<ExpandMoreIcon />
|
||||
}
|
||||
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -976,13 +1087,17 @@ const AgentUI = (props) => {
|
||||
<Button
|
||||
variant="contained"
|
||||
style={{marginTop: 16, }}
|
||||
disabled={questionSubmitDisabled}
|
||||
disabled={questionSubmitDisabled || agentRequestLoading}
|
||||
onClick={() => {
|
||||
submitQuestions(item?.details?.run_details?.id, questionAnswers)
|
||||
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
{agentRequestLoading ?
|
||||
<CircularProgress size={20} style={{marginRight: 10, }} />
|
||||
:
|
||||
"Submit"
|
||||
}
|
||||
</Button>
|
||||
</div>
|
||||
: null}
|
||||
@@ -1078,6 +1193,7 @@ const AgentUI = (props) => {
|
||||
}
|
||||
|
||||
var finishDecisionId = ""
|
||||
var finishAnswer = ""
|
||||
var sortedTimelineItems = []
|
||||
for (var key in agent_data?.decisions) {
|
||||
const item = agent_data.decisions[key]
|
||||
@@ -1105,17 +1221,71 @@ const AgentUI = (props) => {
|
||||
|
||||
if (item?.details?.action === "finish" || item.action === "finish" || item.category == "finish" || item?.details?.action == "finalise") {
|
||||
finishDecisionId = item?.run_details?.id
|
||||
}
|
||||
|
||||
finishAnswer = item?.reason || ""
|
||||
if (item?.fields !== undefined && item?.fields !== null) {
|
||||
// Just choosing the first one
|
||||
for (var fieldKey in item?.fields) {
|
||||
const field = item?.fields[fieldKey]
|
||||
finishAnswer = field?.value || finishAnswer
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timelineItems.sort((a, b) => {
|
||||
if (a.start_time < b.start_time) {
|
||||
return 1;
|
||||
// Fill blank space between items in timeline by adding "empty" decisions:
|
||||
// 1. Sort
|
||||
// 2. Fill blank space
|
||||
// 3. Sort again
|
||||
timelineItems.sort((a, b) => a.start_time - b.start_time)
|
||||
for (var i = 0; i < timelineItems.length - 1; i++) {
|
||||
if (timelineItems?.length <= 2) {
|
||||
break
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
if (i === timelineItems.length - 1) {
|
||||
break
|
||||
}
|
||||
|
||||
const currentItem = timelineItems[i]
|
||||
if (currentItem?.type === "processing") {
|
||||
continue
|
||||
}
|
||||
|
||||
const nextItem = timelineItems[i + 1]
|
||||
if (nextItem?.type === "processing") {
|
||||
continue
|
||||
}
|
||||
|
||||
if (nextItem.start_time - currentItem.end_time > 1) {
|
||||
timelineItems?.push({
|
||||
label: "",
|
||||
type: "processing",
|
||||
category: "processing",
|
||||
status: "FINISHED",
|
||||
start_time: currentItem.end_time,
|
||||
end_time: nextItem.start_time,
|
||||
})
|
||||
}
|
||||
}
|
||||
timelineItems.sort((a, b) => a.start_time - b.start_time)
|
||||
|
||||
const handleKeyDownCont = (e) => {
|
||||
if (finishDecisionId === "") {
|
||||
return
|
||||
}
|
||||
|
||||
const isCmdEnter = e.metaKey && e.key === "Enter"; // macOS
|
||||
const isCtrlEnter = e.ctrlKey && e.key === "Enter"; // Windows/Linux
|
||||
if (isCmdEnter || isCtrlEnter) {
|
||||
e.preventDefault()
|
||||
|
||||
submitQuestions(finishDecisionId, {
|
||||
"continue": continuationText,
|
||||
}, true)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{marginTop: 20, }}>
|
||||
@@ -1151,6 +1321,7 @@ const AgentUI = (props) => {
|
||||
<Box
|
||||
component="form"
|
||||
style={{width: "100%", textAlign: "center",}}
|
||||
onKeyDown={handleKeyDownCont}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -1161,15 +1332,35 @@ const AgentUI = (props) => {
|
||||
}, true)
|
||||
}}
|
||||
>
|
||||
<div style={{display: "flex", maxWidth: 550, minWidth: 550, margin: "auto", marginTop: 50, }}>
|
||||
{finishAnswer !== "" ?
|
||||
<div style={{marginTop: 50, textAlign: "left", }}>
|
||||
<Markdown
|
||||
components={markdownComponents}
|
||||
id="markdown_wrapper"
|
||||
className={"style.reactMarkdown"}
|
||||
escapeHtml={false}
|
||||
skipHtml={false}
|
||||
remarkPlugins={[remarkGfm]}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
minWidth: "100%",
|
||||
}}
|
||||
>
|
||||
{finishAnswer}
|
||||
</Markdown>
|
||||
</div>
|
||||
: null}
|
||||
|
||||
<div style={{display: "flex", maxWidth: 600, minWidth: 600, margin: "auto", marginTop: 50, }}>
|
||||
<div>
|
||||
<TextField
|
||||
label="Add more details to the current task"
|
||||
label="Add more details to continue the current task"
|
||||
variant="outlined"
|
||||
disabled={agentRequestLoading}
|
||||
style={{width: 400, margin: "auto", }}
|
||||
style={{width: 450, margin: "auto", }}
|
||||
multiline
|
||||
minRows={1}
|
||||
minRows={2}
|
||||
value={continuationText}
|
||||
onChange={(e) => {
|
||||
console.log("Value: ", e.target.value)
|
||||
//setActionInput(e.target.value)
|
||||
@@ -1195,7 +1386,7 @@ const AgentUI = (props) => {
|
||||
}}
|
||||
/>
|
||||
<Typography variant="body2" color="textSecondary" style={{marginTop: 10, }}>
|
||||
Any failed tasks will be set to ignored (TBD). <a href="/docs/AI#agent-continuations" target="_blank" rel="noreferrer" style={{color: theme.palette.main, textDecoration: "none", }}>Learn more</a>
|
||||
Any failed tasks will be set to ignored. <a href="/docs/AI#agent-continuations" target="_blank" rel="noreferrer" style={{color: theme.palette.main, textDecoration: "none", }}>Learn more</a>
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography color="textSecondary" variant="body1" style={{marginTop: 25, marginLeft: 20, }}>
|
||||
@@ -1242,7 +1433,7 @@ const AgentUI = (props) => {
|
||||
// 1. Run the execution. Can this be a single-action run?
|
||||
// 2. Get the execution ID and node ID from the response.
|
||||
const uuid = uuidv4()
|
||||
var parsedAction = "list_tickets,API" // Default action for now
|
||||
var parsedAction = "API" // Default action for now
|
||||
if (chosenApps.length > 0) {
|
||||
parsedAction = ""
|
||||
for (var appKey in chosenApps) {
|
||||
@@ -1319,155 +1510,253 @@ const AgentUI = (props) => {
|
||||
cursor: "pointer",
|
||||
}
|
||||
|
||||
|
||||
const typeButtonGroup =
|
||||
<ButtonGroup style={{}}>
|
||||
<Button
|
||||
variant={showAgentStarter ? "contained" : "outlined"}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
if (actionInput === "" || actionInput === undefined || actionInput === null) {
|
||||
setActionInput(data?.original_input || "")
|
||||
}
|
||||
|
||||
//setChosenApps(chosenApps.concat([{
|
||||
|
||||
setTimeout(() => {
|
||||
setShowAgentStarter(true)
|
||||
}, 200)
|
||||
}}
|
||||
>
|
||||
Restart
|
||||
</Button>
|
||||
<Button
|
||||
variant={buttonState === "default" ? "contained" : "outlined"}
|
||||
color="secondary"
|
||||
disabled
|
||||
onClick={() => {
|
||||
setButtonState("default");
|
||||
setShowAgentStarter(false)
|
||||
}}
|
||||
>
|
||||
Default
|
||||
</Button>
|
||||
<Button
|
||||
variant={buttonState === "timeline" ? "contained" : "outlined"}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
setButtonState("timeline");
|
||||
setShowAgentStarter(false)
|
||||
}}
|
||||
>
|
||||
Timeline
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
return (
|
||||
<div style={agentWrapperStyle}>
|
||||
<TextField
|
||||
id="copy_element_shuffle"
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
|
||||
{showAgentStarter ?
|
||||
<Box
|
||||
component="form"
|
||||
style={{textAlign: "center", }}
|
||||
onKeyDown={handleKeyDownRoot}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
submitInput(actionInput);
|
||||
}}
|
||||
>
|
||||
<img src="/images/logos/agent.svg" style={{
|
||||
width: 200,
|
||||
height: 200,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}} />
|
||||
|
||||
<div />
|
||||
|
||||
<Typography variant="h5" style={{marginTop: 30, }}>
|
||||
Shuffle AI Agents
|
||||
</Typography>
|
||||
<div>
|
||||
<div style={{height: showAgentStarter ? "25vh" : "5vh", }}>
|
||||
</div>
|
||||
<div style={agentWrapperStyle}>
|
||||
<div style={{
|
||||
minWidth: 1000, maxWidth: 1000, margin: "auto",
|
||||
}}>
|
||||
<TextField
|
||||
label="What do you want to do?"
|
||||
variant="outlined"
|
||||
disabled={agentRequestLoading}
|
||||
style={{width: 450, marginRight: 20, marginTop: 30, }}
|
||||
multiline
|
||||
minRows={1}
|
||||
defaultValue={actionInput || ""}
|
||||
onChange={(e) => {
|
||||
setActionInput(e.target.value)
|
||||
}}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
agentRequestLoading ?
|
||||
<CircularProgress size={24} style={{marginRight: 10, }} />
|
||||
:
|
||||
<Tooltip title="This is the input for the AI Agent. It can be any valid JSON.">
|
||||
<IconButton type="submit">
|
||||
<SendIcon
|
||||
color="primary"
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
),
|
||||
}}
|
||||
id="copy_element_shuffle"
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
|
||||
<div style={{display: "flex", margin: "auto", paddingTop: 10, minWidth: 300, maxWidth: 300, justifyContent: "center", overflowWrap: "wrap", }}>
|
||||
<div>
|
||||
<Chip
|
||||
id="add_app_chip"
|
||||
icon={<AddIcon />} label="Select Apps"
|
||||
style={chipStyle}
|
||||
onClick={() => {
|
||||
setAppPickerAnchor(document.getElementById("add_app_chip"))
|
||||
{showAgentStarter ?
|
||||
<Box
|
||||
component="form"
|
||||
style={{textAlign: "center", }}
|
||||
onKeyDown={handleKeyDownRoot}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
submitInput(actionInput);
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
<img src="/images/logos/agent.svg" style={{
|
||||
width: 200,
|
||||
height: 200,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}} />
|
||||
*/}
|
||||
|
||||
<div />
|
||||
|
||||
<Typography variant="h2" style={{marginTop: 30, }}>
|
||||
What do you want to do?
|
||||
</Typography>
|
||||
<TextField
|
||||
label="Get my emails for today and summarise them"
|
||||
variant="outlined"
|
||||
disabled={agentRequestLoading}
|
||||
style={{width: 500, marginTop: 30, }}
|
||||
multiline
|
||||
minRows={1}
|
||||
defaultValue={actionInput || ""}
|
||||
onChange={(e) => {
|
||||
setActionInput(e.target.value)
|
||||
}}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
agentRequestLoading ?
|
||||
<CircularProgress size={24} style={{marginRight: 10, }} />
|
||||
:
|
||||
<Tooltip title="This is the input for the AI Agent. It can be any valid JSON.">
|
||||
<IconButton type="submit">
|
||||
<SendIcon
|
||||
color="primary"
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Popover
|
||||
open={appPickerAnchor !== null}
|
||||
anchorEl={appPickerAnchor}
|
||||
onClose={() => {
|
||||
setAppPickerAnchor(null)
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
>
|
||||
<AppSearch
|
||||
userdata={userdata}
|
||||
defaultSearch={""}
|
||||
newSelectedApp={newSelectedApp}
|
||||
setNewSelectedApp={setNewSelectedApp}
|
||||
inputHeight={200}
|
||||
|
||||
<div style={{display: "flex", margin: "auto", paddingTop: 30, minWidth: 300, maxWidth: 300, justifyContent: "center", overflowWrap: "wrap", }}>
|
||||
<div>
|
||||
<Chip
|
||||
id="add_app_chip"
|
||||
icon={<AddIcon />} label="Select Apps / MCPs"
|
||||
style={chipStyle}
|
||||
onClick={() => {
|
||||
setAppPickerAnchor(document.getElementById("add_app_chip"))
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
<Popover
|
||||
open={appPickerAnchor !== null}
|
||||
anchorEl={appPickerAnchor}
|
||||
onClose={() => {
|
||||
setAppPickerAnchor(null)
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
>
|
||||
<AppSearch
|
||||
userdata={userdata}
|
||||
defaultSearch={""}
|
||||
newSelectedApp={newSelectedApp}
|
||||
setNewSelectedApp={setNewSelectedApp}
|
||||
inputHeight={200}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
{chosenApps.map((app, index) => {
|
||||
const chosenName = (app?.name?.charAt(0).toUpperCase() + app?.name?.slice(1))?.replaceAll("_", " ").replaceAll("-", " ")
|
||||
const chosenImagePath = app?.image
|
||||
const chosenImage = <img src={chosenImagePath} style={{width: 24, height: 24, borderRadius: 20, marginRight: 1, }} />
|
||||
|
||||
return (
|
||||
<Chip icon={chosenImage} label={chosenName} variant="outlined"
|
||||
style={chipStyle}
|
||||
onDelete={() => {
|
||||
const newChosenApps = chosenApps.filter((a, i) => i !== index)
|
||||
setChosenApps(newChosenApps)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div style={{marginTop: 20, }}>
|
||||
{execution === undefined || execution === null || execution?.execution_id === undefined || execution?.execution_id === null ? null : typeButtonGroup}
|
||||
</div>
|
||||
|
||||
{/*
|
||||
<div style={{
|
||||
height: 300,
|
||||
width: "100%",
|
||||
|
||||
background: showAgentStarter ? `linear-gradient(to bottom, ${theme.palette.backgroundColor}, #C9591D)` : "inherit",
|
||||
backgroundSize: "100% 100%",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "0px 100px",
|
||||
}} />
|
||||
*/}
|
||||
</Box>
|
||||
:
|
||||
<div>
|
||||
<div style={{display: "flex", }}>
|
||||
<div style={{flex: 2, }}>
|
||||
{typeButtonGroup}
|
||||
|
||||
<ButtonGroup style={{marginLeft: 25, }}>
|
||||
<Tooltip title="Reload the agent data" placement="top">
|
||||
<span>
|
||||
<Button
|
||||
disabled={execution === null || Object.keys(execution).length === 0}
|
||||
style={{}}
|
||||
variant={"outlined"}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
GetExecution(execution?.execution_id, agentActionResult?.action?.id, execution?.authorization)
|
||||
}}
|
||||
>
|
||||
<RefreshIcon />
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
{execution?.status === "EXECUTING" ?
|
||||
<Tooltip title="Stop the agent" placement="top">
|
||||
<span>
|
||||
<Button
|
||||
disabled={execution === null || true}
|
||||
style={{}}
|
||||
variant={"outlined"}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
toast.warn("Not implemented. Should run abort.")
|
||||
}}
|
||||
>
|
||||
<PauseIcon />
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
: null}
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
|
||||
<div style={{flex: 1, }}>
|
||||
<AvatarGroup>
|
||||
{chosenApps?.map((app, index) => {
|
||||
return(
|
||||
<Tooltip title={`Constraint: ${app?.name}`} key={index} placement="top">
|
||||
<Avatar
|
||||
key={index}
|
||||
alt={app?.name}
|
||||
src={app?.large_image}
|
||||
onClick={() => {
|
||||
window.open(`/apps/${app.id}`, '_blank', 'noopener,noreferrer');
|
||||
}}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
width: 30,
|
||||
height: 30,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
})}
|
||||
</AvatarGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{buttonState === "timeline" ?
|
||||
<TimelineRender agent_data={data} />
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
|
||||
{chosenApps.map((app, index) => {
|
||||
const chosenName = (app?.name?.charAt(0).toUpperCase() + app?.name?.slice(1))?.replaceAll("_", " ").replaceAll("-", " ")
|
||||
const chosenImagePath = app?.image
|
||||
const chosenImage = <img src={chosenImagePath} style={{width: 24, height: 24, borderRadius: 20, marginRight: 1, }} />
|
||||
|
||||
return (
|
||||
<Chip icon={chosenImage} label={chosenName} variant="outlined"
|
||||
style={chipStyle}
|
||||
onDelete={() => {
|
||||
const newChosenApps = chosenApps.filter((a, i) => i !== index)
|
||||
setChosenApps(newChosenApps)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Box>
|
||||
:
|
||||
<div>
|
||||
<ButtonGroup style={{marginTop: 50, }}>
|
||||
<Button
|
||||
variant={buttonState === "default" ? "contained" : "outlined"}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
setButtonState("default");
|
||||
}}
|
||||
>
|
||||
Default
|
||||
</Button>
|
||||
<Button
|
||||
variant={buttonState === "timeline" ? "contained" : "outlined"}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
setButtonState("timeline");
|
||||
}}
|
||||
>
|
||||
Timeline
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Tooltip title="Reload the agent data" placement="top">
|
||||
<span>
|
||||
<Button
|
||||
disabled={execution === null || Object.keys(execution).length === 0}
|
||||
style={{marginLeft: 25, }}
|
||||
variant={"outlined"}
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
GetExecution(execution.execution_id, agentActionResult.action.id, execution.authorization)
|
||||
}}
|
||||
>
|
||||
<RefreshIcon />
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
{buttonState === "timeline" ?
|
||||
<TimelineRender agent_data={data} />
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -463,9 +463,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
var to_be_copied = "";
|
||||
const [firstrequest, setFirstrequest] = React.useState(true);
|
||||
const cystyle = useMemo(() => defaultCytoscapeStyle(theme), [themeMode]);
|
||||
// const cystyle = useMemo(() => defaultCytoscapeStyle, [themeMode]);
|
||||
const [apps, setApps] = React.useState([]);
|
||||
|
||||
const cystyle = useMemo(() => defaultCytoscapeStyle(theme, apps), [themeMode, apps]);
|
||||
const [cy, setCy] = React.useState();
|
||||
|
||||
const useStyles = makeStyles({
|
||||
@@ -593,7 +593,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const [showDropdown, setShowDropdown] = React.useState(false);
|
||||
const [triggerActionList, setTriggerActionList] = React.useState([]);
|
||||
|
||||
const [apps, setApps] = React.useState([]);
|
||||
const [filteredApps, setFilteredApps] = React.useState([]);
|
||||
const [prioritizedApps, setPrioritizedApps] = React.useState([])
|
||||
|
||||
@@ -2560,7 +2559,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
// Center and zoom to the node with smooth animation if requested
|
||||
if (config.center) {
|
||||
cy.animate({
|
||||
cy.stop().animate({
|
||||
center: {
|
||||
eles: cyNode
|
||||
},
|
||||
@@ -3324,7 +3323,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
foundnode.animate(
|
||||
foundnode.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -3445,6 +3444,18 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0; i < workflowExecutions.length; i++) {
|
||||
const exec = workflowExecutions[i]
|
||||
if (exec.execution_id === curAction.source_execution) {
|
||||
if (exec?.execution_argument === undefined || exec?.execution_argument === null || exec?.execution_argument.length === 0) {
|
||||
break
|
||||
}
|
||||
|
||||
setExecutionText(exec.execution_argument)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
setExecutionRunning(true)
|
||||
setExecutionRequestStarted(true)
|
||||
var headers = {
|
||||
@@ -3830,7 +3841,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
} else {
|
||||
console.log("Closing auth modal? FAIL")
|
||||
|
||||
toast("Failed to find new authentication. See details in Oauth2 popup window where auth was attempted.");
|
||||
toast.error("Failed to find new authentication. See details in Oauth2 popup window where auth was attempted.");
|
||||
shouldClose = false
|
||||
}
|
||||
} else {
|
||||
@@ -4184,7 +4195,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4201,7 +4212,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
"border-color": "#81c784",
|
||||
}
|
||||
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4250,7 +4261,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4267,7 +4278,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
"border-color": "#81c784",
|
||||
}
|
||||
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4298,7 +4309,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4314,7 +4325,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
"line-gradient-stop-colors": ["grey", "grey"],
|
||||
}
|
||||
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4346,7 +4357,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4363,7 +4374,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
"border-color": color,
|
||||
}
|
||||
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4394,7 +4405,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4450,7 +4461,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -4484,7 +4495,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
node.animate(
|
||||
node.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -8627,7 +8638,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
};
|
||||
}
|
||||
|
||||
event.target.animate(
|
||||
event.target.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -9423,7 +9434,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
if (event.target !== undefined && event.target !== null) {
|
||||
event.target.animate(
|
||||
event.target.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -9741,7 +9752,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
foundnode.animate(
|
||||
foundnode.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -9910,7 +9921,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const animationDuration = 150
|
||||
foundnode.animate(
|
||||
foundnode.stop().animate(
|
||||
{
|
||||
style: parsedStyle,
|
||||
},
|
||||
@@ -12487,7 +12498,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
//}
|
||||
safeRefine(event.currentTarget.value)
|
||||
}}
|
||||
limit={5}
|
||||
limit={15}
|
||||
/>
|
||||
{/*isSearchStalled ? 'My search is stalled' : ''*/}
|
||||
</form>
|
||||
@@ -14360,8 +14371,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
padding: 30,
|
||||
pointerEvents: "auto",
|
||||
color: theme.palette.text.primary,
|
||||
minWidth: isMobile ? "90%" : 650,
|
||||
border: theme.palette.defaultBorder,
|
||||
minWidth: isMobile ? "90%" : 750,
|
||||
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
backgroundColor: "black",
|
||||
@@ -14474,18 +14484,24 @@ const AngularWorkflow = (defaultprops) => {
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
style={{position: "sticky", top: 35, maxHeight: 40, maxWidth: 150, marginRight: 5, }}
|
||||
style={{position: "sticky", top: 50, maxHeight: 40, maxWidth: 150, marginRight: 5, }}
|
||||
onClick={() => {
|
||||
setExecutionText(data)
|
||||
executeWorkflow(data, workflow.start, lastSaved);
|
||||
executeWorkflow(data, workflow.start, lastSaved)
|
||||
|
||||
setExecutionArgumentModalOpen(false)
|
||||
}}
|
||||
>Select</Button>
|
||||
<ReactJson
|
||||
src={validate.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
theme={"summerfruit"}
|
||||
style={{
|
||||
padding: 5,
|
||||
width: "98%",
|
||||
borderRadius: 5,
|
||||
border: "1px solid rgba(255,255,255,0.7)",
|
||||
overflowX: "auto",
|
||||
}}
|
||||
shouldCollapse={(jsonField) => {
|
||||
return collapseField(jsonField)
|
||||
}}
|
||||
@@ -14499,10 +14515,11 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper style={{ padding: 10, marginTop: 10, backgroundColor: theme.palette.platformColor, maxHeight: 100, overflow: "auto", cursor: "pointer", position: "relative", }}
|
||||
<Paper
|
||||
style={{ padding: 10, marginTop: 10, backgroundColor: theme.palette.platformColor, maxHeight: 150, overflow: "auto", position: "relative", border: `2px solid rgba(255,255,255,0.3)`, }}
|
||||
onClick={() => {
|
||||
setExecutionText(data)
|
||||
executeWorkflow(data, workflow.start, lastSaved);
|
||||
//executeWorkflow(data, workflow.start, lastSaved);
|
||||
|
||||
setExecutionArgumentModalOpen(false)
|
||||
}}
|
||||
@@ -14759,6 +14776,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
color: theme.palette.textColor,
|
||||
backgroundColor: 'inherit',
|
||||
zIndex: 10000,
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
<b>PS: Conditions can't be used for loops [ .# ]. Use the filters list action.{" "}</b>
|
||||
@@ -15110,7 +15128,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
key={condition.condition.id}
|
||||
square
|
||||
style={paperVariableStyle}
|
||||
onClick={() => { }}
|
||||
onClick={() => {
|
||||
setLastSaved(false)
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
@@ -15339,6 +15359,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return
|
||||
}
|
||||
|
||||
setLastSaved(false)
|
||||
setSourceValue({
|
||||
name: "source",
|
||||
value: "",
|
||||
@@ -15384,17 +15405,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
// Change Direction of the branch target/source
|
||||
const foundBranch = cy.getElementById(selectedEdge.id)
|
||||
if (foundBranch !== undefined && foundBranch !== null) {
|
||||
console.log("BRANCH: ", foundBranch)
|
||||
const source = foundBranch.data("source")
|
||||
const target = foundBranch.data("target")
|
||||
|
||||
var branchdata = JSON.parse(JSON.stringify(foundBranch.data()))
|
||||
console.log("BEFORE: ", branchdata)
|
||||
console.log("Start node", workflow.start)
|
||||
const startNode = workflow.start
|
||||
if (source === startNode) {
|
||||
toast("Can't point to Start Node")
|
||||
} else {
|
||||
setLastSaved(false)
|
||||
const newid = uuidv4()
|
||||
branchdata.source = target
|
||||
branchdata.target = source
|
||||
@@ -19298,7 +19317,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
toast.info("Successfully changed active organisation - refreshing!");
|
||||
toast.success("Successfully changed active organisation - refreshing!");
|
||||
} else {
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.length > 0) {
|
||||
toast(responseJson.reason);
|
||||
@@ -20649,7 +20668,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const buttonHeights = 45
|
||||
const boxSize = buttonHeights
|
||||
const boxSize = buttonHeights+2
|
||||
const executionButton = executionRunning ? (
|
||||
<Tooltip color="primary" title="Stop execution" placement="top">
|
||||
<span>
|
||||
@@ -20737,20 +20756,17 @@ const AngularWorkflow = (defaultprops) => {
|
||||
>
|
||||
<TextField
|
||||
id="execution_argument_input_field"
|
||||
style={{
|
||||
...theme.palette.textFieldStyle,
|
||||
height: buttonHeights + 2,
|
||||
}}
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
style: {
|
||||
...theme.palette.innerTextfieldStyle,
|
||||
height: buttonHeights + 2,
|
||||
marginTop: -1,
|
||||
border: "none",
|
||||
height: buttonHeights+2,
|
||||
marginTop: 0,
|
||||
|
||||
// Remove left side borderRadius
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
borderTop: "0px solid",
|
||||
}
|
||||
}}
|
||||
disabled={workflow.public}
|
||||
@@ -21687,7 +21703,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex" }}>
|
||||
<div style={{ display: "flex", maxHeight: 500, overflow: "auto",}}>
|
||||
<IconButton
|
||||
style={{
|
||||
marginTop: "auto",
|
||||
@@ -21749,7 +21765,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
onSelect={(select) => {
|
||||
HandleJsonCopy(validate.result, select, "exec");
|
||||
}}
|
||||
name={false}
|
||||
name={"$exec"}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
@@ -21787,7 +21803,26 @@ const AngularWorkflow = (defaultprops) => {
|
||||
)
|
||||
}
|
||||
|
||||
if (execution.execution_source === "authgroups") {
|
||||
if (execution.execution_source?.startsWith("datastore")) {
|
||||
const iconMargin = 7
|
||||
return (
|
||||
<div style={{
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius: borderRadius,
|
||||
backgroundColor: green,
|
||||
}}>
|
||||
<StorageIcon
|
||||
style={{
|
||||
width: size / 3 * 2,
|
||||
height: size / 3 * 2,
|
||||
marginLeft: iconMargin,
|
||||
marginTop: iconMargin,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} else if (execution.execution_source === "authgroups") {
|
||||
const iconMargin = 7
|
||||
return (
|
||||
<div style={{
|
||||
@@ -22943,6 +22978,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</Typography>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{executionData.execution_source !== undefined &&
|
||||
executionData.execution_source !== null &&
|
||||
executionData.execution_source.length > 0 &&
|
||||
@@ -22954,8 +22990,17 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</Typography>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
|
||||
|
||||
{executionData.execution_source === "authgroups" || (executionData.authgroup !== undefined && executionData.authgroup !== null && executionData.authgroup.length > 0) ?
|
||||
{executionData?.execution_source?.startsWith("datastore") ?
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
href={`/admin?tab=datastore${executionData.execution_source.split("|").length > 2 ? "&category="+executionData.execution_source.split("|")[1]+"&key="+executionData.execution_source.split("|")[2] : ""}`}
|
||||
target="_blank"
|
||||
style={{ textDecoration: "none", color: theme.palette.linkColor }}
|
||||
>
|
||||
Datastore Automation
|
||||
</a>
|
||||
:
|
||||
executionData.execution_source === "authgroups" || (executionData.authgroup !== undefined && executionData.authgroup !== null && executionData.authgroup.length > 0) ?
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
href={`/admin?tab=app_auth`}
|
||||
@@ -23614,7 +23659,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
HandleJsonCopy(showResult, select, data.action.label);
|
||||
console.log("SELECTED!: ", select);
|
||||
}}
|
||||
name={"Results for " + data.action.label}
|
||||
name={`$${data?.action?.label?.toLowerCase()}`}
|
||||
/>
|
||||
|
||||
</span>
|
||||
|
||||
@@ -563,7 +563,7 @@ const AppCreator = (defaultprops) => {
|
||||
};
|
||||
|
||||
|
||||
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
|
||||
useEffect(() => {
|
||||
if (window.location.pathname.includes("apps/edit")) {
|
||||
|
||||
@@ -247,7 +247,7 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
|
||||
read_time: 1,
|
||||
})
|
||||
|
||||
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
|
||||
|
||||
// FIXME: This is used, as useEffect() creates an issue with apps not loading at all
|
||||
|
||||
+50
-17
@@ -62,7 +62,6 @@ const dividerColor = "rgb(225, 228, 232)";
|
||||
const hrefStyle = {
|
||||
color: "rgba(255, 255, 255, 0.8)",
|
||||
textDecoration: "none",
|
||||
marginRight: window.location.pathname.includes("/articles/") ? "0.8em" : undefined,
|
||||
};
|
||||
|
||||
|
||||
@@ -387,6 +386,7 @@ export const CodeHandler = (props) => {
|
||||
minWidth: "50%",
|
||||
maxWidth: "100%",
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
whiteSpace: "pre-wrap",
|
||||
overflowY: "auto",
|
||||
// Have it inline
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
@@ -1020,7 +1020,7 @@ const Docs = (defaultprops) => {
|
||||
}
|
||||
|
||||
const fetchDocList = (resetCache = false) => {
|
||||
var url = `${globalUrl}/api/v1/docs`
|
||||
var url = `${globalUrl}/api/v1/docs?resetCache=${resetCache}`
|
||||
if (location.pathname.includes("/legal")) {
|
||||
url = `${globalUrl}/api/v1/docs?folder=legal&resetCache=${resetCache}`
|
||||
} else if (location.pathname.includes("/articles")) {
|
||||
@@ -1047,16 +1047,16 @@ const Docs = (defaultprops) => {
|
||||
.catch((error) => { });
|
||||
};
|
||||
|
||||
const fetchDoc = (docId) => {
|
||||
const fetchDoc = (docId, resetCache = false) => {
|
||||
if (docId === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var url = `${globalUrl}/api/v1/docs/${docId}`
|
||||
var url = `${globalUrl}/api/v1/docs/${docId}?resetCache=${resetCache}`
|
||||
if (location.pathname.includes("/legal")) {
|
||||
url = `${globalUrl}/api/v1/docs/${docId}?folder=legal`
|
||||
url = `${globalUrl}/api/v1/docs/${docId}?folder=legal&resetCache=${resetCache}`
|
||||
} else if (location.pathname.includes("/articles")) {
|
||||
url = `${globalUrl}/api/v1/docs/${docId}?folder=articles`
|
||||
url = `${globalUrl}/api/v1/docs/${docId}?folder=articles&resetCache=${resetCache}`
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
@@ -1082,7 +1082,7 @@ const Docs = (defaultprops) => {
|
||||
autoClose: 2000,
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigate(`/articles/2.0_release`)
|
||||
navigate(`/articles`)
|
||||
}, 2000)
|
||||
return
|
||||
}
|
||||
@@ -1130,7 +1130,8 @@ const Docs = (defaultprops) => {
|
||||
|
||||
const handleResetCache = () => {
|
||||
fetchDocList(true);
|
||||
toast("Cache has been reset");
|
||||
fetchDoc(props.match.params.key, true);
|
||||
toast("Cache and list will be reset in a few seconds");
|
||||
}
|
||||
|
||||
if (firstrequest) {
|
||||
@@ -1344,6 +1345,21 @@ const Docs = (defaultprops) => {
|
||||
tr: TableRowRenderer,
|
||||
th: TableHeaderCellRenderer,
|
||||
td: TableCellRenderer,
|
||||
ul: ({ children }) => (
|
||||
<Box component="ul" sx={{ my: 0.5, fontFamily: '"Segoe UI", Inter, sans-serif', fontSize: "17.6px" }}>
|
||||
{children}
|
||||
</Box>
|
||||
),
|
||||
ol: ({ children }) => (
|
||||
<Box component="ol" sx={{ my: 0.5, fontFamily: '"Segoe UI", Inter, sans-serif', fontSize: "17.6px" }}>
|
||||
{children}
|
||||
</Box>
|
||||
),
|
||||
li: ({ children }) => (
|
||||
<Typography component="li" sx={{ my: 0.5, color: "inherit", fontFamily: '"Segoe UI", Inter, sans-serif', fontSize: "17.6px" }}>
|
||||
{children}
|
||||
</Typography>
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -1355,7 +1371,6 @@ const Docs = (defaultprops) => {
|
||||
|
||||
const activeListItemStyle = {
|
||||
backgroundColor: "rgba(248, 106, 62, 0.08)", // Slight orange tint
|
||||
marginRight: window.location.pathname.includes("/articles/") ? "0.8em" : undefined,
|
||||
borderLeft: "3px solid #f86a3e",
|
||||
paddingLeft: "13px", // Compensate for the border
|
||||
};
|
||||
@@ -1415,6 +1430,7 @@ const Docs = (defaultprops) => {
|
||||
<List style={{
|
||||
listStyle: "none",
|
||||
paddingLeft: "0",
|
||||
paddingRight: isArticlePage ? 15 : undefined,
|
||||
paddingTop: !isArticlePage ? "60px" : undefined,
|
||||
paddingBottom: !isArticlePage ? "30px" : undefined,
|
||||
display: isArticlePage ? sidebarOpen ? "block" : "none" : undefined,
|
||||
@@ -1524,15 +1540,32 @@ const Docs = (defaultprops) => {
|
||||
}
|
||||
</div>
|
||||
<div style={IndexBar}>
|
||||
{userdata?.support && isArticlePage && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={handleResetCache}
|
||||
style={{marginBottom: "15px"}}
|
||||
{userdata?.support && (
|
||||
<Tooltip
|
||||
title="Wait about 5 minutes after updating the file on GitHub, then click to reset the cache. (Support only) "
|
||||
placement="top"
|
||||
componentsProps={{
|
||||
tooltip: {
|
||||
sx: {
|
||||
backgroundColor: "rgba(33, 33, 33, 1)",
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
fontSize: 14,
|
||||
border: "1px solid rgba(73, 73, 73, 1)",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}
|
||||
},
|
||||
}}
|
||||
arrow
|
||||
>
|
||||
Reset Cache
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={handleResetCache}
|
||||
style={{marginBottom: "15px"}}
|
||||
>
|
||||
Reset Cache
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{tocLines.length > 0 ?
|
||||
(
|
||||
|
||||
@@ -111,8 +111,8 @@ const NewDashboard = (props) => {
|
||||
const STATIC_TIME_PERCENT = 'TBD'
|
||||
const STATIC_MONEY_PERCENT = 'TBD'
|
||||
const kpis = [
|
||||
{ value: timeFmt.display, title: timeFmt.title, label: 'Time saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_TIME_PERCENT, color: '#5cc879', disabled: true},
|
||||
{ value: formatCurrencyCompact(totals.moneySavedDollars), label: 'Money saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_MONEY_PERCENT, color: '#5cc879', disabled: true, },
|
||||
//{ value: timeFmt.display, title: timeFmt.title, label: 'Time saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_TIME_PERCENT, color: '#5cc879', disabled: true},
|
||||
//{ value: formatCurrencyCompact(totals.moneySavedDollars), label: 'Money saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_MONEY_PERCENT, color: '#5cc879', disabled: true, },
|
||||
{ value: String(unreadCount), label: 'Total errors', icon: <ErrorOutlineIcon sx={{ color: '#f87171', fontSize: 34, opacity: 0.9 }} />, percentage: "", color: '#f87171' },
|
||||
{ value: String(readCount), label: 'Errors resolved', icon: <TaskAltIcon sx={{ color: '#5cc879', fontSize: 34, opacity: 0.9 }} />, percentage: "", color: '#5cc879' },
|
||||
];
|
||||
@@ -133,12 +133,12 @@ const NewDashboard = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
const anyLoading =
|
||||
loadingSfw ||
|
||||
loadingRot ||
|
||||
//loadingSfw ||
|
||||
//loadingRot ||
|
||||
loadingNoti ||
|
||||
loadingSelectedOrgStats ||
|
||||
loadingSelectedOrgStats //||
|
||||
!selectedOrganization ||
|
||||
!selectedOrgForStats;
|
||||
//!selectedOrgForStats;
|
||||
setShowOverlay(anyLoading);
|
||||
}, [
|
||||
loadingSfw,
|
||||
@@ -399,6 +399,7 @@ const NewDashboard = (props) => {
|
||||
headerSubtitle="Complete these steps to start seeing insights."
|
||||
/>
|
||||
)}
|
||||
|
||||
{showOverlay && (
|
||||
<div style={{ position: 'absolute', inset: 0, background: 'rgba(17,17,17,0.6)', backdropFilter: 'blur(2px)', zIndex: 10, display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: 12 }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
|
||||
@@ -407,6 +408,7 @@ const NewDashboard = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Header / Greeting */}
|
||||
<Box style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', margin: '8px 0 16px 0' }}>
|
||||
<Typography variant="h5">{`${getGreeting()}, ${displayName ?? 'User'}!`}</Typography>
|
||||
|
||||
@@ -25,7 +25,7 @@ const SetAuthentication = (props) => {
|
||||
const [loadFail, setLoadFail] = useState("");
|
||||
const [appAuthentication, setAppAuthentication] = React.useState([]);
|
||||
|
||||
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
//const alert = useAlert();
|
||||
|
||||
const parseIncomingOpenapiData = (data) => {
|
||||
|
||||
@@ -47,7 +47,7 @@ const Welcome = (props) => {
|
||||
}
|
||||
}, [activeStep])
|
||||
|
||||
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (process.env.IS_SSR === "true");
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
|
||||
const [steps, setSteps] = useState([
|
||||
"Help us get to know you",
|
||||
"Find your Apps",
|
||||
|
||||
@@ -343,7 +343,7 @@ export const GetIconInfo = (action) => {
|
||||
"protect",
|
||||
],
|
||||
},
|
||||
{ key: "intel", values: ["intel", "feed", "threat intel", "threat intelligence", "ti", "t.i.", "t.i", "ti.", "rule", "technique", "tactic", "techniques", "tactics", "ioc", "indicator", "hash", "ip", "url", "domain", ] },
|
||||
{ key: "intel", values: ["intel", "feed", "threat intel", "threat intelligence", "ti", "t.i.", "t.i", "ti.", "rule", "technique", "tactic", "techniques", "tactics", "ioc", "indicator", "hash", "ip", "url", "domain", "sha", "md5", ] },
|
||||
];
|
||||
|
||||
var selectedKey = ""
|
||||
@@ -3346,7 +3346,7 @@ const Workflows2 = (props) => {
|
||||
}
|
||||
style={{
|
||||
textDecoration: "none",
|
||||
color: "inherit",
|
||||
color: theme.palette.text.primary,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
@@ -5149,7 +5149,7 @@ const Workflows2 = (props) => {
|
||||
|
||||
{backgroundWorkflows.length > 0 &&
|
||||
<Tab
|
||||
label={`Background Processes`}
|
||||
label={`Security Bundle`}
|
||||
value={4}
|
||||
style={{
|
||||
...tabStyle,
|
||||
|
||||
Reference in New Issue
Block a user