Fixed the merge issue
This commit is contained in:
@@ -24,9 +24,12 @@ import {
|
||||
Chip,
|
||||
Checkbox,
|
||||
Tooltip,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
LinearProgress
|
||||
} from "@mui/material";
|
||||
|
||||
import { useNavigate, Link } from "react-router-dom";
|
||||
import { useNavigate, Link, json } from "react-router-dom";
|
||||
import { Autocomplete } from "@mui/material";
|
||||
import { toast } from "react-toastify"
|
||||
|
||||
@@ -35,12 +38,15 @@ import {
|
||||
ContentCopy as ContentCopyIcon,
|
||||
Draw as DrawIcon,
|
||||
Close as CloseIcon,
|
||||
Delete,
|
||||
RestaurantRounded,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
//import { useAlert
|
||||
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
|
||||
import BillingStats from "../components/BillingStats.jsx";
|
||||
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
|
||||
const Billing = (props) => {
|
||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, clickedFromOrgTab } = props;
|
||||
@@ -58,6 +64,56 @@ const Billing = (props) => {
|
||||
const [dealValue, setDealValue] = React.useState("");
|
||||
const [dealDiscount, setDealDiscount] = React.useState("");
|
||||
const [dealerror, setDealerror] = React.useState("");
|
||||
const [openChangeEmailBox, setOpenChangeEmailBox] = useState(false);
|
||||
const [isMouseOverOnChangeEmail, setIsMouseOverOnChangeEmail] = useState(false);
|
||||
const [currentAppRunsInPercentage, setCurrentAppRunsInPercentage] = useState(0);
|
||||
const [currentAppRunsInNumber, setCurrentAppRunsInNumber] = useState(0);
|
||||
const [alertThresholds, setAlertThresholds] = useState(selectedOrganization.Billing !== undefined && selectedOrganization.Billing.AlertThreshold !== undefined && selectedOrganization.Billing.AlertThreshold !== null ? selectedOrganization.Billing.AlertThreshold : [{ percentage: '', count: '', Email_send: false }]);
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (userdata.app_execution_limit !== undefined && userdata.app_execution_usage !== undefined) {
|
||||
const percentage = (userdata.app_execution_usage / userdata.app_execution_limit) * 100;
|
||||
setCurrentAppRunsInPercentage(Math.round(percentage));
|
||||
setCurrentAppRunsInNumber(userdata.app_execution_limit - userdata.app_execution_usage);
|
||||
}
|
||||
}, [userdata]);
|
||||
|
||||
|
||||
const [BillingEmail, setBillingEmail] = useState(selectedOrganization.Billing !== undefined && selectedOrganization.Billing.Email !== undefined && selectedOrganization.Billing.Email != null && selectedOrganization.Billing.Email.length > 0 ? selectedOrganization.Billing.Email : selectedOrganization.org);
|
||||
|
||||
useState(() => {
|
||||
// Set the billing email
|
||||
setBillingEmail(
|
||||
selectedOrganization.Billing !== undefined &&
|
||||
selectedOrganization.Billing.Email !== undefined &&
|
||||
selectedOrganization.Billing.Email.length > 0
|
||||
? selectedOrganization.Billing.Email
|
||||
: selectedOrganization.org
|
||||
);
|
||||
|
||||
// Set and sort the alert thresholds
|
||||
const alertThresholds = selectedOrganization.Billing !== undefined &&
|
||||
selectedOrganization.Billing.AlertThreshold !== undefined &&
|
||||
selectedOrganization.Billing.AlertThreshold !== null
|
||||
? selectedOrganization.Billing.AlertThreshold
|
||||
: [{ percentage: '', count: '', Email_send: false }];
|
||||
|
||||
const sortedAlertThresholds = alertThresholds.sort((a, b) => {
|
||||
const countA = parseFloat(a.count);
|
||||
const countB = parseFloat(b.count);
|
||||
if (isNaN(countA)) return 1;
|
||||
if (isNaN(countB)) return -1;
|
||||
|
||||
return countA - countB;
|
||||
});
|
||||
|
||||
setAlertThresholds(sortedAlertThresholds);
|
||||
|
||||
const findCurrentIndex = sortedAlertThresholds.some(threshold => threshold.Email_send === false);
|
||||
setCurrentIndex(findCurrentIndex ? sortedAlertThresholds.findIndex(threshold => threshold.Email_send === false) : - 1);
|
||||
|
||||
}, [selectedOrganization]);
|
||||
|
||||
const stripe = typeof window === 'undefined' || window.location === undefined ? "" : props.stripeKey === undefined ? "" : window.Stripe ? window.Stripe(props.stripeKey) : ""
|
||||
const products = [
|
||||
@@ -238,6 +294,7 @@ const Billing = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const sendSignatureRequest = (subscription) => {
|
||||
const url = `${globalUrl}/api/v1/orgs/${selectedOrganization.id}`;
|
||||
|
||||
@@ -275,6 +332,7 @@ const Billing = (props) => {
|
||||
const [signatureOpen, setSignatureOpen] = React.useState(false);
|
||||
const [tosChecked, setTosChecked] = React.useState(subscription.eula_signed)
|
||||
const [hovered, setHovered] = React.useState(false)
|
||||
const [newBillingEmail, setNewBillingEmail] = useState('');
|
||||
|
||||
var top_text = "Base Cloud Access"
|
||||
if (subscription.limit === undefined && subscription.level === undefined || subscription.level === null || subscription.level === 0) {
|
||||
@@ -327,6 +385,78 @@ const Billing = (props) => {
|
||||
newPaperstyle.backgroundColor = theme.palette.surfaceColor
|
||||
}
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpenChangeEmailBox(true);
|
||||
};
|
||||
|
||||
const handleCloseChangeEmailBox = () => {
|
||||
setOpenChangeEmailBox(false);
|
||||
};
|
||||
|
||||
|
||||
const getCircularReplacer = () => {
|
||||
const seen = new WeakSet();
|
||||
return (key, value) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (seen.has(value)) {
|
||||
return;
|
||||
}
|
||||
seen.add(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
const HandleChangeBillingEmail = (orgId) => {
|
||||
const email = newBillingEmail;
|
||||
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
|
||||
console.log("Pattern matches: ", emailPattern.test(email));
|
||||
if (!emailPattern.test(email)) {
|
||||
toast("Please enter a valid email address");
|
||||
return;
|
||||
} else {
|
||||
setNewBillingEmail(email);
|
||||
}
|
||||
|
||||
toast("Updating billing email. Please Wait")
|
||||
|
||||
const data = {
|
||||
org_id: orgId,
|
||||
email: newBillingEmail,
|
||||
billing: {
|
||||
email: newBillingEmail,
|
||||
},
|
||||
};
|
||||
|
||||
const url = `${globalUrl}/api/v1/orgs/${orgId}/billing`;
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Bad status code in get org:", response.status);
|
||||
}
|
||||
return response.json();
|
||||
}).then((responseJson) => {
|
||||
console.log("Got org:", responseJson);
|
||||
if (responseJson.success === true) {
|
||||
toast.success("Successfully updated billing email");
|
||||
setBillingEmail(newBillingEmail);
|
||||
setOpenChangeEmailBox(false);
|
||||
} else {
|
||||
toast.error("Failed to update billing email. Please try again.");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Error getting org:", error);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
style={newPaperstyle}
|
||||
@@ -587,7 +717,79 @@ const Billing = (props) => {
|
||||
`You are not subscribed to any plan and are using the free plan with max 10,000 app runs per month. Upgrade to deactivate this limit.`
|
||||
}
|
||||
</Typography>
|
||||
Billing email: {selectedOrganization.org}
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Typography variant="body2" style={{}}>
|
||||
Billing email: {BillingEmail}
|
||||
</Typography>
|
||||
{userdata.has_card_available === true && (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleClickOpen}
|
||||
onMouseOver={() => setIsMouseOverOnChangeEmail(true)}
|
||||
onMouseOut={() => setIsMouseOverOnChangeEmail(false)}
|
||||
style={{
|
||||
width: 'auto',
|
||||
height: 20,
|
||||
textTransform: 'none',
|
||||
marginLeft: 'auto',
|
||||
backgroundColor: 'transparent',
|
||||
color: '#f86743',
|
||||
boxShadow: 'none',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
transition: 'background-color 0.3s, color 0.3s'
|
||||
}}
|
||||
>
|
||||
Change
|
||||
</Button>
|
||||
)}
|
||||
<Dialog
|
||||
open={openChangeEmailBox}
|
||||
onClose={handleCloseChangeEmailBox}
|
||||
PaperProps={{
|
||||
style: {
|
||||
padding: '20px',
|
||||
borderRadius: '8px',
|
||||
maxWidth: '500px',
|
||||
width: '100%'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogTitle style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Change Billing Email</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText style={{ marginBottom: '20px' }}>
|
||||
Enter the new billing email address.
|
||||
</DialogContentText>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="email"
|
||||
label="New Billing Email"
|
||||
type="email"
|
||||
fullWidth
|
||||
value={newBillingEmail}
|
||||
onKeyPress={(event) => { if (event.key === 'Enter') HandleChangeBillingEmail(selectedOrganization.id) }}
|
||||
onChange={(e) => setNewBillingEmail(e.target.value)}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={handleCloseChangeEmailBox}
|
||||
color="primary"
|
||||
style={{ textTransform: 'none', marginRight: '10px' }}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
style={{ textTransform: 'none' }}
|
||||
onClick={(event) => HandleChangeBillingEmail(selectedOrganization.id)}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
{/*isCloud ?
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -617,7 +819,7 @@ const Billing = (props) => {
|
||||
}}
|
||||
onClick={() => {
|
||||
if (isCloud) {
|
||||
handlePayasyougo(userdata)
|
||||
handlePayasyougo(userdata, selectedOrganization, BillingEmail)
|
||||
//navigate("/pricing?tab=cloud&highlight=true")
|
||||
} else {
|
||||
//window.open("https://shuffler.io/pricing?tab=onprem&highlight=true", "_blank")
|
||||
@@ -967,6 +1169,130 @@ const Billing = (props) => {
|
||||
toast("Failed adding deal reg: ", error);
|
||||
});
|
||||
};
|
||||
const addAlertThreshold = () => {
|
||||
setAlertThresholds([...alertThresholds, { percentage: '', count: '', Email_send: false }]);
|
||||
};
|
||||
|
||||
const updateAlertThreshold = (index, field, value) => {
|
||||
|
||||
if (field === 'percentage') {
|
||||
if (value > 100 || value < 0) {
|
||||
value = 0
|
||||
toast("The percentage value should be between 0 and 100")
|
||||
}
|
||||
} else if (field === 'count') {
|
||||
if (value < 0 || value >= userdata.app_execution_limit) {
|
||||
value = 0
|
||||
toast("The count value should be greater than 0 and less than the total app execution limit")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const totalValue = userdata.app_execution_limit;
|
||||
const newAlertThresholds = alertThresholds.map((threshold, i) => {
|
||||
if (i === index) {
|
||||
const newValue = parseFloat(value);
|
||||
if (field === 'percentage') {
|
||||
const newCount = (newValue / 100) * totalValue;
|
||||
return {
|
||||
...threshold,
|
||||
percentage: isNaN(newValue) ? '' : Math.round(newValue),
|
||||
count: isNaN(newCount) ? '' : Math.round(newCount),
|
||||
Email_send: false
|
||||
};
|
||||
} else if (field === 'count') {
|
||||
const newPercentage = (newValue / totalValue) * 100;
|
||||
return {
|
||||
...threshold,
|
||||
count: newValue,
|
||||
percentage: isNaN(newPercentage) ? '' : Math.round(newPercentage),
|
||||
Email_send: false
|
||||
};
|
||||
}
|
||||
}
|
||||
return threshold;
|
||||
});
|
||||
setAlertThresholds(newAlertThresholds);
|
||||
};
|
||||
|
||||
|
||||
const handleDeleteAlertThreshold = (index) => {
|
||||
const newAlertThresholds = alertThresholds.filter((_, i) => i !== index);
|
||||
setAlertThresholds(newAlertThresholds);
|
||||
|
||||
// Update currentIndex based on remaining elements
|
||||
const findCurrentIndex = newAlertThresholds.some(threshold => threshold.Email_send === false);
|
||||
setCurrentIndex(findCurrentIndex ? newAlertThresholds.findIndex(threshold => threshold.Email_send === false) : - 1);
|
||||
};
|
||||
|
||||
const HandleEditOrgForAlertThreshold = (orgId) => {
|
||||
|
||||
// Use the `some` method to check for invalid counts
|
||||
const invalidCount = alertThresholds.some((threshold) => {
|
||||
if (threshold.count === '') {
|
||||
toast("Please enter a valid Count or Percentage value");
|
||||
return true; // Stop checking further and return true if invalid
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// If any invalid count is found, return early
|
||||
if (invalidCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
toast("Updating Email Alert Threshold. Please wait...");
|
||||
|
||||
const data = {
|
||||
org_id: orgId,
|
||||
billing: {
|
||||
email: BillingEmail,
|
||||
AlertThreshold: alertThresholds.map(threshold => ({
|
||||
...threshold,
|
||||
percentage: parseInt(threshold.percentage, 10),
|
||||
count: parseInt(threshold.count, 10),
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
const url = `${globalUrl}/api/v1/orgs/${orgId}`;
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Bad status code in get org:", response.status);
|
||||
}
|
||||
return response.json();
|
||||
}).then((responseJson) => {
|
||||
console.log("Got org:", responseJson);
|
||||
if (responseJson.success === true) {
|
||||
toast.success("Successfully updated Email Alert Thresholds");
|
||||
const findCurrentIndex = alertThresholds.some(threshold => threshold.Email_send === false);
|
||||
setCurrentIndex(findCurrentIndex ? alertThresholds.findIndex(threshold => threshold.Email_send === false) : - 1);
|
||||
} else {
|
||||
toast.error("Failed to update Email Alert Thresholds. Please try again.");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Error getting org:", error);
|
||||
});
|
||||
};
|
||||
|
||||
const getSafeValue = (value) => {
|
||||
|
||||
if (value === undefined || value === null || isNaN(value)) {
|
||||
return 0;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const isChildOrg = userdata.active_org.creator_org !== "" && userdata.active_org.creator_org !== undefined && userdata.active_org.creator_org !== null
|
||||
return (
|
||||
@@ -1009,8 +1335,6 @@ const Billing = (props) => {
|
||||
<a href={"https://github.com/Shuffle/Shuffle-docs/tree/master/handbook/Sales"} target="_blank" rel="noopener noreferrer" style={{ textDecoration: "none", color: "#f85a3e" }}>
|
||||
Sales Process
|
||||
</a>
|
||||
|
||||
|
||||
</div>
|
||||
:
|
||||
null
|
||||
@@ -1333,9 +1657,144 @@ const Billing = (props) => {
|
||||
|
||||
</div>
|
||||
) : null*/}
|
||||
<div style={{ marginTop: 100, }}>
|
||||
<div style={{ marginTop: 50, marginLeft: 10 }}>
|
||||
<Typography
|
||||
style={{ marginTop: 40, marginLeft: 10, marginBottom: 5 }}
|
||||
style={{ marginTop: 40, marginBottom: 5 }}
|
||||
variant="h4"
|
||||
>
|
||||
Manage Billing
|
||||
</Typography>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 0, marginBottom: 10 }}>
|
||||
Manage your billing and licensing information below. When you reach the certain thresholds of your subscription limit, you will be notified by email.
|
||||
</Typography>
|
||||
<Typography variant="body1">Current Usage:</Typography>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={currentAppRunsInPercentage}
|
||||
style={{
|
||||
width: "50%",
|
||||
height: 15,
|
||||
borderRadius: 10,
|
||||
margin: '10px 0',
|
||||
marginBottom: 10,
|
||||
}}
|
||||
/>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
You have used <strong>{currentAppRunsInPercentage}%</strong> of total app execution limit or <strong>{userdata.app_execution_usage}</strong> app runs out of <strong>{userdata.app_execution_limit}</strong> app runs.
|
||||
</Typography>
|
||||
|
||||
<div>
|
||||
<Typography variant="body1" style={{ marginTop: 20 }}>
|
||||
Set email alert thresholds for app runs
|
||||
</Typography>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 10 }}>
|
||||
You will be notified by email when you reach the
|
||||
{currentIndex !== -1
|
||||
? " " + getSafeValue(alertThresholds[currentIndex].percentage) + '%' + " "
|
||||
: " " + '0%' + " "
|
||||
}
|
||||
of your total app execution limit or
|
||||
{currentIndex !== -1
|
||||
? " " + getSafeValue(alertThresholds[currentIndex].count) + " "
|
||||
: " " + 0 + " "}
|
||||
app runs.
|
||||
</Typography>
|
||||
|
||||
<div style={{ marginTop: 15 }}>
|
||||
{alertThresholds.map((threshold, index) => (
|
||||
<div key={index} style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<TextField
|
||||
style={{
|
||||
marginTop: 10,
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
width: 250,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
height: 50,
|
||||
color: 'white',
|
||||
},
|
||||
endAdornment: '%',
|
||||
}}
|
||||
color="primary"
|
||||
fullWidth
|
||||
label="Alert threshold (%)"
|
||||
type="number"
|
||||
value={threshold.percentage}
|
||||
onChange={(e) => updateAlertThreshold(index, 'percentage', e.target.value)}
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
inputProps={{
|
||||
max: 100,
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
style={{
|
||||
marginTop: 10,
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
width: 250,
|
||||
marginLeft: 15,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
height: 50,
|
||||
color: 'white',
|
||||
},
|
||||
}}
|
||||
color="primary"
|
||||
fullWidth
|
||||
label="Alert threshold (count)"
|
||||
type="number"
|
||||
value={threshold.count}
|
||||
onChange={(e) => updateAlertThreshold(index, 'count', e.target.value)}
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
/>
|
||||
{
|
||||
alertThresholds.length > 1 &&
|
||||
(
|
||||
<Button
|
||||
disableRipple
|
||||
disableElevation
|
||||
sx={{
|
||||
padding: 0,
|
||||
color: 'red',
|
||||
'&:hover': {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
}}
|
||||
|
||||
onClick={() => { handleDeleteAlertThreshold(index) }}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={{ marginTop: 15, textTransform: 'none' }}
|
||||
onClick={addAlertThreshold}
|
||||
>
|
||||
Add Threshold
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={{ marginTop: 15, textTransform: 'none', marginLeft: 20 }}
|
||||
onClick={() => { HandleEditOrgForAlertThreshold(selectedOrganization.id) }}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
<div style={{ marginTop: 40, display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography
|
||||
style={{ marginTop: 10, marginLeft: 10, marginBottom: 5 }}
|
||||
variant="h4"
|
||||
>
|
||||
Utilization & Stats
|
||||
|
||||
@@ -217,6 +217,17 @@ const ParsedAction = (props) => {
|
||||
selectedAction, selectedApp,setNewSelectedAction, workflow,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
setParamValues(selectedAction.parameters.map((param) => {
|
||||
return {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
}
|
||||
}))
|
||||
},[
|
||||
selectedAction, selectedApp,setNewSelectedAction, workflow,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAction.parameters === null || selectedAction.parameters === undefined) {
|
||||
return
|
||||
@@ -972,10 +983,12 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
selectedActionParameters[count].autocompleted = false
|
||||
selectedAction.parameters[count].autocompleted = false
|
||||
selectedActionParameters[count].value = data
|
||||
selectedAction.parameters[count].value = data
|
||||
}, 100);
|
||||
setSelectedAction(selectedAction)
|
||||
//setUpdate(Math.random())
|
||||
//setUpdate(event.target.value)
|
||||
@@ -1143,7 +1156,6 @@ const ParsedAction = (props) => {
|
||||
|
||||
// FIXME: Issue #40 - selectedActionParameters not reset
|
||||
if (Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0) {
|
||||
|
||||
var wrapperapp = {
|
||||
"id": "",
|
||||
"name": "noapp",
|
||||
|
||||
@@ -3804,15 +3804,9 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
if (connected.length > 0 && connected !== undefined) {
|
||||
for (let connectkey in connected) {
|
||||
const edge = connected[connectkey]
|
||||
if (edge.data.decorator && edge.data.label === releaseToConnectLabel) {
|
||||
// Transform to normal edge
|
||||
const currentedge = cy.getElementById(edge.data.id)
|
||||
if (currentedge !== undefined && currentedge !== null) {
|
||||
currentedge.data("decorator", false)
|
||||
currentedge.data("label", "")
|
||||
}
|
||||
continue
|
||||
}
|
||||
//console.log("EDGE:", edge)
|
||||
|
||||
//const edge = edgeBase.json()
|
||||
|
||||
const sourcenode = cy.getElementById(edge.data.source)
|
||||
const destinationnode = cy.getElementById(edge.data.target)
|
||||
@@ -4027,87 +4021,19 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
}
|
||||
|
||||
if (nodedata.id === selectedAction.id) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((nodedata.trigger_type === "SUBFLOW" || nodedata.trigger_type === "USERINPUT" || nodedata.type === "ACTION") && !nodedata.isStartNode) {
|
||||
// Check if it already has any non-decorator branches attached to it
|
||||
const branches = cy.elements('edge').jsons()
|
||||
var branchFound = false
|
||||
var decoratorIds = []
|
||||
for (var branchkey in branches) {
|
||||
if (branches[branchkey].data.source === nodedata.id || branches[branchkey].data.target === nodedata.id) {
|
||||
|
||||
if (branches[branchkey].data.decorator === true) {
|
||||
|
||||
// Add the source/destination
|
||||
if (branches[branchkey].data.source === nodedata.id) {
|
||||
decoratorIds.push(branches[branchkey].data.target)
|
||||
} else {
|
||||
decoratorIds.push(branches[branchkey].data.source)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
branchFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!branchFound) {
|
||||
//console.log("Found action during drag. Checking closest nodes as it doesn't have a valid branch")
|
||||
var closestNode = null
|
||||
var minDistance = 300
|
||||
|
||||
const draggedNode = event.target
|
||||
const allnodes = cy.nodes().jsons()
|
||||
for (var nodekey in allnodes) {
|
||||
const node = allnodes[nodekey]
|
||||
if (node.data.id === nodedata.id) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decorators
|
||||
if (node.data.attachedTo !== undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (node.position === undefined || node.position === null || node.position.x === undefined || node.position.y === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (node.data.type !== "ACTION" && node.data.type !== "TRIGGER") {
|
||||
continue
|
||||
}
|
||||
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(draggedNode.position('x') - node.position.x, 2) +
|
||||
Math.pow(draggedNode.position('y') - node.position.y, 2)
|
||||
)
|
||||
|
||||
if (decoratorIds.includes(node.data.id)) {
|
||||
//console.log("Found existing decorator for: ", node.data.app_name, "Distance: ", distance)
|
||||
|
||||
if (distance > 300) {
|
||||
// Remove the branch
|
||||
const edgeToRemove = cy.getElementById(branches[branchkey].data.id)
|
||||
if (edgeToRemove !== null && edgeToRemove !== undefined) {
|
||||
//console.log("Removing edge: ", edgeToRemove)
|
||||
edgeToRemove.remove()
|
||||
//decoratorIds.splice(decoratorIds.indexOf(node.data.id), 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance
|
||||
closestNode = node
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Tried looking for the closest node by position. aStar path not working entirely.
|
||||
console.log("NODE: ", event.target)
|
||||
const closestNode = cy.elements().aStar({
|
||||
root: nodedata.id,
|
||||
goal: 'node',
|
||||
directed: false,
|
||||
})
|
||||
|
||||
if (closestNode !== null && closestNode !== undefined) {
|
||||
//console.log("Closest node app: ", closestNode.data.app_name, "Distance: ", minDistance)
|
||||
@@ -4220,11 +4146,11 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
}
|
||||
|
||||
// Ensure it only happens once
|
||||
document.removeEventListener("mousemove", onMouseUpdate, false)
|
||||
}
|
||||
document.removeEventListener("mousemove", onMouseUpdate, false);
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMouseUpdate, false)
|
||||
}
|
||||
document.addEventListener("mousemove", onMouseUpdate, false);
|
||||
};
|
||||
|
||||
|
||||
useBeforeunload(() => {
|
||||
|
||||
@@ -2153,7 +2153,7 @@ const Workflows = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{width: "100%", minWidth: 321, position: "relative", border: highlightIds.includes(data.id) ? "2px solid #f85a3e" : isDistributed || hasSuborgs ? "1px solid #40E0D0" : "inherit", borderRadius: theme.palette.borderRadius, }}>
|
||||
<div style={{width: "100%", minWidth: 320, position: "relative", border: highlightIds.includes(data.id) ? "2px solid #f85a3e" : isDistributed || hasSuborgs ? "1px solid #40E0D0" : "inherit", borderRadius: theme.palette.borderRadius, }}>
|
||||
<Paper square style={paperAppStyle}>
|
||||
{selectedCategory !== "" ?
|
||||
<Tooltip title={`Usecase Category: ${selectedCategory}`} placement="bottom">
|
||||
|
||||
Reference in New Issue
Block a user