Sync from cloud for 2.1.0-rc1

This commit is contained in:
Frikky
2025-06-04 18:37:36 +02:00
parent 90d909e5da
commit 6ad756f8d8
13 changed files with 357 additions and 86 deletions
+1 -1
View File
@@ -1463,7 +1463,7 @@ const ActionsList = memo(({
<Tooltip title="Go to app" placement="right">
<div style={{ display: "flex", alignItems: "center" }}>
<img
src={openapi?.info["x-logo"]}
src={openapi?.info["x-logo"]?.length > 0 ? openapi?.info["x-logo"] : theme?.palette?.defaultImage}
width={48}
height={48}
alt="app logo"
+153 -8
View File
@@ -83,18 +83,17 @@ const AppAuthTab = memo((props) => {
const [appAuthenticationGroupId, setAppAuthenticationGroupId] = React.useState("");
const [appAuthenticationGroups, setAppAuthenticationGroups] = React.useState([]);
const [appAuthenticationGroupName, setAppAuthenticationGroupName] = React.useState("");
const [selectedSubOrg, setSelectedSubOrg] = useState([]);
const [appAuthenticationGroupDescription, setAppAuthenticationGroupDescription] = React.useState("");
const [appsForAppAuthGroup, setAppsForAppAuthGroup] = React.useState([]);
const [searchQuery, setSearchQuery] = React.useState("");
const [showAppModal, setShowAppModal] = useState(false)
const [selectedAuthId, setSelectedAuthId] = useState("");
const [showDistributionPopup, setShowDistributionPopup] = useState(false);
const [showAuthenticationLoader, setShowAuthenticationLoader] = useState(true)
const [showAppAuthGroupLoader, setShowAppAuthGroupLoader] = useState(true)
const { themeMode, supportEmail, brandColor } = useContext(Context)
const theme = getTheme(themeMode, brandColor)
const changeDistribution = (data) => {
//changeDistributed(data, !isDistributed)
editAuthenticationConfig(data.id, "suborg_distribute")
}
useEffect(() => {
getAppAuthentication();
@@ -214,11 +213,39 @@ const AppAuthTab = memo((props) => {
});
};
const editAuthenticationConfig = (id, parentAction) => {
const handleSelectSubOrg = (id, action) => {
if (action === "all") {
const childOrgs = userdata.orgs.filter(
(data) => data.creator_org === userdata.active_org.id
);
setSelectedSubOrg((prev) => {
if (prev.length === childOrgs.length) {
// If all child orgs are already selected, clear the selection
return [];
} else {
// Otherwise, select all child org IDs
return childOrgs.map((data) => data.id);
}
});
} else if (action === "none") {
setSelectedSubOrg([]);
} else {
setSelectedSubOrg((prev) => {
if (prev.includes(id)) {
return prev.filter((data) => data !== id);
} else {
return [...prev, id];
}
});
}
};
const editAuthenticationConfig = (id, parentAction, selectedSuborgs) => {
const data = {
id: id,
action: parentAction !== undefined && parentAction !== null ? parentAction : "assign_everywhere",
}
selected_suborgs: selectedSuborgs !== undefined && selectedSuborgs !== null ? selectedSuborgs : [],
}
const url = globalUrl + "/api/v1/apps/authentication/" + id + "/config";
@@ -240,6 +267,7 @@ const AppAuthTab = memo((props) => {
} else {
toast("Successfully updated auth!");
setSelectedUserModalOpen(false);
setShowDistributionPopup(false);
setTimeout(() => {
getAppAuthentication();
}, 1000);
@@ -251,6 +279,106 @@ const AppAuthTab = memo((props) => {
});
};
const changeDistribution = (id, selectedSubOrg) => {
editAuthenticationConfig(id, "suborg_distribute", [...new Set(selectedSubOrg)])
}
const cacheDistributionModal = showDistributionPopup ? (
<Dialog
open={showDistributionPopup}
onClose={() => {setShowDistributionPopup(false);setSelectedAuthId("")}}
PaperProps={{
sx: {
borderRadius: theme?.palette?.DialogStyle?.borderRadius,
border: theme?.palette?.DialogStyle?.border,
fontFamily: theme?.typography?.fontFamily,
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
zIndex: 1000,
minWidth: "600px",
minHeight: "320px",
overflow: "auto",
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogActions-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
},
}}
>
<DialogTitle>
<Typography variant="h5" color="textPrimary">
Select sub-org to distribute Datastore key
</Typography>
</DialogTitle>
<DialogContent style={{ color: "rgba(255,255,255,0.65)" }}>
<MenuItem value="none" onClick={()=> {handleSelectSubOrg(null, "none")}}>None</MenuItem>
<MenuItem value="all" onClick={()=> {handleSelectSubOrg(null, "all")}}>All</MenuItem>
{userdata.orgs.map((data, index) => {
if (data.creator_org !== userdata.active_org.id) {
return null;
}
const imagesize = 22;
const imageStyle = {
width: imagesize,
height: imagesize,
pointerEvents: "none",
marginRight: 10,
marginLeft: data.id === userdata.active_org.id ? 0 : 20,
};
const image = data.image === "" ? (
<img alt={data.name} src={theme.palette.defaultImage} style={imageStyle} />
) : (
<img alt={data.name} src={data.image} style={imageStyle} />
);
return (
<MenuItem
key={index}
value={data.id}
onClick={() => handleSelectSubOrg(data.id)}
style={{ display: "flex", alignItems: "center" }}
>
<Checkbox
checked={selectedSubOrg.includes(data.id)}
/>
{image}
<span style={{ marginLeft: 8 }}>{data.name}</span>
</MenuItem>
);
})}
<div style={{ display: "flex", marginTop: 20 }}>
<Button
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, color: theme.palette.primary.main }}
onClick={() => {setShowDistributionPopup(false); setSelectedAuthId("")}}
color="primary"
>
Cancel
</Button>
<Button
variant="contained"
style={{ borderRadius: "2px", textTransform: 'none', fontSize:16, marginLeft: 10 }}
onClick={() => {
changeDistribution(selectedAuthId, selectedSubOrg);
}}
color="primary"
>
Submit
</Button>
</div>
</DialogContent>
</Dialog>
) : null;
const editAuthenticationModal = selectedAuthenticationModalOpen ? (
<Dialog
open={selectedAuthenticationModalOpen}
@@ -857,6 +985,7 @@ const AppAuthTab = memo((props) => {
return (
<div style={{width: "100%", minHeight: 1100, maxHeight: 1700, overflowY: "auto", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin',boxSizing: 'border-box', padding: "27px 10px 19px 27px", height:"100%", backgroundColor: theme.palette.platformColor,borderTopRightRadius: '8px', borderBottomRightRadius: 8, borderLeft: theme.palette.defaultBorder, }}>
{appModal}
{cacheDistributionModal}
<div style={{ height: "100%", width: "calc(100% - 20px)", scrollbarColor: theme.palette.scrollbarColorTransparent, scrollbarWidth: 'thin'}}>
<div style={{ width: 'auto', display:'flex',}}>
<div style={{display: 'flex', flexDirection: 'column'}}>
@@ -1004,7 +1133,7 @@ const AppAuthTab = memo((props) => {
];
}
const isDistributed = data.suborg_distributed === true ? true : false;
const isDistributed = data?.suborg_distribution?.length > 0 || data?.suborg_distributed ? true : false;
var validIcon = <CheckCircleIcon style={{ color: "green" }} />
if (data.validation !== null && data.validation !== undefined && data.validation.valid === false) {
@@ -1260,7 +1389,23 @@ const AppAuthTab = memo((props) => {
style={{ }}
color="secondary"
onClick={() => {
changeDistribution(data, !isDistributed)
setShowDistributionPopup(true)
if(data?.suborg_distribution?.length > 0){
setSelectedSubOrg(data.suborg_distribution)
}else{
setSelectedSubOrg([])
}
setSelectedAuthId(data.id)
if (data?.suborg_distributed) {
const allSuborg = userdata?.orgs?.map((data, index) => {
if (data.creator_org !== userdata.active_org.id) {
return null;
}
return data.id;
})
setSelectedSubOrg(allSuborg.filter((data) => data !== null))
}
}}
/>
</Tooltip>
+8 -5
View File
@@ -33,7 +33,7 @@ const Branding = (props) => {
//const alert = useAlert();
const [publishingInfo, setPublishingInfo] = useState("");
const [publishRequirements, setPublishRequirements] = useState([])
const [currentSelectedTheme, setCurrentSelectedTheme] = useState("dark");
const [currentSelectedTheme, setCurrentSelectedTheme] = useState(themeMode);
const [integrationPartner, setIntegrationPartner] = useState(false);
const [changingTheme, setChangingTheme] = useState(false);
const theme = getTheme(themeMode, brandColor)
@@ -190,6 +190,13 @@ const Branding = (props) => {
})
};
useEffect(() => {
if (userdata && userdata?.active_org && userdata?.active_org?.branding?.theme?.length > 0) {
console.log("Setting current selected theme from userdata", userdata?.active_org?.branding?.theme);
setCurrentSelectedTheme(userdata?.active_org?.branding?.theme);
}
},[userdata]);
// Should enable / disable org branding
const handleChangePublishing = () => {
console.log("Handle change publishing");
@@ -247,10 +254,6 @@ const Branding = (props) => {
setCurrentSelectedTheme(userdata?.active_org?.branding.theme);
}
if (userdata.support) {
setCurrentSelectedTheme(localStorage.getItem("theme") || "dark");
}
if (
selectedOrganization &&
selectedOrganization?.branding?.brand_color &&
+9 -2
View File
@@ -213,9 +213,16 @@ const CacheView = memo((props) => {
const cache = {
key: dataValue.key,
value: value,
category: selectedCategory,
category: selectedCategory,
}
if (listCache.length > 0) {
const selectedCache = listCache.find((data) => data.key === dataValue.key);
if (selectedCache?.suborg_distribution?.length > 0) {
cache.suborg_distribution = selectedCache.suborg_distribution;
}
}
setCacheInput([cache]);
fetch(globalUrl + `/api/v1/orgs/${orgId}/set_cache`, {
@@ -805,7 +812,7 @@ const CacheView = memo((props) => {
}}
>
<AddIcon/>
Category (beta)
Category
</Button>
</Tooltip>
}
+3 -9
View File
@@ -212,13 +212,7 @@ const EditWorkflow = (props) => {
//minWidth: isMobile ? "90%" : newWorkflow === true ? 1000 : 550,
//maxWidth: isMobile ? "90%" : newWorkflow === true ? 1000 : 550,
borderRadius: theme.palette.DialogStyle.borderRadius,
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
'& .MuiDialogContent-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
'& .MuiDialogTitle-root': {
backgroundColor: theme?.palette?.DialogStyle?.backgroundColor,
},
backgroundColor: themeMode === "dark" ? "black" : theme?.palette?.DialogStyle?.backgroundColor,
},
}}
>
@@ -299,10 +293,10 @@ const EditWorkflow = (props) => {
right: 20,
bottom: 0,
zIndex: 1002,
backgroundColor: theme.palette.DialogStyle.backgroundColor,
height: 75,
paddingTop: 20,
paddingLeft: 30,
backgroundColor: themeMode === "dark" ? "#262626" : theme.palette.DialogStyle.backgroundColor,
}}>
<Button
variant="contained"
@@ -1292,7 +1286,7 @@ const EditWorkflow = (props) => {
{newWorkflow === true ?
<span style={{ paddingTop: 30, backgroundColor: theme.palette.DialogStyle.backgroundColor }}>
<span style={{ paddingTop: 30 }}>
<Typography variant="h6" style={{ marginLeft: 30, paddingBottom: 0, }}>
Relevant Workflows
</Typography>
+11 -5
View File
@@ -117,6 +117,14 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [setSearchBarModalOpen]);
useEffect(() => {
if (userdata && userdata?.active_org?.branding?.theme?.length > 0) {
setCurrentSelectedTheme(userdata?.active_org?.branding?.theme);
}else if (userdata && userdata?.theme?.length > 0) {
setCurrentSelectedTheme(userdata?.theme);
}
}, [userdata]);
const CustomPopper = (props) => {
return (
@@ -436,11 +444,7 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
toast("Failed updating org: ", responseJson.reason);
} else {
handleThemeChange(newTheme)
setCurrentSelectedTheme(newTheme);
}
}
})
)
.catch((error) => {
@@ -586,6 +590,8 @@ const LeftSideBar = ({ userdata, serverside, globalUrl, notifications, }) => {
if (newTheme === currentSelectedTheme) {
return;
}
handleThemeChange(newTheme)
setCurrentSelectedTheme(newTheme);
if (userdata?.org_status?.includes("integration_partner")){
handleChangeTheme(newTheme);
} else {
+60 -23
View File
@@ -3750,41 +3750,46 @@ const ParsedAction = (props) => {
boxShadow={2}
backgroundColor={theme.palette.textFieldStyle}
display="flex"
height={"100%"}
flexDirection="column"
>
<Box display="flex" alignItems="center" justifyContent="space-between">
<Typography variant="body1" style={{ flexGrow: 1 }}>
<Typography sx={{fontSize: "16px"}} style={{ flexGrow: 1 }}>
{tmpitem.charAt(0).toUpperCase() + tmpitem.slice(1)}
</Typography>
<IconButton size="small"
{/* <IconButton size="small"
onClick={() => {
setUiBox("closed")
}}
>
<CloseIcon fontSize="small" />
</IconButton>
</IconButton> */}
</Box>
<Divider sx={{ backgroundColor: theme.palette.surfaceColor, marginTop: "5px", marginBottom: "10px", height: "3px" }} />
<Divider sx={{ backgroundColor: theme.palette.surfaceColor, marginTop: "5px", marginBottom: "10px", height: "1px" }} />
<Box display="flex" flexDirection="column">
<Typography variant="body2" mb={0.5}>
<Typography sx={{fontSize: "14px"}} mb={0.5}>
<strong>Required:</strong> {data.required === true || data.configuration === true ? "True" : "False"}
</Typography>
<Typography variant="body2" mb={0.5}>
<strong>Description:</strong> {description}
</Typography>
<Typography variant="body2">
{
data.description !== undefined && data.description !== null && data.description.length > 0 ?
<Typography sx={{fontSize: "14px"}} mb={0.5}>
<strong>Description:</strong> {description}
</Typography>
: null
}
<Typography sx={{fontSize: "14px"}}>
<strong>Ex. :</strong> {data?.example?.length > 0 ? data.example : "No example available"}
</Typography>
{
data?.configuration === true ?
(
<Typography variant="body2" mt={0.5}>
<Typography sx={{fontSize: "14px"}} mt={0.5}>
<strong>Auth: </strong>Use "\$" instead of "$"
</Typography>
) : null
}
<div onClick={(e) => {
{/* <div onClick={(e) => {
e.preventDefault()
e.stopPropagation()
@@ -3794,7 +3799,7 @@ const ParsedAction = (props) => {
<Typography style={{ marginTop: 10, color: "#FF8544", cursor: "pointer", }} variant="body2">
Don't show again
</Typography>
</div>
</div> */}
</Box>
</Box>
);
@@ -4734,8 +4739,9 @@ const ParsedAction = (props) => {
{isFirstOptional ? <Divider style={{ backgroundColor: "rgba(255,255,255,0.1)", marginBottom: 20, }} /> : null}
{showButtonField === true ? hideBodyButtonValue : null}
<div
style={{ marginTop: 18, marginBottom: 0, display: "flex" }}
style={{ marginTop: 18, marginBottom: "4px", display: "flex", width: "100%", justifyContent: "space-between", alignItems: "center"}}
>
<div style={{display: "flex", alignItems: "center", justifyContent: "flex-start"}}>
{data.configuration === true ? (
<Tooltip
title={buttonTitle}
@@ -4794,28 +4800,59 @@ const ParsedAction = (props) => {
<StorageIcon style={{
color: "#FF8544",
marginRight: 10,
marginBottom: "-5px",
}} />
</a>
</Tooltip>
: null}
<div
style={{
flex: "10",
marginTop: "auto",
marginBottom: "auto",
color: theme.palette.textPrimary,
<Tooltip
title={tooltipDescription}
placement="left"
sx={{
zIndex: 0,
}}
PopperProps={{
sx: {
'& .MuiTooltip-tooltip': {
backgroundColor: 'transparent',
boxShadow: 'none',
},
'& .MuiTooltip-arrow': {
color: 'transparent',
},
},
modifiers: [
{
name: 'offset',
options: {
offset: (data?.configuration || showCacheConfig || hasAutocomplete) ? [0, 31] : [0,0]
},
},
],
}}
>
{tmpitem} <span style={{ color: theme.palette.main }}>{selectedActionParameters[count].required || selectedActionParameters[count].configuration ? "*" : ""}</span>
</div>
<Typography
sx={{
marginTop: "auto",
width: "fit-content",
cursor: "pointer",
color: theme.palette.textPrimary,
fontFamily: theme.typography.fontFamily,
"&:hover": {
color: theme.palette.main,
},
}}
>
{tmpitem} <span style={{ color: theme.palette.main }}>{selectedActionParameters[count].required || selectedActionParameters[count].configuration ? "*" : ""}</span>
</Typography>
</Tooltip>
{parentParamValue !== undefined && parentParamValue !== null && parentParamValue !== "" && parentParamValue !== data.value ?
<Tooltip title={`Parent value is different. Click to reset.`} placement="top" arrow>
<RestoreIcon
style={{
marginRight: 10,
marginBottom: 5,
cursor: "pointer",
color: theme.palette.distributionColor,
}}
@@ -4828,7 +4865,7 @@ const ParsedAction = (props) => {
/>
</Tooltip>
: null}
</div>
{((data.options !== undefined && data.options !== null && data.options.length > 0) || (selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0)) ? null :
<Tooltip title="Expand editor window" placement="top">
+6 -6
View File
@@ -76,7 +76,6 @@ const UserManagmentTab = memo((props) => {
const [ipSelected, setIpSelected] = React.useState("");
const [userLogViewing, setUserLogViewing] = React.useState({});
const { themeMode, supportEmail, brandColor } = useContext(Context);
const theme = getTheme(themeMode, brandColor);
@@ -1359,7 +1358,7 @@ const UserManagmentTab = memo((props) => {
}}
>
<ListItem style={{ width: "100%", padding: "10px 10px 10px 0px", verticalAlign: 'middle', borderBottom: theme.palette.defaultBorder, display: "table-row" }}>
{["Region", "Username", /*"API Key",*/ "Role", /*"Active",*/ "Type", "MFA", ...(selectedOrganization?.child_orgs?.length > 0 ? ["Suborgs"]: []), "Actions", "Last Login"].map((header, index) => (
{[...(isCloud ? ["Region"] : []), "Username", /*"API Key",*/ "Role", /*"Active",*/ "Type", "MFA", ...(selectedOrganization?.child_orgs?.length > 0 ? ["Suborgs"]: []), "Actions", "Last Login"].map((header, index) => (
<ListItemText
key={index}
primary={header}
@@ -1384,7 +1383,7 @@ const UserManagmentTab = memo((props) => {
backgroundColor: theme.palette.platformColor,
}}
>
{Array(9)
{Array(isCloud ? 7 : 6)
.fill()
.map((_, colIndex) => (
<ListItemText
@@ -1485,14 +1484,15 @@ const UserManagmentTab = memo((props) => {
return regionCode;
};
const userRegion = data?.user_geo_info?.country?.iso_code?.length > 0 ? data?.user_geo_info?.country?.iso_code : data?.active_org?.region_url?.length > 0 ? getRegionFlag(data?.active_org?.region_url) : "eu";
const userRegion = data?.user_geo_info?.country?.iso_code?.length > 0 ? data?.user_geo_info?.country?.iso_code : selectedOrganization?.region_url?.length > 0 ? getRegionFlag(selectedOrganization?.region_url) : "eu";
return (
<ListItem key={index} style={{ backgroundColor: bgColor, display: 'table-row', borderBottomLeftRadius: users?.length - 1 === index ? 8 : 0, borderBottomRightRadius: users?.length - 1 === index ? 8 : 0 }}>
<ListItemText
{isCloud ? (
<ListItemText
primary={(<img src={`https://flagcdn.com/48x36/${userRegion.toLowerCase()}.png`} alt={data?.user_geo_info?.country?.iso_code} style={{ marginRight: 30, width: 25, height: 23, }} />)}
style={{ display: 'table-cell', verticalAlign: 'middle', textAlign: 'center' }}
/>
/>) : null}
<ListItemText
primary={(
<Tooltip title={data.username || 'No username available'}>
+55 -7
View File
@@ -31,6 +31,13 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle
const [roleRequired, setRoleRequired] = React.useState(selectedOrganization?.sso_config?.role_required || false);
const [showOpenIdCred, setShowOpenIdCred] = React.useState(false);
const [showSamlCred, setShowSamlCred] = React.useState(false);
const [skipSSOForAdmin, setSkipSSOForAdmin] = React.useState(
selectedOrganization?.sso_config === undefined
? false
: selectedOrganization?.sso_config?.skip_sso_for_admins === undefined
? false
: selectedOrganization?.sso_config?.skip_sso_for_admins
);
const [ssoEntrypoint, setSsoEntrypoint] = React.useState(
selectedOrganization.sso_config === undefined
? ""
@@ -127,6 +134,10 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle
setRoleRequired(selectedOrganization?.sso_config?.role_required)
}
if (skipSSOForAdmin !== selectedOrganization?.sso_config?.skip_sso_for_admins) {
setSkipSSOForAdmin(selectedOrganization?.sso_config?.skip_sso_for_admins)
}
},[selectedOrganization])
const orgSaveButton = (
@@ -170,9 +181,14 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle
SSORequired: SSORequired,
auto_provision: autoPrivision,
role_required: roleRequired,
}
skip_sso_for_admins: skipSSOForAdmin,
},
undefined,
{},
"sso_config"
)
}
>
Save Changes
{/* <SaveIcon /> */}
@@ -206,12 +222,9 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle
openidAuthorization === "" &&
openidToken === ""
) {
if (!autoPrivision) {
toast.error(
"Please fill in fields for either OpenID connect or SSO before continuing. "
);
return;
}
toast.error(
"Please fill in fields for either OpenID connect or SSO before continuing. "
);
} else {
setAutoProvision((prev)=> !prev);
toast.info("Toggled Auto Provisioning. Remember to save.");
@@ -232,6 +245,12 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle
toast.info("Toggled Role Required. Remember to save.");
}
}
const handlechangeSkipSSOForAdmin = (event) => {
setSkipSSOForAdmin((prev) => !prev);
toast.info("Toggled Skip SSO for Admins. Remember to save.");
};
const HandleTestSSO = () => {
const url = `${globalUrl}/api/v1/orgs/${selectedOrganization?.id}/change`;
@@ -385,6 +404,35 @@ const SSOTab = ({selectedOrganization, userdata, isEditOrgTab, globalUrl, handle
</div>
</div>
{userdata && userdata?.active_org?.creator_org?.length > 0 ? null :
<div
style={{
display: "flex",
flexDirection: "column",
width: "100%",
justifyContent: 'flex-start',
marginTop: 30
}}
>
<Typography
variant="body2"
color="textSecondary"
style={{ marginTop: 5, marginBottom: 5, color: "rgba(158, 158, 158, 1)", fontSize: 16, fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", fontWeight: 400 }}
>
Skip SSO for Admins. When enabled, parent org admins will be able switch to the sub-organization without SSO.
</Typography>
<div>
<Switch
checked={skipSSOForAdmin}
onChange={handlechangeSkipSSOForAdmin}
sx={{marginBottom: 0.6, marginTop: 0.6}}
name="onOffSwitch"
color="primary"
title="Disable auto-provisioning of users in SSO"
/>
</div>
</div>
}
<div
style={{
+3 -1
View File
@@ -237,7 +237,8 @@ const Admin2 = (props) => {
defaults,
sso_config,
lead_info,
{ mfa_required } = {}
{ mfa_required } = {},
editing,
) => {
const data = {
name: name,
@@ -248,6 +249,7 @@ const Admin2 = (props) => {
sso_config: sso_config,
lead_info: lead_info,
mfa_required: mfa_required !== undefined ? mfa_required : selectedOrganization?.mfa_required,
editing: editing?.length > 0 ? editing : "",
};
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
+34 -7
View File
@@ -1973,7 +1973,7 @@ const AppCreator = (defaultprops) => {
// Saving the app that's been configured.
// Save SAVE app
const submitApp = () => {
toast("Uploading and building app " + name);
toast.info("Uploading and building app " + name + ". This may take a minute or two.");
setAppBuilding(true);
setErrorCode("");
@@ -2600,15 +2600,23 @@ const AppCreator = (defaultprops) => {
}
if (setExtraAuth.length > 0) {
const invalidfieldnames = ["apikey", "username", "password", "username_basic", "password_basic", "url", "access_token"]
for (let authkey in extraAuth) {
const curauth = extraAuth[authkey];
if (curauth.name.length === 0 || curauth.name.toLowerCase() == "url") {
toast("Can't add extra auth with empty name or Name URL");
setAppBuilding(false);
return;
}
// Additional comparisonchecks
if (authenticationOption !== "No authentication" && authenticationOption !== "") {
if (invalidfieldnames.includes(curauth.name.toLowerCase())) {
toast.warn("Skipping extra auth field: " + curauth.name + ". This is not valid.")
continue
}
}
data.components.securitySchemes[curauth.name] = {
type: "apiKey",
in: curauth.type,
@@ -2662,9 +2670,15 @@ const AppCreator = (defaultprops) => {
if (responseJson.reason !== undefined) {
setErrorCode(responseJson.reason);
toast.error("Failed to build: " + responseJson.reason, {
autoClose: 10000
})
if (responseJson.details !== undefined && responseJson.details !== null) {
toast.error("Failed to build - contact support@shuffler.io: " + responseJson.details, {
autoClose: 60000
})
} else {
toast.error("Failed to build: " + responseJson.reason, {
autoClose: 10000
})
}
}
} else {
toast.success("Successfully built openapi app! Added job to rebuild it in your hybrid runtime locations (Orborus).");
@@ -2678,7 +2692,7 @@ const AppCreator = (defaultprops) => {
.catch((error) => {
setAppBuilding(false);
setErrorCode(error.toString());
toast(error.toString());
toast.error(error.toString());
});
};
@@ -2810,10 +2824,21 @@ const AppCreator = (defaultprops) => {
margin="normal"
variant="outlined"
defaultValue={extraAuth[index].name}
helperText={
<Typography variant="caption" style={{ color: theme.palette.error.main, marginTop: 10, marginBottom: 10, }}>
{extraAuth[index]?.name?.toLowerCase() === "url"
|| extraAuth[index]?.name?.toLowerCase() === "apikey"
? `ERROR: Invalid key: ${extraAuth[index].name}. ` : ""}
</Typography>
}
onChange={(e) => {
extraAuth[index].name = e.target.value;
setExtraAuth(extraAuth);
}}
onBlur={(e) => {
// Forcerender
setUpdate(Math.random());
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
@@ -5865,7 +5890,9 @@ const AppCreator = (defaultprops) => {
</h2>
</Link>
<h2>
{name}{" "}
<Link to={props?.match?.params?.appid !== undefined && props?.match?.params?.appid !== null && props?.match?.params?.appid.length > 0 ? `/apps/${props?.match?.params?.appid}` : "/apps" } style={{ textDecoration: "none", color: theme.palette.text.primary }}>
{name}{" "}
</Link>
{actions === null ||
actions === undefined ||
actions.length === 0 ? null : (
+12 -12
View File
@@ -3121,12 +3121,12 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
style={{ marginBottom: 0, marginLeft: 0, marginRight: 0, minWidth: 800, maxWidth: 800, margin: "auto", }}
aria-label="disabled tabs example"
>
<Tab style={{marginLeft: 0, color: theme.palette.text.primary }} icon={<DescriptionIcon />} label="Docs" />
<Tab icon={appType === 0 || appType === 2 ? <OpenInNewIcon /> : <AppsIcon />} label={appType === 0 || appType === 2 ? "Explore the API" : "Try it out"} />
<Tab style={{marginLeft: 0, color: theme.palette.text.primary, textTransform: "none",}} icon={<DescriptionIcon />} label="Docs" />
<Tab style={{color: theme.palette.text.primary, textTransform: "none", }} icon={appType === 0 || appType === 2 ? <OpenInNewIcon /> : <AppsIcon />} label={appType === 0 || appType === 2 ? "Try the API" : "Try it out"} />
<Tab icon={<ShowChartIcon />} style={{color: theme.palette.text.primary}} label="Stats" />
<Tab icon={<PolylineIcon />} disabled style={{color: theme.palette.text.secondary}} label="Integrations" />
<Tab icon={<PersonIcon />} disabled={userdata.support !== true} style={{color: userdata.support !== true ? theme.palette.text.secondary: theme.palette.text.primary}} label="Creator" value={4} />
<Tab icon={<ShowChartIcon />} style={{color: theme.palette.text.primary, textTransform: "none", }} label="Stats & Downloads" />
<Tab icon={<PolylineIcon />} style={{color: theme.palette.text.primary, textTransform: "none", }} disabled style={{color: theme.palette.text.secondary}} label="Integrations" />
<Tab icon={<PersonIcon />} disabled={userdata.support !== true} style={{color: userdata.support !== true ? theme.palette.text.secondary: theme.palette.text.primary, textTransform: "none", }} label="Creator" value={4} />
</Tabs>
<div style={{ marginTop: 25 }}>
{selectedTab === 1 && app.skipped_build == false ? (
@@ -3135,8 +3135,8 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
<SelectedActionView action={currentAction} />
</div>
<div style={{ marginLeft: 25, maxWidth: 350 }}>
{currentAction.description !== undefined && currentAction.description !== null && currentAction.description !== "" ?
<div
{currentAction.description !== undefined && currentAction.description !== null && currentAction.description !== "" ?
<div
style={{
maxHeight: 175,
overflowX: "hidden",
@@ -3253,11 +3253,11 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
Use the App onprem (hybrid)
</Typography>
<Typography variant="body2" color="textSecondary" style={{marginTop: 5, }}>
Due to using docker containers with privately uploaded containers, we had to use a custom registry. Use the command below to download the image to the server if it fails to run.
Custom uses a custom Docker registry for private containers. Use the command below to download the app image to a server if it fails to do so automatically.
It will authenticate and authorize you, before redirecting to a Signed URL on https://storage.googleapis.com
The downloadable image may not be ready until 5 minutes after the app was built.
<b>&nbsp;Now also works for ARM containers!</b>
<b>&nbsp;Now also works for ARM containers (?arch=arm)!</b>
</Typography>
<div
@@ -4027,7 +4027,7 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
</IconButton>
) : null}
{selectedOrganization !== undefined && selectedOrganization !== null && selectedOrganization.id !== undefined && userdata.support === true ?
{selectedOrganization !== undefined && selectedOrganization !== null && selectedOrganization.id !== undefined ?
// Iconbutton for authentication with just an icon. Link to /apps/authentication?app_id=app.id
<IconButton
color="secondary"
@@ -4165,7 +4165,7 @@ const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)";
style={{ height: 40, marginTop: 5, marginLeft: 5, }}
>
<OpenInNewIcon style={{marginRight: 5, }}/>
Explore API
Try the API
</Button>
</a>
<Select
@@ -191,6 +191,7 @@ const SetAuthentication = (props) => {
appAuthentication={appAuthentication} />}
</Typography>
{/*
<Typography variant="h6" style={{ marginTop: 50, marginBottom: 20, }}>
What can they do with this?
</Typography>
@@ -217,6 +218,7 @@ const SetAuthentication = (props) => {
</div>
</div>
</Typography>
*/}
</div>
<>
<div style={{ height: 100, }}></div>