diff --git a/frontend/src/components/AppFramework.jsx b/frontend/src/components/AppFramework.jsx
index 43caf58c..0d475b0d 100644
--- a/frontend/src/components/AppFramework.jsx
+++ b/frontend/src/components/AppFramework.jsx
@@ -545,9 +545,49 @@ const AppFramework = (props) => {
const alert = useAlert()
+ const handleLoadNextSuggestion = (frameworkData) => {
+ console.log("Should check for next apps to load from App suggestion model")
+ //fetch(globalUrl + "/api/v1/workflows/usecases", {
+ //credentials: "include",
+
+ fetch("https://europe-west2-shuffler.cloudfunctions.net/app_recommendations", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ body: JSON.stringify(frameworkData),
+ cors: "no-cors",
+ })
+ .then((response) => {
+ //if (response.status !== 200) {
+ // console.log("Status not 200 for framework!");
+ //}
+
+ return response.json();
+ })
+ .then((responseJson) => {
+ console.log("Response: ", responseJson)
+ //if (responseJson.success === false) {
+ // if (responseJson.reason !== undefined) {
+ // alert.error("Failed updating: " + responseJson.reason)
+ // } else {
+ // alert.error("Failed to update framework for your org.")
+ // }
+ //} else {
+ // alert.info("Updated usecase.")
+ //}
+ })
+ .catch((error) => {
+ //alert.error(error.toString());
+ //setFrameworkLoaded(true)
+ })
+ }
+
const showRecommendations = (changed, frameworkData) => {
console.log("Inside recommendation loader")
setChangedApp(changed)
+ handleLoadNextSuggestion(frameworkData)
// Alternative changed
// This is for secondary values like email = comms
diff --git a/frontend/src/components/OrgHeader.jsx b/frontend/src/components/OrgHeader.jsx
index 881c303b..46b8266c 100644
--- a/frontend/src/components/OrgHeader.jsx
+++ b/frontend/src/components/OrgHeader.jsx
@@ -29,6 +29,7 @@ const OrgHeader = (props) => {
setSelectedOrganization,
globalUrl,
isCloud,
+ adminTab,
} = props;
const theme = useTheme();
@@ -41,103 +42,7 @@ const OrgHeader = (props) => {
const [orgDescription, setOrgDescription] = React.useState(
selectedOrganization.description
);
- const [appDownloadUrl, setAppDownloadUrl] = React.useState(
- selectedOrganization.defaults === undefined
- ? "https://github.com/frikky/shuffle-apps"
- : selectedOrganization.defaults.app_download_repo === undefined ||
- selectedOrganization.defaults.app_download_repo.length === 0
- ? "https://github.com/frikky/shuffle-apps"
- : selectedOrganization.defaults.app_download_repo
- );
- const [appDownloadBranch, setAppDownloadBranch] = React.useState(
- selectedOrganization.defaults === undefined
- ? defaultBranch
- : selectedOrganization.defaults.app_download_branch === undefined ||
- selectedOrganization.defaults.app_download_branch.length === 0
- ? defaultBranch
- : selectedOrganization.defaults.app_download_branch
- );
- const [workflowDownloadUrl, setWorkflowDownloadUrl] = React.useState(
- selectedOrganization.defaults === undefined
- ? "https://github.com/frikky/shuffle-apps"
- : selectedOrganization.defaults.workflow_download_repo === undefined ||
- selectedOrganization.defaults.workflow_download_repo.length === 0
- ? "https://github.com/frikky/shuffle-workflows"
- : selectedOrganization.defaults.workflow_download_repo
- );
- const [workflowDownloadBranch, setWorkflowDownloadBranch] = React.useState(
- selectedOrganization.defaults === undefined
- ? defaultBranch
- : selectedOrganization.defaults.workflow_download_branch === undefined ||
- selectedOrganization.defaults.workflow_download_branch.length === 0
- ? defaultBranch
- : selectedOrganization.defaults.workflow_download_branch
- );
- const [ssoEntrypoint, setSsoEntrypoint] = React.useState(
- selectedOrganization.sso_config === undefined
- ? ""
- : selectedOrganization.sso_config.sso_entrypoint === undefined ||
- selectedOrganization.sso_config.sso_entrypoint.length === 0
- ? ""
- : selectedOrganization.sso_config.sso_entrypoint
- );
- const [ssoCertificate, setSsoCertificate] = React.useState(
- selectedOrganization.sso_config === undefined
- ? ""
- : selectedOrganization.sso_config.sso_certificate === undefined ||
- selectedOrganization.sso_config.sso_certificate.length === 0
- ? ""
- : selectedOrganization.sso_config.sso_certificate
- );
- const [notificationWorkflow, setNotificationWorkflow] = React.useState(
- selectedOrganization.defaults === undefined
- ? ""
- : selectedOrganization.defaults.notification_workflow === undefined ||
- selectedOrganization.defaults.notification_workflow.length === 0
- ? ""
- : selectedOrganization.defaults.notification_workflow
- );
- const [documentationReference, setDocumentationReference] = React.useState(
- selectedOrganization.defaults === undefined
- ? ""
- : selectedOrganization.defaults.documentation_reference === undefined ||
- selectedOrganization.defaults.documentation_reference.length === 0
- ? ""
- : selectedOrganization.defaults.documentation_reference
- );
- const [openidClientId, setOpenidClientId] = React.useState(
- selectedOrganization.sso_config === undefined
- ? ""
- : selectedOrganization.sso_config.client_id === undefined ||
- selectedOrganization.sso_config.client_id.length === 0
- ? ""
- : selectedOrganization.sso_config.client_id
- );
- const [openidClientSecret, setOpenidClientSecret] = React.useState(
- selectedOrganization.sso_config === undefined
- ? ""
- : selectedOrganization.sso_config.client_secret === undefined ||
- selectedOrganization.sso_config.client_secret.length === 0
- ? ""
- : selectedOrganization.sso_config.client_secret
- );
- const [openidAuthorization, setOpenidAuthorization] = React.useState(
- selectedOrganization.sso_config === undefined
- ? ""
- : selectedOrganization.sso_config.openid_authorization === undefined ||
- selectedOrganization.sso_config.openid_authorization.length === 0
- ? ""
- : selectedOrganization.sso_config.openid_authorization
- );
- const [openidToken, setOpenidToken] = React.useState(
- selectedOrganization.sso_config === undefined
- ? ""
- : selectedOrganization.sso_config.openid_token === undefined ||
- selectedOrganization.sso_config.openid_token.length === 0
- ? ""
- : selectedOrganization.sso_config.openid_token
- )
const [file, setFile] = React.useState("");
const [fileBase64, setFileBase64] = React.useState(
@@ -249,20 +154,8 @@ const OrgHeader = (props) => {
selectedOrganization.id,
selectedOrganization.image,
{
- app_download_repo: appDownloadUrl,
- app_download_branch: appDownloadBranch,
- workflow_download_repo: workflowDownloadUrl,
- workflow_download_branch: workflowDownloadBranch,
- notification_workflow: notificationWorkflow,
- documentation_reference: documentationReference,
},
{
- sso_entrypoint: ssoEntrypoint,
- sso_certificate: ssoCertificate,
- client_id: openidClientId,
- client_secret: openidClientSecret,
- openid_authorization: openidAuthorization,
- openid_token: openidToken,
}
)
}
@@ -291,6 +184,7 @@ const OrgHeader = (props) => {
}}
/>
);
+
return (
-
-
{
- setExpanded(!expanded);
- }}
- >
- {expanded ? : }
-
- {expanded ? (
-
-
-
- Notification Workflow ID
- {
- setNotificationWorkflow(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
-
-
- Org Documentation reference
- {
- setDocumentationReference(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
- {isCloud ? null :
-
- OpenID connect
-
-
-
- Client ID
- 0
- }
- id="outlined-with-placeholder"
- margin="normal"
- variant="outlined"
- placeholder="The OpenID client ID from the identity provider"
- value={openidClientId}
- onChange={(e) => {
- setOpenidClientId(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
-
-
- Client Secret (optional)
- 0
- }
- id="outlined-with-placeholder"
- margin="normal"
- variant="outlined"
- placeholder="The OpenID client secret - DONT use this if dealing with implicit auth / PKCE"
- value={openidClientSecret}
- onChange={(e) => {
- setOpenidClientSecret(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
-
-
-
-
- Authorization URL
- {
- setOpenidAuthorization(e.target.value)
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
-
-
- Token URL
- {
- setOpenidToken(e.target.value)
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
-
-
- }
- {/*isCloud ? null : */}
-
- SAML SSO (v1.1)
-
-
-
- SSO Entrypoint (IdP)
- 0
- }
- id="outlined-with-placeholder"
- margin="normal"
- variant="outlined"
- placeholder="The entrypoint URL from your provider"
- value={ssoEntrypoint}
- onChange={(e) => {
- setSsoEntrypoint(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
-
-
- SSO Certificate (X509)
- {
- setSsoCertificate(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
-
- {isCloud ?
-
- IdP URL for Shuffle: https://shuffler.io/api/v1/login_sso
-
- : null}
-
- {isCloud ? null : (
-
-
- App Download URL
- {
- setAppDownloadUrl(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
- )}
- {isCloud ? null : (
-
-
- App Download Branch
- {
- setAppDownloadBranch(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
- )}
- {isCloud ? null : (
-
-
- Workflow Download URL
- {
- setWorkflowDownloadUrl(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
- )}
- {isCloud ? null : (
-
-
- Workflow Download Branch
- {
- setWorkflowDownloadBranch(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
- )}
-
-
- {orgSaveButton}
-
- {/*
-
- {expanded ?
-
- :
-
- }
-
- */}
-
- ) : null}
-
);
};
diff --git a/frontend/src/components/RenderCytoscape.jsx b/frontend/src/components/RenderCytoscape.jsx
new file mode 100644
index 00000000..18c9815c
--- /dev/null
+++ b/frontend/src/components/RenderCytoscape.jsx
@@ -0,0 +1,157 @@
+import React, { useState, useEffect, useLayoutEffect } from "react";
+import * as cytoscape from "cytoscape";
+import CytoscapeComponent from "react-cytoscapejs";
+import cystyle from "../defaultCytoscapeStyle";
+
+const surfaceColor = "#27292D";
+const CytoscapeWrapper = (props) => {
+ const { globalUrl, inworkflow } = props;
+
+ const [elements, setElements] = useState([]);
+ const [workflow, setWorkflow] = useState(inworkflow);
+ const [cy, setCy] = React.useState();
+ const bodyWidth = 200;
+ const bodyHeight = 150;
+
+ const setupGraph = () => {
+ const actions = workflow.actions.map((action) => {
+ const node = {};
+ node.position = action.position;
+ node.data = action;
+
+ node.data._id = action["id"];
+ node.data.type = "ACTION";
+ node.isStartNode = action["id"] === workflow.start;
+
+ var example = "";
+ if (
+ action.example !== undefined &&
+ action.example !== null &&
+ action.example.length > 0
+ ) {
+ example = action.example;
+ }
+
+ node.data.example = example;
+ return node;
+ });
+
+ const triggers = workflow.triggers.map((trigger) => {
+ const node = {};
+ node.position = trigger.position;
+ node.data = trigger;
+
+ node.data._id = trigger["id"];
+ node.data.type = "TRIGGER";
+
+ return node;
+ });
+
+ // FIXME - tmp branch update
+ var insertedNodes = [].concat(actions, triggers);
+ const edges = workflow.branches.map((branch, index) => {
+ //workflow.branches[index].conditions = [{
+
+ const edge = {};
+ var conditions = workflow.branches[index].conditions;
+ if (conditions === undefined || conditions === null) {
+ conditions = [];
+ }
+
+ var label = "";
+ if (conditions.length === 1) {
+ label = conditions.length + " condition";
+ } else if (conditions.length > 1) {
+ label = conditions.length + " conditions";
+ }
+
+ edge.data = {
+ id: branch.id,
+ _id: branch.id,
+ source: branch.source_id,
+ target: branch.destination_id,
+ label: label,
+ conditions: conditions,
+ hasErrors: branch.has_errors,
+ };
+
+ // This is an attempt at prettier edges. The numbers are weird to work with.
+ /*
+ //http://manual.graphspace.org/projects/graphspace-python/en/latest/demos/edge-types.html
+ const sourcenode = actions.find(node => node.data._id === branch.source_id)
+ const destinationnode = actions.find(node => node.data._id === branch.destination_id)
+ if (sourcenode !== undefined && destinationnode !== undefined && branch.source_id !== branch.destination_id) {
+ //node.data._id = action["id"]
+ console.log("SOURCE: ", sourcenode.position)
+ console.log("DESTINATIONNODE: ", destinationnode.position)
+
+ var opposite = true
+ if (sourcenode.position.x > destinationnode.position.x) {
+ opposite = false
+ } else {
+ opposite = true
+ }
+
+ edge.style = {
+ 'control-point-distance': opposite ? ["25%", "-75%"] : ["-10%", "90%"],
+ 'control-point-weight': ['0.3', '0.7'],
+ }
+ }
+ */
+
+ return edge;
+ });
+
+ setWorkflow(workflow);
+
+ // Verifies if a branch is valid and skips others
+ var newedges = [];
+ for (var key in edges) {
+ var item = edges[key];
+
+ const sourcecheck = insertedNodes.find(
+ (data) => data.data.id === item.data.source
+ );
+ const destcheck = insertedNodes.find(
+ (data) => data.data.id === item.data.target
+ );
+ if (sourcecheck === undefined || destcheck === undefined) {
+ continue;
+ }
+
+ newedges.push(item);
+ }
+
+ insertedNodes = insertedNodes.concat(newedges);
+ setElements(insertedNodes);
+ };
+
+ if (elements.length === 0) {
+ setupGraph();
+ }
+
+ return (
+ {
+ // FIXME: There's something specific loading when
+ // you do the first hover of a node. Why is this different?
+ //console.log("CY: ", incy)
+ setCy(incy);
+ }}
+ />
+ );
+};
+
+export default CytoscapeWrapper;
diff --git a/frontend/src/components/Searchfield.jsx b/frontend/src/components/Searchfield.jsx
new file mode 100644
index 00000000..43fa7934
--- /dev/null
+++ b/frontend/src/components/Searchfield.jsx
@@ -0,0 +1,648 @@
+import React, {useState, useEffect, useRef} from 'react';
+
+import { useNavigate, Link, useParams } from "react-router-dom";
+import { useTheme } from '@material-ui/core/styles';
+import SearchIcon from '@material-ui/icons/Search';
+
+import {
+ Chip,
+ IconButton,
+ TextField,
+ InputAdornment,
+ List,
+ Card,
+ ListItem,
+ ListItemAvatar,
+ ListItemText,
+ Avatar,
+ Typography,
+ Tooltip,
+} from '@material-ui/core';
+
+import {
+ AvatarGroup,
+} from "@mui/material"
+
+import {Close as CloseIcon, Folder as FolderIcon, Polymer as PolymerIcon, LibraryBooks as LibraryBooksIcon} from '@material-ui/icons'
+
+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 SearchField = props => {
+ const { serverside, userdata } = props
+
+ const theme = useTheme();
+ let navigate = useNavigate();
+ const borderRadius = 3
+ const node = useRef()
+ const [searchOpen, setSearchOpen] = useState(false)
+ const [oldPath, setOldPath] = useState("")
+
+ 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)
+ }
+
+ //useEffect(() => {
+ // if (searchOpen) {
+ // var tarfield = document.getElementById("shuffle_search_field")
+ // tarfield.focus()
+ // }
+ //}, searchOpen)
+
+ const SearchBox = ({currentRefinement, refine, isSearchStalled, } ) => {
+
+ /*
+ 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');
+ }
+ }}>
+ {
+ 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)
+
+ 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}?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)
+ }}>
+ {
+ setMouseHoverIndex(index)
+ }}>
+
+ {avatar}
+
+
+ {/*
+
+
+
+
+
+ */}
+
+
+ )})
+ }
+
+ {type === "documentation" ?
+
+
+ Search by
+
+
+
+
+
+ : null}
+
+ )
+ }
+
+ const CustomSearchBox = connectSearchBox(SearchBox)
+ const CustomAppHits = connectHits(AppHits)
+ const CustomWorkflowHits = connectHits(WorkflowHits)
+ const CustomDocHits = connectHits(DocHits)
+
+ return (
+
+ {
+ console.log("CLICKED")
+ }}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default SearchField;
diff --git a/frontend/src/components/ShuffleCodeEditor.jsx b/frontend/src/components/ShuffleCodeEditor.jsx
index 5ba568f2..7bd3119a 100644
--- a/frontend/src/components/ShuffleCodeEditor.jsx
+++ b/frontend/src/components/ShuffleCodeEditor.jsx
@@ -641,9 +641,10 @@ const CodeEditor = (props) => {
backgroundColor: theme.palette.surfaceColor,
color: "white",
minWidth: isMobile ? "100%" : 600,
+ maxHeight: isMobile ? "100%" : 800,
padding: isMobile ? "25px 10px 25px 10px" : 25,
border: theme.palette.defaultBorder,
- zIndex: 10012,
+ zIndex: 12501,
},
}}
>
diff --git a/frontend/src/components/UsecaseSearch.jsx b/frontend/src/components/UsecaseSearch.jsx
index d5d3acf2..b71e9257 100644
--- a/frontend/src/components/UsecaseSearch.jsx
+++ b/frontend/src/components/UsecaseSearch.jsx
@@ -1590,7 +1590,7 @@ const UsecaseSearch = (props) => {
style={{ textDecoration: "none", }}
>