diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod
index cfa07b93..4895bf22 100644
--- a/backend/go-app/go.mod
+++ b/backend/go-app/go.mod
@@ -20,7 +20,7 @@ require (
github.com/gorilla/mux v1.8.1
github.com/h2non/filetype v1.1.3
github.com/satori/go.uuid v1.2.0
- github.com/shuffle/shuffle-shared v0.6.30
+ github.com/shuffle/shuffle-shared v0.6.31
golang.org/x/crypto v0.22.0
google.golang.org/api v0.176.1
google.golang.org/grpc v1.63.2
diff --git a/backend/go-app/go.sum b/backend/go-app/go.sum
index 358b0d50..4c0d4206 100644
--- a/backend/go-app/go.sum
+++ b/backend/go-app/go.sum
@@ -441,6 +441,8 @@ github.com/shuffle/shuffle-shared v0.6.26 h1:UZ4o3s+GPULLv/gy31SdhUw1ttvF+f1FfP1
github.com/shuffle/shuffle-shared v0.6.26/go.mod h1:rWkh1eWdIx7OqQzJ1+JzF3Hck1X/Ty1WkUtjLrp+CU4=
github.com/shuffle/shuffle-shared v0.6.27 h1:q4qZD6bGZFIvZ5Y10unGr3N3rZ7OryWyvvaGgANZJZU=
github.com/shuffle/shuffle-shared v0.6.27/go.mod h1:rWkh1eWdIx7OqQzJ1+JzF3Hck1X/Ty1WkUtjLrp+CU4=
+github.com/shuffle/shuffle-shared v0.6.31 h1:MK1SW1pwjIP7hznq+mMlTPM1R3LIOfi1/bUL5xFSg/8=
+github.com/shuffle/shuffle-shared v0.6.31/go.mod h1:rWkh1eWdIx7OqQzJ1+JzF3Hck1X/Ty1WkUtjLrp+CU4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
diff --git a/backend/go-app/main.go b/backend/go-app/main.go
index 525a4b3e..98718c19 100755
--- a/backend/go-app/main.go
+++ b/backend/go-app/main.go
@@ -759,6 +759,8 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
}
}
+ go shuffle.CheckSessionOrgs(ctx, userInfo)
+
//log.Printf("%s %s", session.Session, UserInfo.Session)
//if session.Session != userInfo.Session {
// log.Printf("Session %s is not the same as %s for %s. %s", userInfo.Session, session.Session, userInfo.Username, err)
diff --git a/frontend/src/components/NewHeader.jsx b/frontend/src/components/NewHeader.jsx
index 19c26fb5..1d088170 100644
--- a/frontend/src/components/NewHeader.jsx
+++ b/frontend/src/components/NewHeader.jsx
@@ -500,12 +500,15 @@ const Header = (props) => {
//globalUrl = responseJson.region_url
}
if (responseJson["reason"] === "SSO_REDIRECT") {
- window.location.href = responseJson["url"]
- return
+ setTimeout(() => {
+ toast.info("Redirecting to SSO login page as SSO is required for this organization.")
+ window.location.href = responseJson["url"]
+ return
+ }, 2000)
}
setTimeout(() => {
- window.location.reload();
+ window.location.reload()
}, 2000);
toast("Successfully changed active organization - refreshing!");
diff --git a/frontend/src/components/OrgHeaderexpanded.jsx b/frontend/src/components/OrgHeaderexpanded.jsx
index 2efae52a..2293e641 100644
--- a/frontend/src/components/OrgHeaderexpanded.jsx
+++ b/frontend/src/components/OrgHeaderexpanded.jsx
@@ -1,913 +1,911 @@
-import React, { useEffect } from "react";
-
-import { makeStyles } from "@mui/styles";
-import theme from '../theme.jsx';
-import { toast } from "react-toastify"
-import Chip from '@mui/material/Chip';
-import Stack from '@mui/material/Stack';
-import SubflowSuggestions from "../components/SubflowSuggestions.jsx";
-
-import {
- FormControl,
- InputLabel,
- Paper,
- OutlinedInput,
- Checkbox,
- Card,
- Tooltip,
- FormControlLabel,
- Typography,
- Switch,
- Select,
- MenuItem,
- Divider,
- TextField,
- Button,
- Tabs,
- Tab,
- Grid,
- IconButton,
- Autocomplete,
- Dialog,
- DialogTitle,
- DialogActions,
- DialogContent,
- Box
-} from "@mui/material";
-
-import {
- ExpandLess as ExpandLessIcon,
- ExpandMore as ExpandMoreIcon,
- Save as SaveIcon,
-} from "@mui/icons-material";
-
-const useStyles = makeStyles({
- notchedOutline: {
- borderColor: "#f85a3e !important",
- },
-})
-
-const OrgHeaderexpanded = (props) => {
- const {
- userdata,
- selectedOrganization,
- setSelectedOrganization,
- globalUrl,
- isCloud,
- adminTab,
- } = props;
-
- const classes = useStyles();
- const defaultBranch = "master";
-
- const [orgName, setOrgName] = React.useState(selectedOrganization.name);
- 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 [SSORequired, setSSORequired] = React.useState(selectedOrganization.sso_config === undefined
- ? false
- : selectedOrganization.sso_config.SSORequired === undefined
- ? false
- : selectedOrganization.sso_config.SSORequired);
-
- 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 [workflows, setWorkflows] = React.useState([])
- const [workflow, setWorkflow] = React.useState({})
-
- const getAvailableWorkflows = (trigger_index) => {
- fetch(globalUrl + "/api/v1/workflows", {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- Accept: "application/json",
- },
- credentials: "include",
- })
- .then((response) => {
- if (response.status !== 200) {
- console.log("Status not 200 for workflows :O!");
- return;
- }
- return response.json();
- })
- .then((responseJson) => {
- if (responseJson !== undefined) {
- setWorkflows(responseJson)
-
- if (selectedOrganization.defaults !== undefined && selectedOrganization.defaults.notification_workflow !== undefined) {
-
- const workflow = responseJson.find((workflow) => workflow.id === selectedOrganization.defaults.notification_workflow)
- if (workflow !== undefined && workflow !== null) {
- setWorkflow(workflow)
- }
- }
- }
- })
- .catch((error) => {
- console.log("Error getting workflows: " + error);
- })
- }
-
- useEffect(() => {
- getAvailableWorkflows()
- }, [])
-
- const handleEditOrg = (
- name,
- description,
- orgId,
- image,
- defaults,
- sso_config
- ) => {
-
- const data = {
- name: name,
- description: description,
- org_id: orgId,
- image: image,
- defaults: defaults,
- sso_config: sso_config,
- };
-
- const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
- 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 updating org: ", responseJson.reason);
- } else {
- toast("Successfully edited org!");
- }
- })
- )
- .catch((error) => {
- toast("Err: " + error.toString());
- });
- };
-
-
- const handleWorkflowSelectionUpdate = (e, isUserinput) => {
- if (e.target.value === undefined || e.target.value === null || e.target.value.id === undefined) {
- console.log("Returning as there's no id")
- return null
- }
-
- setWorkflow(e.target.value)
- setNotificationWorkflow(e.target.value.id)
- toast("Updated notification workflow. Don't forget to save!")
- }
-
- const orgSaveButton = (
-
-
-
- handleEditOrg(
- orgName,
- orgDescription,
- 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,
- }
- )
- }
- >
-
-
-
-
- );
-
- const toggleBetweenRequiredOrOptional = (event) => {
- setSSORequired(event.target.checked);
- };
-
- return (
-
-
-
-
- Notification Workflow
-
- {/*
-
- */}
-
-
-
- {workflows !== undefined && workflows !== null && workflows.length > 0 ?
-
{
- if (
- option === undefined ||
- option === null ||
- option.name === undefined ||
- option.name === null
- ) {
- return "No Workflow Selected";
- }
-
- const newname = (
- option.name.charAt(0).toUpperCase() + option.name.substring(1)
- ).replaceAll("_", " ");
- return newname;
- }}
- options={workflows}
- fullWidth
- style={{
- backgroundColor: theme.palette.inputColor,
- height: 50,
- borderRadius: theme.palette.borderRadius,
- }}
- onChange={(event, newValue) => {
- console.log("Found value: ", newValue)
-
- var parsedinput = { target: { value: newValue } }
-
- // For variables
- if (typeof newValue === 'string' && newValue.startsWith("$")) {
- parsedinput = {
- target: {
- value: {
- "name": newValue,
- "id": newValue,
- "actions": [],
- "triggers": [],
- }
- }
- }
- }
-
- handleWorkflowSelectionUpdate(parsedinput)
- }}
- renderOption={(props, data, state) => {
- if (data.id === workflow.id) {
- data = workflow;
- }
-
- return (
-
- {data.image !== undefined && data.image !== null && data.image.length > 0 ?
-
- : null}
-
- Choose {data.name}
-
-
- } placement="bottom">
- {
- var parsedinput = { target: { value: data } }
- handleWorkflowSelectionUpdate(parsedinput)
- }}
- >
- {data.name}
-
-
- )
- }}
- renderInput={(params) => {
- return (
-
- );
- }}
- />
- :
- {
- setNotificationWorkflow(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
- }
-
- {orgSaveButton}
-
-
-
-
-
-
- Org Documentation reference
- {
- setDocumentationReference(e.target.value);
- }}
- InputProps={{
- classes: {
- notchedOutline: classes.notchedOutline,
- },
- style: {
- color: "white",
- },
- }}
- />
-
-
- {/* {isCloud ? null : */}
-
-
-
- {SSORequired ? 'Required' : 'Optional'}
-
-
Make SAML SSO or OpenID Authentication Required or Optional for Your Organization.
-
-
-
-
- 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 ?
-
- :
-
- }
-
- */}
-
-
- )
-}
-
+import React, { useEffect } from "react";
+
+import { makeStyles } from "@mui/styles";
+import theme from '../theme.jsx';
+import { toast } from "react-toastify"
+import Chip from '@mui/material/Chip';
+import Stack from '@mui/material/Stack';
+import SubflowSuggestions from "../components/SubflowSuggestions.jsx";
+
+import {
+ FormControl,
+ InputLabel,
+ Paper,
+ OutlinedInput,
+ Checkbox,
+ Card,
+ Tooltip,
+ FormControlLabel,
+ Typography,
+ Switch,
+ Select,
+ MenuItem,
+ Divider,
+ TextField,
+ Button,
+ Tabs,
+ Tab,
+ Grid,
+ IconButton,
+ Autocomplete,
+ Dialog,
+ DialogTitle,
+ DialogActions,
+ DialogContent,
+ Box
+} from "@mui/material";
+
+import {
+ ExpandLess as ExpandLessIcon,
+ ExpandMore as ExpandMoreIcon,
+ Save as SaveIcon,
+} from "@mui/icons-material";
+
+const useStyles = makeStyles({
+ notchedOutline: {
+ borderColor: "#f85a3e !important",
+ },
+})
+
+const OrgHeaderexpanded = (props) => {
+ const {
+ userdata,
+ selectedOrganization,
+ setSelectedOrganization,
+ globalUrl,
+ isCloud,
+ adminTab,
+ } = props;
+
+ const classes = useStyles();
+ const defaultBranch = "master";
+
+ const [orgName, setOrgName] = React.useState(selectedOrganization.name);
+ 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 [SSORequired, setSSORequired] = React.useState(selectedOrganization.sso_config === undefined
+ ? false
+ : selectedOrganization.sso_config.SSORequired === undefined
+ ? false
+ : selectedOrganization.sso_config.SSORequired);
+
+ 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 [workflows, setWorkflows] = React.useState([])
+ const [workflow, setWorkflow] = React.useState({})
+
+ const getAvailableWorkflows = (trigger_index) => {
+ fetch(globalUrl + "/api/v1/workflows", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for workflows :O!");
+ return;
+ }
+ return response.json();
+ })
+ .then((responseJson) => {
+ if (responseJson !== undefined) {
+ setWorkflows(responseJson)
+
+ if (selectedOrganization.defaults !== undefined && selectedOrganization.defaults.notification_workflow !== undefined) {
+
+ const workflow = responseJson.find((workflow) => workflow.id === selectedOrganization.defaults.notification_workflow)
+ if (workflow !== undefined && workflow !== null) {
+ setWorkflow(workflow)
+ }
+ }
+ }
+ })
+ .catch((error) => {
+ console.log("Error getting workflows: " + error);
+ })
+ }
+
+ useEffect(() => {
+ getAvailableWorkflows()
+ }, [])
+
+ const handleEditOrg = (
+ name,
+ description,
+ orgId,
+ image,
+ defaults,
+ sso_config
+ ) => {
+
+ const data = {
+ name: name,
+ description: description,
+ org_id: orgId,
+ image: image,
+ defaults: defaults,
+ sso_config: sso_config,
+ };
+
+ const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
+ 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 updating org: ", responseJson.reason);
+ } else {
+ toast("Successfully edited org!");
+ }
+ })
+ )
+ .catch((error) => {
+ toast("Err: " + error.toString());
+ });
+ };
+
+
+ const handleWorkflowSelectionUpdate = (e, isUserinput) => {
+ if (e.target.value === undefined || e.target.value === null || e.target.value.id === undefined) {
+ console.log("Returning as there's no id")
+ return null
+ }
+
+ setWorkflow(e.target.value)
+ setNotificationWorkflow(e.target.value.id)
+ toast("Updated notification workflow. Don't forget to save!")
+ }
+
+ const orgSaveButton = (
+
+
+
+ handleEditOrg(
+ orgName,
+ orgDescription,
+ 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,
+ SSORequired: SSORequired
+ }
+ )
+ }
+ >
+
+
+
+
+ );
+
+ const toggleBetweenRequiredOrOptional = (event) => {
+ if (ssoEntrypoint === "" && openidAuthorization === "" && openidToken === "") {
+ if (!SSORequired) {
+ toast.error("Please fill in fields for either OpenID connect or SSO before continuing. ")
+ return
+ }
+ } else {
+ toast.info("Toggled SSO. Remember to save.")
+ }
+
+ setSSORequired(event.target.checked)
+ };
+
+ return (
+
+
+
+
+ Notification Workflow
+
+ {/*
+
+ */}
+
+
+
+ {workflows !== undefined && workflows !== null && workflows.length > 0 ?
+
{
+ if (
+ option === undefined ||
+ option === null ||
+ option.name === undefined ||
+ option.name === null
+ ) {
+ return "No Workflow Selected";
+ }
+
+ const newname = (
+ option.name.charAt(0).toUpperCase() + option.name.substring(1)
+ ).replaceAll("_", " ");
+ return newname;
+ }}
+ options={workflows}
+ fullWidth
+ style={{
+ backgroundColor: theme.palette.inputColor,
+ height: 50,
+ borderRadius: theme.palette.borderRadius,
+ }}
+ onChange={(event, newValue) => {
+ console.log("Found value: ", newValue)
+
+ var parsedinput = { target: { value: newValue } }
+
+ // For variables
+ if (typeof newValue === 'string' && newValue.startsWith("$")) {
+ parsedinput = {
+ target: {
+ value: {
+ "name": newValue,
+ "id": newValue,
+ "actions": [],
+ "triggers": [],
+ }
+ }
+ }
+ }
+
+ handleWorkflowSelectionUpdate(parsedinput)
+ }}
+ renderOption={(props, data, state) => {
+ if (data.id === workflow.id) {
+ data = workflow;
+ }
+
+ return (
+
+ {data.image !== undefined && data.image !== null && data.image.length > 0 ?
+
+ : null}
+
+ Choose {data.name}
+
+
+ } placement="bottom">
+ {
+ var parsedinput = { target: { value: data } }
+ handleWorkflowSelectionUpdate(parsedinput)
+ }}
+ >
+ {data.name}
+
+
+ )
+ }}
+ renderInput={(params) => {
+ return (
+
+ );
+ }}
+ />
+ :
+ {
+ setNotificationWorkflow(e.target.value);
+ }}
+ InputProps={{
+ classes: {
+ notchedOutline: classes.notchedOutline,
+ },
+ style: {
+ color: "white",
+ },
+ }}
+ />
+ }
+
+ {orgSaveButton}
+
+
+
+
+
+
+ Org Documentation reference
+ {
+ setDocumentationReference(e.target.value);
+ }}
+ InputProps={{
+ classes: {
+ notchedOutline: classes.notchedOutline,
+ },
+ style: {
+ color: "white",
+ },
+ }}
+ />
+
+
+ {/* {isCloud ? null : */}
+ Single Signon - SAML/OpenID
+
+
Make SAML SSO or OpenID Authentication required/optional for your organization. Tip: Do not make it required until you have tested the URL directly.
+
+ {
+ toggleBetweenRequiredOrOptional(e)
+ }}
+ name="onOffSwitch"
+ color="primary"
+ title="Make SAML SSO or OpenID Authentication Required or Optional for Your Organization"
+ />
+ {SSORequired ? 'Required' : 'Optional'}
+
+
+
+
+
+ OpenID connect
+
+
+
+ Client ID
+ {
+ setOpenidClientId(e.target.value);
+ }}
+ InputProps={{
+ classes: {
+ notchedOutline: classes.notchedOutline,
+ },
+ style: {
+ color: "white",
+ },
+ }}
+ />
+
+
+
+
+ Client Secret (optional)
+ {
+ 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)
+ {
+ 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 ?
+
+ :
+
+ }
+
+ */}
+
+
+ )
+}
+
export default OrgHeaderexpanded;