Merge pull request #1558 from Monilprajapati/2.0.0

App page modal and some fixes
This commit is contained in:
Frikky
2024-11-30 14:42:52 +01:00
committed by GitHub
6 changed files with 810 additions and 194 deletions
+14
View File
@@ -24,6 +24,7 @@ import DashboardView from "./views/DashboardViews.jsx";
import AdminSetup from "./views/AdminSetup"; import AdminSetup from "./views/AdminSetup";
import Admin from "./views/Admin"; import Admin from "./views/Admin";
import Docs from "./views/Docs.jsx"; import Docs from "./views/Docs.jsx";
import Usecases2 from "./views/Usecases2.jsx";
//import Introduction from "./views/Introduction"; //import Introduction from "./views/Introduction";
import SetAuthentication from "./views/SetAuthentication"; import SetAuthentication from "./views/SetAuthentication";
import SetAuthenticationSSO from "./views/SetAuthenticationSSO"; import SetAuthenticationSSO from "./views/SetAuthenticationSSO";
@@ -383,6 +384,19 @@ const App = (message, props) => {
{...props} {...props}
/> />
} }
/>
<Route
exact
path="/usecases2"
element={
<Usecases2
userdata={userdata}
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
globalUrl={globalUrl}
{...props}
/>
}
/> />
<Route <Route
exact exact
+584
View File
@@ -0,0 +1,584 @@
import React, { useEffect, useState } from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
IconButton,
Typography,
Box,
Button,
Stack,
Avatar,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import EditIcon from '@mui/icons-material/Edit';
import Search from '@mui/icons-material/Search';
import AddIcon from '@mui/icons-material/Add';
import ForkRightIcon from '@mui/icons-material/ForkRight';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import LaunchIcon from '@mui/icons-material/Launch';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import { CloudDownloadOutlined } from '@mui/icons-material';
import { findSpecificApp } from './AppFramework';
const AppModal = ({ open, onClose, app, userdata, globalUrl }) => {
const [frameworkData, setFrameworkData] = useState({})
const [usecases, setUsecases] = useState([])
const [workflows, setWorkflows] = useState([])
const [prevSubcase, setPrevSubcase] = useState({})
const [inputUsecase, setInputUsecase] = useState({})
const [latestUsecase, setLatestUsecase] = useState([])
const [foundAppUsecase, setFoundAppUsecase] = useState({})
const parseUsecase = (subcase) => {
const srcdata = findSpecificApp(frameworkData, subcase.type)
const dstdata = findSpecificApp(frameworkData, subcase.last)
if (srcdata !== undefined && srcdata !== null) {
subcase.srcimg = srcdata.large_image
subcase.srcapp = srcdata.name
}
if (dstdata !== undefined && dstdata !== null) {
subcase.dstimg = dstdata.large_image
subcase.dstapp = dstdata.name
}
return subcase
}
const getFramework = () => {
fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for framework!");
}
return response.json();
})
.then((responseJson) => {
if (responseJson.success === false) {
const preparedData = {
"siem": findSpecificApp({}, "SIEM"),
"communication": findSpecificApp({}, "COMMUNICATION"),
"assets": findSpecificApp({}, "ASSETS"),
"cases": findSpecificApp({}, "CASES"),
"network": findSpecificApp({}, "NETWORK"),
"intel": findSpecificApp({}, "INTEL"),
"edr": findSpecificApp({}, "EDR"),
"iam": findSpecificApp({}, "IAM"),
"email": findSpecificApp({}, "EMAIL"),
}
setFrameworkData(preparedData)
} else {
setFrameworkData(responseJson)
}
})
.catch((error) => {
console.log("Error getting framework: ", error)
})
}
const fetchUsecases = (workflows) => {
fetch(globalUrl + "/api/v1/workflows/usecases", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for usecases");
}
return response.json();
})
.then((responseJson) => {
const newUsecases = [...usecases]
newUsecases.forEach((category, index) => {
category.list.forEach((subcase, subindex) => {
getUsecase(subcase, index, subindex)
})
})
setLatestUsecase(newUsecases)
// Matching workflows with usecases
if (responseJson.success !== false) {
if (workflows !== undefined && workflows !== null && workflows.length > 0) {
var categorydata = responseJson
var newcategories = []
for (var key in categorydata) {
var category = categorydata[key]
category.matches = []
for (var subcategorykey in category.list) {
var subcategory = category.list[subcategorykey]
subcategory.matches = []
for (var workflowkey in workflows) {
const workflow = workflows[workflowkey]
if (workflow.usecase_ids !== undefined && workflow.usecase_ids !== null) {
for (var usecasekey in workflow.usecase_ids) {
if (workflow.usecase_ids[usecasekey].toLowerCase() === subcategory?.name?.toLowerCase()) {
category.matches.push({
"workflow": workflow.id,
"category": subcategory?.name,
})
subcategory.matches.push(workflow)
break
}
}
}
if (subcategory.matches.length > 0) {
break
}
}
}
newcategories.push(category)
}
if (newcategories !== undefined && newcategories !== null && newcategories.length > 0) {
setUsecases(newcategories)
} else {
setUsecases(responseJson)
}
} else {
setUsecases(responseJson)
}
}
})
.catch((error) => {
//toast("ERROR: " + error.toString());
console.log("ERROR: " + error.toString());
});
};
const getAvailableWorkflows = () => {
fetch(globalUrl + "/api/v1/workflows", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
fetchUsecases()
console.log("Status not 200 for workflows :O!: ", response.status);
return;
}
return response.json();
})
.then((responseJson) => {
fetchUsecases(responseJson)
if (responseJson !== undefined) {
setWorkflows(responseJson);
}
})
.catch((error) => {
fetchUsecases()
//toast(error.toString());
});
}
const getUsecase = (subcase, index, subindex) => {
subcase = parseUsecase(subcase)
setPrevSubcase(subcase)
fetch(`${globalUrl}/api/v1/workflows/usecases/${escape(subcase?.name?.replaceAll(" ", "_"))}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for framework!");
}
return response.json();
})
.then((responseJson) => {
var parsedUsecase = responseJson
if (responseJson.success === false) {
parsedUsecase = subcase
} else {
parsedUsecase = responseJson
parsedUsecase.srcimg = subcase.srcimg
parsedUsecase.srcapp = subcase.srcapp
parsedUsecase.dstimg = subcase.dstimg
parsedUsecase.dstapp = subcase.dstapp
}
// Look for the type of app and fill in img1, srcapp...
setInputUsecase(parsedUsecase)
})
.catch((error) => {
//toast(error.toString());
setInputUsecase(subcase)
console.log("Error getting usecase: ", error)
})
}
useEffect(() => {
getAvailableWorkflows()
getFramework()
}, [app])
useEffect(() => {
const foundCategory = latestUsecase?.find((category) =>
category?.list?.some((subcase) => subcase?.srcapp === app?.name || subcase?.dstapp === app?.name)
);
const foundSubcase = foundCategory?.list?.find(
(subcase) => subcase?.srcapp === app?.name || subcase?.dstapp === app?.name
);
setFoundAppUsecase(foundSubcase);
}, [latestUsecase])
const isCloud =
window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io" || window.location.host === "localhost:3000"
? true
: false;
var newAppname = app?.name;
if (newAppname === undefined) {
newAppname = "Undefined";
} else {
newAppname = newAppname.charAt(0).toUpperCase() + newAppname.substring(1);
newAppname = newAppname?.replaceAll("_", " ");
}
var canEditApp = userdata.admin === "true" || userdata.id === app?.owner || app?.owner === "" || (userdata.admin === "true" && userdata.active_org.id === app?.reference_org) || !app?.generated
return (
<Dialog
open={open}
onClose={onClose}
maxWidth="sm"
fullWidth
PaperProps={{
sx: {
borderRadius: 3,
border: "1px solid var(--Container-Stroke, #494949)",
backgroundColor: "var(--Container, #212121)",
minWidth: '440px',
fontFamily: "Inter"
}
}}
>
<DialogTitle
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
pb: 1,
pt: 2,
px: 3
}}
>
<Typography variant="h5" component="div" sx={{ fontWeight: 500 }}>
About Gmail
</Typography>
<IconButton
onClick={onClose}
sx={{
color: 'text.secondary',
'&:hover': { bgcolor: 'action.hover' }
}}
>
<CloseIcon />
</IconButton>
</DialogTitle>
<DialogContent>
<Box sx={{ display: 'flex', alignItems: 'space-between', justifyContent: 'space-between', pt: 2 }}>
<div style={{ display: "flex", flexDirection: "row", gap: 10, fontFamily: "Inter" }}>
<img
alt={app?.name}
src={app?.large_image || app?.image_url}
style={{
borderRadius: 4,
maxWidth: 100,
minWidth: 100,
maxHeight: "100%",
display: "block",
margin: "0 auto",
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.2)"
}}
/>
<div style={{ display: "flex", flexDirection: "column", justifyContent: "center" }}>
<div style={{
display: "flex",
flexDirection: "row",
}}>
<Typography variant="h6" component="div" sx={{ fontWeight: 600 }}>
{newAppname}
</Typography>
{
isCloud && (
<a
rel="noopener noreferrer"
href={"https://shuffler.io/apps/" + app?.id}
style={{ textDecoration: "none", color: "#f85a3e", marginTop: "-2px" }}
target="_blank"
>
<IconButton
style={{
color: "#f85a3e",
fontSize: 20,
}}
>
<OpenInNewIcon />
</IconButton>
</a>
)
}
</div>
<Typography
variant="body2"
color="textSecondary"
>
{app?.categories ? app.categories.join(", ") : "Communication"}
</Typography>
</div>
</div>
<div style={{ display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "center", gap: 10 }}>
<Button
variant="contained"
sx={{
bgcolor: '#ff7043',
'&:hover': { bgcolor: '#f4511e' },
textTransform: 'none',
borderRadius: 1,
py: 1,
display: 'flex',
alignItems: 'center'
}}
>
<CloudDownloadOutlined />
</Button>
<Button
variant="contained"
sx={{
bgcolor: '#ff7043',
'&:hover': { bgcolor: '#f4511e' },
textTransform: 'none',
borderRadius: 1,
py: 1,
display: 'flex',
alignItems: 'center'
}}
startIcon={
canEditApp ? <EditIcon /> : <ForkRightIcon />
}
>
{canEditApp ? "Edit" : "Fork"}
</Button>
</div>
</Box>
<div style={{
display: "flex",
justifyContent: "space-between",
fontFamily: "Inter",
padding: "26px 0px"
}}>
<div style={{
textAlign: "start",
flex: 1,
}}>
<Typography variant="h4" sx={{
fontWeight: 700,
mb: 0.3,
color: '#fff'
}}>
20
</Typography>
<Typography variant="body2" sx={{ color: 'rgba(255, 255, 255, 0.7)' }}>
Public Workflow
</Typography>
</div>
<div style={{
flex: 1,
textAlign: "start",
borderLeft: "1px solid rgba(255, 255, 255, 0.12)",
paddingLeft: "10px",
height: "100%",
}}>
<Typography variant="h4" sx={{
fontWeight: 700,
mb: 0.3,
color: '#fff'
}}>
{Array.isArray(app?.actions) ? app.actions.length : app?.actions}
</Typography>
<Typography variant="body2" sx={{ color: 'rgba(255, 255, 255, 0.7)' }}>
Actions
</Typography>
</div>
<div style={{
borderLeft: "1px solid rgba(255, 255, 255, 0.12)",
flex: 1,
paddingLeft: "10px",
paddingTop: "5px"
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '4px', marginBottom: "5px" }}>
{
app?.collection ? (
<>
<CheckCircleIcon sx={{ color: '#4CAF50' }} />
<Typography variant="body1" sx={{
fontWeight: 500,
color: '#fff',
marginTop: "1px"
}}>
app.collection
</Typography>
</>
) : "No collection yet"
}
</div>
<Typography variant="body2" sx={{ color: 'rgba(255, 255, 255, 0.7)', marginLeft: "1px" }}>
Part of a collection
</Typography>
</div>
</div>
<div style={{
display: "flex",
flexDirection: "column",
justifyContent: "start",
width: "100%"
}}>
<div style={{
fontFamily: "Inter",
fontSize: "16px",
fontWeight: 500,
color: "#fff",
marginBottom: "5px"
}}>
{
(foundAppUsecase?.srcapp !== undefined && foundAppUsecase?.dstapp !== undefined) ? (
"Connect " + foundAppUsecase?.srcapp?.replaceAll("_", " ") + " to " + foundAppUsecase?.dstapp?.replaceAll("_", " ")
) : (
"Connect " + app?.name + " to any tool"
)
}
</div>
<Box sx={{
bgcolor: 'action.hover',
p: 2,
borderRadius: 1,
display: 'flex',
alignItems: 'center',
mb: 3
}}>
<Stack direction="row" spacing={-1}>
{
foundAppUsecase === undefined ? (
<Avatar sx={{ width: 32, height: 32, bgcolor: 'background.paper', border: 1, borderColor: 'divider' }}>
<Search sx={{ color: 'text.primary', zIndex: 10, fontSize: 18}} />
</Avatar>
) : (
<Avatar
src={foundAppUsecase?.srcimg}
sx={{
width: 32,
height: 32,
bgcolor: 'background.paper',
border: 1,
borderColor: 'divider',
zIndex: 10
}}
/>
)
}
{
foundAppUsecase === undefined ? (
<Avatar sx={{ width: 32, height: 32, bgcolor: 'background.paper', border: 1, borderColor: 'divider' }}>
<AddIcon sx={{ color: 'text.primary', zIndex: 10, fontSize: 18}} />
</Avatar>
) : (
<Avatar
src={foundAppUsecase?.dstimg}
sx={{
width: 32,
height: 32,
bgcolor: 'background.paper',
border: 1,
borderColor: 'divider',
zIndex: 10
}}
/>
)
}
</Stack>
<Typography sx={{ ml: 2, fontSize: "14px", letterSpacing: "0.5px" }}>
{foundAppUsecase?.name || "Search for a Usecase"}
</Typography>
</Box>
</div>
<div style={{ display: "flex", justifyContent: "center", fontFamily: "Inter" }}>
<Button
variant="contained"
sx={{
bgcolor: '#ff7043',
'&:hover': {
bgcolor: '#f4511e'
},
textTransform: 'none',
borderRadius: 1,
py: 1,
px: 5,
fontSize: "16px",
tracking: "0.5px",
color: "black"
}}
>
Create a Usecase
</Button>
</div>
</DialogContent>
</Dialog >
);
};
export default AppModal;
@@ -324,7 +324,7 @@ const ConfigureWorkflow = (props) => {
} }
} }
if (app.authentication.type === "oauth2" || app.authentication.type === "oauth2-app") { if (app?.authentication?.type === "oauth2" || app?.authentication?.type === "oauth2-app") {
filled = false filled = false
action.auth_type = "oauth2" action.auth_type = "oauth2"
@@ -848,7 +848,7 @@ const ConfigureWorkflow = (props) => {
{opened ? {opened ?
<div style={{padding: 12, }}> <div style={{padding: 12, }}>
{action.app.authentication.type === "oauth2-app" || action.app.authentication.type === "oauth2" || action.auth_type === "oauth2" ? {action.app?.authentication?.type === "oauth2-app" || action.app?.authentication?.type === "oauth2" || action.auth_type === "oauth2" ?
<div> <div>
<AuthenticationOauth2 <AuthenticationOauth2
selectedApp={action.app} selectedApp={action.app}
@@ -945,7 +945,7 @@ const ConfigureWorkflow = (props) => {
) )
})} })}
{action.app.authentication.type !== "oauth2-app" && action.app.authentication.type !== "oauth2" ? {action.app?.authentication?.type !== "oauth2-app" && action.app?.authentication?.type !== "oauth2" ?
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
+37 -22
View File
@@ -25,6 +25,7 @@ import { toast } from "react-toastify";
import algoliasearch from "algoliasearch/lite"; import algoliasearch from "algoliasearch/lite";
import { debounce } from "lodash"; import { debounce } from "lodash";
import AppSelection from "../components/AppSelection.jsx"; import AppSelection from "../components/AppSelection.jsx";
import AppModal from "../components/AppModal.jsx";
const searchClient = algoliasearch( const searchClient = algoliasearch(
@@ -33,7 +34,7 @@ const searchClient = algoliasearch(
); );
// AppCard Component // AppCard Component
const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab }) => { const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick }) => {
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000"; const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000";
const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`; const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`;
@@ -66,11 +67,8 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
width: '100%', width: '100%',
backgroundColor: mouseHoverIndex === index ? "#2F2F2F" : "#212121" backgroundColor: mouseHoverIndex === index ? "#2F2F2F" : "#212121"
}} }}
onClick={(event) => { onClick={() => {
// if (!event.target.closest('.deactivate-button')) { handleAppClick(data);
// window.location.href = appUrl;
// }
console.log("clicked");
}} }}
> >
<img <img
@@ -188,6 +186,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
const Hits = ({ const Hits = ({
userdata, userdata,
hits, hits,
handleAppClick,
setIsAnyAppActivated, setIsAnyAppActivated,
searchQuery, searchQuery,
globalUrl, globalUrl,
@@ -208,7 +207,6 @@ const Hits = ({
}; };
//Function for activation and deactivation of app //Function for activation and deactivation of app
const handleActivateButton = (event, data, type) => { const handleActivateButton = (event, data, type) => {
@@ -315,13 +313,13 @@ const Hits = ({
transitionDelay: `${workflowDelay}ms`, transitionDelay: `${workflowDelay}ms`,
}} }}
> >
<Grid> <div
<a onClick={
href={appUrl} () => {
rel="noopener noreferrer" handleAppClick(data);
target="_blank" }
}
style={{ style={{
textDecoration: "none",
color: "#f85a3e", color: "#f85a3e",
}} }}
> >
@@ -500,8 +498,7 @@ const Hits = ({
</div> </div>
</ButtonBase> </ButtonBase>
</Paper> </Paper>
</a> </div>
</Grid>
</Zoom> </Zoom>
); );
})} })}
@@ -569,7 +566,7 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
setSearchQuery(value); setSearchQuery(value);
removeQuery("q"); removeQuery("q");
refine(value); refine(value);
}, 300) // Adjust the delay as needed }, 300)
).current; ).current;
useEffect(() => { useEffect(() => {
@@ -702,8 +699,8 @@ const Apps2 = (props) => {
const [mouseHoverIndex, setMouseHoverIndex] = useState(-1); const [mouseHoverIndex, setMouseHoverIndex] = useState(-1);
var counted = 0; var counted = 0;
const [showNoAppFound, setShowNoAppFound] = useState(false); const [showNoAppFound, setShowNoAppFound] = useState(false);
const [openModal, setOpenModal] = useState(false);
const [selectedApp, setSelectedApp] = useState(null);
const [appFramework, setAppFramework] = useState(undefined); const [appFramework, setAppFramework] = useState(undefined);
const [defaultSearch, setDefaultSearch] = useState(""); const [defaultSearch, setDefaultSearch] = useState("");
// Set the current tab based on the query parameter // Set the current tab based on the query parameter
@@ -799,6 +796,7 @@ const Apps2 = (props) => {
} }
}; };
// Only fetch if we have required data // Only fetch if we have required data
if (globalUrl && (currTab === 0 || (currTab === 1 && userdata?.id))) { if (globalUrl && (currTab === 0 || (currTab === 1 && userdata?.id))) {
fetchApps(); fetchApps();
@@ -883,7 +881,7 @@ const Apps2 = (props) => {
const handleCreateApp = (e) => { const handleCreateApp = (e) => {
e.preventDefault(); e.preventDefault();
console.log("Create app clicked") setOpenModal(true);
}; };
@@ -941,7 +939,6 @@ const Apps2 = (props) => {
queryParams.set('tab', newQueryParam); queryParams.set('tab', newQueryParam);
queryParams.delete('q'); queryParams.delete('q');
window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`); window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`);
console.log("Apps to show", appsToShow)
}; };
@@ -968,9 +965,24 @@ const Apps2 = (props) => {
setSelectedLabel(value); setSelectedLabel(value);
}; };
const handleAppClick = (app) => {
setSelectedApp(app);
setOpenModal(true);
}
const handleAppModalClose = () => {
setOpenModal(false)
}
return ( return (
<InstantSearch searchClient={searchClient} indexName="appsearch"> <InstantSearch searchClient={searchClient} indexName="appsearch">
<AppModal
open={openModal}
onClose={handleAppModalClose}
app={selectedApp}
userdata={userdata}
globalUrl={globalUrl}
/>
<div style={boxStyle}> <div style={boxStyle}>
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none' }}> <Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none' }}>
Apps Apps
@@ -1103,7 +1115,7 @@ const Apps2 = (props) => {
{appsToShow?.length > 0 && appsToShow !== undefined && !isLoading ? ( {appsToShow?.length > 0 && appsToShow !== undefined && !isLoading ? (
<div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f" }}> <div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f" }}>
{appsToShow.map((data, index) => ( {appsToShow.map((data, index) => (
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} /> <AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} handleAppClick={handleAppClick} />
))} ))}
</div> </div>
) : ( ) : (
@@ -1137,7 +1149,9 @@ const Apps2 = (props) => {
{appsToShow?.length > 0 && appsToShow !== undefined ? ( {appsToShow?.length > 0 && appsToShow !== undefined ? (
<div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f" }}> <div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f" }}>
{appsToShow.map((data, index) => ( {appsToShow.map((data, index) => (
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} /> <AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab}
handleAppClick={handleAppClick}
/>
))} ))}
</div> </div>
) : ( ) : (
@@ -1156,6 +1170,7 @@ const Apps2 = (props) => {
<CustomHits <CustomHits
isLoggedIn={isLoggedIn} isLoggedIn={isLoggedIn}
userdata={userdata} userdata={userdata}
handleAppClick={handleAppClick}
setIsAnyAppActivated={setIsAnyAppActivated} setIsAnyAppActivated={setIsAnyAppActivated}
hitsPerPage={5} hitsPerPage={5}
globalUrl={globalUrl} globalUrl={globalUrl}
+4 -1
View File
@@ -183,7 +183,10 @@ const LoginDialog = (props) => {
if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) { if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) {
console.log("RUN Welcome!!") console.log("RUN Welcome!!")
window.location.pathname = "/welcome?tab=2" setTimeout(() => {
navigate("/welcome?tab=2")
},200)
// window.location.pathname = ""
return return
} }
+2 -2
View File
@@ -692,7 +692,7 @@ const UsecaseListComponent = (props) => {
// This is the start of a dashboard that can be used. // This is the start of a dashboard that can be used.
// What data do we fill in here? Idk // What data do we fill in here? Idk
const Dashboard = (props) => { const Usecases2 = (props) => {
const { globalUrl, isLoggedIn, userdata } = props; const { globalUrl, isLoggedIn, userdata } = props;
//const alert = useAlert(); //const alert = useAlert();
const { leftSideBarOpenByClick} = useContext(Context); const { leftSideBarOpenByClick} = useContext(Context);
@@ -1250,4 +1250,4 @@ const Dashboard = (props) => {
return dataWrapper return dataWrapper
}; };
export default Dashboard; export default Usecases2;