Onprem X Cloud sync commit. Large changes to the navbar mechanisms
This commit is contained in:
@@ -1243,25 +1243,28 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTriggerIndex === undefined || selectedTriggerIndex === null || selectedTriggerIndex < 0) {
|
||||
console.log("Failed in trigger selection: ", selectedTrigger)
|
||||
return
|
||||
}
|
||||
|
||||
//console.log("Failed in trigger selection: ", selectedTriggerIndex, "Trigger: ", selectedTrigger)
|
||||
|
||||
var found = null
|
||||
/*
|
||||
try {
|
||||
for (var key in workflows) {
|
||||
const curworkflow = workflows[key]
|
||||
const curtrigger = curworkflow?.triggers[selectedTriggerIndex]
|
||||
if (curtrigger === undefined || curtrigger === null) {
|
||||
console.log("Failed in trigger selection (1): ", curworkflow)
|
||||
continue
|
||||
}
|
||||
|
||||
if (curtrigger?.parameters === undefined || curtrigger?.parameters === null || curtrigger?.parameters.length === 0) {
|
||||
console.log("Failed in trigger selection (2): ", curworkflow)
|
||||
continue
|
||||
}
|
||||
|
||||
if (curtrigger?.parameters[0] === undefined || curtrigger?.parameters[0] === null || curtrigger?.parameters[0].value === undefined || curtrigger?.parameters[0].value === null) {
|
||||
console.log("Failed in trigger selection (3): ", curworkflow)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1275,10 +1278,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setSubworkflow(found)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Failed in trigger selection: ", e)
|
||||
return
|
||||
console.log("Failed in trigger selection (4): ", e)
|
||||
//return
|
||||
}
|
||||
*/
|
||||
|
||||
if (found) {
|
||||
const startNode = found.actions?.find((action) => action.id === workflow?.triggers[selectedTriggerIndex]?.parameters[3]?.value)
|
||||
@@ -2725,6 +2727,11 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const monitorUpdates = () => {
|
||||
if (cy === undefined || cy === null) {
|
||||
console.log("No cy found to verify startnode.")
|
||||
return true
|
||||
}
|
||||
|
||||
var firstnode = cy.getElementById(workflow.start);
|
||||
if (firstnode.length === 0) {
|
||||
var found = false;
|
||||
@@ -2732,7 +2739,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (workflow.actions[actionkey].isStartNode) {
|
||||
console.log("Updating startnode");
|
||||
workflow.start = workflow.actions[actionkey].id;
|
||||
firstnode = cy.getElementById(workflow.actions[actionkey].id);
|
||||
firstnode = cy.getElementById(workflow.actions[actionkey].id);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -2822,10 +2829,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
var curelements = cy.elements();
|
||||
for (let i = 0; i < curelements.length; i++) {
|
||||
curelements[i].addClass("not-executing-highlight");
|
||||
}
|
||||
if (cy !== undefined && cy !== null) {
|
||||
var curelements = cy.elements();
|
||||
for (let i = 0; i < curelements.length; i++) {
|
||||
curelements[i].addClass("not-executing-highlight");
|
||||
}
|
||||
}
|
||||
|
||||
var headers = {
|
||||
"Content-Type": "application/json",
|
||||
@@ -2836,6 +2845,11 @@ const AngularWorkflow = (defaultprops) => {
|
||||
headers["Org-Id"] = workflow.org_id
|
||||
}
|
||||
|
||||
if (workflow?.id === undefined || workflow?.id === null || workflow?.id?.length === 0) {
|
||||
console.log("No workflow id found during execution")
|
||||
workflow.id = props.match.params.key
|
||||
}
|
||||
|
||||
const data = { execution_argument: executionArgument, start: startNode };
|
||||
// fetch(`${globalUrl}/api/v1/workflows/${props.match.params.key}/execute`,
|
||||
fetch(`${globalUrl}/api/v1/workflows/${workflow.id}/execute`,
|
||||
@@ -4116,10 +4130,14 @@ const AngularWorkflow = (defaultprops) => {
|
||||
var execFound = new URLSearchParams(cursearch).get("execution_id");
|
||||
var sessionToken = new URLSearchParams(cursearch).get("session_token");
|
||||
if (execFound === null && sessionToken === null) {
|
||||
toast(`You don't have access to this workflow or loading failed. Redirecting to workflows in a few seconds..`)
|
||||
|
||||
toast.error(`You don't have access to this workflow or loading failed. Redirecting to workflows in a few seconds. If you recently deleted this workflow, speak with support@shuffler.io to recover it from a revision.`, {
|
||||
autoClose: 10000,
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.pathname = "/workflows";
|
||||
}, 2000);
|
||||
}, 2500);
|
||||
|
||||
} else if (sessionToken !== null && workflow_id === "3abdfb21-b40f-4e50-b855-ac0d62f83cbe") {
|
||||
toast(`Injecting session token and reloading workflow..`)
|
||||
@@ -4396,7 +4414,11 @@ const AngularWorkflow = (defaultprops) => {
|
||||
console.log("Node not found: ", target_id)
|
||||
}
|
||||
|
||||
cy.fit(null, 400);
|
||||
try {
|
||||
cy.fit(null, 400);
|
||||
} catch (e) {
|
||||
console.log("Error in fitting (1): ", e)
|
||||
}
|
||||
cy.on("add", "node", (e) => onNodeAdded(e));
|
||||
cy.on("add", "edge", (e) => onEdgeAdded(e));
|
||||
} else {
|
||||
@@ -4529,12 +4551,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setSelectedApp({});
|
||||
setSelectedComment({})
|
||||
setSelectedEdge({})
|
||||
//setSelectedActionEnvironment({})
|
||||
setTriggerAuthentication({})
|
||||
setLocalFirstrequest(true)
|
||||
|
||||
setSelectedTrigger({});
|
||||
setSelectedTriggerIndex(-1)
|
||||
setSubworkflow({})
|
||||
setUpdate(Math.random())
|
||||
|
||||
// Can be used for right side view
|
||||
@@ -4635,7 +4657,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
.then(() => {
|
||||
console.log("DONE: ", workflow_id);
|
||||
getWorkflow(workflow_id.value, nodedata);
|
||||
cy.fit(null, 300);
|
||||
|
||||
try {
|
||||
cy.fit(null, 300);
|
||||
} catch (e) {
|
||||
console.log("Error in fitting (2): ", e)
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -6856,10 +6883,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
var found = false;
|
||||
for (let branchkey in workflow.branches) {
|
||||
if (workflow.branches[branchkey].destination_id === edge.source && workflow.branches[branchkey].source_id === edge.target) {
|
||||
toast("A branch in the opposite direction already exists")
|
||||
event.target.remove()
|
||||
found = true
|
||||
break
|
||||
|
||||
// Find the branch as well
|
||||
const foundbranch = cy.getElementById(workflow.branches[branchkey].id)
|
||||
if (foundbranch !== undefined && foundbranch !== null && foundbranch.data() !== undefined && foundbranch.data() !== null) {
|
||||
toast("A branch in the opposite direction already exists")
|
||||
event.target.remove()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (workflow.branches[branchkey].destination_id === edge.target && workflow.branches[branchkey].source_id === edge.source) {
|
||||
@@ -7657,6 +7689,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
//if (nodedata.id === selectedAction.id || nodedata.id === selectedTrigger.id) {
|
||||
// return
|
||||
//}
|
||||
//
|
||||
if (nodedata.name === "switch" || nodedata.app_id === "shuffle_agent") {
|
||||
return
|
||||
}
|
||||
|
||||
var parsedStyle = {
|
||||
"border-width": "1px",
|
||||
@@ -7883,8 +7919,14 @@ const AngularWorkflow = (defaultprops) => {
|
||||
var parentNode = cy.$("#" + event.target.data("id"));
|
||||
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
||||
|
||||
const px = parentNode.position("x") - 65;
|
||||
const py = parentNode.position("y") - 5;
|
||||
var xDiff = 0
|
||||
var yDiff = 0
|
||||
if (parentNode.data("app_id") === "shuffle_agent") {
|
||||
xDiff = 70
|
||||
}
|
||||
|
||||
const px = parentNode.position("x") - 65 - xDiff
|
||||
const py = parentNode.position("y") - 5 - yDiff
|
||||
const circleId = (newNodeId = uuidv4());
|
||||
|
||||
parentNode.data("circleId", circleId);
|
||||
@@ -8205,8 +8247,14 @@ const AngularWorkflow = (defaultprops) => {
|
||||
var parentNode = cy.$("#" + event.target.data("id"));
|
||||
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
||||
|
||||
const px = parentNode.position("x") + 100;
|
||||
const py = parentNode.position("y") + 35;
|
||||
var xDiff = 0
|
||||
var yDiff = 0
|
||||
if (parentNode.data("app_id") === "shuffle_agent") {
|
||||
xDiff = 70
|
||||
}
|
||||
|
||||
const px = parentNode.position("x") + 100 - xDiff;
|
||||
const py = parentNode.position("y") + 35 - yDiff;
|
||||
const circleId = (newNodeId = uuidv4());
|
||||
|
||||
parentNode.data("circleId", circleId);
|
||||
@@ -8240,8 +8288,14 @@ const AngularWorkflow = (defaultprops) => {
|
||||
var parentNode = cy.$("#" + event.target.data("id"));
|
||||
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
|
||||
|
||||
const px = parentNode.position("x") - 65;
|
||||
const py = parentNode.position("y") + 35;
|
||||
var xDiff = 0
|
||||
var yDiff = 0
|
||||
if (parentNode.data("app_id") === "shuffle_agent") {
|
||||
xDiff = 70
|
||||
}
|
||||
|
||||
const px = parentNode.position("x") - 65 - xDiff;
|
||||
const py = parentNode.position("y") + 35 - yDiff;
|
||||
const circleId = (newNodeId = uuidv4());
|
||||
|
||||
parentNode.data("circleId", circleId);
|
||||
@@ -8400,7 +8454,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
} else {
|
||||
|
||||
addCopyButton(event);
|
||||
addStartnodeButton(event);
|
||||
|
||||
if (nodedata.app_id !== "shuffle_agent") {
|
||||
addStartnodeButton(event);
|
||||
}
|
||||
}
|
||||
|
||||
// autocomplete
|
||||
@@ -8416,7 +8473,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (nodedata.name === "switch") {
|
||||
if (nodedata.name === "switch" || nodedata.app_id === "shuffle_agent") {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9105,7 +9162,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
// Reset view for cytoscape
|
||||
if (cy !== undefined && cy !== null) {
|
||||
cy.add(insertedNodes)
|
||||
cy.fit(null, 250)
|
||||
|
||||
try {
|
||||
cy.fit(null, 250)
|
||||
} catch (error) {
|
||||
console.log("Error fitting cytoscape (3): ", error)
|
||||
}
|
||||
} else {
|
||||
setElements(insertedNodes)
|
||||
}
|
||||
@@ -9314,7 +9376,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
.then((responseJson) => {
|
||||
if (responseJson === null) {
|
||||
//console.log("No revisions found")
|
||||
return
|
||||
|
||||
//toast.warning("No revisions found")
|
||||
return
|
||||
}
|
||||
|
||||
if (responseJson.success === false) {
|
||||
@@ -9502,7 +9566,11 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
// preview: true,
|
||||
|
||||
cy.fit(null, 400)
|
||||
try {
|
||||
cy.fit(null, 400)
|
||||
} catch (error) {
|
||||
console.log("Error fitting cytoscape (4): ", error)
|
||||
}
|
||||
|
||||
cy.on("boxselect", "node", (e) => {
|
||||
if (e.target.data("isButton") || e.target.data("isDescriptor") || e.target.data("isSuggestion")) {
|
||||
@@ -12210,7 +12278,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
// Add Shuffle DB with cache keys if available
|
||||
let cacheKey = {
|
||||
type: "Shuffle DB",
|
||||
name: "Shuffle DB",
|
||||
name: "Shuffle Datastore",
|
||||
value: "$shuffle_cache",
|
||||
highlight: "shuffle_cache",
|
||||
autocomplete: "shuffle_cache",
|
||||
@@ -17643,7 +17711,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
id="suborg-changer"
|
||||
style={{ color: "rgba(255,255,255,0.7)", }}
|
||||
>
|
||||
Select an Org
|
||||
Select an Org ({originalWorkflow?.suborg_distribution?.length})
|
||||
</InputLabel>
|
||||
<Select
|
||||
style={{
|
||||
@@ -17662,12 +17730,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}}
|
||||
labelId="suborg-changer"
|
||||
value={workflow.org_id}
|
||||
disabled={savingState !== 0 || suborgWorkflows?.length === 0}
|
||||
disabled={savingState !== 0 || suborgWorkflows?.length === 0 || allTriggers === undefined}
|
||||
onChange={(e) => {
|
||||
if (lastSaved === false && originalWorkflow.id === workflow.id) {
|
||||
setSuborgWorkflows([])
|
||||
saveWorkflow(workflow, undefined, undefined, e.target.value)
|
||||
toast.warn("Saving workflow first due to detected changes. Please try to change workflow again when it is finished.", {
|
||||
toast.warn(`Saving workflow first due to detected changes. If more than 10 auth`, {
|
||||
autoClose: 2000,
|
||||
})
|
||||
return
|
||||
@@ -17693,6 +17761,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
ReactDOM.unstable_batchedUpdates(() => {
|
||||
setAllTriggers(undefined)
|
||||
setSelectedTriggerIndex(-1)
|
||||
getEnvironments(e.target.value)
|
||||
getAppAuthentication(undefined, undefined, undefined, e.target.value)
|
||||
|
||||
@@ -663,7 +663,7 @@ const ApiExplorerWrapper = (props) => {
|
||||
}
|
||||
}
|
||||
} else if (validate.result.status === 404) {
|
||||
toast.error("Page not found. Please try a different URL.")
|
||||
//toast.error("Page not found. Please try a different URL.")
|
||||
} else if (validate.result.error !== undefined && validate.result.error !== null && validate.result.error.length > 0) {
|
||||
if (validate.result.error.toLowerCase().includes("max retries")) {
|
||||
toast.error("Are you sure the URL is correct? It seems like the server is not responding.")
|
||||
|
||||
@@ -281,7 +281,7 @@ export const appCategories = [
|
||||
"name": "AI",
|
||||
"color": "#FFC107",
|
||||
"icon": "AI",
|
||||
"action_labels": ["Answer Question", "Run Action"],
|
||||
"action_labels": ["Answer Question", "Run Action", "Run LLM",],
|
||||
},
|
||||
{
|
||||
"name": "Other",
|
||||
|
||||
@@ -1215,7 +1215,7 @@ const DocsWrapper = memo(({isLoggedIn, isLoaded, children })=>{
|
||||
minWidth: isMobile ? null : (isLoggedIn && isLoaded) ? leftSideBarOpenByClick ? 800 : 900 : null, margin: "auto",
|
||||
position: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? "relative" : "static",
|
||||
left: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? 120 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0,
|
||||
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick && (isLoggedIn && isLoaded) ? 160 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
|
||||
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick && (isLoggedIn && isLoaded) ? 90 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
|
||||
transition: "left 0.3s ease-in-out, min-width 0.3s ease-in-out, max-width 0.3s ease-in-out, position 0.3s ease-in-out, margin 0.3s ease-in-out, margin-left 0.3s ease"
|
||||
}}>
|
||||
{children}
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
Chip,
|
||||
Checkbox,
|
||||
Fade,
|
||||
Skeleton,
|
||||
} from "@mui/material";
|
||||
|
||||
import {
|
||||
@@ -140,12 +141,166 @@ const UsecaseListComponent = (props) => {
|
||||
const [firstLoad, setFirstLoad] = useState(true)
|
||||
const [apps, setApps] = useState([])
|
||||
|
||||
const [autoOpenUsecase, setAutoOpenUsecase] = useState(null);
|
||||
|
||||
const classes = useStyles();
|
||||
let navigate = useNavigate();
|
||||
|
||||
const [mitreTags, setMitreTags] = useState([]);
|
||||
|
||||
// Add loading state
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
// Add this useEffect to handle URL parameters on load
|
||||
useEffect(() => {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
const params = Object.fromEntries(urlSearchParams.entries());
|
||||
|
||||
const selectedUsecase = params["selected_object"];
|
||||
if (selectedUsecase && keys.length > 0) {
|
||||
const usecaseName = selectedUsecase.toLowerCase().replaceAll("_", " ");
|
||||
|
||||
// Find the matching usecase in the keys
|
||||
for (const category of keys) {
|
||||
const foundUsecase = category.list.find(
|
||||
usecase => usecase.name.toLowerCase().replaceAll("_", " ") === usecaseName
|
||||
);
|
||||
|
||||
if (foundUsecase) {
|
||||
setAutoOpenUsecase(foundUsecase);
|
||||
|
||||
// Wait for render then scroll
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById(usecaseName);
|
||||
if (element) {
|
||||
element.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
inline: "center"
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [keys]);
|
||||
|
||||
// Add useEffect to handle auto-opening
|
||||
useEffect(() => {
|
||||
if (autoOpenUsecase) {
|
||||
getUsecase(autoOpenUsecase, 0, 0);
|
||||
setAutoOpenUsecase(null);
|
||||
}
|
||||
}, [autoOpenUsecase]);
|
||||
|
||||
// Loading skeleton component
|
||||
const LoadingSkeleton = () => (
|
||||
<div style={{paddingTop: 75, minHeight: 1000, textAlign: "left"}}>
|
||||
{/* Header skeleton */}
|
||||
<Skeleton variant="text" width={200} height={40} sx={{ bgcolor: 'grey.800' }} />
|
||||
<Skeleton variant="text" width="60%" height={24} sx={{ marginTop: 3, bgcolor: 'grey.800' }} />
|
||||
|
||||
{/* Apps selection skeleton */}
|
||||
<Skeleton variant="text" width={150} height={24} sx={{ marginTop: 5, marginBottom: 10 }} />
|
||||
<Paper style={{
|
||||
height: 60,
|
||||
width: "97.5%",
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
borderRadius: theme.palette?.borderRadius || 5,
|
||||
display: "flex",
|
||||
padding: "0 25px",
|
||||
}}>
|
||||
{/* App icons skeleton */}
|
||||
<div style={{flex: 10, display: "flex", gap: 25, alignItems: "center"}}>
|
||||
{[1, 2, 3, 4, 5].map((app) => (
|
||||
<Skeleton
|
||||
key={app}
|
||||
variant="circular"
|
||||
width={40}
|
||||
height={40}
|
||||
sx={{ bgcolor: 'grey.800' }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{/* Add more apps button skeleton */}
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width={150}
|
||||
height={40}
|
||||
sx={{
|
||||
marginTop: "10px",
|
||||
borderRadius: 20,
|
||||
bgcolor: 'grey.800'
|
||||
}}
|
||||
/>
|
||||
</Paper>
|
||||
|
||||
{/* Usecase categories skeleton - 3 sections: Collect, Enrich, Detect */}
|
||||
{[1, 2, 3,4,5].map((category) => (
|
||||
<div key={category} style={{marginTop: category === 1 ? 20: 45}}>
|
||||
{/* Category title with color indicator */}
|
||||
<Typography variant="body1" style={{marginBottom: 15}}>
|
||||
<Skeleton
|
||||
variant="text"
|
||||
width={200}
|
||||
height={24}
|
||||
sx={{
|
||||
bgcolor: category === 1 ? '#f85a3e33' :
|
||||
category === 2 ? '#ffb00d33' :
|
||||
category === 3 ? '#2196f333' :
|
||||
category === 4 ? '#4caf5033' :
|
||||
category === 5 ? '#9c27b033' : '#00000033'
|
||||
}}
|
||||
/>
|
||||
</Typography>
|
||||
<Grid container spacing={1}>
|
||||
{[1, 2, 3].map((item) => (
|
||||
<Grid item xs={isMobile ? 12 : 4} key={item}>
|
||||
<Paper
|
||||
style={{
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
borderRadius: theme.palette?.borderRadius || 5,
|
||||
padding: "10px 20px",
|
||||
height: 80,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 15
|
||||
}}
|
||||
>
|
||||
{/* App icons container */}
|
||||
<div style={{display: "flex", gap: 5}}>
|
||||
<Skeleton
|
||||
variant="circular"
|
||||
width={30}
|
||||
height={30}
|
||||
sx={{ bgcolor: 'grey.800' }}
|
||||
/>
|
||||
<Skeleton
|
||||
variant="circular"
|
||||
width={30}
|
||||
height={30}
|
||||
sx={{ bgcolor: 'grey.800' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Usecase title */}
|
||||
<Skeleton
|
||||
variant="text"
|
||||
width="70%"
|
||||
height={24}
|
||||
sx={{ bgcolor: 'grey.800' }}
|
||||
/>
|
||||
</Paper>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
|
||||
const parseUsecase = (subcase, inputFramework) => {
|
||||
var useFramework = frameworkData
|
||||
@@ -187,6 +342,7 @@ const UsecaseListComponent = (props) => {
|
||||
}, [frameworkData])
|
||||
|
||||
const loadApps = () => {
|
||||
setIsLoading(true);
|
||||
fetch(`${globalUrl}/api/v1/apps`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
@@ -220,9 +376,11 @@ const UsecaseListComponent = (props) => {
|
||||
}
|
||||
|
||||
setApps(responseJson);
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("App loading error: " + error.toString());
|
||||
setIsLoading(false);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -231,15 +389,23 @@ const UsecaseListComponent = (props) => {
|
||||
}, [])
|
||||
|
||||
if (keys === undefined || keys === null || keys.length === 0) {
|
||||
return null
|
||||
return <LoadingSkeleton />;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Timeout 50ms to delay it slightly
|
||||
const getUsecase = (subcase, index, subindex) => {
|
||||
subcase = parseUsecase(subcase)
|
||||
setPrevSubcase(subcase)
|
||||
// Update URL with selected usecase
|
||||
const usecaseName = subcase.name.toLowerCase().replaceAll(" ", "_")
|
||||
const newUrl = `?selected_object=${usecaseName}`
|
||||
|
||||
// Force URL update even if it's the same usecase
|
||||
navigate(newUrl, { replace: true })
|
||||
|
||||
// Parse and fetch usecase data
|
||||
subcase = parseUsecase(subcase)
|
||||
setPrevSubcase(subcase)
|
||||
|
||||
fetch(`${globalUrl}/api/v1/workflows/usecases/${escape(subcase.name.replaceAll(" ", "_"))}`, {
|
||||
method: "GET",
|
||||
@@ -415,6 +581,19 @@ const UsecaseListComponent = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Then, add a cleanup function for URL params when drawer closes
|
||||
const handleUsecaseClose = () => {
|
||||
// Remove the selected_object parameter from URL
|
||||
navigate("/usecases", { replace: true })
|
||||
|
||||
// Reset relevant state
|
||||
setInputUsecase({})
|
||||
setExpandedIndex(-1)
|
||||
setExpandedItem(-1)
|
||||
setFirstLoad(false)
|
||||
setSelectedWorkflows([])
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{paddingTop: 75, minHeight: 1000, textAlign: "left",}}>
|
||||
<Typography variant="h4" style={{color: "white", }}>
|
||||
@@ -645,10 +824,10 @@ const UsecaseListComponent = (props) => {
|
||||
|
||||
return (
|
||||
<Grid id={fixedName} item xs={isMobile ? 12 : 4} key={subindex} style={{}} onClick={() => {
|
||||
if (fixedName === "reporting") {
|
||||
getUsecase(subcase, index, subindex)
|
||||
return
|
||||
}
|
||||
// if (fixedName === "reporting") {
|
||||
// getUsecase(subcase, index, subindex)
|
||||
// return
|
||||
// }
|
||||
|
||||
//setSelectedWorkflows([])
|
||||
if (selectedItem) {
|
||||
@@ -678,6 +857,8 @@ const UsecaseListComponent = (props) => {
|
||||
workflowBuilt={workflowBuilt}
|
||||
inputWorkflowId={workflowBuilt}
|
||||
usecaseDetails={usecaseDetails}
|
||||
isModalOpenDefault={autoOpenUsecase?.name === subcase.name}
|
||||
onClose={handleUsecaseClose}
|
||||
/>
|
||||
|
||||
</Grid>
|
||||
@@ -717,6 +898,7 @@ const Usecases2 = (props) => {
|
||||
window.location.host === "localhost:3002" ||
|
||||
window.location.host === "shuffler.io";
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedUsecaseCategory.length === 0) {
|
||||
@@ -729,71 +911,8 @@ const Usecases2 = (props) => {
|
||||
}
|
||||
}, [selectedUsecaseCategory])
|
||||
|
||||
const checkSelectedParams = () => {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||
const params = Object.fromEntries(urlSearchParams.entries())
|
||||
|
||||
const curpath = typeof window === "undefined" || window.location === undefined ? "" : window.location.pathname;
|
||||
const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
|
||||
|
||||
const foundQuery = params["selected"]
|
||||
if (foundQuery !== null && foundQuery !== undefined) {
|
||||
setSelectedUsecaseCategory(foundQuery)
|
||||
|
||||
const newitem = removeParam("selected", cursearch);
|
||||
navigate(curpath + newitem)
|
||||
}
|
||||
|
||||
const baseItem = document.getElementById("reporting")
|
||||
if (baseItem !== undefined && baseItem !== null) {
|
||||
baseItem.click()
|
||||
|
||||
// Find close window button -> go to top
|
||||
const foundButton = document.getElementById("close_selection")
|
||||
if (foundButton !== undefined && foundButton !== null) {
|
||||
foundButton.click()
|
||||
}
|
||||
|
||||
// Scroll back to top
|
||||
window.scrollTo(0, 0)
|
||||
}
|
||||
|
||||
const foundQuery2 = params["selected_object"]
|
||||
if (foundQuery2 !== null && foundQuery2 !== undefined) {
|
||||
// Take a random object, quickly click it, then go to this one
|
||||
// Something is weird with loading apps without it
|
||||
|
||||
const queryName = foundQuery2.toLowerCase().replaceAll("_", " ")
|
||||
// Waiting a bit for it to render
|
||||
setTimeout(() => {
|
||||
const foundItem = document.getElementById(queryName)
|
||||
if (foundItem !== undefined && foundItem !== null) {
|
||||
foundItem.click()
|
||||
// Scroll to it
|
||||
|
||||
setTimeout(() => {
|
||||
foundItem.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
inline: "center"
|
||||
})
|
||||
}, 100)
|
||||
} else {
|
||||
//console.log("Couldn't find item with name ", queryName)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (usecases.length > 0) {
|
||||
//console.log(usecases)
|
||||
checkSelectedParams()
|
||||
}
|
||||
}, [usecases])
|
||||
|
||||
const getFramework = () => {
|
||||
setIsLoading(true);
|
||||
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
@@ -831,6 +950,7 @@ const Usecases2 = (props) => {
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
setIsLoading(false);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user