front file added
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,377 @@
|
|||||||
|
import React, {useEffect, useState} from 'react';
|
||||||
|
|
||||||
|
import ReactGA from 'react-ga';
|
||||||
|
import { useTheme } from '@material-ui/core/styles';
|
||||||
|
import {Link} from 'react-router-dom';
|
||||||
|
|
||||||
|
import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon } from '@material-ui/icons';
|
||||||
|
|
||||||
|
import algoliasearch from 'algoliasearch/lite';
|
||||||
|
import { InstantSearch, Configure, connectSearchBox, connectHits, connectHitInsights } from 'react-instantsearch-dom';
|
||||||
|
|
||||||
|
import aa from 'search-insights'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Zoom,
|
||||||
|
Grid,
|
||||||
|
Paper,
|
||||||
|
TextField,
|
||||||
|
ButtonBase,
|
||||||
|
InputAdornment,
|
||||||
|
Typography,
|
||||||
|
Button,
|
||||||
|
Tooltip
|
||||||
|
} from '@material-ui/core';
|
||||||
|
|
||||||
|
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
||||||
|
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
||||||
|
const AppGrid1 = props => {
|
||||||
|
const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata, searchValue } = props
|
||||||
|
|
||||||
|
const isCloud =
|
||||||
|
window.location.host === "localhost:3000" ||
|
||||||
|
window.location.host === "shuffler.io";
|
||||||
|
|
||||||
|
const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
|
||||||
|
const xs = parsedXs === undefined || parsedXs === null ? isMobile ? 6 : 2 : parsedXs
|
||||||
|
const theme = useTheme();
|
||||||
|
//const [apps, setApps] = React.useState([]);
|
||||||
|
//const [filteredApps, setFilteredApps] = React.useState([]);
|
||||||
|
const [formMail, setFormMail] = React.useState("");
|
||||||
|
const [message, setMessage] = React.useState("");
|
||||||
|
const [formMessage, setFormMessage] = React.useState("");
|
||||||
|
|
||||||
|
const buttonStyle = {borderRadius: 30, height: 50, width: 220, margin: isMobile ? "15px auto 15px auto" : 20, fontSize: 18,}
|
||||||
|
|
||||||
|
const innerColor = "rgba(255,255,255,0.65)"
|
||||||
|
const borderRadius = 3
|
||||||
|
window.title = "Shuffle | Apps | Find and integrate any app"
|
||||||
|
|
||||||
|
const submitContact = (email, message) => {
|
||||||
|
const data = {
|
||||||
|
"firstname": "",
|
||||||
|
"lastname": "",
|
||||||
|
"title": "",
|
||||||
|
"companyname": "",
|
||||||
|
"email": email,
|
||||||
|
"phone": "",
|
||||||
|
"message": message,
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorMessage = "Something went wrong. Please contact frikky@shuffler.io directly."
|
||||||
|
|
||||||
|
fetch(globalUrl+"/api/v1/contact", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(response => {
|
||||||
|
if (response.success === true) {
|
||||||
|
setFormMessage(response.reason)
|
||||||
|
//alert.info("Thanks for submitting!")
|
||||||
|
} else {
|
||||||
|
setFormMessage(errorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
setFormMail("")
|
||||||
|
setMessage("")
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
setFormMessage(errorMessage)
|
||||||
|
console.log(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const SearchBox = ({currentRefinement, refine, isSearchStalled} ) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window !== undefined && window.location !== undefined && window.location.search !== undefined && window.location.search !== null) {
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||||
|
const params = Object.fromEntries(urlSearchParams.entries())
|
||||||
|
const foundQuery = {searchValue}
|
||||||
|
if (foundQuery !== null && foundQuery !== undefined) {
|
||||||
|
console.log("Got query: ", foundQuery)
|
||||||
|
refine(foundQuery)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form noValidate action="" role="search">
|
||||||
|
<input
|
||||||
|
fullWidth
|
||||||
|
style={{backgroundColor: theme.palette.inputColor, borderRadius: borderRadius, margin: 10, width: "100%",}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
fontSize: "1em",
|
||||||
|
height: 50,
|
||||||
|
},
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SearchIcon style={{marginLeft: 5}}/>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
autoComplete='off'
|
||||||
|
type="hidden"
|
||||||
|
color="primary"
|
||||||
|
defaultValue={currentRefinement}
|
||||||
|
placeholder="Find Apps..."
|
||||||
|
id="shuffle_search_field"
|
||||||
|
onChange={(event) => {
|
||||||
|
refine(event.currentTarget.value)
|
||||||
|
}}
|
||||||
|
limit={5}
|
||||||
|
/>
|
||||||
|
{/*isSearchStalled ? 'My search is stalled' : ''*/}
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var workflowDelay = -50
|
||||||
|
const Hits = ({ hits, insights }) => {
|
||||||
|
const [mouseHoverIndex, setMouseHoverIndex] = useState(-1)
|
||||||
|
var counted = 0
|
||||||
|
|
||||||
|
//console.log(hits)
|
||||||
|
//var curhits = hits
|
||||||
|
//if (hits.length > 0 && defaultApps.length === 0) {
|
||||||
|
// setDefaultApps(hits)
|
||||||
|
//}
|
||||||
|
|
||||||
|
//const [defaultApps, setDefaultApps] = React.useState([])
|
||||||
|
//console.log(hits)
|
||||||
|
//if (hits.length > 0 && hits.length !== innerHits.length) {
|
||||||
|
// setInnerHits(hits)
|
||||||
|
//}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{hits.map((data, index) => {
|
||||||
|
|
||||||
|
workflowDelay += 50
|
||||||
|
|
||||||
|
const paperStyle = {
|
||||||
|
backgroundColor: index === mouseHoverIndex ? "rgba(255,255,255,0.8)" : theme.palette.inputColor,
|
||||||
|
color: index === mouseHoverIndex ? theme.palette.inputColor : "rgba(255,255,255,0.8)",
|
||||||
|
border: `1px solid ${innerColor}`,
|
||||||
|
padding: 15,
|
||||||
|
cursor: "pointer",
|
||||||
|
position: "relative",
|
||||||
|
minHeight: 116,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counted === 12/xs*rowHandler) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
counted += 1
|
||||||
|
var parsedname = ""
|
||||||
|
for (var key = 0; key < data.name.length; key++) {
|
||||||
|
var character = data.name.charAt(key)
|
||||||
|
if (character === character.toUpperCase()) {
|
||||||
|
//console.log(data.name[key], data.name[key+1])
|
||||||
|
if (data.name.charAt(key+1) !== undefined && data.name.charAt(key+1) === data.name.charAt(key+1).toUpperCase()) {
|
||||||
|
} else {
|
||||||
|
parsedname += " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedname += character
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedname = (parsedname.charAt(0).toUpperCase()+parsedname.substring(1)).replaceAll("_", " ")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Zoom key={index} in={true} style={{ transitionDelay: `${workflowDelay}ms` }}>
|
||||||
|
<Grid item xs={xs} key={index}>
|
||||||
|
<Link to={`/apps/${data.objectID}?queryID=${data.__queryID}`} style={{textDecoration: "none", color: "#f85a3e"}}>
|
||||||
|
<Paper elevation={0} style={paperStyle} onMouseOver={() => {
|
||||||
|
setMouseHoverIndex(index)
|
||||||
|
/*
|
||||||
|
ReactGA.event({
|
||||||
|
category: "app_grid_view",
|
||||||
|
action: `search_bar_click`,
|
||||||
|
label: "",
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
}} onMouseOut={() => {
|
||||||
|
setMouseHoverIndex(-1)
|
||||||
|
}} onClick={() => {
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "app_grid_view",
|
||||||
|
action: `app_${parsedname}_${data.id}_click`,
|
||||||
|
label: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
|
||||||
|
console.log(searchClient)
|
||||||
|
aa('init', {
|
||||||
|
appId: searchClient.appId,
|
||||||
|
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
|
||||||
|
})
|
||||||
|
|
||||||
|
const timestamp = new Date().getTime()
|
||||||
|
aa('sendEvents', [
|
||||||
|
{
|
||||||
|
eventType: 'click',
|
||||||
|
eventName: 'Product Clicked',
|
||||||
|
index: 'appsearch',
|
||||||
|
objectIDs: [data.objectID],
|
||||||
|
timestamp: timestamp,
|
||||||
|
queryID: data.__queryID,
|
||||||
|
positions: [data.__position],
|
||||||
|
userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
}}>
|
||||||
|
<ButtonBase style={{padding: 5, borderRadius: 3, minHeight: 100, minWidth: 100,}}>
|
||||||
|
<img alt={data.name} src={data.image_url} style={{width: "100%", maxWidth: 100, minWidth: 100, minHeight: 100, maxHeight: 100, display: "block", margin: "0 auto"}} />
|
||||||
|
</ButtonBase>
|
||||||
|
<div/>
|
||||||
|
{index === mouseHoverIndex || showName === true ?
|
||||||
|
parsedname
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
{data.generated ?
|
||||||
|
<Tooltip title={"Created with App editor"} style={{marginTop: "28px", width: "100%"}} aria-label={data.name}>
|
||||||
|
{data.invalid ?
|
||||||
|
<CloudQueueIcon style={{position: "absolute", top: 1, left: 3, height: 16, width: 16, color: theme.palette.primary.main }}/>
|
||||||
|
:
|
||||||
|
<CloudQueueIcon style={{position: "absolute", top: 1, left: 3, height: 16, width: 16, color: "rgba(255,255,255,0.95)",}}/>
|
||||||
|
}
|
||||||
|
</Tooltip>
|
||||||
|
:
|
||||||
|
<Tooltip title={"Created with python (custom app)"} style={{marginTop: "28px", width: "100%"}} aria-label={data.name}>
|
||||||
|
<CodeIcon style={{position: "absolute", top: 1, left: 3, height: 16, width: 16, color: "rgba(255,255,255,0.95)",}}/>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
</Paper>
|
||||||
|
</Link>
|
||||||
|
</Grid>
|
||||||
|
</Zoom>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomSearchBox = connectSearchBox(SearchBox)
|
||||||
|
const CustomHits = connectHits(Hits)
|
||||||
|
//const CustomHits = connectHitInsights(aa)(Hits)
|
||||||
|
const selectButtonStyle = {
|
||||||
|
minWidth: 150,
|
||||||
|
maxWidth: 150,
|
||||||
|
minHeight: 50,
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{width: "100%", textAlign: "center", position: "relative", height: "100%", display: "flex"}}>
|
||||||
|
{/*
|
||||||
|
<div style={{padding: 10, }}>
|
||||||
|
<Button
|
||||||
|
style={selectButtonStyle}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => {
|
||||||
|
const searchField = document.createElement("shuffle_search_field")
|
||||||
|
console.log("Field: ", searchField)
|
||||||
|
if (searchField !== null & searchField !== undefined) {
|
||||||
|
console.log("Set field.")
|
||||||
|
searchField.value = "WHAT WABALABA"
|
||||||
|
searchField.setAttribute("value", "WHAT WABALABA")
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cases
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
*/}
|
||||||
|
<div style={{width: "100%", position: "relative", height: "100%",}}>
|
||||||
|
<InstantSearch searchClient={searchClient} indexName="appsearch">
|
||||||
|
<div style={{maxWidth: 450, margin: "auto", marginTop: 15, marginBottom: 15, }}>
|
||||||
|
<CustomSearchBox />
|
||||||
|
</div>
|
||||||
|
<CustomHits hitsPerPage={5}/>
|
||||||
|
<Configure clickAnalytics />
|
||||||
|
</InstantSearch>
|
||||||
|
{showSuggestion === true ?
|
||||||
|
<div style={{paddingTop: 0, maxWidth: isMobile ? "100%" : "60%", margin: "auto"}}>
|
||||||
|
<Typography variant="h6" style={{color: "white", marginTop: 50,}}>
|
||||||
|
Can't find what you're looking for?
|
||||||
|
</Typography>
|
||||||
|
<div style={{flex: "1", display: "flex", flexDirection: "row", textAlign: "center",}}>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
style={{flex: "1", marginRight: "15px", backgroundColor: theme.palette.inputColor}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "#ffffff",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="Email (optional)"
|
||||||
|
type="email"
|
||||||
|
id="email-handler"
|
||||||
|
autoComplete="email"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
onChange={e => setFormMail(e.target.value)}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
style={{flex: "1", backgroundColor: theme.palette.inputColor}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "#ffffff",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="What apps do you want to see?"
|
||||||
|
type=""
|
||||||
|
id="standard-required"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
autoComplete="off"
|
||||||
|
onChange={e => setMessage(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
style={buttonStyle}
|
||||||
|
disabled={message.length === 0}
|
||||||
|
onClick={() => {
|
||||||
|
submitContact(formMail, message)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
<Typography style={{color: "white"}} variant="body2">{formMessage}</Typography>
|
||||||
|
</div>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
<span style={{position: "absolute", display: "flex", textAlign: "right", float: "right", right: 0, bottom: 120, }}>
|
||||||
|
<Typography variant="body2" color="textSecondary" style={{}}>
|
||||||
|
Search by
|
||||||
|
</Typography>
|
||||||
|
<a rel="noopener noreferrer" href="https://www.algolia.com/" target="_blank" style={{textDecoration: "none", color: "white"}}>
|
||||||
|
<img src={"/images/logo-algolia-nebula-blue-full.svg"} alt="Algolia logo" style={{height: 17, marginLeft: 5, marginTop: 3,}} />
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppGrid1;
|
||||||
@@ -0,0 +1,468 @@
|
|||||||
|
|
||||||
|
import { Grid, Divider, List, ListItem, ListItemText } from "@mui/material";
|
||||||
|
import { experimentalStyled as styled } from '@mui/material/styles';
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import Paper from "@material-ui/core/Paper";
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import Box from '@material-ui/core/Box';
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
|
||||||
|
import algoliasearch from "algoliasearch";
|
||||||
|
//import algoliarecommend from "algoliarecommend";
|
||||||
|
|
||||||
|
const searchClient = algoliasearch(
|
||||||
|
"JNSS5CFDZZ",
|
||||||
|
"db08e40265e2941b9a7d8f644b6e5240"
|
||||||
|
);
|
||||||
|
|
||||||
|
// https://www.algolia.com/doc/api-client/getting-started/install/
|
||||||
|
/*const algoliarecommend = require('@algolia/recommend');
|
||||||
|
|
||||||
|
const client = algoliarecommend(
|
||||||
|
"NSS5CFDZZ",
|
||||||
|
"db08e40265e2941b9a7d8f644b6e5240"
|
||||||
|
);*/
|
||||||
|
|
||||||
|
|
||||||
|
const Item = styled(Paper)(({ theme }) => ({
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
border: "0.0625rem solid #b2b2b2",
|
||||||
|
borderRadius: "1.5625rem",
|
||||||
|
boxSizing: "content-box",
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
width: "200px",
|
||||||
|
textAlign: 'center',
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
marginTop: "20px",
|
||||||
|
marginBottom: "20px",
|
||||||
|
color: "textPrimary"
|
||||||
|
}));
|
||||||
|
const AppExplorer = (props) => {
|
||||||
|
const [algoliaResult, setAlgoliaResult] = useState("");
|
||||||
|
|
||||||
|
const runAlgoliaAppSearch = (query) => {
|
||||||
|
const index = searchClient.initIndex("appsearch");
|
||||||
|
|
||||||
|
index
|
||||||
|
.search(`${query}`)
|
||||||
|
.then(({ hits }) => {
|
||||||
|
setAlgoliaResult(hits);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
runAlgoliaAppSearch("wazuh")
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
const brandApp = () => {
|
||||||
|
const index = searchClient.initIndex("appsearch");
|
||||||
|
|
||||||
|
const replicaIndex = searchClient.initIndex('appsearch');
|
||||||
|
replicaIndex.setSettings({
|
||||||
|
customRanking: [
|
||||||
|
"asc(time_edited)"
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(({ hits }) => {
|
||||||
|
console.log(hits);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
brandApp()
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
/*const trandingApp = () => {
|
||||||
|
|
||||||
|
const index = client.getTrendingGlobalItems([
|
||||||
|
{
|
||||||
|
indexName: "appsearch",
|
||||||
|
threshold: 60
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.then(({ results }) => {
|
||||||
|
console.log(results);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
trandingApp();
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SideBar = {
|
||||||
|
minWidth: 250,
|
||||||
|
|
||||||
|
borderRight: "1px solid rgba(255,255,255,0.3)",
|
||||||
|
left: 0,
|
||||||
|
position: "sticky",
|
||||||
|
minHeight: "90vh",
|
||||||
|
maxHeight: "90vh",
|
||||||
|
overflowX: "hidden",
|
||||||
|
overflowY: "auto",
|
||||||
|
zIndex: 1000,
|
||||||
|
color: "white"
|
||||||
|
};
|
||||||
|
const contentbar = {
|
||||||
|
padding: "40px",
|
||||||
|
|
||||||
|
};
|
||||||
|
const boxdata = {
|
||||||
|
paddingLeft: "30px"
|
||||||
|
}
|
||||||
|
const link = {
|
||||||
|
textDecoration: "none"
|
||||||
|
}
|
||||||
|
const catItems = (
|
||||||
|
<div style={SideBar}>
|
||||||
|
<List>
|
||||||
|
<ListItem >
|
||||||
|
<ListItemText>
|
||||||
|
<span><Typography variant="primary">Categories</Typography></span>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<span></span>
|
||||||
|
<Divider />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
ASSETS
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
CASES
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
COMMS
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
EDR & AV
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
IAM
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
INTEL
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
NETWORK
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary">
|
||||||
|
SIEM
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
|
||||||
|
{catItems}
|
||||||
|
<div style={contentbar}>
|
||||||
|
<Grid>
|
||||||
|
<Grid item xl={8} style={{ "border": "20px" }}>
|
||||||
|
|
||||||
|
<Typography type="title" variant="h6">
|
||||||
|
Getting Started
|
||||||
|
</Typography>
|
||||||
|
<div style={{
|
||||||
|
paddingLeft: "50px",
|
||||||
|
|
||||||
|
}}>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={{ xs: 1, md: 4 }}
|
||||||
|
columns={{ xs: 4, sm: 8, md: 12 }}
|
||||||
|
>
|
||||||
|
{Array.from(Array(algoliaResult.length)).map((_, index) => (
|
||||||
|
|
||||||
|
<Grid item xs={2} sm={4} md={4} key={index}>
|
||||||
|
<a href={algoliaResult[0]["objectID"]} style={link}>
|
||||||
|
<Item>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="column" style={{ float: "left" }}>
|
||||||
|
<img src={algoliaResult[0]["image_url"]} alt="shuffle" width="50px" />
|
||||||
|
</div>
|
||||||
|
<div class="column " style={boxdata}>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body1">
|
||||||
|
{algoliaResult[0]["name"]}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body2">
|
||||||
|
{algoliaResult[0]["description"].substring(0, 20)}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Item>
|
||||||
|
</a>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
<Grid item xl={8} style={{ "border": "20px" }}>
|
||||||
|
|
||||||
|
<Typography type="title" variant="h6">
|
||||||
|
Most Popular
|
||||||
|
</Typography>
|
||||||
|
<div style={{
|
||||||
|
paddingLeft: "50px",
|
||||||
|
|
||||||
|
}}>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={{ xs: 1, md: 3 }}
|
||||||
|
columns={{ xs: 4, sm: 8, md: 12 }}
|
||||||
|
>
|
||||||
|
{Array.from(Array(3)).map((_, index) => (
|
||||||
|
<Grid item xs={2} sm={4} md={4} key={index}>
|
||||||
|
<a href="#" style={link}>
|
||||||
|
<Item>
|
||||||
|
<div class="row">
|
||||||
|
<div class="column" style={{ float: "left" }}>
|
||||||
|
<img src="/images/testing.png" alt="shuffle" width="50px" />
|
||||||
|
</div>
|
||||||
|
<div class="column " style={boxdata}>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body1">
|
||||||
|
App Name
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body2">
|
||||||
|
Description
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Item>
|
||||||
|
</a>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Grid item xl={8} style={{ "border": "20px" }}>
|
||||||
|
|
||||||
|
<Typography type="title" variant="h6">
|
||||||
|
Brand New
|
||||||
|
</Typography>
|
||||||
|
<div style={{
|
||||||
|
paddingLeft: "50px",
|
||||||
|
|
||||||
|
}}>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={{ xs: 1, md: 3 }}
|
||||||
|
columns={{ xs: 4, sm: 8, md: 12 }}
|
||||||
|
>
|
||||||
|
{Array.from(Array(3)).map((_, index) => (
|
||||||
|
<Grid item xs={2} sm={4} md={4} key={index}>
|
||||||
|
<a href="#" style={link}>
|
||||||
|
<Item>
|
||||||
|
<div class="row">
|
||||||
|
<div class="column" style={{ float: "left" }}>
|
||||||
|
<img src="/images/testing.png" alt="shuffle" width="50px" />
|
||||||
|
</div>
|
||||||
|
<div class="column " style={boxdata}>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body1">
|
||||||
|
App Name
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body2">
|
||||||
|
Description
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Item>
|
||||||
|
</a>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={{ xs: 1, md: 3 }}
|
||||||
|
columns={{ xs: 4, sm: 8, md: 12 }}
|
||||||
|
>
|
||||||
|
{Array.from(Array(3)).map((_, index) => (
|
||||||
|
<Grid item xs={2} sm={4} md={4} key={index}>
|
||||||
|
|
||||||
|
<div className="row" >
|
||||||
|
<div className="column" style={{ float: "left", width: "33.33%", marginTop: "20px", marginBottom: "20px", }}>
|
||||||
|
<img src="/images/shuffle_logo.png" alt="shuffle" width="200px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Grid item xl={8} style={{ "border": "20px" }}>
|
||||||
|
|
||||||
|
<Typography type="title" variant="h6">
|
||||||
|
Hybrid work
|
||||||
|
</Typography>
|
||||||
|
<div style={{
|
||||||
|
paddingLeft: "50px",
|
||||||
|
|
||||||
|
}}>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={{ xs: 1, md: 3 }}
|
||||||
|
columns={{ xs: 4, sm: 8, md: 12 }}
|
||||||
|
>
|
||||||
|
{Array.from(Array(3)).map((_, index) => (
|
||||||
|
<Grid item xs={2} sm={4} md={4} key={index}>
|
||||||
|
<a href="#" style={link}>
|
||||||
|
<Item>
|
||||||
|
<div class="row">
|
||||||
|
<div class="column" style={{ float: "left" }}>
|
||||||
|
<img src="/images/testing.png" alt="shuffle" width="50px" />
|
||||||
|
</div>
|
||||||
|
<div class="column " style={boxdata}>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body1">
|
||||||
|
App Name
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div style={boxdata}>
|
||||||
|
<Typography align="left" variant="body2">
|
||||||
|
Description
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Item>
|
||||||
|
</a>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<div className="row" style={{ display: "flex" }}>
|
||||||
|
<div className="col" style={{ width: "40%", marginTop: "50px" }}>
|
||||||
|
<Typography variant="h6">Don't see it? Build it!</Typography>
|
||||||
|
<Typography variant="body2">Use our APIs to create an app that makes your working life better.And maybe even share it with the world.</Typography>
|
||||||
|
<a href="#" target="_blank" rel="nonref"
|
||||||
|
style={{
|
||||||
|
background: "#FF4500",
|
||||||
|
borderRadius: "3.125rem",
|
||||||
|
color: "#fff",
|
||||||
|
display: "block",
|
||||||
|
fontSize: ".9375rem",
|
||||||
|
fontWeight: "500",
|
||||||
|
height: "1rem",
|
||||||
|
letterSpacing: "-.02em",
|
||||||
|
lineHeight: ".875rem",
|
||||||
|
marginTop: "1.5rem",
|
||||||
|
padding: "1.3125rem 1.375rem",
|
||||||
|
textAlign: "center",
|
||||||
|
textDecoration: "none",
|
||||||
|
width: "8.5rem"
|
||||||
|
}}><span>visit developer portal</span></a>
|
||||||
|
</div>
|
||||||
|
<div className="col" style={{ float: "right" }}>
|
||||||
|
<div className="row" style={{ float: "left", marginLeft: "90px" }}>
|
||||||
|
<div className="column" style={{ float: "left", margin: "60px 10px 20px 30px" }}>
|
||||||
|
<img src="/images/demo1.png" alt="shuffle" width="90px" />
|
||||||
|
</div>
|
||||||
|
<div className="column" style={{ float: "left", margin: "60px 10px 20px 30px" }}>
|
||||||
|
<img src="/images/demo1.png" alt="shuffle" width="90px" />
|
||||||
|
</div>
|
||||||
|
<div className="column" style={{ float: "left", margin: "60px 10px 20px 30px" }}>
|
||||||
|
<img src="/images/demo1.png" alt="shuffle" width="90px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default AppExplorer;
|
||||||
@@ -0,0 +1,789 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Grid, Container, Divider, CardMedia, List, ListItem, ListItemText } from "@mui/material";
|
||||||
|
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
|
import CardContent from "@material-ui/core/CardContent";
|
||||||
|
|
||||||
|
import Table from "@material-ui/core/Table";
|
||||||
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
import TableContainer from "@material-ui/core/TableContainer";
|
||||||
|
import TableHead from "@material-ui/core/TableHead";
|
||||||
|
import TableRow from "@material-ui/core/TableRow";
|
||||||
|
import Paper from "@material-ui/core/Paper";
|
||||||
|
|
||||||
|
import { LineChart, LineSeries, BarChart } from "reaviz";
|
||||||
|
import { Gridline, GridStripe } from "reaviz";
|
||||||
|
import { GridlineSeries } from "reaviz";
|
||||||
|
|
||||||
|
import InputLabel from '@material-ui/core/InputLabel';
|
||||||
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
import Select from '@material-ui/core/Select';
|
||||||
|
|
||||||
|
import { styled, alpha } from '@mui/material/styles';
|
||||||
|
import AppBar from '@mui/material/AppBar';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import InputBase from '@mui/material/InputBase';
|
||||||
|
import Badge from '@mui/material/Badge';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import Menu from '@mui/material/Menu';
|
||||||
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
|
import AccountCircle from '@mui/icons-material/AccountCircle';
|
||||||
|
import MailIcon from '@mui/icons-material/Mail';
|
||||||
|
import NotificationsIcon from '@mui/icons-material/Notifications';
|
||||||
|
import MoreIcon from '@mui/icons-material/MoreVert';
|
||||||
|
import SearchField from "../components/Searchfield";
|
||||||
|
import { SpaRounded } from "@material-ui/icons";
|
||||||
|
import { isMobile } from "react-device-detect"
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
key: new Date("11/29/2019"),
|
||||||
|
data: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: new Date("11/30/2019"),
|
||||||
|
data: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: new Date("12/01/2019"),
|
||||||
|
data: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: new Date("12/02/2019"),
|
||||||
|
data: 18,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const useStyles1 = makeStyles((theme) => ({
|
||||||
|
formControl: {
|
||||||
|
margin: theme.spacing(1),
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
selectEmpty: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
const useStyles = makeStyles({
|
||||||
|
table: {
|
||||||
|
minWidth: 650,
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
minWidth: 275,
|
||||||
|
},
|
||||||
|
bullet: {
|
||||||
|
display: "inline-block",
|
||||||
|
margin: "0 2px",
|
||||||
|
transform: "scale(0.8)",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
pos: {
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function createData(name, calories, fat, carbs, protein) {
|
||||||
|
return { name, calories, fat, carbs, protein };
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = [
|
||||||
|
createData("Frozen yoghurt", 159, 6.0, 24, 4.0),
|
||||||
|
createData("Ice cream sandwich", 237, 9.0, 37, 4.3),
|
||||||
|
createData("Eclair", 262, 16.0, 24, 6.0),
|
||||||
|
createData("Cupcake", 305, 3.7, 67, 4.3),
|
||||||
|
createData("Gingerbread", 356, 16.0, 49, 3.9),
|
||||||
|
];
|
||||||
|
|
||||||
|
const Search = styled('div')(({ theme }) => ({
|
||||||
|
position: 'relative',
|
||||||
|
borderRadius: theme.shape.borderRadius,
|
||||||
|
backgroundColor: alpha(theme.palette.common.white, 0.15),
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: alpha(theme.palette.common.white, 0.25),
|
||||||
|
},
|
||||||
|
marginRight: theme.spacing(2),
|
||||||
|
marginLeft: 0,
|
||||||
|
width: '100%',
|
||||||
|
[theme.breakpoints.up('sm')]: {
|
||||||
|
marginLeft: theme.spacing(3),
|
||||||
|
width: 'auto',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const SearchIconWrapper = styled('div')(({ theme }) => ({
|
||||||
|
padding: theme.spacing(0, 2),
|
||||||
|
height: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledInputBase = styled(InputBase)(({ theme }) => ({
|
||||||
|
color: 'inherit',
|
||||||
|
'& .MuiInputBase-input': {
|
||||||
|
padding: theme.spacing(1, 1, 1, 0),
|
||||||
|
// vertical padding + font size from searchIcon
|
||||||
|
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
|
||||||
|
transition: theme.transitions.create('width'),
|
||||||
|
width: '100%',
|
||||||
|
[theme.breakpoints.up('md')]: {
|
||||||
|
width: '20ch',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
function PrimarySearchAppBar() {
|
||||||
|
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||||
|
const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null);
|
||||||
|
|
||||||
|
const isMenuOpen = Boolean(anchorEl);
|
||||||
|
const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);
|
||||||
|
|
||||||
|
const handleProfileMenuOpen = (event) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMobileMenuClose = () => {
|
||||||
|
setMobileMoreAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
handleMobileMenuClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMobileMenuOpen = (event) => {
|
||||||
|
setMobileMoreAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuId = 'primary-search-account-menu';
|
||||||
|
const renderMenu = (
|
||||||
|
<Menu
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right',
|
||||||
|
}}
|
||||||
|
id={menuId}
|
||||||
|
keepMounted
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right',
|
||||||
|
}}
|
||||||
|
open={isMenuOpen}
|
||||||
|
onClose={handleMenuClose}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleMenuClose}>Profile</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose}>My account</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
|
||||||
|
const mobileMenuId = 'primary-search-account-menu-mobile';
|
||||||
|
const renderMobileMenu = (
|
||||||
|
<Menu
|
||||||
|
anchorEl={mobileMoreAnchorEl}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right',
|
||||||
|
}}
|
||||||
|
id={mobileMenuId}
|
||||||
|
keepMounted
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right',
|
||||||
|
}}
|
||||||
|
open={isMobileMenuOpen}
|
||||||
|
onClose={handleMobileMenuClose}
|
||||||
|
>
|
||||||
|
<MenuItem>
|
||||||
|
<IconButton size="large" aria-label="show 4 new mails" color="inherit">
|
||||||
|
<Badge badgeContent={4} color="error">
|
||||||
|
<MailIcon />
|
||||||
|
</Badge>
|
||||||
|
</IconButton>
|
||||||
|
<p>Messages</p>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem>
|
||||||
|
<IconButton
|
||||||
|
size="large"
|
||||||
|
aria-label="show 17 new notifications"
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
|
<Badge badgeContent={17} color="error">
|
||||||
|
<NotificationsIcon />
|
||||||
|
</Badge>
|
||||||
|
</IconButton>
|
||||||
|
<p>Notifications</p>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={handleProfileMenuOpen}>
|
||||||
|
<IconButton
|
||||||
|
size="large"
|
||||||
|
aria-label="account of current user"
|
||||||
|
aria-controls="primary-search-account-menu"
|
||||||
|
aria-haspopup="true"
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
|
<AccountCircle />
|
||||||
|
</IconButton>
|
||||||
|
<p>Profile</p>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<AppBar position="fixed" style={{ backgroundColor: "black", boxShadow: "unset" }}>
|
||||||
|
<Toolbar>
|
||||||
|
<img src="/images/Shuffle_logo.png" style={{ height: "3rem", width: "3rem" }} alt="shuffle img" />
|
||||||
|
<SearchField />
|
||||||
|
{/* <Box sx={{ flexGrow: 1 }} /> */}
|
||||||
|
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
{renderMobileMenu}
|
||||||
|
{renderMenu}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppHub = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const classes1 = useStyles1();
|
||||||
|
|
||||||
|
const [usecases, setUsecases] = React.useState([
|
||||||
|
{
|
||||||
|
"name": "1. Collect",
|
||||||
|
"color": "#c51152",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "Email management",
|
||||||
|
"priority": 100,
|
||||||
|
"type": "communication",
|
||||||
|
"items": {
|
||||||
|
"name": "Release a quarantined message",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "EDR to ticket",
|
||||||
|
"priority": 100,
|
||||||
|
"type": "edr",
|
||||||
|
"items": {
|
||||||
|
"name": "Get host information",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SIEM to ticket",
|
||||||
|
"priority": 100,
|
||||||
|
"type": "siem",
|
||||||
|
"description": "Ensure tickets are forwarded to the correct destination. Alternatively add enrichment on it's way there.",
|
||||||
|
"video": "https://www.youtube.com/watch?v=FBISHA7V15c&t=197s&ab_channel=OpenSecure",
|
||||||
|
"blogpost": "https://medium.com/shuffle-automation/introducing-shuffle-an-open-source-soar-platform-part-1-58a529de7d12",
|
||||||
|
"reference_image": "/images/detectionframework.png",
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2-way Ticket synchronization",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ChatOps",
|
||||||
|
"priority": 70,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Threat Intel received",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Assign tickets",
|
||||||
|
"priority": 30,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firewall alerts",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {
|
||||||
|
"name": "URL filtering",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IDS/IPS alerts",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {
|
||||||
|
"name": "Manage policies",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Deduplicate information",
|
||||||
|
"priority": 70,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2. Enrich",
|
||||||
|
"color": "#f4c20d",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "Internal Enrichment",
|
||||||
|
"priority": 100,
|
||||||
|
"items": {
|
||||||
|
"name": "...",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "External historical Enrichment",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {
|
||||||
|
"name": "...",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Realtime",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {
|
||||||
|
"name": "Analyze screenshots",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "3. Detect",
|
||||||
|
"color": "#3cba54",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "Search SIEM (Sigma)",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {
|
||||||
|
"name": "Endpoint",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Search EDR (OSQuery)",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Search emails (Sublime)",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {
|
||||||
|
"name": "Check headers and IOCs",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Search IOCs (ioc-finder)",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Search files (Yara)",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Memory Analysis (Volatility)",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IDS & IPS (Snort/Surricata)",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Validate old tickets",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Honeypot access",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {
|
||||||
|
"name": "...",
|
||||||
|
"items": {}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "4. Respond",
|
||||||
|
"color": "#4885ed",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "Eradicate malware",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Quarantine host(s)",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Block IPs, URLs, Domains and Hashes",
|
||||||
|
"priority": 90,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Trigger scans",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Update indicators (FW, EDR, SIEM...)",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Autoblock activity when threat intel is received",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lock/Delete/Reset account",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lock vault",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Increase authentication",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get policies from assets",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Run ansible scripts",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "5. Verify",
|
||||||
|
"color": "#7f00ff",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "Discover vulnerabilities",
|
||||||
|
"priority": 80,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Discover assets",
|
||||||
|
"priority": 80,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ensure policies are followed",
|
||||||
|
"priority": 80,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Find Inactive users",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Botnet tracker",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ensure access rights match HR systems",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ensure onboarding is followed",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Third party apps in SaaS",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Devices used for your cloud account",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Too much access in GCP/Azure/AWS/ other clouds",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Certificate validation",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Domain investigation with LetsEncrypt",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Monitor new DNS entries for domain with passive DNS",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Monitor and track password dumps",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Monitor for mentions of domain on darknet sites",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {},
|
||||||
|
"matches": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Reporting",
|
||||||
|
"priority": 50,
|
||||||
|
"items": {
|
||||||
|
"name": "Monthly reports",
|
||||||
|
"items": {
|
||||||
|
"name": "...",
|
||||||
|
"items": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const SideBar = {
|
||||||
|
minWidth: 250,
|
||||||
|
maxWidth: 300,
|
||||||
|
borderRight: "1px solid rgba(255,255,255,0.3)",
|
||||||
|
left: 0,
|
||||||
|
position: "sticky",
|
||||||
|
minHeight: "90vh",
|
||||||
|
maxHeight: "90vh",
|
||||||
|
overflowX: "hidden",
|
||||||
|
overflowY: "auto",
|
||||||
|
zIndex: 1000,
|
||||||
|
color: "black"
|
||||||
|
};
|
||||||
|
|
||||||
|
const [age, setAge] = React.useState(0);
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setAge(event.target.value);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Card>
|
||||||
|
<CardContent style={{ padding: 0 }}>
|
||||||
|
<div style={{
|
||||||
|
background: "url('/images/home-header-bg.png')", height: "450px", backgroundSize: "cover",
|
||||||
|
backgroundRepeat: "no-repeat",
|
||||||
|
backgroundPosition: "center",
|
||||||
|
position: "relative"
|
||||||
|
}}>
|
||||||
|
<div style={{ width: "95%", margin: "auto", position: "relative", height: "450px" }}>
|
||||||
|
<div>
|
||||||
|
<PrimarySearchAppBar />
|
||||||
|
</div>
|
||||||
|
<div style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: "10%",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%"
|
||||||
|
}}>
|
||||||
|
<div>
|
||||||
|
<img src="/images/Shuffle_logo.png" style={{ height: "4rem", width: "4rem" }} alt="shuffle img" />
|
||||||
|
<Typography type="title" variant="h1" color="#ef5d29">
|
||||||
|
SHUFFLE
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<SearchField />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<div style={SideBar}>
|
||||||
|
<List>
|
||||||
|
<ListItem >
|
||||||
|
<ListItemText>
|
||||||
|
<span style={{ fontSize: "25px", fontFamily: "revert", fontWeight: "bold" }}>Categories</span>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<span></span>
|
||||||
|
<Divider />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<span style={{ fontSize: "25px", fontFamily: "revert" }}>Workflows</span>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<span style={{ fontSize: "25px", fontFamily: "revert" }}>Apps</span>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<span style={{ fontSize: "25px", fontFamily: "revert" }}>Docs</span>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "20px", width: "100%" }}>
|
||||||
|
<Typography type="title" variant="h2" color="black">
|
||||||
|
Workflow
|
||||||
|
</Typography>
|
||||||
|
<div style={{ width: "100%", minHeight: isMobile ? 0 : 71, maxHeight: isMobile ? 0 : 71, }}>
|
||||||
|
{!isMobile && usecases !== null && usecases !== undefined && usecases.length > 0 ?
|
||||||
|
<div style={{ display: "flex", }}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{usecases.map((usecase, index) => {
|
||||||
|
//console.log(usecase)
|
||||||
|
return (
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<Paper
|
||||||
|
key={usecase.name}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
marginRight: index === usecases.length - 1 ? 0 : 10,
|
||||||
|
cursor: "pointer",
|
||||||
|
overflow: "hidden",
|
||||||
|
padding: 10,
|
||||||
|
border: "0.0625rem solid #b2b2b2",
|
||||||
|
borderRadius: "1.5625rem",
|
||||||
|
boxSizing: "content-box",
|
||||||
|
cursor: "pointer",
|
||||||
|
height: "70px",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
console.log("clicked...")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<a href={`/usecases?selected=${usecase.name}`} rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", }}>
|
||||||
|
<Typography variant="body1" color="textPrimary">
|
||||||
|
{usecase.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="textSecondary">
|
||||||
|
In use: {usecase.matches.length}/{usecase.list.length}
|
||||||
|
</Typography>
|
||||||
|
</a>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Card>
|
||||||
|
<CardContent style={{ padding: 0 }}>
|
||||||
|
<Typography type="title" variant="h3" color="#ffffff" style={{
|
||||||
|
backgroundColor: "black", padding: "10px", height: "200px",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center"
|
||||||
|
}}>
|
||||||
|
footer
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppHub;
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { Grid, Container, Divider, CardMedia, List, ListItem, ListItemText } from "@mui/material";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
|
||||||
|
import theme from '../theme';
|
||||||
|
import {isMobile} from "react-device-detect";
|
||||||
|
import AppGrid1 from "../components/AppGrid1.jsx"
|
||||||
|
import WorkflowGrid from "../components/WorkflowGrid.jsx"
|
||||||
|
import CreatorGrid from "../components/CreatorGrid.jsx"
|
||||||
|
import DocsGrid from "../components/DocsGrid.jsx"
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import { useNavigate, Link } from "react-router-dom";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Tabs,
|
||||||
|
Paper,
|
||||||
|
Tab,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Business as BusinessIcon,
|
||||||
|
Apps as AppsIcon,
|
||||||
|
Polymer as PolymerIcon,
|
||||||
|
EmojiObjects as EmojiObjectsIcon,
|
||||||
|
Description as DescriptionIcon,
|
||||||
|
} from "@material-ui/icons";
|
||||||
|
|
||||||
|
|
||||||
|
const bodyDivStyle = {
|
||||||
|
margin: "auto",
|
||||||
|
maxWidth: 1024,
|
||||||
|
scrollX: "hidden",
|
||||||
|
overflowX: "hidden",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be different if logged in :|
|
||||||
|
const Appdemo = (props) => {
|
||||||
|
const { globalUrl, isLoaded, serverside, userdata, hidemargins, } = props;
|
||||||
|
const [appCategory,setAppCategory] = useState();
|
||||||
|
let navigate = useNavigate();
|
||||||
|
|
||||||
|
const [curTab, setCurTab] = useState(0);
|
||||||
|
const iconStyle = { marginRight: 10 };
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (serverside !== true && window.location.search !== undefined && window.location.search !== null) {
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||||
|
const params = Object.fromEntries(urlSearchParams.entries())
|
||||||
|
const foundTab = params["tab"]
|
||||||
|
if (foundTab !== null && foundTab !== undefined) {
|
||||||
|
for (var key in Object.keys(views)) {
|
||||||
|
const value = views[key]
|
||||||
|
console.log(key, value)
|
||||||
|
if (value === foundTab) {
|
||||||
|
setConfig("", key)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (serverside === true) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const boxStyle = {
|
||||||
|
color: "white",
|
||||||
|
flex: "1",
|
||||||
|
marginLeft: 10,
|
||||||
|
marginRight: 10,
|
||||||
|
paddingLeft: 30,
|
||||||
|
paddingRight: 30,
|
||||||
|
paddingBottom: 30,
|
||||||
|
paddingTop: hidemargins === true ? 0 : 30,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
overflowX: "hidden",
|
||||||
|
minHeight: 400,
|
||||||
|
}
|
||||||
|
const NoArguments_NoReturn = () => {
|
||||||
|
|
||||||
|
alert('Function Called...');
|
||||||
|
|
||||||
|
}
|
||||||
|
const SideBar = {
|
||||||
|
minWidth: 250,
|
||||||
|
maxWidth: 300,
|
||||||
|
borderRight: "1px solid rgba(255,255,255,0.3)",
|
||||||
|
left: 0,
|
||||||
|
position: "sticky",
|
||||||
|
minHeight: "90vh",
|
||||||
|
maxHeight: "90vh",
|
||||||
|
overflowX: "hidden",
|
||||||
|
overflowY: "auto",
|
||||||
|
zIndex: 1000,
|
||||||
|
color: "white"
|
||||||
|
};
|
||||||
|
const catItems = (
|
||||||
|
<div style={SideBar}>
|
||||||
|
<List>
|
||||||
|
<ListItem >
|
||||||
|
<ListItemText>
|
||||||
|
<span><Typography variant="primary">Categories</Typography></span>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<span></span>
|
||||||
|
<Divider />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button id="ASSETS" variant="primary" onClick={()=>{setAppCategory("assets")}}>
|
||||||
|
ASSETS
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary" onClick={()=>{setAppCategory("cases")}}>
|
||||||
|
CASES
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary" onClick={()=>{setAppCategory("comms")}}>
|
||||||
|
COMMS
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary" onClick={()=>{setAppCategory("edr av")}}>
|
||||||
|
EDR & AV
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary" onClick={()=>{setAppCategory("iam")}}>
|
||||||
|
IAM
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary" onClick={()=>{setAppCategory("intel")}}>
|
||||||
|
INTEL
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary" onClick={()=>{setAppCategory("network")}}>
|
||||||
|
NETWORK
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText>
|
||||||
|
<Button variant="primary" onClick={()=>{setAppCategory("siem")}}>
|
||||||
|
SIEM
|
||||||
|
</Button>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const views = {
|
||||||
|
0: "apps",
|
||||||
|
1: "workflows",
|
||||||
|
2: "docs",
|
||||||
|
3: "creators",
|
||||||
|
}
|
||||||
|
|
||||||
|
const setConfig = (event, inputValue) => {
|
||||||
|
const newValue = parseInt(inputValue)
|
||||||
|
|
||||||
|
setCurTab(newValue)
|
||||||
|
if (newValue === 0) {
|
||||||
|
document.title = "Shuffle - search - apps";
|
||||||
|
} else if (newValue === 1) {
|
||||||
|
document.title = "Shuffle - search - workflows";
|
||||||
|
} else if (newValue === 2) {
|
||||||
|
document.title = "Shuffle - search - documentation";
|
||||||
|
} else if (newValue === 3) {
|
||||||
|
document.title = "Shuffle - search - creators";
|
||||||
|
} else {
|
||||||
|
document.title = "Shuffle - search";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||||
|
const params = Object.fromEntries(urlSearchParams.entries())
|
||||||
|
const foundQuery = params["q"]
|
||||||
|
var extraQ = ""
|
||||||
|
if (foundQuery !== null && foundQuery !== undefined) {
|
||||||
|
extraQ = "&q="+foundQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((serverside === false || serverside === undefined) && window.location.pathname.includes("/search")) {
|
||||||
|
navigate(`/search?tab=${views[newValue]}`+extraQ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoaded === false) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Random names for type & autoComplete. Didn't research :^)
|
||||||
|
const landingpageDataBrowser =
|
||||||
|
<div style={{paddingBottom: hidemargins === true ? 0 : 100, color: "white", backgroundColor: theme.palette.surfacColor}}>
|
||||||
|
<div style={boxStyle}>
|
||||||
|
<Tabs
|
||||||
|
style={{width: 610, margin: "auto", marginTop: hidemargins === true ? 0 : 25, }}
|
||||||
|
value={curTab}
|
||||||
|
indicatorColor="primary"
|
||||||
|
textColor="secondary"
|
||||||
|
onChange={setConfig}
|
||||||
|
aria-label="disabled tabs example"
|
||||||
|
>
|
||||||
|
<Tab
|
||||||
|
label=<span>
|
||||||
|
<AppsIcon style={iconStyle} /> Apps
|
||||||
|
</span>
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Tabs>
|
||||||
|
{curTab === 0 ?
|
||||||
|
<AppGrid1 maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} searchValue={appCategory} key={appCategory} />
|
||||||
|
:
|
||||||
|
curTab === 1 ?
|
||||||
|
window.location.pathname === "/search" ?
|
||||||
|
<WorkflowGrid maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||||
|
:
|
||||||
|
<WorkflowGrid maxRows={3} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||||
|
:
|
||||||
|
curTab === 2 ?
|
||||||
|
<DocsGrid maxRows={6} parsedXs={12} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||||
|
:
|
||||||
|
curTab === 3 ?
|
||||||
|
<CreatorGrid parsedXs={4} showSuggestion={true} globalUrl={globalUrl} isMobile={isMobile} userdata={userdata} />
|
||||||
|
:
|
||||||
|
null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
//{/*alternativeView={true} />*/}
|
||||||
|
|
||||||
|
const loadedCheck = isLoaded ?
|
||||||
|
<div>
|
||||||
|
<div style={bodyDivStyle}>{landingpageDataBrowser}</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// #1f2023?
|
||||||
|
return(
|
||||||
|
<div style={{backgroundColor: "#1f2023", display: "flex"}}>
|
||||||
|
{catItems}
|
||||||
|
{loadedCheck}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Appdemo;
|
||||||
Reference in New Issue
Block a user