From 7ea11f67d0d0102bbe30bad81b13e2f4d4911d0b Mon Sep 17 00:00:00 2001 From: Monil Prajapati Date: Thu, 9 Nov 2023 00:33:28 +0530 Subject: [PATCH] Sidebar UI changed --- frontend/package.json | 4 +- frontend/src/views/Docs.jsx | 539 ++++++++++++++++++------------------ 2 files changed, 278 insertions(+), 265 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index eb3cfe90..1ab7f422 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -76,10 +76,10 @@ "shellwords": "^0.1.1", "simplebar": "^4.2.3", "styled-components": "^4.4.0", + "webpack": "^5.88.2", "yaml": "^1.7.2", "yamljs": "^0.3.0", - "zone.js": "^0.13.1", - "webpack": "^5.88.2" + "zone.js": "^0.13.1" }, "scripts": { "start": "HTTPS=false&&PORT=3000 GENERATE_SOURCEMAP=false react-scripts --openssl-legacy-provider start", diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx index da00e61d..ba56b835 100755 --- a/frontend/src/views/Docs.jsx +++ b/frontend/src/views/Docs.jsx @@ -6,11 +6,13 @@ import { useParams, useNavigate, Link } from "react-router-dom"; import { isMobile } from "react-device-detect"; import theme from '../theme.jsx'; import remarkGfm from 'remark-gfm' +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { - Grid, - TextField, - IconButton, + Grid, + TextField, + IconButton, Tooltip, Divider, Button, @@ -19,11 +21,14 @@ import { Typography, Paper, List, + Collapse, + ListItemButton, + ListItemText } from "@mui/material"; -import { - Link as LinkIcon, - Edit as EditIcon, +import { + Link as LinkIcon, + Edit as EditIcon, } from "@mui/icons-material"; const Body = { @@ -34,7 +39,7 @@ const Body = { display: "flex", height: "100%", color: "white", - position: "relative", + position: "relative", //textAlign: "center", }; @@ -57,27 +62,28 @@ const innerHrefStyle = { const Docs = (defaultprops) => { const { globalUrl, selectedDoc, serverside, serverMobile } = defaultprops; - let navigate = useNavigate(); + let navigate = useNavigate(); - // Quickfix for react router 5 -> 6 - const params = useParams(); - //var props = JSON.parse(JSON.stringify(defaultprops)) - var props = Object.assign({selected: false}, defaultprops); - props.match = {} - props.match.params = params + // Quickfix for react router 5 -> 6 + const params = useParams(); + //var props = JSON.parse(JSON.stringify(defaultprops)) + var props = Object.assign({ selected: false }, defaultprops); + props.match = {} + props.match.params = params - useEffect(() => { - //if (params["key"] === undefined) { - // navigate("/docs/about") - // return - //} - }, []) - //console.log("PARAMS: ", params) + useEffect(() => { + //if (params["key"] === undefined) { + // navigate("/docs/about") + // return + //} + }, []) + //console.log("PARAMS: ", params) const [mobile, setMobile] = useState(serverMobile === true || isMobile === true ? true : false); const [data, setData] = useState(""); const [firstrequest, setFirstrequest] = useState(true); const [list, setList] = useState([]); + const [isopen, setOpen] = useState(-1); const [, setListLoaded] = useState(false); const [anchorEl, setAnchorEl] = React.useState(null); const [headingSet, setHeadingSet] = React.useState(false); @@ -98,29 +104,34 @@ const Docs = (defaultprops) => { setAnchorEl(null); } + const handleCollapse = (index) => { + setOpen(isopen === index ? -1 : index) + }; + const SidebarPaperStyle = { backgroundColor: theme.palette.surfaceColor, overflowX: "hidden", position: "relative", - padding: 30, + paddingLeft: 15, + paddingRight: 15, paddingTop: 15, marginTop: 15, - minHeight: "80vh", + minHeight: "80vh", //height: "50vh", }; const SideBar = { - minWidth: 250, - maxWidth: 300, - left: 0, - position: "sticky", - top: 50, - minHeight: "90vh", - maxHeight: "90vh", - overflowX: "hidden", - overflowY: "auto", - zIndex: 1000, - //borderRight: "1px solid rgba(255,255,255,0.3)", + minWidth: 300, + width: "20%", + left: 0, + position: "sticky", + top: 50, + minHeight: "90vh", + maxHeight: "90vh", + overflowX: "hidden", + overflowY: "auto", + zIndex: 1000, + //borderRight: "1px solid rgba(255,255,255,0.3)", }; const fetchDocList = () => { @@ -142,7 +153,7 @@ const Docs = (defaultprops) => { } setListLoaded(true); }) - .catch((error) => {}); + .catch((error) => { }); }; const fetchDocs = (docId) => { @@ -157,16 +168,16 @@ const Docs = (defaultprops) => { .then((responseJson) => { if (responseJson.success) { setData(responseJson.reason); - if (docId === undefined) { - document.title = "Shuffle documentation introduction"; - } else { - document.title = "Shuffle " + docId + " documentation"; - } + if (docId === undefined) { + document.title = "Shuffle documentation introduction"; + } else { + document.title = "Shuffle " + docId + " documentation"; + } - if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.includes("404: Not Found")) { - navigate("/docs") - return - } + if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.includes("404: Not Found")) { + navigate("/docs") + return + } if (responseJson.meta !== undefined) { setSelectedMeta(responseJson.meta); @@ -226,7 +237,7 @@ const Docs = (defaultprops) => { setData("# Error\nThis page doesn't exist."); } }) - .catch((error) => {}); + .catch((error) => { }); }; if (firstrequest) { @@ -245,18 +256,18 @@ const Docs = (defaultprops) => { if (!serverside) { fetchDocList(); - //const propkey = props.match.params.key - //if (propkey === undefined) { - // navigate("/docs/about") - // return null - //} - // - if (props.match.params.key === undefined) { + //const propkey = props.match.params.key + //if (propkey === undefined) { + // navigate("/docs/about") + // return null + //} + // + if (props.match.params.key === undefined) { - } else { - console.log("DOCID: ", props.match.params.key) - fetchDocs(props.match.params.key) - } + } else { + console.log("DOCID: ", props.match.params.key) + fetchDocs(props.match.params.key) + } } } } @@ -283,7 +294,7 @@ const Docs = (defaultprops) => { .join(" ") .split("-") .join(" ") - .split("?")[0] + .split("?")[0] //console.log(name) var found = false; @@ -357,15 +368,15 @@ const Docs = (defaultprops) => { color: "rgba(255, 255, 255, 0.65)", overflow: "hidden", paddingBottom: 100, - margin: "auto", - maxWidth: "100%", - minWidth: "100%", - overflow: "hidden", - fontSize: isMobile ? "1.3rem" : "1.0rem", + margin: "auto", + maxWidth: "100%", + minWidth: "100%", + overflow: "hidden", + fontSize: isMobile ? "1.3rem" : "1.0rem", }; function OuterLink(props) { - console.log("Link: ", props.href) + console.log("Link: ", props.href) if (props.href.includes("http") || props.href.includes("mailto")) { return ( { } function CodeHandler(props) { - console.log("PROPS: ", props) + console.log("PROPS: ", props) - const propvalue = props.value !== undefined && props.value !== null ? props.value : props.children !== undefined && props.children !== null && props.children.length > 0 ? props.children[0] : "" + const propvalue = props.value !== undefined && props.value !== null ? props.value : props.children !== undefined && props.children !== null && props.children.length > 0 ? props.children[0] : "" return (
{ }} > {propvalue} + style={{ + // Wrap if larger than X + whiteSpace: "pre-wrap", + overflow: "auto", + }} + >{propvalue}
); } @@ -436,7 +447,7 @@ const Docs = (defaultprops) => { display: "flex", }} > -
+
{mobile ? null : ( { href={selectedMeta.link} style={{ textDecoration: "none", color: "#f85a3e" }} > - @@ -469,15 +480,15 @@ const Docs = (defaultprops) => {
{mobile || - selectedMeta.contributors === undefined || - selectedMeta.contributors === null ? ( + selectedMeta.contributors === undefined || + selectedMeta.contributors === null ? ( "" ) : (
{selectedMeta.contributors.slice(0, 7).map((data, index) => { return ( { //} - const CustomButton = (props) => { - const {title, icon, link} = props + const CustomButton = (props) => { + const { title, icon, link } = props - const [hover, setHover] = useState(false) + const [hover, setHover] = useState(false) - return ( - -
{ - if (link === "" || link === undefined) { - event.preventDefault() - console.log("IN CLICK!") - if (window.drift !== undefined) { - window.drift.api.startInteraction({ interactionId: 340043 }) - } else { - console.log("Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift) - } - } else { - console.log("Link defined: ", link) - } - }} onMouseOver={() => { - setHover(true) - }} - onMouseOut={() => { - setHover(false); - }} - > - {icon} - - {title} - -
-
- ) - } + > +
{ + if (link === "" || link === undefined) { + event.preventDefault() + console.log("IN CLICK!") + if (window.drift !== undefined) { + window.drift.api.startInteraction({ interactionId: 340043 }) + } else { + console.log("Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift) + } + } else { + console.log("Link defined: ", link) + } + }} onMouseOver={() => { + setHover(true) + }} + onMouseOut={() => { + setHover(false); + }} + > + {icon} + + {title} + +
+ + ) + } - const DocumentationButton = (props) => { - const {item, link} = props + const DocumentationButton = (props) => { + const { item, link } = props - const [hover, setHover] = useState(false); + const [hover, setHover] = useState(false); - console.log("Link: ", link) - if (link === undefined || link === null) { - return null - } + console.log("Link: ", link) + if (link === undefined || link === null) { + return null + } - return ( - -
{ - setHover(true) - }} - onMouseOut={() => { - setHover(false); - }} - > - - {item} - -
- - ) - } + return ( + +
{ + setHover(true) + }} + onMouseOut={() => { + setHover(false); + }} + > + + {item} + +
+ + ) + } - const headerStyle = { - marginTop: 25, - } + const headerStyle = { + marginTop: 25, + } - const mainpageInfo = -
- - Documentation - -
- /> - link="https://discord.gg/B2CBzUm" /> -
+ const mainpageInfo = +
+ + Documentation + +
+ /> + link="https://discord.gg/B2CBzUm" /> +
-
- Tutorial - - Dive in. Hands-on is the best approach to see how Shuffle can transform your security operations. Our set of tutorials and videos teach you how to build your skills. Check out the getting started section to give it a go! - +
+ Tutorial + + Dive in. Hands-on is the best approach to see how Shuffle can transform your security operations. Our set of tutorials and videos teach you how to build your skills. Check out the getting started section to give it a go! + - Why Shuffle? - - Security first. We incentivize trying before buying, and give you the full set of tools you need to automate your operations. What's more is we also help you find usecases that fit your unique needs. Accessibility is key, and we intend to help every SOC globally use and share their usecases. - + Why Shuffle? + + Security first. We incentivize trying before buying, and give you the full set of tools you need to automate your operations. What's more is we also help you find usecases that fit your unique needs. Accessibility is key, and we intend to help every SOC globally use and share their usecases. + - Get help - - Our promise is to make it easier and easier to automate your operations. In some cases however, it may be good with a helping hand. That's where Shuffle's consultancy and support services come in handy. We help you build and automate your operational processes to a level you haven't seen before with the help of our usecases. - + Get help + + Our promise is to make it easier and easier to automate your operations. In some cases however, it may be good with a helping hand. That's where Shuffle's consultancy and support services come in handy. We help you build and automate your operational processes to a level you haven't seen before with the help of our usecases. + - APIs - - Learn. We're all about learning, and are continuously creating documentation and video tutorials to better understand how to get started. APIs are an extremely important part of how the internet works today, and our goal is helping every security professional learn about them. - + APIs + + Learn. We're all about learning, and are continuously creating documentation and video tutorials to better understand how to get started. APIs are an extremely important part of how the internet works today, and our goal is helping every security professional learn about them. + - Workflow building - - Build. Creating workflows has never been easier. Jump into things with our getting Started section and build to your hearts content. Workflows make it all come together, with an easy to use area. - + Workflow building + + Build. Creating workflows has never been easier. Jump into things with our getting Started section and build to your hearts content. Workflows make it all come together, with an easy to use area. + - Managing Shuffle - - Organize. Whether an organization of 1000 or 1, management tools are necessary. In Shuffle we offer full user management, MFA and single-signon options, multi-tenancy and a lot more - for free! - -
+ Managing Shuffle + + Organize. Whether an organization of 1000 or 1, management tools are necessary. In Shuffle we offer full user management, MFA and single-signon options, multi-tenancy and a lot more - for free! + +
- {/* + {/* {list.map((data, index) => { const item = data.name; @@ -696,7 +707,7 @@ const Docs = (defaultprops) => { */} - {/* + {/* { }} /> */} -
+
+ // PostDataBrowser Section const postDataBrowser = list === undefined || list === null ? null : (
@@ -741,52 +753,53 @@ const Docs = (defaultprops) => { item.charAt(0).toUpperCase() + item.substring(1).split("_").join(" ").split("-").join(" "); - const itemMatching = props.match.params.key === undefined ? false : + const itemMatching = props.match.params.key === undefined ? false : props.match.params.key.toLowerCase() === item.toLowerCase(); - //const [tocLines, setTocLines] = React.useState([]); return ( -
  • - + { setTocLines([]); fetchDocs(item); + handleCollapse(index); }} > - - > {newname} - - + {newname} + + {isopen === index ? : } + {itemMatching && - tocLines !== null && - tocLines !== undefined && - tocLines.length > 0 ? ( -
    + tocLines !== null && + tocLines !== undefined && + tocLines.length > 0 ? ( + {tocLines.map((data, index) => { - //console.log(data) return ( - {}} > - - - {data.text} - - + {data.text} + + ); })} -
    + ) : null}
  • ); @@ -794,37 +807,37 @@ const Docs = (defaultprops) => {
    -
    - {props.match.params.key === undefined ? - mainpageInfo - : -
    - - {data} - -
    - } -
    +
    + {props.match.params.key === undefined ? + mainpageInfo + : +
    + + {data} + +
    + } +
    ); - // remarkPlugins={[remarkGfm]} + // remarkPlugins={[remarkGfm]} const mobileStyle = { color: "white", @@ -882,32 +895,32 @@ const Docs = (defaultprops) => { })}
    - {props.match.params.key === undefined ? - mainpageInfo - : -
    - - {data} - -
    - } + {props.match.params.key === undefined ? + mainpageInfo + : +
    + + {data} + +
    + } { // // {imageModal} - // Padding and zIndex etc set because of footer in cloud. + // Padding and zIndex etc set because of footer in cloud. const loadedCheck = ( -
    +
    {postDataBrowser} {postDataMobile}