Tons of minor fixes from cloud sync

This commit is contained in:
Frikky
2025-07-11 16:04:14 +02:00
parent 4f48d71252
commit 7e9cdce4b6
29 changed files with 1788 additions and 1015 deletions
+184 -23
View File
@@ -10,10 +10,14 @@ import {
DialogTitle,
DialogContent,
Typography,
IconButton,
Paper,
LinearProgress,
Grid,
Button,
Tooltip,
Autocomplete,
TextField,
} from '@mui/material';
import {
@@ -22,7 +26,7 @@ import {
} from '@mui/icons-material';
const CollectIngestModal = (props) => {
const { globalUrl, open, setOpen } = props;
const { globalUrl, open, setOpen, workflows, getWorkflows, apps, } = props;
const { themeMode, brandColor } = useContext(Context);
const theme = getTheme(themeMode, brandColor);
@@ -37,12 +41,17 @@ const CollectIngestModal = (props) => {
return null
}
const startIngestion = (appname, index) => {
console.log("APPNAME:", appname, "INDEX:", index)
const startIngestion = (bundleName, appnames, category, index) => {
const body = {
"app_name": appname,
"label": appname,
var body = {
"label": bundleName,
"app_name": appnames,
"category": "",
}
if (category !== undefined && category !== null) {
body.category = category
}
const url = `${globalUrl}/api/v2/workflows/generate`
@@ -61,21 +70,27 @@ const CollectIngestModal = (props) => {
return response.json();
})
.then((data) => {
if (getWorkflows !== undefined) {
getWorkflows()
}
console.log("Ingestion started successfully:", data);
toast.success(`Ingestion for ${appname} started successfully!`);
toast.success(`Ingestion for ${bundleName} started successfully!`);
})
.catch((error) => {
console.error("Error starting ingestion:", error);
toast.error(`Failed to start ingestion for ${appname}. Please try again.`);
toast.error(`Failed to start ingestion for ${bundleName}. Please try again or contact support@shuffler.io if this persists.`);
});
}
const IngestItem = (props) => {
const { type, index } = props
const { type, appCategory, index } = props
const [hovering, setHovering] = useState(false);
const [isFinished, setIsFinished] = useState(false);
const [selectedApps, setSelectedApps] = useState([]);
//const [isFinished, setIsFinished] = useState(false);
const appname = type
const ingestedAmount = 20
@@ -85,24 +100,93 @@ const CollectIngestModal = (props) => {
"name": appname,
})
var foundMatchingWorkflow = null
if (workflows !== undefined && workflows !== null && workflows.length > 0) {
const parsedName = type.toLowerCase().replaceAll(" ", "_");
const foundWorkflow = workflows.find((workflow) => {
return workflow?.name?.toLowerCase().replaceAll(" ", "_") === parsedName
})
if (foundWorkflow !== undefined && foundWorkflow !== null) {
foundMatchingWorkflow = foundWorkflow
// Find relevant apps and maps them
if (apps.length > 0 && selectedApps.length === 0 && foundWorkflow?.actions !== undefined && foundWorkflow?.actions !== null && foundWorkflow?.actions.length > 0) {
var newSelectedApps = []
for (var actionkey in foundWorkflow.actions) {
const action = foundWorkflow.actions[actionkey]
if (action?.app_name !== "Singul" && action?.app_id !== "integration") {
continue
}
for (var paramkey in action.parameters) {
const param = action.parameters[paramkey]
if (!((param.name === "app_name" || param.name === "appName") && param.value !== undefined && param.value !== null && param.value.length > 0)) {
continue
}
// Find the app in available apps
const parsedname = param.value.replaceAll(" ", "_").toLowerCase()
for (var appkey in apps) {
const appname = apps[appkey].name.replaceAll(" ", "_").toLowerCase()
if (appname === parsedname) {
newSelectedApps.push(apps[appkey])
break
}
}
break
}
}
if (newSelectedApps.length > 0) {
setSelectedApps(newSelectedApps)
}
}
}
}
var matchingapps = []
if (appCategory !== undefined && appCategory !== null && appCategory.length > 0 && apps !== undefined && apps !== null && apps.length > 0) {
for (var appkey in apps) {
const app = apps[appkey]
for (var categorykey in app.categories) {
const category = app.categories[categorykey]
if (category.toLowerCase() === appCategory.toLowerCase()) {
matchingapps.push(app)
}
}
}
}
return (
//<Grid item xs={hovering ? 12 : 5.9}
<Grid item xs={12}
style={{
minHeight: hovering ? 225 : 145,
maxHeight: hovering ? 225 : 145,
minHeight: hovering ? 250 : 140,
maxHeight: hovering ? "auto" : 140,
cursor: "pointer",
position: "relative",
transition: "all 0.3s ease-in-out",
borderRadius: theme.palette.borderRadius,
border: hovering ? `2px solid ${theme.palette.primary.main}` : isFinished ? `2px solid ${theme.palette.success.main}` : `2px solid ${theme.palette.secondary.main}`,
border: hovering ? `2px solid ${theme.palette.primary.main}` : foundMatchingWorkflow !== null ? `2px solid ${theme.palette.success.main}` : `2px solid ${theme.palette.secondary.main}`,
textAlign: "center",
marginBottom: 5,
overflow: "hidden",
}}
onMouseEnter={() => setHovering(true)}
onMouseEnter={() => {
//if (foundMatchingWorkflow !== null) {
//} else {
setHovering(true)
//}
}}
onMouseLeave={() => setHovering(false)}
>
<div style={{marginTop: 35, marginBottom: 35, }}>
@@ -116,18 +200,92 @@ const CollectIngestModal = (props) => {
</Typography>
</div>
<Button variant="contained" onClick={() => {
toast.info("Starting ingest for relevant apps")
startIngestion(appname, index)
}}>
Start Ingestion
</Button>
<div style={{display: "flex", width: 400, margin: "auto", }}>
{matchingapps.length > 0 ?
<Autocomplete
style={{flex: 1, }}
multiple
filterSelectedOptions
options={matchingapps}
value={selectedApps}
onChange={(event, value) => {
setSelectedApps(value)
}}
getOptionLabel={(option) => {
const parsedname = option.name.replaceAll("_", " ")
return (
<div>
<img src={option?.large_image} alt={option.name} style={{ width: 24, height: 24, marginRight: 10, borderRadius: 5, }} />
<Typography variant="body1" style={{ display: "inline-block", verticalAlign: "middle", marginTop: -12, }}>
{parsedname}
</Typography>
</div>
)
}}
renderInput={(params) => {
return (
<TextField
{...params}
variant="outlined"
label="Select apps"
/>
)
}}
/>
: null}
<Button
style={{flex: 1, }}
variant={foundMatchingWorkflow !== null ? "outlined" : "contained"}
onClick={() => {
//if (foundMatchingWorkflow !== null) {
// toast.error("Deletion not implemented for this POC. Please delete the workflow.")
//}
//else {
toast.info("Starting ingest for relevant apps")
var newapps = ""
for (var key in selectedApps) {
const app = selectedApps[key]
if (newapps.length > 0) {
newapps += ","
}
newapps += app.name
}
startIngestion(appname, newapps, appCategory, index)
//}
}}>
{foundMatchingWorkflow !== null ?
"Re-Create Ingestion"
:
"Start Ingestion"
}
</Button>
</div>
{foundMatchingWorkflow !== null ?
<a href={`/workflows/${foundMatchingWorkflow.id}`} target="_blank" rel="noopener noreferrer">
<Tooltip title="View Workflow" placement="right">
<IconButton style={{position: "absolute", top: 10, right: 10, marginLeft: 15, }}>
<RocketIcon style={{ }} />
</IconButton>
</Tooltip>
</a>
: null}
{hovering ?
<div>
</div>
: null}
{isFinished ?
{foundMatchingWorkflow !== null ?
<div>
<Typography variant="body1" style={{
position: "absolute",
@@ -137,6 +295,8 @@ const CollectIngestModal = (props) => {
}}>
{ingestedAmount} / X
</Typography>
{/*
<LinearProgress
style={{
width: "100%",
@@ -146,6 +306,7 @@ const CollectIngestModal = (props) => {
variant="determinate"
fullWidth value={{ingestedAmount}}
/>
*/}
</div>
: null}
</Grid>
@@ -189,13 +350,13 @@ const CollectIngestModal = (props) => {
</Typography>
<Grid container>
<IngestItem type="Ingest Tickets" index={1} />
<IngestItem type="Ingest Tickets" appCategory={"cases"} index={1} />
<IngestItem type="Enable Threat feeds" index={2} />
<IngestItem type="Track Assets" index={2} />
<IngestItem type="Enable Search" index={2} />
<IngestItem type="Enable Mitre Att&ck techniques" index={2} />
<IngestItem type="Enable Detection Rules" index={2} />
<IngestItem type="Ingest Logs" index={2} />
<IngestItem type="Track Assets" appCategory={"assets"} index={2} />
</Grid>
</DialogContent>
</Dialog>