import React, { memo, useEffect, useState, useContext } from "react"; import { makeStyles } from "@mui/styles"; import { toast } from "react-toastify" import { getTheme } from '../theme.jsx'; import { Context } from "../context/ContextApi.jsx"; //import { useAlert import { FormControl, InputLabel, Paper, OutlinedInput, Checkbox, Card, Tooltip, FormControlLabel, Chip, Link, Typography, Switch, Select, MenuItem, Divider, ListItemText, TextField, Button, Tabs, Tab, Grid, Autocomplete, } from "@mui/material"; import { ExpandLess as ExpandLessIcon, ExpandMore as ExpandMoreIcon, Save as SaveIcon, CookieSharp, } from "@mui/icons-material"; import CloudSyncTab from "./CloudSyncTab.jsx"; const useStyles = makeStyles({ notchedOutline: { borderColor: "#f85a3e !important", }, }); const OrgHeaderexpandedNew = (props) => { const { userdata, selectedOrganization, setSelectedOrganization, globalUrl, isCloud, adminTab, selectedStatus, setSelectedStatus, isEditOrgTab, handleStatusChange } = props; const classes = useStyles(); const defaultBranch = "main"; const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { PaperProps: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 300, borderRadius: 4, overflowY: "scroll", }, }, getContentAnchorEl: () => null, }; const [orgName, setOrgName] = 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 [openNotification, setOpenNotification] = React.useState(false); const { themeMode, supportEmail, brandColor } = useContext(Context); const theme = getTheme(themeMode, brandColor); 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 [documentationReference, setDocumentationReference] = React.useState( selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.documentation_reference === undefined || selectedOrganization.defaults.documentation_reference.length === 0 ? "" : selectedOrganization.defaults.documentation_reference ); const [newsletter, setNewsletter] = React.useState( selectedOrganization.defaults === undefined ? true : selectedOrganization.defaults.newsletter === undefined || selectedOrganization.defaults.newsletter.length === 0 ? true : !selectedOrganization.defaults.newsletter ) const [weeklyRecommendations, setWeeklyRecommendations] = React.useState( selectedOrganization.defaults === undefined ? true : selectedOrganization.defaults.weekly_recommendations === undefined || selectedOrganization.defaults.weekly_recommendations.length === 0 ? true : !selectedOrganization.defaults.weekly_recommendations ) const [uploadRepo, setUploadRepo] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_repo === undefined || selectedOrganization.defaults.workflow_upload_repo.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_repo) const [uploadBranch, setUploadBranch] = React.useState(selectedOrganization.defaults === undefined ? defaultBranch : selectedOrganization.defaults.workflow_upload_branch === undefined || selectedOrganization.defaults.workflow_upload_branch.length === 0 ? defaultBranch : selectedOrganization.defaults.workflow_upload_branch) const [uploadUsername, setUploadUsername] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_username === undefined || selectedOrganization.defaults.workflow_upload_username.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_username) const [uploadToken, setUploadToken] = React.useState("") const [regionStatus, setRegionStatus] = useState(); useEffect(() => { if (documentationReference !== selectedOrganization?.defaults?.documentation_reference) { setDocumentationReference(selectedOrganization?.defaults?.documentation_reference) } if (uploadRepo !== selectedOrganization?.defaults?.workflow_upload_repo) { setUploadRepo(selectedOrganization?.defaults?.workflow_upload_repo) } if (uploadBranch !== selectedOrganization?.defaults?.workflow_upload_branch) { setUploadBranch(selectedOrganization?.defaults?.workflow_upload_branch) } if (uploadUsername !== selectedOrganization?.defaults?.workflow_upload_username) { setUploadUsername(selectedOrganization?.defaults?.workflow_upload_username) } // Not showing the token in the UI (cause it's in plain text) // if (uploadToken !== selectedOrganization?.defaults?.workflow_upload_token) { // setUploadToken(selectedOrganization?.defaults?.workflow_upload_token) // } }, [selectedOrganization]) useEffect(() => { if (selectedOrganization !== undefined && selectedOrganization !== null) { if ((orgName === undefined || orgName === null || orgName.length === 0) && selectedOrganization?.name !== orgName) { setOrgName(selectedOrganization?.name) } if ((orgDescription === undefined || orgDescription === null || orgDescription.length === 0) && selectedOrganization?.description !== orgDescription) { setOrgDescription(selectedOrganization?.description) } } }, [selectedOrganization]) const handleEditOrg = ( name, description, orgId, image, defaults, sso_config, lead_info, ) => { const data = { name: name, description: description, org_id: orgId, image: image, defaults: defaults, sso_config: sso_config, lead_info: lead_info, mfa_required: selectedOrganization?.mfa_required, Billing: selectedOrganization?.Billing, }; 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 handleSendChangeRegionMail = (region) => { if (selectedOrganization === undefined || selectedOrganization === null) { toast.error(`Failed to send request for changing region. Please contact ${supportEmail}`) return } const regionToCloudRegion = { 'US': 'us-west2', 'EU': 'europe-west3', 'CA': 'northamerica-northeast1', 'UK': 'europe-west2', 'EU-2': 'europe-west3' }; const destinationRegion = regionToCloudRegion[region] || region; var data = { dst_region: destinationRegion } toast.info("Sending request for changing region to " + region) fetch(`${globalUrl}/api/v1/orgs/${selectedOrganization?.id}/change/region/request`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", body: JSON.stringify(data), }).then((response) => { if (response.status !== 200) { toast.error(`Failed to send request for changing region. Please contact ${supportEmail}`) } else { toast.success("Successfully sent request for region change. We will process the move and contact you shortly.") } }).catch((err) => { console.log(err) toast.error(`Failed to send request for changing region. Please contact ${supportEmail}`) }) } const setSelectedRegion = (region) => { // send a POST request to /api/v1/orgs/{org_id}/region with the region as the body const regionMap = { "US": "us-west2", "EU": "europe-west2", "CA": "northamerica-northeast1", "UK": "europe-west2", "EU-2": "europe-west3", "AUS": "australia-southeast1" }; region = regionMap[region] || region; var data = { dst_region: region } toast.info("Changing region to " + region + "...This may take a few minutes.") fetch(`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/change/region`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", body: JSON.stringify(data), timeOut: 1000 }).then((response) => { if (response.status !== 200) { response.json().then((reason) => { toast.error("Failed to change region: " + reason.reason) }).catch((err) => { toast.error("Failed to change region") }); } else { toast("Region changed successfully! Reloading in 5 seconds..") // Reload the page in 2 seconds setTimeout(() => { window.location.reload() }, 5000) } // return responseJson }) } const orgSaveButton = ( ); return (
{/* Email settings Enable or disable email notifications for your organization.
{ setNewsletter(e.target.checked) }} disabled={!isCloud} /> { setWeeklyRecommendations(e.target.checked) }} disabled={!isCloud} />
*/}
Name { if ((orgName !== selectedOrganization?.name) && (orgName !== "")) { handleEditOrg( orgName, orgDescription, selectedOrganization.id, selectedOrganization.image, { app_download_repo: selectedOrganization?.defaults?.app_download_repo, app_download_branch: selectedOrganization?.defaults?.app_download_branch, workflow_download_repo: selectedOrganization?.defaults?.workflow_download_repo, workflow_download_branch: selectedOrganization?.defaults?.workflow_download_branch, notification_workflow: selectedOrganization?.defaults?.notification_workflow, documentation_reference: selectedOrganization?.defaults?.documentation_reference, workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo, workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch, workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username, workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token, newsletter: !newsletter, weekly_recommendations: !weeklyRecommendations, }, { sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint, sso_certificate: selectedOrganization?.sso_config?.sso_certificate, client_id: selectedOrganization?.sso_config?.client_id, client_secret: selectedOrganization?.sso_config?.client_secret, openid_authorization: selectedOrganization?.sso_config?.openid_authorization, openid_token: selectedOrganization?.sso_config?.openid_token, SSORequired: selectedOrganization?.sso_config?.SSORequired, auto_provision: selectedOrganization?.sso_config?.auto_provision, } ) } }} onChange={(e) => { if (e.target.value.length > 100) { toast("Choose a shorter name."); return; } setOrgName(e.target.value); }} color="primary" InputProps={{ style: { color: theme.palette.textFieldStyle.color, height: "35px", fontSize: "1em", borderRadius: 4, backgroundColor: theme.palette.textFieldStyle.backgroundColor, }, classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, }} />
{userdata?.support ? (
Status
) : null} {isCloud ? (
Change Region
) : null}
Description
{ if ((orgDescription !== selectedOrganization?.description) && (orgDescription !== "")) { handleEditOrg( orgName, orgDescription, selectedOrganization.id, selectedOrganization.image, { app_download_repo: selectedOrganization?.defaults?.app_download_repo, app_download_branch: selectedOrganization?.defaults?.app_download_branch, workflow_download_repo: selectedOrganization?.defaults?.workflow_download_repo, workflow_download_branch: selectedOrganization?.defaults?.workflow_download_branch, notification_workflow: selectedOrganization?.defaults?.notification_workflow, documentation_reference: selectedOrganization?.defaults?.documentation_reference, workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo, workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch, workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username, workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token, newsletter: !newsletter, weekly_recommendations: !weeklyRecommendations, }, { sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint, sso_certificate: selectedOrganization?.sso_config?.sso_certificate, client_id: selectedOrganization?.sso_config?.client_id, client_secret: selectedOrganization?.sso_config?.client_secret, openid_authorization: selectedOrganization?.sso_config?.openid_authorization, openid_token: selectedOrganization?.sso_config?.openid_token, SSORequired: selectedOrganization?.sso_config?.SSORequired, auto_provision: selectedOrganization?.sso_config?.auto_provision, } ) } }} onChange={(e) => { setOrgDescription(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, height: 89, borderRadius: 4, }, }} />
Preferences {/*isCloud ? : null*/}
{/* Add a Workflow that receives notifications from Shuffle when an error occurs in one of your workflows */} Org Documentation reference Add a URL that is added as a link, pointing to any external documentation page you want. { if (documentationReference !== selectedOrganization?.defaults?.documentation_reference) { handleEditOrg( orgName, orgDescription, selectedOrganization.id, selectedOrganization.image, { app_download_repo: selectedOrganization?.defaults?.app_download_repo, app_download_branch: selectedOrganization?.defaults?.app_download_branch, workflow_download_repo: selectedOrganization?.defaults?.workflow_download_repo, workflow_download_branch: selectedOrganization?.defaults?.workflow_download_branch, notification_workflow: selectedOrganization?.defaults?.notification_workflow, documentation_reference: documentationReference, workflow_upload_repo: selectedOrganization?.defaults?.workflow_upload_repo, workflow_upload_branch: selectedOrganization?.defaults?.workflow_upload_branch, workflow_upload_username: selectedOrganization?.defaults?.workflow_upload_username, workflow_upload_token: selectedOrganization?.defaults?.workflow_upload_token, newsletter: !newsletter, weekly_recommendations: !weeklyRecommendations, }, { sso_entrypoint: selectedOrganization?.sso_config?.sso_entrypoint, sso_certificate: selectedOrganization?.sso_config?.sso_certificate, client_id: selectedOrganization?.sso_config?.client_id, client_secret: selectedOrganization?.sso_config?.client_secret, openid_authorization: selectedOrganization?.sso_config?.openid_authorization, openid_token: selectedOrganization?.sso_config?.openid_token, SSORequired: selectedOrganization?.sso_config?.SSORequired, auto_provision: selectedOrganization?.sso_config?.auto_provision, } ) if (userdata.org_status.includes("integration_partner")) { toast.info("Reloading page to update the changes everywhere") setTimeout(() => { window.location.reload() }, 5000) } } }} onChange={(e) => { setDocumentationReference(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35 }, }} /> {!userdata?.support === true && (!selectedOrganization || selectedOrganization?.creator_org === undefined || selectedOrganization?.creator_org === null || selectedOrganization?.creator_org?.length > 0) ? null : } Workflow Backup Repository Decide where workflows are backed up in a Git repository. Will create logs and notifications if upload fails. The repository and branch must already have been initialized. Files will show up in the repo root in the /orgId/workflow-status/workflowId.json format. MSSP: If suborg exists, this will automatically be applied for them as well (not retroactive). Credentials are encrypted. Repository for workflow backup { setUploadRepo(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} /> Branch { setUploadBranch(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} /> Username for backup of workflows { setUploadUsername(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} /> New Git token/password { setUploadToken(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} type="password" /> {/*isCloud ? null : */} {isCloud ? null : ( App Download URL { setAppDownloadUrl(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, backgroundColor: theme.palette.textFieldStyle.backgroundColor, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} /> )} {isCloud ? null : ( App Download Branch { setAppDownloadBranch(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} /> )} {isCloud ? null : ( Workflow Download URL { setWorkflowDownloadUrl(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} /> )} {isCloud ? null : ( Workflow Download Branch { setWorkflowDownloadBranch(e.target.value); }} InputProps={{ classes: { notchedOutline: isEditOrgTab ? null : classes.notchedOutline, }, style: { color: theme.palette.textFieldStyle.color, fontWeight: 400, fontSize: 16, borderRadius: 4, height: 35, }, }} /> )} {/* {expanded ? : } */}
{orgSaveButton}
) } export default OrgHeaderexpandedNew; const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userdata, handleSendChangeRegionMail }) => { // Show from options: "us-west2", "europe-west2", "europe-west3", "northamerica-northeast1" // var regions = ["us-west2", "europe-west2", "europe-west3", "northamerica-northeast1"] const regionMapping = { "US": "us", "EU-2": "eu", "CA": "ca", "UK": "gb", "AUS": "au", }; //let regiontag = "UK"; let regiontag = "UK"; let regionCode = "gb"; const regionsplit = selectedOrganization?.region_url?.split("."); if (regionsplit?.length > 2 && !regionsplit[0]?.includes("shuffler")) { const namesplit = regionsplit[0]?.split("/"); regiontag = namesplit[namesplit.length - 1]; if (regiontag === "california") { regiontag = "US"; regionCode = "us"; } else if (regiontag === "frankfurt") { regiontag = "EU-2"; regionCode = "eu"; } else if (regiontag === "ca") { regiontag = "CA"; regionCode = "ca"; } else if (regiontag === "au") { regiontag = "AUS"; regionCode = "au" } else if (regiontag === "uk") { regiontag = "UK"; regionCode = "gb" } } return ( {/* Region */} ); })