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 */}
);
})