import React, { memo, useContext, useEffect, useState } from 'react'; import { Edit as EditIcon, SelectAll as SelectAllIcon, Delete as DeleteIcon, CheckCircle as CheckCircleIcon, Cancel as CancelIcon, Search as SearchIcon, Clear as ClearIcon, DragIndicator as DragIndicatorIcon, Close as CloseIcon, LockOpen as LockOpenIcon, } from "@mui/icons-material"; import { useNavigate } from "react-router-dom"; import { toast } from "react-toastify"; import theme from "../theme.jsx"; import Markdown from "react-markdown"; import AuthenticationOauth2 from "../components/Oauth2Auth.jsx"; import { isMobile } from "react-device-detect" import PaperComponent from "../components/PaperComponent.jsx"; import { CodeHandler, Img, OuterLink, } from '../views/Docs.jsx' import { v4 as uuidv4} from "uuid"; import { Divider, List, ListItem, ListItemText, IconButton, Tooltip, Chip, Checkbox, Typography, TextField, Button, Dialog, DialogTitle, DialogActions, DialogContent, Select, FormControl, InputLabel, MenuItem, FormControlLabel, InputAdornment, Grid, Zoom, Paper, Skeleton, Link, } from "@mui/material"; import algoliasearch from "algoliasearch/lite"; import { InstantSearch, Configure, connectSearchBox, connectHits, connectHitInsights, RefinementList, ClearRefinements, connectStateResults } from "react-instantsearch-dom"; import aa from "search-insights"; import { Context } from '../context/ContextApi.jsx'; const searchClient = algoliasearch( "JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240" ) const AppAuthTab = memo((props) => { const { globalUrl, userdata, isCloud, selectedOrganization } = props; const [selectedAuthentication, setSelectedAuthentication] = React.useState({}); const [authentication, setAuthentication] = React.useState([]); const [selectedUserModalOpen, setSelectedUserModalOpen] = React.useState(false); const [authenticationFields, setAuthenticationFields] = React.useState([]); const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] = React.useState(false); const [appAuthenticationGroupEnvironment, setAppAuthenticationGroupEnvironment] = React.useState(""); const [environments, setEnvironments] = React.useState([]); const [listItemExpanded, setListItemExpanded] = React.useState(-1); const [appAuthenticationGroupModalOpen, setAppAuthenticationGroupModalOpen] = React.useState(false); const [appAuthenticationGroupId, setAppAuthenticationGroupId] = React.useState(""); const [appAuthenticationGroups, setAppAuthenticationGroups] = React.useState([]); const [appAuthenticationGroupName, setAppAuthenticationGroupName] = React.useState(""); const [appAuthenticationGroupDescription, setAppAuthenticationGroupDescription] = React.useState(""); const [appsForAppAuthGroup, setAppsForAppAuthGroup] = React.useState([]); const [searchQuery, setSearchQuery] = React.useState(""); const [showAppModal, setShowAppModal] = useState(false) const [showAuthenticationLoader, setShowAuthenticationLoader] = useState(true) const [showAppAuthGroupLoader, setShowAppAuthGroupLoader] = useState(true) const changeDistribution = (data) => { //changeDistributed(data, !isDistributed) editAuthenticationConfig(data.id, "suborg_distribute") } useEffect(() => { getAppAuthentication(); getAppAuthenticationGroups(); getEnvironments(); }, []) const getAppAuthentication = () => { fetch(globalUrl + "/api/v1/apps/authentication", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for apps :O!"); return; } return response.json(); }) .then((responseJson) => { if (responseJson.success === true) { setAuthentication(responseJson.data); setShowAuthenticationLoader(false) } else { toast("Failed getting authentications"); } }) .catch((error) => { toast(error.toString()); }); }; const updateAppAuthentication = (field) => { setSelectedAuthenticationModalOpen(true); setSelectedAuthentication(field); //{selectedAuthentication.fields.map((data, index) => { var newfields = []; for (var key in field.fields) { newfields.push({ key: field.fields[key].key, value: "", }); } setAuthenticationFields(newfields); }; const saveAuthentication = (authentication) => { const data = authentication; const url = globalUrl + "/api/v1/apps/authentication"; fetch(url, { mode: "cors", method: "PUT", body: JSON.stringify(data), credentials: "include", crossDomain: true, withCredentials: true, headers: { "Content-Type": "application/json; charset=utf-8", }, }) .then((response) => response.json().then((responseJson) => { if (responseJson["success"] === false) { // Check if .reason exists if (responseJson.reason !== undefined) { toast("Failed changing authentication: " + responseJson.reason); } else { toast("Failed changing authentication"); } } else { getAppAuthentication(); setSelectedAuthentication({}); setSelectedAuthenticationModalOpen(false); } }) ) .catch((error) => { toast("Err: " + error.toString()); }); }; const deleteAuthentication = (data) => { toast("Deleting auth " + data.label); // Just use this one? const url = globalUrl + "/api/v1/apps/authentication/" + data.id; console.log("URL: ", url); fetch(url, { method: "DELETE", credentials: "include", headers: { "Content-Type": "application/json", }, }) .then((response) => response.json().then((responseJson) => { if (responseJson.success === false) { toast("Failed deleting auth"); } else { // Need to wait because query in ES is too fast setTimeout(() => { getAppAuthentication(); }, 1000); //toast("Successfully deleted authentication!") } }) ) .catch((error) => { console.log("Error in userdata: ", error); }); }; const editAuthenticationConfig = (id, parentAction) => { const data = { id: id, action: parentAction !== undefined && parentAction !== null ? parentAction : "assign_everywhere", } const url = globalUrl + "/api/v1/apps/authentication/" + id + "/config"; fetch(url, { mode: "cors", method: "POST", body: JSON.stringify(data), credentials: "include", crossDomain: true, withCredentials: true, headers: { "Content-Type": "application/json; charset=utf-8", }, }) .then((response) => response.json().then((responseJson) => { if (responseJson["success"] === false) { toast("Failed overwriting appauth"); } else { toast("Successfully updated auth!"); setSelectedUserModalOpen(false); setTimeout(() => { getAppAuthentication(); }, 1000); } }) ) .catch((error) => { toast("Err: " + error.toString()); }); }; const editAuthenticationModal = selectedAuthenticationModalOpen ? ( { setSelectedAuthenticationModalOpen(false); }} PaperProps={{ sx: { borderRadius: theme?.palette?.DialogStyle?.borderRadius, border: theme?.palette?.DialogStyle?.border, minWidth: "800px", minHeight: "320px", fontFamily: theme?.typography?.fontFamily, backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, zIndex: 1000, '& .MuiDialogContent-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogTitle-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogActions-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, }, }} > Edit authentication for {selectedAuthentication.app.name.replaceAll("_", " ")} ( {selectedAuthentication.label}) You can not see the previous values for an authentication while editing. This is to keep your data secure. You can overwrite one- or multiple fields at a time. Authentication Label { selectedAuthentication.label = e.target.value }} /> {selectedAuthentication.type === "oauth" || selectedAuthentication.type === "oauth2" || selectedAuthentication.type === "oauth2-app" ?
Only the name and url can be modified for Oauth2/OpenID connect. Please remake the authentication if you want to change the other fields like Client ID, Secret, Scopes etc.
: null} {selectedAuthentication.fields.map((data, index) => { var fieldname = data.key.replaceAll("_", " ") if (fieldname.endsWith(" basic")) { fieldname = fieldname.substring(0, fieldname.length - 6) } if (selectedAuthentication.type === "oauth" || selectedAuthentication.type === "oauth2" || selectedAuthentication.type === "oauth2-app") { if (selectedAuthentication.fields[index].key !== "url") { return null } } //console.log("DATA: ", data, selectedAuthentication) return (
{fieldname} { authenticationFields[index].value = e.target.value; setAuthenticationFields(authenticationFields); }} />
); })}
) : null; const getEnvironments = () => { fetch(globalUrl + "/api/v1/getenvironments", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for apps :O!"); return; } return response.json(); }) .then((responseJson) => { setEnvironments(responseJson); // Helper info for users in case they have a large queue and don't know about queue flushing if (responseJson !== undefined && responseJson !== null && responseJson.length > 0) { if (responseJson.length === 1 && responseJson[0].Type !== "cloud") { setListItemExpanded(0) } for (var i = 0; i < responseJson.length; i++) { const env = responseJson[i]; // Check if queuesize is too large if ( env.queue !== undefined && env.queue !== null && env.queue > 100 ) { toast( "Queue size for " + env.name + " is very large. We recommend you to reduce it by flushing the queue before continuing.", ); break; } } } }) .catch((error) => { toast(error.toString()); }); }; const getAppAuthenticationGroups = () => { //console.log("DEBUG: Skipping app auth group loading") //return fetch(globalUrl + "/api/v1/authentication/group", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for apps :O!"); return; } return response.json(); }) .then((responseJson) => { if (responseJson.success === true) { setAppAuthenticationGroups(responseJson.data); setShowAppAuthGroupLoader(false) } }) .catch((error) => { toast(error.toString()); }); }; const deleteAppAuthenticationGroup = (appAuthGroupId) => { const url = `${globalUrl}/api/v1/authentication/group/${appAuthGroupId}` fetch(url, { method: "DELETE", credentials: "include", headers: { "Content-Type": "application/json", }, }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for deleting app auth group"); } return response.json(); }) .then((responseJson) => { if (responseJson.success === false) { toast("Failed to delete app authentication group"); } else { toast("App authentication group deleted") getAppAuthenticationGroups() } }) .catch((error) => { toast(error.toString()) }) } const createAppAuthenticationGroup = (name, environment, description, appAuthIds) => { // Makes list of ids into a full-on list of auth, but just with the ID // The backend fills in the rest console.log("INput auth: ", appAuthIds) let app_auths = appAuthIds.map((appAuthId) => { return { id: appAuthId }; }) var parsedAppGroup = { label: name, environment: environment, description: description, app_auths: app_auths } if (appAuthenticationGroupId !== undefined && appAuthenticationGroupId !== null && appAuthenticationGroupId !== "") { parsedAppGroup.id = appAuthenticationGroupId } fetch(globalUrl + "/api/v1/authentication/group", { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", body: JSON.stringify(parsedAppGroup), }) .then((response) => { if (response.status !== 200) { throw new Error("Failed to create app authentication group"); } return response.json(); }) .then((responseJson) => { if (responseJson.success === false) { toast("Failed to create. Please try again, or contact support@shuffler.io") } else { // Close the modal setAppAuthenticationGroupModalOpen(false) toast("App authentication group created") getAppAuthenticationGroups() } }) .catch((error) => { toast(error.toString()); }); }; const handleAppAuthGroupCheckbox = (data) => { //let groupApp = data.app.id var newappauth = appsForAppAuthGroup if (appsForAppAuthGroup.includes(data.app.id)) { newappauth = newappauth.filter((item) => item !== data.app.id) } if (appsForAppAuthGroup.includes(data.id)) { // Remove app from app auth group newappauth = newappauth.filter((item) => item !== data.id) setAppsForAppAuthGroup(newappauth) return } for (var i = 0; i < authentication.length; i++) { if (authentication[i].id === data.id) { continue } if (!appsForAppAuthGroup.includes(authentication[i].id)) { continue } if (authentication[i].app.id === data.app.id) { // Remove app from app auth group newappauth = newappauth.filter((item) => item !== authentication[i].id) toast(`App ${data.app.name} is already in this group`) } } setAppsForAppAuthGroup(newappauth.concat(data.id)) } const authenticationView = appAuthenticationGroupModalOpen ? (
{/* (appAuthenticationGroupModalOpen : { */} {appAuthenticationGroupModalOpen && ( { setAppAuthenticationGroupModalOpen(false); setAppAuthenticationGroupId("") setAppAuthenticationGroupName("") setAppAuthenticationGroupEnvironment("") setAppAuthenticationGroupDescription("") setAppsForAppAuthGroup([]) }} PaperProps={{ sx: { borderRadius: theme?.palette?.DialogStyle?.borderRadius, border: theme?.palette?.DialogStyle?.border, minWidth: "1000px", padding: "25px", paddingLeft: "50px", minHeight: "320px", fontFamily: theme?.typography?.fontFamily, backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, zIndex: 1000, '& .MuiDialogContent-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogTitle-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogActions-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, }, }} sx={{ "& .MuiDialog-paper": { backgroundColor: "rgb(26, 26, 26)", }, }} > App Authentication Groups
Name { setAppAuthenticationGroupName(event.target.value); }} />
Evironment {environments !== undefined && environments !== null && environments.length > 0 ? : Locations failed to load. Please try again }
{/* Show a check box list of all app authentications to add to the auth group */}
{authentication.map((data, index) => { var checked = data.checked if (data.label !== undefined && data.label !== null && data.label.toLowerCase() === "kms shuffle storage") { return null } if (checked === undefined || checked === null) { checked = false } if (appsForAppAuthGroup.includes(data.id)) { checked = true } return (
{ handleAppAuthGroupCheckbox(data) }} name={data.label} disabled={data.app.id in appsForAppAuthGroup} />
} label={data.label} />
) })}
)}
): null const appModal = showAppModal ? ( { setShowAppModal(false); }} PaperProps={{ sx: { borderRadius: theme?.palette?.DialogStyle?.borderRadius, border: theme?.palette?.DialogStyle?.border, width: '700px', maxWidth: '700px', overflowY: 'hidden', height: "600px", maxHeight: "600px", fontFamily: theme?.typography?.fontFamily, zIndex: 1000, '& .MuiDialogContent-root': { padding: '30px', backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogTitle-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogActions-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, }, }} >
Add App Authentication
) : null; return (
{appModal}

App Authentication

Control the authentication options for individual apps.   Learn more about App Authentication
{isCloud ? : null}
{/* */}
{["Valid", "Label", "App Name", "Workflows", "Fields", "Edited", "Actions", "Distribution"].map((header, index) => ( ))} {showAuthenticationLoader ? [...Array(6)].map((_, rowIndex) => ( {Array(8) .fill() .map((_, colIndex) => ( ))} )) : authentication?.length === 0 ? (
No authentication found.
):authentication.map((data, index) => { var bgColor = "#212121"; if (index % 2 === 0) { bgColor = "#1A1A1A"; } //console.log("Auth data: ", data) if (data.type === "oauth2") { data.fields = [ { key: "url", value: "Secret. Replaced during app execution!", }, { key: "client_id", value: "Secret. Replaced during app execution!", }, { key: "client_secret", value: "Secret. Replaced during app execution!", }, { key: "scope", value: "Secret. Replaced during app execution!", }, ]; } const isDistributed = data.suborg_distributed === true ? true : false; var validIcon = if (data.validation !== null && data.validation !== undefined && data.validation.valid === false) { if (data.validation.changed_at === 0) { validIcon = "" } else { validIcon = } } return ( {validIcon} )} style={{ display: "table-cell", verticalAlign: 'middle', minWidth: 60 }} primaryTypographyProps={{ style: { padding: "8px 8px 8px 15px", } }} onClick={() => { if (data.validation === null || data.validation === undefined) { return } if (data.validation.workflow_id === undefined || data.validation.workflow_id === null || data.validation.workflow_id.length === 0) { toast.warn("No workflow runs found for this auth yet. Check back later.") return } const url = `/workflows/${data.validation.workflow_id}?execution_id=${data.validation.execution_id}&node=${data.validation.node_id}` window.open(url, "_blank") }} /> {data?.app?.name?.replaceAll("_", " ")} } primaryTypographyProps={{ style: { padding: 8 } }} style={{ marginLeft: 10, display: "table-cell", textAlign: 'center', verticalAlign: 'middle', padding: 8 }} /> { return data.key; }) .join(", ") } primaryTypographyProps={{ style: { padding: 8 } }} style={{ overflow: "auto", display: "table-cell", verticalAlign: 'middle' }} /> { updateAppAuthentication(data); }} disabled={data.org_id !== selectedOrganization.id} > Edit icon {data.defined ? ( { editAuthenticationConfig(data.id); }} > ) : ( {}} disabled={data.org_id !== selectedOrganization.id} > )} { deleteAuthentication(data); }} > delete icon {selectedOrganization.id !== undefined && data.org_id !== selectedOrganization.id ? : { changeDistribution(data, !isDistributed) }} /> } ); })}
{editAuthenticationModal} {authenticationView}
{/*

App Authentication Groups

Disabled until further notice. Makes a workflow run replicate across all relevant authentications in an app auth group. Useful when the EXACT same workflow is supposed to run many times from one single input. {" "} Learn more about App Authentication Groups
{["Label", "Environment", "App Auth", "Created At", "Actions"].map((header, index) => ( ))} {showAppAuthGroupLoader ? [...Array(6)].map((_, rowIndex) => ( {Array(5) .fill() .map((_, colIndex) => ( ))} )) : appAuthenticationGroups.length === 0 ? (
No authentication groups found.
): appAuthenticationGroups.map((data, index) => { var bgColor = "#212121"; if (index % 2 === 0) { bgColor = "#1A1A1A"; } if (data.app_auths === undefined || data.app_auths === null) { data.app_auths = [] } return ( {data.app_auths.map((appAuth, index) => { if (appAuth.app.large_image === undefined || appAuth.app.large_image === null || appAuth.app.large_image === "") { const foundImage = authentication.find((auth) => auth.app.id === appAuth.app.id) if (foundImage !== undefined) { appAuth.app.large_image = foundImage.app.large_image appAuth.app.name = foundImage.app.name } } const tooltip = `${appAuth.app.name.replaceAll("_", " ")} (authname: ${appAuth.label})` return ( {appAuth.app.name} ) })}
} style={{ display:'table-cell', verticalAlign: 'middle' }} /> { setAppAuthenticationGroupId(data.id) setAppAuthenticationGroupName(data.label) setAppAuthenticationGroupDescription(data.description) setAppsForAppAuthGroup(data.app_auths.map((appAuth) => appAuth.id)) setAppAuthenticationGroupEnvironment(data.environment) setAppAuthenticationGroupModalOpen(true) }} > edit icon { deleteAppAuthenticationGroup(data.id) }} > delete icon
} style={{ display:'table-cell', verticalAlign: 'middle' }} /> ); } )}
*/}
); }); export default AppAuthTab; const SearchBox = ({ currentRefinement, refine, isSearchStalled, searchQuery, setSearchQuery }) => { const handleSearch = (e) => { refine(searchQuery.trim()); }; return (
), endAdornment: ( {searchQuery?.length > 0 && ( { setSearchQuery('') // removeQuery("q"); refine('') }} /> )} ), }} autoComplete="off" color="primary" placeholder="Search more than 2500 Apps" id="shuffle_search_field" onChange={(event) => { setSearchQuery(event.currentTarget.value); // removeQuery("q"); refine(event.currentTarget.value); }} onKeyDown={(event) => { if(event.key === "Enter") { event.preventDefault(); } }} limit={5} /> {/*isSearchStalled ? 'My search is stalled' : ''*/} ); }; const Hits = ({ hits, insights, setIsAnyAppActivated, searchQuery, isCloud, globalUrl, userdata, getAppAuthentication }) => { const [mouseHoverIndex, setMouseHoverIndex] = useState(-1); const [selectedAppData, setSelectedAppData] = useState({}) const [appid, setAppId] = useState("") const [selectedAuthentication, setSelectedAuthentication] = useState({}) const [authenticationModalOpen, setAuthenticationModalOpen] = useState(false) const [authenticationType, setAuthenticationType] = React.useState(""); const [appAuthentication, setAppAuthentication] = useState([]); const [selectedMeta, setSelectedMeta] = useState(undefined); const [selectedAction, setSelectedAction] = useState( { "app_name": selectedAppData.name, "app_id": selectedAppData.id, "app_version": selectedAppData.version, "large_image": selectedAppData.large_image, } ) const navigate = useNavigate(); const normalizedString = (name) => { if (typeof name === 'string') { return name.replace(/_/g, ' '); } else { return name; } }; let workflowDelay = 0; const isHeader = true; const paperStyle = { color: "rgba(241, 241, 241, 1)", padding: isHeader ? null : 15, cursor: "pointer", width: '100%', maxHeight: 96, borderRadius: 4, transition: 'background-color 0.3s ease', }; const base64_decode = (str) => { return decodeURIComponent( atob(str) .split("") .map(function (c) { return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); }) .join("") ); }; const handleAppAuthenticationType = (selectedAppData)=> { if (selectedAppData.authentication === undefined || selectedAppData.authentication === null) { setAuthenticationType({ type: "", }) selectedAppData.authentication = { type: "", required: false, } } else { setAuthenticationType( selectedAppData.authentication.type === "oauth2-app" || (selectedAppData.authentication.type === "oauth2" && selectedAppData.authentication.redirect_uri !== undefined && selectedAppData.authentication.redirect_uri !== null) ? { type: selectedAppData.authentication.type, redirect_uri: selectedAppData.authentication.redirect_uri, refresh_uri: selectedAppData.authentication.refresh_uri, token_uri: selectedAppData.authentication.token_uri, scope: selectedAppData.authentication.scope, client_id: selectedAppData.authentication.client_id, client_secret: selectedAppData.authentication.client_secret, grant_type: selectedAppData.authentication.grant_type, } : { type: "", } ) } } function Heading(props) { const element = React.createElement( `h${props.level}`, { style: { marginTop: 40 } }, props.children ); return ( {props.level !== 1 ? ( ) : null} {element} ); } const getAppDocs = (appname, location, version) => { fetch(`${globalUrl}/api/v1/docs/${appname}?location=${location}&version=${version}`, { headers: { Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status === 200) { //toast("Successfully GOT app "+appId) } else { //toast("Failed getting app"); } return response.json(); }) .then((responseJson) => { if (responseJson.success === true) { if (responseJson.meta !== undefined && responseJson.meta !== null && Object.getOwnPropertyNames(responseJson.meta).length > 0) { setSelectedMeta(responseJson.meta) } if (responseJson.reason !== undefined && responseJson.reason !== undefined && responseJson.reason.length > 0) { if (!responseJson.reason.includes("404: Not Found") && responseJson.reason.length > 25) { // Translate into markdown ![]() const imgRegex = / ({ ...prevState, documentation: newdata, })); } } } }) .catch((error) => { toast(error.toString()); }); }; const handleDecodeOfOpenApiData = (data) => { var appexists = false; var parsedapp = {}; if (data.app !== undefined && data.app !== null) { var parsedBaseapp = ""; try { parsedBaseapp = base64_decode(data.app); } catch (e) { parsedBaseapp = data; } parsedapp = JSON.parse(parsedBaseapp); parsedapp.name = parsedapp.name.replaceAll("_", " "); appexists = parsedapp.name !== undefined && parsedapp.name !== null && parsedapp.name.length !== 0; if(parsedapp?.id.length > 0){ setSelectedAppData(parsedapp) handleAppAuthenticationType(parsedapp) const apptype = selectedAppData?.generated === false ? "python" : "openapi" getAppDocs(parsedapp.name, apptype, parsedapp.version); setAuthenticationModalOpen(true); } } if (data.openapi === undefined || data.openapi === null) { return; } var parsedDecoded = ""; try { parsedDecoded = base64_decode(data.openapi); } catch (e) { parsedDecoded = data; } parsedapp = JSON.parse(parsedDecoded); data = parsedapp.body === undefined ? parsedapp : JSON.parse(parsedapp.body); }; const getAppData = (appid) => { if (appid === undefined || appid === null || appid.length === 0) { return; } const url = `${globalUrl}/api/v1/apps/${appid}/config`; fetch(url, { credentials: "include", method: "GET", headers: { "Content-Type": "application/json", }, }) .then((response) => { if (response.status !== 200) { toast.error("Failed to get app data or App doesn't. Please contact support@shuffler.io"); return; } return response.json(); }) .then((responseJson) => { if (responseJson.success === true) { handleDecodeOfOpenApiData(responseJson); } else { toast.error("Failed to get app data or App doesn't exist"); } }) .catch((error) => { console.error("error for app is :", error); }); }; const UpdateAppAuthentication = (data) => { if (data === undefined || data === null) { return; } const filteredData = data.filter((appAuth) => appAuth?.app?.id === appid); if (filteredData.length === 0) { setAppAuthentication([]); setSelectedAuthentication({}); } else { setAppAuthentication(filteredData); setSelectedAuthentication(filteredData[0]); } }; const HandleAppAuthentication = ()=>{ const url = `${globalUrl}/api/v1/apps/authentication`; fetch(url, { method: "GET", headers: { "Content-Type": "application/json", }, credentials: "include", }).then((response) => { if (response.status !== 200) { return; } return response.json(); }).then((responseJson) => { if (responseJson.success === true) { UpdateAppAuthentication(responseJson.data); } else { toast.error("Failed to get app authentication data"); } }).catch((error) => { console.error("error for app is :", error); }); } const handleAppAuthenticationNew = (data) => () => { const appid = data.objectID; if (appid > 0) { setAppId(appid); } if (appid.length > 0) { toast.info(`Getting authentication for ${data.name}. Please wait...`); getAppData(appid); HandleAppAuthentication(); } } const AuthenticationData = (props) => { const selectedApp = props.app; const [authenticationOption, setAuthenticationOptions] = React.useState({ app: JSON.parse(JSON.stringify(selectedApp)), fields: {}, label: "", usage: [ { // workflow_id: workflow.id, }, ], id: uuidv4(), active: true, }); if ( selectedApp.authentication === undefined || selectedApp.authentication.parameters === null || selectedApp.authentication.parameters === undefined || selectedApp.authentication.parameters.length === 0 ) { return ( {selectedApp.name} does not require authentication ); } authenticationOption.app.actions = []; for (let paramkey in selectedApp.authentication.parameters) { if ( authenticationOption.fields[ selectedApp.authentication.parameters[paramkey].name ] === undefined ) { authenticationOption.fields[ selectedApp.authentication.parameters[paramkey].name ] = ""; } } const setNewAppAuth = (appAuthData, refresh) => { setSelectedAuthentication(appAuthData); var headers = { "Content-Type": "application/json", "Accept": "application/json", } headers["Org-Id"] = userdata?.active_org?.id fetch(globalUrl + "/api/v1/apps/authentication", { method: "PUT", headers: headers, body: JSON.stringify(appAuthData), credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for setting app auth :O!"); if (response.status === 400) { toast.error("Failed setting new auth. Please try again", { "autoClose": true, }) } } return response.json(); }) .then((responseJson) => { if (!responseJson.success) { toast.error("Error: " + responseJson.reason, { "autoClose": false, }) } else { HandleAppAuthentication() setAuthenticationModalOpen(false) getAppAuthentication() } }) .catch((error) => { console.log("New auth error: ", error.toString()); }); }; const handleSubmitCheck = () => { if (authenticationOption.label.length === 0) { authenticationOption.label = `Auth for ${selectedApp.name}`; } for (let paramkey in selectedApp.authentication.parameters) { if ( authenticationOption.fields[ selectedApp.authentication.parameters[paramkey].name ].length === 0 ) { if ( selectedApp.authentication.parameters[paramkey].value !== undefined && selectedApp.authentication.parameters[paramkey].value !== null && selectedApp.authentication.parameters[paramkey].value.length > 0 ) { authenticationOption.fields[ selectedApp.authentication.parameters[paramkey].name ] = selectedApp.authentication.parameters[paramkey].value; } else { if ( selectedApp.authentication.parameters[paramkey].schema.type === "bool" ) { authenticationOption.fields[ selectedApp.authentication.parameters[paramkey].name ] = "false"; } else { toast( "Field " + selectedApp.authentication.parameters[paramkey].name + " can't be empty" ); return; } } } } var newAuthOption = JSON.parse(JSON.stringify(authenticationOption)); var newFields = []; for (let authkey in newAuthOption.fields) { const value = newAuthOption.fields[authkey]; newFields.push({ "key": authkey, "value": value, }); } newAuthOption.fields = newFields setNewAppAuth(newAuthOption) } if (authenticationOption.label === null || authenticationOption.label === undefined) { authenticationOption.label = selectedApp.name + " authentication"; } return (
Authentication for {selectedApp.name.replaceAll("_", " ", -1)}
What is app authentication?
These are required fields for authenticating with {selectedApp.name}
Label for you to remember { authenticationOption.label = event.target.value; }} />
{selectedApp.authentication.parameters.map((data, index) => { if (data.value === "" || data.value === null || data.value === undefined || data.name === "url") { } return (
{data.name} {data.schema !== undefined && data.schema !== null && data.schema.type === "bool" ? ( ) : ( { authenticationOption.fields[data.name] = event.target.value; }} /> )}
); })}
); }; const authenticationModal = authenticationModalOpen ? ( {setSelectedMeta(undefined)}} PaperProps={{ style: { pointerEvents: "auto", color: "white", minWidth: 1100, minHeight: 700, maxHeight: 700, padding: 15, overflow: "hidden", zIndex: 10012, border: theme.palette.defaultBorder, }, }} >
{ selectedAppData.reference_info === undefined || selectedAppData.reference_info === null || selectedAppData.reference_info.github_url === undefined || selectedAppData.reference_info.github_url === null || selectedAppData.reference_info.github_url.length === 0 ? ( {`Documentation ) : ( {`Documentation )}
{ setAuthenticationModalOpen(false); }} >
{authenticationType.type === "oauth2" || authenticationType.type === "oauth2-app" ? : }
{selectedAppData.documentation === undefined || selectedAppData.documentation === null || selectedAppData.documentation.length === 0 ? (
{selectedAppData?.description}
There is no Shuffle-specific documentation for this app yet outside of the general description above. Documentation is written for each api, and is a community effort. We hope to see your contribution!
Want to help the making of, or improve this app?{" "}
Join the community on Discord!
Want to help change this app directly? {selectedAppData.reference_info === undefined || selectedAppData.reference_info === null || selectedAppData.reference_info.github_url === undefined || selectedAppData.reference_info.github_url === null || selectedAppData.reference_info.github_url.length === 0 ? ( Check it out on Github! ) : ( Check it out on Github! )}
) : (
{selectedMeta !== undefined && selectedMeta !== null && Object.getOwnPropertyNames(selectedMeta).length > 0 && selectedMeta.name !== undefined && selectedMeta.name !== null ?
{isMobile ? null : ( )} {isMobile ? null : (
)} {selectedMeta.read_time} minute {selectedMeta.read_time === 1 ? "" : "s"} to read
{isMobile || selectedMeta.contributors === undefined || selectedMeta.contributors === null ? ( "" ) : (
{selectedMeta.contributors.slice(0, 7).map((data, index) => { return ( {data.url} ); })}
)}
: null} {selectedAppData.documentation}
)}
) : null; return (
{authenticationModal} {hits.length === 0 && searchQuery.length >= 0 ? (
No Apps Found
) : (
); })}
)}
); }; const CustomSearchBox = connectSearchBox(SearchBox); const CustomHits = connectHits(Hits);