781 lines
33 KiB
React
781 lines
33 KiB
React
import React, { useEffect, useState, useContext } from "react";
|
|
import {
|
|
FormControl,
|
|
Card,
|
|
Tooltip,
|
|
Typography,
|
|
TextField,
|
|
Button,
|
|
Grid,
|
|
ListItem,
|
|
ListItemText,
|
|
ListItemAvatar,
|
|
IconButton,
|
|
Avatar,
|
|
Zoom,
|
|
InputAdornment,
|
|
Switch,
|
|
Skeleton
|
|
} from "@mui/material";
|
|
import { ToastContainer, toast } from "react-toastify";
|
|
import {
|
|
Edit as EditIcon,
|
|
Polyline as PolylineIcon,
|
|
CheckCircle as CheckCircleIcon,
|
|
Close as CloseIcon,
|
|
Visibility as VisibilityIcon,
|
|
VisibilityOff as VisibilityOffIcon,
|
|
} from "@mui/icons-material";
|
|
import theme from "../theme.jsx";
|
|
import { styled } from '@mui/styles';
|
|
import { Context } from "../context/ContextApi.jsx";
|
|
|
|
const CloudSyncTab = (props) => {
|
|
const {
|
|
userdata,
|
|
globalUrl,
|
|
serverside
|
|
} = props;
|
|
const [cloudSyncApikey, setCloudSyncApikey] = useState("");
|
|
const [loading, setLoading] = useState(false);
|
|
const [showApiKey, setShowApiKey] = useState(false);
|
|
const [orgSyncResponse, setOrgSyncResponse] = React.useState("");
|
|
const [organizationFeatures, setOrganizationFeatures] = React.useState({});
|
|
const [selectedOrganization, setSelectedOrganization] = React.useState({});
|
|
const [selectedStatus, setSelectedStatus] = React.useState([]);
|
|
const [orgRequest, setOrgRequest] = React.useState(true);
|
|
const [userSettings, setUserSettings] = React.useState({});
|
|
const [, forceUpdate] = React.useState();
|
|
const itemColor = "white";
|
|
const isCloud = window?.location?.host === "localhost:3002" || window?.location?.host === "shuffler.io";
|
|
useEffect(() => { getSettings(); }, []);
|
|
const GridItem = (props) => {
|
|
const [expanded, setExpanded] = React.useState(false);
|
|
const [showEdit, setShowEdit] = React.useState(false);
|
|
const [newValue, setNewValue] = React.useState(-100);
|
|
|
|
const primary = props.data.primary;
|
|
const secondary = props.data.secondary;
|
|
const primaryIcon = props.data.icon;
|
|
const secondaryIcon = props.data.active ?
|
|
<CheckCircleIcon style={{ color: "green" }} />
|
|
:
|
|
<CloseIcon style={{ color: "red" }} />
|
|
|
|
const submitFeatureEdit = (sync_features) => {
|
|
if (!userdata.support) {
|
|
console.log("User does not have support access and can't edit features");
|
|
return
|
|
}
|
|
|
|
sync_features.editing = true
|
|
const data = {
|
|
org_id: selectedOrganization.id,
|
|
sync_features: sync_features,
|
|
};
|
|
console.log("sync_features: ", sync_features);
|
|
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 enableFeature = () => {
|
|
console.log("Enabling " + primary)
|
|
|
|
console.log(selectedOrganization.sync_features)
|
|
// Check if primary is in sync_features
|
|
var tmpprimary = primary.replaceAll(" ", "_")
|
|
if (!(tmpprimary in selectedOrganization.sync_features)) {
|
|
console.log("Primary not in sync_features: " + tmpprimary)
|
|
return
|
|
}
|
|
|
|
if (props.data.active) {
|
|
selectedOrganization.sync_features[tmpprimary].active = false
|
|
} else {
|
|
selectedOrganization.sync_features[tmpprimary].active = true
|
|
}
|
|
|
|
setSelectedOrganization(selectedOrganization)
|
|
forceUpdate(Math.random())
|
|
submitFeatureEdit(selectedOrganization.sync_features)
|
|
}
|
|
|
|
const submitEdit = (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
// Check if primary is in sync_features
|
|
var tmpprimary = primary.replaceAll(" ", "_")
|
|
if (!(tmpprimary in selectedOrganization.sync_features)) {
|
|
console.log("Primary not in sync_features: " + tmpprimary)
|
|
return
|
|
}
|
|
|
|
// Make it into a number
|
|
var tmp = parseInt(newValue)
|
|
if (isNaN(tmp)) {
|
|
console.log("Not a number: " + newValue)
|
|
return
|
|
}
|
|
|
|
selectedOrganization.sync_features[tmpprimary].limit = tmp
|
|
|
|
setSelectedOrganization(selectedOrganization)
|
|
forceUpdate(Math.random())
|
|
submitFeatureEdit(selectedOrganization.sync_features)
|
|
}
|
|
const handleToggleFeature = (e) => {
|
|
// Your logic for toggling the feature's active state
|
|
console.log(`Toggling ${primary}`);
|
|
if (!isCloud || userdata.support !== true) {
|
|
return
|
|
}
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
enableFeature()
|
|
};
|
|
|
|
return (
|
|
<Grid
|
|
item
|
|
xs={4}
|
|
>
|
|
<div
|
|
style={{
|
|
margin: 4,
|
|
backgroundColor: "#1a1a1a",
|
|
borderRadius: 8,
|
|
color: "white",
|
|
minHeight: expanded ? 250 : "inherit",
|
|
maxHeight: expanded ? 300 : "inherit",
|
|
boxShadow: "none",
|
|
}}
|
|
>
|
|
<ListItem
|
|
style={{ cursor: "pointer", }}
|
|
onClick={() => {
|
|
setExpanded(prev => !prev);
|
|
if(showEdit){
|
|
setShowEdit(false)
|
|
}
|
|
}}
|
|
>
|
|
<ListItemAvatar>
|
|
<Avatar>{primaryIcon}</Avatar>
|
|
</ListItemAvatar>
|
|
<ListItemText
|
|
style={{ textTransform: "capitalize", color: "#F1F1F1", fontSize: 14, fontWeight: 400, }}
|
|
primary={primary}
|
|
/>
|
|
{isCloud && userdata.support === true ?
|
|
<Tooltip title="Edit features (support users only)">
|
|
<EditIcon
|
|
color="secondary"
|
|
style={{ marginRight: 10, cursor: "pointer", }}
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
console.log('expanded', expanded)
|
|
if (expanded){
|
|
setExpanded(false)
|
|
}
|
|
if (showEdit) {
|
|
setShowEdit(false)
|
|
return
|
|
}
|
|
|
|
console.log("Edit")
|
|
|
|
setShowEdit(true)
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
: null}
|
|
{userdata.support === true ?(
|
|
<Tooltip title={props.data.active ? 'Disable feature' : 'Enable feature'}>
|
|
<Switch
|
|
checked={props.data.active}
|
|
onChange={handleToggleFeature}
|
|
color="primary"
|
|
inputProps={{ 'aria-label': 'feature toggle' }}
|
|
sx={{
|
|
'& .MuiSwitch-switchBase.Mui-checked': {
|
|
color: '#FFFFFF',
|
|
},
|
|
'& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': {
|
|
backgroundColor: props.data.active ? '#2BC07E' : "#9e9e9e",
|
|
},
|
|
"& .MuiSwitch-track": {
|
|
backgroundColor: props.data.active ? '#2BC07E' : "#9e9e9e"
|
|
}
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
):(
|
|
<Tooltip title={props.data.active ? "Disable feature" : "Enable feature"}>
|
|
<span
|
|
style={{ cursor: "pointer", marginTop: 5, }}
|
|
onClick={(e) => {
|
|
if (!isCloud || userdata.support !== true) {
|
|
return
|
|
}
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
enableFeature()
|
|
}}
|
|
>
|
|
{secondaryIcon}
|
|
</span>
|
|
</Tooltip>
|
|
)}
|
|
|
|
</ListItem>
|
|
{expanded ?
|
|
<div style={{ padding: 15 }}>
|
|
<Typography>
|
|
<b>Usage: </b>
|
|
{props.data.limit === 0 ? (
|
|
"Unlimited"
|
|
) : (
|
|
<span>
|
|
{props.data.usage} / {props.data.limit === "" ? "Unlimited" : props.data.limit}
|
|
</span>
|
|
)}
|
|
</Typography>
|
|
{/*<Typography>
|
|
Data sharing: {props.data.data_collection}
|
|
</Typography>*/}
|
|
<Typography style={{ maxHeight: 150, overflowX: "hidden", overflowY: "auto" }}><b>Description:</b> {secondary}</Typography>
|
|
</div>
|
|
: null}
|
|
|
|
|
|
{showEdit ?
|
|
<FormControl fullWidth onSubmit={(e) => {
|
|
console.log("Submit")
|
|
submitEdit(e)
|
|
}}>
|
|
<span style={{ display: "flex",}}>
|
|
|
|
<TextField
|
|
style={{ flex: 3, }}
|
|
color="primary"
|
|
label={"Edit value"}
|
|
defaultValue={props.data.limit}
|
|
sx={{
|
|
marginTop: 0.5,
|
|
marginBottom: 0.5
|
|
}}
|
|
onChange={(event) => {
|
|
setNewValue(event.target.value)
|
|
}}
|
|
/>
|
|
<Button
|
|
style={{ flex: 1, }}
|
|
variant="contained"
|
|
disabled={newValue < -1}
|
|
onClick={(e) => {
|
|
console.log("Submit 2")
|
|
submitEdit(e)
|
|
}}
|
|
sx={{
|
|
marginTop: 0.5,
|
|
maarginBottom: 0.5
|
|
}}
|
|
>
|
|
Submit
|
|
</Button>
|
|
</span>
|
|
</FormControl>
|
|
: null}
|
|
</div>
|
|
</Grid>
|
|
);
|
|
};
|
|
const handleGetOrg = (orgId) => {
|
|
|
|
if (serverside !== true && window.location.search !== undefined && window.location.search !== null) {
|
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
|
const params = Object.fromEntries(urlSearchParams.entries());
|
|
const foundorgid = params["org_id"];
|
|
if (foundorgid !== undefined && foundorgid !== null) {
|
|
orgId = foundorgid;
|
|
}
|
|
}
|
|
|
|
if (orgId.length === 0) {
|
|
toast("Organization ID not defined. Please contact us on https://shuffler.io if this persists logout.");
|
|
return;
|
|
}
|
|
|
|
// Just use this one?
|
|
|
|
fetch(`${globalUrl}/api/v1/orgs/${orgId}`, {
|
|
method: "GET",
|
|
credentials: "include",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
})
|
|
.then((response) => {
|
|
if (response.status === 401) {
|
|
}
|
|
|
|
return response.json();
|
|
})
|
|
.then((responseJson) => {
|
|
if (responseJson["success"] === false) {
|
|
toast("Failed getting your org. If this persists, please contact support.");
|
|
} else {
|
|
if (
|
|
responseJson.sync_features === undefined ||
|
|
responseJson.sync_features === null
|
|
) {
|
|
responseJson.sync_features = {};
|
|
}
|
|
|
|
setSelectedOrganization(responseJson)
|
|
var lists = {
|
|
active: {
|
|
triggers: [],
|
|
features: [],
|
|
sync: [],
|
|
},
|
|
inactive: {
|
|
triggers: [],
|
|
features: [],
|
|
sync: [],
|
|
},
|
|
};
|
|
setOrganizationFeatures(lists);
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
console.log("Error getting org: ", error);
|
|
toast("Error getting current organization");
|
|
});
|
|
};
|
|
const handleStopOrgSync = (org_id) => {
|
|
if (org_id === undefined || org_id === null) {
|
|
toast("Couldn't get org " + org_id);
|
|
return;
|
|
}
|
|
|
|
const data = {};
|
|
|
|
const url = globalUrl + "/api/v1/orgs/" + org_id + "/stop_sync";
|
|
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) => {
|
|
if (response.status === 200) {
|
|
console.log("Cloud sync success?");
|
|
toast("Successfully stopped cloud sync");
|
|
} else {
|
|
console.log("Cloud sync fail?");
|
|
toast(
|
|
"Failed stopping sync. Try again, and contact support if this persists."
|
|
);
|
|
}
|
|
|
|
return response.json();
|
|
})
|
|
.then((responseJson) => {
|
|
setTimeout(() => {
|
|
handleGetOrg(org_id);
|
|
}, 1000);
|
|
})
|
|
.catch((error) => {
|
|
toast("Err: " + error.toString());
|
|
});
|
|
};
|
|
|
|
const enableCloudSync = (apikey, organization, disableSync) => {
|
|
setOrgSyncResponse("");
|
|
|
|
const data = {
|
|
apikey: apikey,
|
|
organization: organization,
|
|
disable: disableSync,
|
|
};
|
|
|
|
const url = globalUrl + "/api/v1/cloud/setup";
|
|
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) => {
|
|
setLoading(false);
|
|
if (response.status === 200) {
|
|
console.log("Cloud sync success?");
|
|
} else {
|
|
console.log("Cloud sync fail?");
|
|
}
|
|
|
|
return response.json();
|
|
//setTimeout(() => {
|
|
//}, 1000)
|
|
})
|
|
.then((responseJson) => {
|
|
console.log("RESP: ", responseJson);
|
|
if (
|
|
responseJson.success === false &&
|
|
responseJson.reason !== undefined
|
|
) {
|
|
setOrgSyncResponse(responseJson.reason);
|
|
toast("Failed to handle sync: " + responseJson.reason);
|
|
} else if (!responseJson.success) {
|
|
toast("Failed to handle sync.");
|
|
} else {
|
|
//getOrgs(); API no longer in use, as it's in handleInfo request
|
|
if (disableSync) {
|
|
toast("Successfully disabled sync!");
|
|
setOrgSyncResponse("Successfully disabled syncronization");
|
|
} else {
|
|
toast("Cloud Syncronization successfully set up!");
|
|
setOrgSyncResponse(
|
|
"Successfully started syncronization. Cloud features you now have access to can be seen below."
|
|
);
|
|
}
|
|
|
|
selectedOrganization.cloud_sync = !selectedOrganization.cloud_sync;
|
|
setSelectedOrganization(selectedOrganization);
|
|
setCloudSyncApikey("");
|
|
|
|
handleGetOrg(userdata.active_org.id);
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
setLoading(false);
|
|
toast("Err: " + error.toString());
|
|
});
|
|
};
|
|
const getSettings = () => {
|
|
fetch(globalUrl + "/api/v1/getsettings", {
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
},
|
|
credentials: "include",
|
|
})
|
|
.then((response) => {
|
|
if (response.status !== 200) {
|
|
console.log("Status not 200 when getting settings :O!");
|
|
}
|
|
|
|
return response.json();
|
|
})
|
|
.then((responseJson) => {
|
|
setUserSettings(responseJson);
|
|
})
|
|
.catch((error) => {
|
|
console.log(error);
|
|
});
|
|
};
|
|
if (
|
|
selectedOrganization.id === undefined &&
|
|
userdata !== undefined &&
|
|
userdata.active_org !== undefined &&
|
|
orgRequest === true
|
|
) {
|
|
setOrgRequest(false);
|
|
handleGetOrg(userdata.active_org.id);
|
|
}
|
|
|
|
return (
|
|
<div style={{padding: "27px 10px 19px 27px",}}>
|
|
<div style={{ marginBottom: 20 }}>
|
|
<h2
|
|
style={{ marginBottom: 8, marginTop: 0, color: "#ffffff" }}
|
|
>
|
|
Cloud syncronization
|
|
</h2>
|
|
<span style={{ color: "#C8C8C8", fontSize: 16, fontWeight: 400, }}>
|
|
What does <a href="/docs/organizations#cloud_sync" target="_blank" rel="noopener noreferrer" style={{ color: "rgba(255, 132, 68, 1)", fontSize: 16, textDecoration: 'none', }}>cloud sync</a> do? Cloud synchronization is a way of getting more out of Shuffle. Shuffle will ALWAYS make every option open source, but features relying on other users can't be done without a collaborative approach.
|
|
</span>
|
|
</div>
|
|
|
|
{isCloud ? (
|
|
<div style={{ marginTop: 15, display: "flex" }}>
|
|
<div style={{ flex: 1 }}>
|
|
<Typography style={{fontWeight: 400, fontSize: 16, color: "#F1F1F1"}}>
|
|
Currently syncronizing:{" "}
|
|
{selectedOrganization.cloud_sync_active === true
|
|
? <span style={{ color: "#4CFD72", fontSize: 16, marginLeft: 16}}>True</span>
|
|
: <span style={{ color: "#FD4C62", fontSize: 16, marginLeft: 16 }}>False</span>}
|
|
</Typography>
|
|
{selectedOrganization.cloud_sync_active ? (
|
|
<Typography style={{}}>
|
|
Syncronization interval:{" "}
|
|
{selectedOrganization.sync_config.interval === 0
|
|
? "60"
|
|
: selectedOrganization.sync_config.interval}
|
|
</Typography>
|
|
) : null}
|
|
<Typography
|
|
style={{
|
|
whiteSpace: "nowrap",
|
|
marginTop: 25,
|
|
marginRight: 10,
|
|
fontSize: 16,
|
|
fontWeight: 400,
|
|
fontFamily: theme.typography.fontFamily,
|
|
}}
|
|
>
|
|
Your Api key
|
|
</Typography>
|
|
{userSettings?.apikey === undefined || userSettings?.apikey === null || userSettings?.apikey?.length <=0 ? (
|
|
<Skeleton variant="rectangular" animation="wave" sx={{backgroundColor: '#212121', border: '1px solid #646464', width: 500, height: 50, marginTop: 2 }}/>
|
|
):
|
|
<div style={{ display: "flex" }}>
|
|
<TextField
|
|
color="primary"
|
|
style={{
|
|
backgroundColor: theme.palette.inputColor,
|
|
maxWidth: 500,
|
|
height: 35
|
|
}}
|
|
InputProps={{
|
|
sx: {
|
|
height: "35px",
|
|
color: "white",
|
|
fontSize: "1em",
|
|
backgroundColor: '#212121',
|
|
},
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton
|
|
aria-label="toggle password visibility"
|
|
onClick={() => {
|
|
setShowApiKey(!showApiKey)
|
|
}}
|
|
>
|
|
{showApiKey ? <VisibilityIcon /> : <VisibilityOffIcon />}
|
|
</IconButton>
|
|
</InputAdornment>
|
|
)
|
|
}}
|
|
required
|
|
fullWidth={true}
|
|
disabled={true}
|
|
autoComplete="cloud apikey"
|
|
id="apikey_field"
|
|
margin="normal"
|
|
placeholder="Cloud Apikey"
|
|
variant="outlined"
|
|
value={userSettings?.apikey}
|
|
defaultValue={userSettings?.apikey}
|
|
type={!isCloud || showApiKey ? "text" : "password"}
|
|
/>
|
|
{selectedOrganization.cloud_sync_active ? (
|
|
<Button
|
|
style={{
|
|
width: 150,
|
|
height: 50,
|
|
marginLeft: 10,
|
|
marginTop: 17,
|
|
}}
|
|
variant={
|
|
selectedOrganization.cloud_sync_active === true
|
|
? "outlined"
|
|
: "contained"
|
|
}
|
|
color="primary"
|
|
onClick={() => {
|
|
handleStopOrgSync(selectedOrganization.id);
|
|
}}
|
|
>
|
|
Stop Sync
|
|
</Button>
|
|
) : null}
|
|
</div>}
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div>
|
|
<div style={{ display: "flex", marginBottom: 20 }}>
|
|
<TextField
|
|
color="primary"
|
|
style={{
|
|
backgroundColor: "#1a1a1a",
|
|
marginRight: 10,
|
|
height: 35,
|
|
}}
|
|
InputProps={{
|
|
style: {
|
|
height: "35px",
|
|
color: "white",
|
|
fontSize: "1em",
|
|
},
|
|
}}
|
|
required
|
|
fullWidth={true}
|
|
disabled={selectedOrganization.cloud_sync}
|
|
autoComplete="cloud apikey"
|
|
id="apikey_field"
|
|
margin="normal"
|
|
placeholder="Cloud Apikey"
|
|
variant="outlined"
|
|
onChange={(event) => {
|
|
setCloudSyncApikey(event.target.value);
|
|
}}
|
|
/>
|
|
<Button
|
|
disabled={
|
|
(!selectedOrganization.cloud_sync &&
|
|
cloudSyncApikey.length === 0) ||
|
|
loading
|
|
}
|
|
style={{ marginTop: 15, height: 35, width: 150, textTransform: 'none', fontSize: 16, color: (!selectedOrganization.cloud_sync &&
|
|
cloudSyncApikey.length === 0) ||
|
|
loading ? null : "#1a1a1a", backgroundColor: (!selectedOrganization.cloud_sync &&
|
|
cloudSyncApikey.length === 0) ||
|
|
loading? null : "#FF8544" }}
|
|
onClick={() => {
|
|
setLoading(true);
|
|
enableCloudSync(
|
|
cloudSyncApikey,
|
|
selectedOrganization,
|
|
selectedOrganization.cloud_sync
|
|
);
|
|
}}
|
|
color="primary"
|
|
variant={
|
|
selectedOrganization.cloud_sync === true
|
|
? "outlined"
|
|
: "contained"
|
|
}
|
|
>
|
|
{selectedOrganization.cloud_sync
|
|
? "Stop sync"
|
|
: "Start sync"}
|
|
</Button>
|
|
</div>
|
|
{orgSyncResponse.length > 0 ? (
|
|
<Typography style={{ marginTop: 5, marginBottom: 10 }}>
|
|
Message from Shuffle Cloud: <b>{orgSyncResponse}</b>
|
|
</Typography>
|
|
) : null}
|
|
</div>
|
|
)}
|
|
|
|
<h2 style={{ marginLeft: 5, marginTop: 40, marginBottom: 5 }}>
|
|
Features
|
|
</h2>
|
|
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 24, fontSize: 16, fontWeight: 400, marginLeft: 5, color: "#C8C8C8" }}>
|
|
Features and Limitations that are currently available to you in your Cloud or Hybrid Organization. App Executions (App Runs) reset monthly. If the organization is a customer or in a trial, these features limitations are not always enforced. </Typography>
|
|
<Grid container style={{ width: "100%", marginBottom: 15, }}>
|
|
|
|
{selectedOrganization.sync_features === undefined ||
|
|
selectedOrganization.sync_features === null
|
|
? <Grid container spacing={2} justifyContent="center">
|
|
{[...Array(18)].map((_, i) => (
|
|
<Grid item xs={12} sm={6} md={4} key={i}>
|
|
<div
|
|
style={{
|
|
margin: 4,
|
|
borderRadius: 8,
|
|
minHeight: "inherit",
|
|
maxHeight: "inherit",
|
|
boxShadow: "none",
|
|
display: 'flex',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
<Skeleton
|
|
variant="rectangular"
|
|
height={50}
|
|
width={343}
|
|
sx={{ backgroundColor: '#1a1a1a', display: 'flex', borderRadius: 1 }}
|
|
animation="wave"
|
|
/>
|
|
</div>
|
|
</Grid>
|
|
))}
|
|
</Grid>
|
|
: Object.keys(selectedOrganization.sync_features).map(function (
|
|
key,
|
|
index
|
|
) {
|
|
|
|
if (key === "schedule" || key === "apps" || key === "updates" || key === "editing") {
|
|
return null;
|
|
}
|
|
|
|
const item = selectedOrganization.sync_features[key];
|
|
if (item === null) {
|
|
return null
|
|
}
|
|
|
|
const newkey = key.replaceAll("_", " ");
|
|
const griditem = {
|
|
primary: newkey,
|
|
secondary:
|
|
item.description === undefined ||
|
|
item.description === null ||
|
|
item.description.length === 0
|
|
? "Not defined yet"
|
|
: item.description,
|
|
limit: item.limit,
|
|
usage: item.usage === undefined ||
|
|
item.usage === null ? 0 : item.usage,
|
|
data_collection: "None",
|
|
active: item.active,
|
|
icon: <PolylineIcon style={{ color: "#1a1a1a" }} />,
|
|
};
|
|
|
|
return (
|
|
<Zoom key={index}>
|
|
<GridItem data={griditem} />
|
|
</Zoom>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CloudSyncTab;
|