diff --git a/frontend/package.json b/frontend/package.json
index eb3cfe90..0cb2e764 100755
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -60,6 +60,7 @@
"react-driftjs": "^1.2.2",
"react-dropzone": "^14.2.3",
"react-ga4": "^2.0.0",
+ "react-hotkeys": "^2.0.0",
"react-instantsearch-dom": "^6.28.0",
"react-json-pretty": "^2.2.0",
"react-json-view": "^1.21.3",
@@ -76,10 +77,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/components/SearchData.jsx b/frontend/src/components/SearchData.jsx
new file mode 100644
index 00000000..cc9c1551
--- /dev/null
+++ b/frontend/src/components/SearchData.jsx
@@ -0,0 +1,800 @@
+import React, { useState, useEffect, useRef } from 'react';
+
+import theme from '../theme.jsx';
+import { useNavigate, Link, useParams } from "react-router-dom";
+
+import {
+ Chip,
+ IconButton,
+ TextField,
+ InputAdornment,
+ List,
+ Card,
+ ListItem,
+ ListItemAvatar,
+ ListItemText,
+ Avatar,
+ Grid,
+ Typography,
+ Tooltip,
+ Divider,
+ Button,
+} from '@mui/material';
+import ArticleIcon from '@mui/icons-material/Article';
+import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
+import ManageSearchIcon from '@mui/icons-material/ManageSearch';
+import {
+ AvatarGroup,
+} from "@mui/material"
+
+import { Search as SearchIcon, Close as CloseIcon, Folder as FolderIcon, Code as CodeIcon, LibraryBooks as LibraryBooksIcon } from '@mui/icons-material'
+
+import algoliasearch from 'algoliasearch/lite';
+import aa from 'search-insights'
+import { InstantSearch, Configure, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom';
+//import { InstantSearch, SearchBox, Hits, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom';
+
+// https://www.algolia.com/doc/api-reference/widgets/search-box/react/
+const chipStyle = {
+ backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
+}
+
+const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
+const SearchData = props => {
+ const { serverside, userdata, setModalOpen, modalOpen } = props
+
+ let navigate = useNavigate();
+ const borderRadius = 3
+ const node = useRef()
+ const [searchOpen, setSearchOpen] = useState(true)
+ const [value, setValue] = useState("");
+ const [userTyped, setUserTyped] = useState(false)
+
+ if (serverside === true) {
+ return null
+ }
+
+ //if (window !== undefined && window.location !== undefined && window.location.pathname === "/search") {
+ // return null
+ //}
+
+ const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
+
+ //if (window.location.pathname !== oldPath) {
+ // setSearchOpen(false)
+ // setOldPath(window.location.pathname)
+ //}
+
+ //if (window.location.pathname === "/search") {
+ // setModalOpen(true)
+ //}
+ // if (window.location.pathname === "/docs" || window.location.pathname === "/apps" || window.location.pathname === "/usecases" ) {
+ // setModalOpen(false)
+ // }
+
+ //useEffect(() => {
+ // if (searchOpen) {
+ // var tarfield = document.getElementById("shuffle_search_field")
+ // tarfield.focus()
+ // }
+ //}, searchOpen)
+
+ const SearchBox = ({ currentRefinement, refine, isSearchStalled, }) => {
+ const keyPressHandler = (e) => {
+ // e.preventDefault();
+ if (e.which === 13) {
+ // alert("You pressed enter!");
+ navigate("/search?q=" + currentRefinement, { state: value, replace: true });
+ setSearchOpen(false)
+ setModalOpen(false)
+ return
+ }
+ };
+ /*
+ endAdornment: (
+ {
+ event.preventDefault()
+ }}>
+ {
+ setSearchOpen(false)
+ }} />
+
+ ),
+ */
+
+ return (
+
+ )
+ }
+
+ const WorkflowHits = ({ hits }) => {
+ const [mouseHoverIndex, setMouseHoverIndex] = useState(0)
+
+ var tmp = searchOpen
+ if (!searchOpen) {
+ return null
+ }
+
+
+ const positionInfo = document.activeElement.getBoundingClientRect()
+ const outerlistitemStyle = {
+ width: "100%",
+ overflowX: "hidden",
+ overflowY: "hidden",
+ borderBottom: "1px solid rgba(255,255,255,0.4)",
+ }
+
+ if (hits.length > 4) {
+ hits = hits.slice(0, 4)
+ }
+
+ var type = "workflows"
+ const baseImage =
+
+ return (
+
+
+ Workflows
+
+
+
+ {hits.length === 0 ?
+
+ console.log(hits)}>
+
+
+
+
+
+
+ :
+ hits.map((hit, index) => {
+ const innerlistitemStyle = {
+ width: positionInfo.width + 35,
+ overflowX: "hidden",
+ overflowY: "hidden",
+ borderBottom: "1px solid rgba(255,255,255,0.4)",
+ backgroundColor: mouseHoverIndex === index ? "#1f2023" : "inherit",
+ cursor: "pointer",
+ marginLeft: 5,
+ marginRight: 5,
+ maxHeight: 75,
+ minHeight: 75,
+ maxWidth: 420,
+ minWidth: "100%",
+ }
+
+ const name = hit.name === undefined ?
+ hit.filename.charAt(0).toUpperCase() + hit.filename.slice(1).replaceAll("_", " ") + " - " + hit.title :
+ (hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
+ const secondaryText = hit.description !== undefined && hit.description !== null && hit.description.length > 3 ? hit.description.slice(0, 40) + "..." : ""
+ const appGroup = hit.action_references === undefined || hit.action_references === null ? [] : hit.action_references
+ const avatar = baseImage
+
+ var parsedUrl = isCloud ? `/workflows/${hit.objectID}` : `https://shuffler.io/workflows/${hit.objectID}`
+
+ parsedUrl += `?queryID=${hit.__queryID}`
+
+ //
+ return (
+ {
+ //console.log("CLICK")
+ setSearchOpen(true)
+
+ aa('init', {
+ appId: searchClient.appId,
+ apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
+ })
+
+ const timestamp = new Date().getTime()
+ aa('sendEvents', [
+ {
+ eventType: 'click',
+ eventName: 'Workflow Clicked',
+ index: 'workflows',
+ objectIDs: [hit.objectID],
+ timestamp: timestamp,
+ queryID: hit.__queryID,
+ positions: [hit.__position],
+ userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
+ }
+ ])
+
+ if (!isCloud) {
+ event.preventDefault()
+ window.open(parsedUrl, '_blank');
+ }
+ setModalOpen(false)
+ }}>
+ {
+ setMouseHoverIndex(index)
+ }}>
+
+ {avatar}
+
+
+
+
+ {appGroup.map((app, index) => {
+ // Putting all this in secondary of ListItemText looked weird.
+ return (
+ {
+ navigate("/apps/" + app.id)
+ }}
+ >
+
+
+
+
+ )
+ })}
+
+
+ {/*
+
+
+
+
+
+ */}
+
+
+ )
+ })
+ }
+
+ {/*
+
+
+
+ See all workflows
+
+
+
+ */}
+
+ )
+ }
+
+ const AppHits = ({ hits }) => {
+ const [mouseHoverIndex, setMouseHoverIndex] = useState(0)
+
+ var tmp = searchOpen
+ if (!searchOpen) {
+ return null
+ }
+
+ const positionInfo = document.activeElement.getBoundingClientRect()
+ const outerlistitemStyle = {
+ width: "100%",
+ overflowX: "hidden",
+ overflowY: "hidden",
+ borderBottom: "1px solid rgba(255,255,255,0.4)",
+ }
+
+ if (hits.length > 4) {
+ hits = hits.slice(0, 4)
+ }
+
+ var type = "app"
+ const baseImage =
+
+ return (
+
+ {/* {
+ setSearchOpen(false)
+ }}>
+
+ */}
+
+ Apps
+
+
+
+ {hits.length === 0 ?
+
+ console.log(hits)}>
+
+
+
+
+
+
+ :
+ hits.map((hit, index) => {
+ const innerlistitemStyle = {
+ width: positionInfo.width + 35,
+ overflowX: "hidden",
+ overflowY: "hidden",
+ borderBottom: "1px solid rgba(255,255,255,0.4)",
+ backgroundColor: mouseHoverIndex === index ? "#1f2023" : "inherit",
+ cursor: "pointer",
+ marginLeft: 5,
+ marginRight: 5,
+ maxHeight: 75,
+ minHeight: 75,
+ maxWidth: 420,
+ minWidth: "100%",
+ }
+
+ const name = hit.name === undefined ?
+ hit.filename.charAt(0).toUpperCase() + hit.filename.slice(1).replaceAll("_", " ") + " - " + hit.title :
+ (hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
+
+ var secondaryText = hit.data !== undefined ? hit.data.slice(0, 40) + "..." : ""
+ const avatar = hit.image_url === undefined ?
+ baseImage
+ :
+
+
+ //console.log(hit)
+ if (hit.categories !== undefined && hit.categories !== null && hit.categories.length > 0) {
+ secondaryText = hit.categories.slice(0, 3).map((data, index) => {
+ if (index === 0) {
+ return data
+ }
+
+ return ", " + data
+
+ /*
+ {
+ //handleChipClick
+ }}
+ variant="outlined"
+ color="primary"
+ />
+ */
+ })
+ }
+
+ var parsedUrl = isCloud ? `/apps/${hit.objectID}` : `https://shuffler.io/apps/${hit.objectID}`
+ parsedUrl += `?queryID=${hit.__queryID}`
+
+ return (
+ {
+ console.log("CLICK")
+ setSearchOpen(true)
+ setModalOpen(false)
+
+ aa('init', {
+ appId: searchClient.appId,
+ apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
+ })
+
+ const timestamp = new Date().getTime()
+ aa('sendEvents', [
+ {
+ eventType: 'click',
+ eventName: 'App Clicked',
+ index: 'appsearch',
+ objectIDs: [hit.objectID],
+ timestamp: timestamp,
+ queryID: hit.__queryID,
+ positions: [hit.__position],
+ userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
+ }
+ ])
+
+ if (!isCloud) {
+ event.preventDefault()
+ window.open(parsedUrl, '_blank');
+ }
+ }}>
+ {
+ setMouseHoverIndex(index)
+ }}>
+
+ {avatar}
+
+
+ {/*
+
+
+
+
+
+ */}
+
+
+ )
+ })
+ }
+
+ {/*
+
+
+ See more
+
+
+ */}
+
+ )
+ }
+
+ const DocHits = ({ hits }) => {
+ const [mouseHoverIndex, setMouseHoverIndex] = useState(0)
+
+ var tmp = searchOpen
+ if (!searchOpen) {
+ return null
+ }
+
+
+ const positionInfo = document.activeElement.getBoundingClientRect()
+ const outerlistitemStyle = {
+ width: "100%",
+ overflowX: "hidden",
+ overflowY: "hidden",
+ borderBottom: "1px solid rgba(255,255,255,0.4)",
+ }
+
+ if (hits.length > 4) {
+ hits = hits.slice(0, 4)
+ }
+
+ const type = "documentation"
+ const baseImage =
+
+ //console.log(type, hits.length, hits)
+
+ return (
+
+ {/* {
+ setSearchOpen(false)
+ }}>
+
+ */}
+
+ Documentation
+
+ {/*
+ {
+ setSearchOpen(false)
+ }}>
+
+
+ */}
+
+ {hits.length === 0 ?
+
+ console.log(hits)}>
+
+
+
+
+
+
+ :
+ hits.map((hit, index) => {
+ const innerlistitemStyle = {
+ width: positionInfo.width + 35,
+ overflowX: "hidden",
+ overflowY: "hidden",
+ borderBottom: "1px solid rgba(255,255,255,0.4)",
+ backgroundColor: mouseHoverIndex === index ? "#1f2023" : "inherit",
+ cursor: "pointer",
+ marginLeft: 5,
+ marginRight: 5,
+ maxHeight: 75,
+ minHeight: 75,
+ maxWidth: 420,
+ minWidth: "100%",
+ }
+
+ var name = hit.name === undefined ?
+ hit.filename.charAt(0).toUpperCase() + hit.filename.slice(1).replaceAll("_", " ") + " - " + hit.title
+ :
+ (hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
+
+ if (name.length > 30) {
+ name = name.slice(0, 30) + "..."
+ }
+ const secondaryText = hit.data !== undefined ? hit.data.slice(0, 40) + "..." : ""
+ const avatar = hit.image_url === undefined ?
+ baseImage
+ :
+
+
+ var parsedUrl = hit.urlpath !== undefined ? hit.urlpath : ""
+ parsedUrl += `?queryID=${hit.__queryID}`
+ if (parsedUrl.includes("/apps/")) {
+ const extraHash = hit.url_hash === undefined ? "" : `#${hit.url_hash}`
+
+ parsedUrl = `/apps/${hit.filename}`
+ parsedUrl += `?tab=docs&queryID=${hit.__queryID}${extraHash}`
+ }
+
+ return (
+ {
+ aa('init', {
+ appId: searchClient.appId,
+ apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
+ })
+
+ const timestamp = new Date().getTime()
+ aa('sendEvents', [
+ {
+ eventType: 'click',
+ eventName: 'Document Clicked',
+ index: 'documentation',
+ objectIDs: [hit.objectID],
+ timestamp: timestamp,
+ queryID: hit.__queryID,
+ positions: [hit.__position],
+ userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
+ }
+ ])
+
+ console.log("CLICK")
+ setSearchOpen(true)
+ setModalOpen(false)
+ }}>
+ {
+ setMouseHoverIndex(index)
+ }}>
+
+ {avatar}
+
+
+ {/*
+
+
+
+
+
+ */}
+
+
+ )
+ })
+ }
+
+
+ )
+ }
+
+ const CustomSearchBox = connectSearchBox(SearchBox)
+ const CustomAppHits = connectHits(AppHits)
+ const CustomWorkflowHits = connectHits(WorkflowHits)
+ const CustomDocHits = connectHits(DocHits)
+
+ const modalView = (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+ const gettingStartData = (
+
+
+
+
+
+ Getting Started
+
+
+
+ { window.location = "/docs"; }} style={{ textDecoration: "none", color: "var(--Paragraph-text, #C8C8C8)", display: "flex" }}>
+ Documentation
+
+
+
+
+
+
+ Onprem Installation
+
+
+
+
+
+
+
+ Explore Usecases
+
+
+
+
+
+ Find public workflows
+
+
+
+
+
+
+
+
+
+
+ Popular searches
+
+
+
+
+ Create Apps
+
+
+
+
+
+ Find Apps
+
+
+
+
+
+ Workflows
+
+
+
+
+
+ Creator
+
+
+
+
+
+
+ {/*
+
+
+
+ Popular searches
+
+
+
+
+ Apps
+
+
+
+ Workflows
+
+
+
+ Creator
+
+
+
+
+ */}
+
+
+
+
+ )
+
+ return (
+
+ {
+ console.log("CLICKED 1")
+ }}>
+
+ {
+ console.log("Click 2")
+ }}/>
+ {modalView}
+
+ {gettingStartData}
+
+ )
+}
+
+export default SearchData;