Fixed relevant stats & license trackers to make it easier to use
This commit is contained in:
@@ -120,10 +120,11 @@ const Billing = (props) => {
|
||||
minHeight: 280,
|
||||
maxWidth: 400,
|
||||
width: "100%",
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
backgroundColor: theme.palette.platformColor,
|
||||
borderRadius: theme.palette.borderRadius*2,
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
marginRight: 10,
|
||||
marginTop: 15,
|
||||
}
|
||||
|
||||
const isCloud =
|
||||
@@ -273,6 +274,7 @@ const Billing = (props) => {
|
||||
|
||||
const [signatureOpen, setSignatureOpen] = React.useState(false);
|
||||
const [tosChecked, setTosChecked] = React.useState(subscription.eula_signed)
|
||||
const [hovered, setHovered] = React.useState(false)
|
||||
|
||||
var top_text = "Base Cloud Access"
|
||||
if (subscription.limit === undefined && subscription.level === undefined || subscription.level === null || subscription.level === 0) {
|
||||
@@ -321,8 +323,16 @@ const Billing = (props) => {
|
||||
newPaperstyle.border = "1px solid #f85a3e"
|
||||
}
|
||||
|
||||
if (hovered) {
|
||||
newPaperstyle.backgroundColor = theme.palette.surfaceColor
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper style={newPaperstyle}>
|
||||
<Paper
|
||||
style={newPaperstyle}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
<Dialog
|
||||
open={signatureOpen}
|
||||
PaperProps={{
|
||||
@@ -960,16 +970,16 @@ const Billing = (props) => {
|
||||
|
||||
const isChildOrg = userdata.active_org.creator_org !== "" && userdata.active_org.creator_org !== undefined && userdata.active_org.creator_org !== null
|
||||
return (
|
||||
<div>
|
||||
<div style={{}}>
|
||||
{addDealModal}
|
||||
<Typography variant="h4" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
Billing
|
||||
Billing & Licensing
|
||||
</Typography>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 0, marginBottom: 10}}>
|
||||
{isCloud ?
|
||||
"We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below."
|
||||
"Get more out of Shuffle by adding your credit card, such as no App Run limitations, and priority support from our team. We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below."
|
||||
:
|
||||
"Shuffle is an Open Source automation platform, and no license is required to use it. You may however activate Cloud Sync, get our Scale license, get help with Kubernetes, or talk to Shuffle's Support team to get automation help."
|
||||
"Shuffle is an Open Source automation platform, and no license is required. We do however offer a Scale license with HA guarantees, along with support hours. By buying a license on https://shuffler.io, you can get access to the license immediately, and if Cloud Syncronisation is enabled, the UI in your local instance will also update."
|
||||
}
|
||||
</Typography>
|
||||
|
||||
@@ -1315,7 +1325,7 @@ const Billing = (props) => {
|
||||
|
||||
</div>
|
||||
) : null*/}
|
||||
<div style={{ marginTop: 30, }}>
|
||||
<div style={{ marginTop: 100, }}>
|
||||
<Typography
|
||||
style={{ marginTop: 40, marginLeft: 10, marginBottom: 5 }}
|
||||
variant="h4"
|
||||
|
||||
@@ -636,13 +636,13 @@ const AppStats = (defaultprops) => {
|
||||
|
||||
const data = (
|
||||
<div className="content" style={{width: "100%", margin: "auto", }}>
|
||||
<Typography variant="body1" style={{margin: "auto", marginLeft: 10, marginBottom: 20, }}>
|
||||
<Typography variant="body1" style={{margin: "auto", marginLeft: 10, marginBottom: 20, }} color="textSecondary">
|
||||
All shown statistics are gathered from <a
|
||||
href={`${globalUrl}/api/v1/orgs/${selectedOrganization.id}/stats`}
|
||||
target="_blank"
|
||||
style={{ textDecoration: "none", color: "#f85a3e",}}
|
||||
>Your Organization Statistics </a>
|
||||
This is a feature to help give you more insight into Shuffle, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b>
|
||||
>Your Organisation Statistics. </a>
|
||||
It exists to give you more insight into your workflows, and to understand your utilization of the Shuffle platform. <b>The billing tracker is in Beta, and is always calculated manually before being invoiced.</b>
|
||||
</Typography>
|
||||
|
||||
<div style={{display: "flex", textAlign: "center",}}>
|
||||
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
Publish as PublishIcon,
|
||||
OpenInNew as OpenInNewIcon,
|
||||
Add as AddIcon,
|
||||
Remove as RemoveIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
const EditWorkflow = (props) => {
|
||||
@@ -76,7 +77,8 @@ const EditWorkflow = (props) => {
|
||||
const [name, setName] = React.useState(workflow.name !== undefined ? workflow.name : "")
|
||||
const [dueDate, setDueDate] = React.useState(workflow.due_date !== undefined && workflow.due_date !== null && workflow.due_date !== 0 ? dayjs(workflow.due_date*1000) : dayjs().subtract(1, 'day'))
|
||||
|
||||
const [inputFields, setInputFields] = React.useState([])
|
||||
console.log("WORKFLOW: ", workflow)
|
||||
const [inputQuestions, setInputQuestions] = React.useState(workflow.input_questions !== undefined && workflow.input_questions !== null ? JSON.parse(JSON.stringify(workflow.input_questions)) : [])
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
@@ -232,7 +234,91 @@ const EditWorkflow = (props) => {
|
||||
</div>
|
||||
</DialogTitle>
|
||||
<FormControl>
|
||||
<DialogContent style={{paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, }}>
|
||||
<div style={{width: 600, position: "fixed", left: 0, bottom: 0, zIndex: 1002, backgroundColor: "rgba(53,53,53,1)", height: 75, paddingTop: 20, paddingLeft: 75, }}>
|
||||
{/*
|
||||
<Button
|
||||
style={{}}
|
||||
onClick={() => {
|
||||
if (setNewWorkflow !== undefined) {
|
||||
setWorkflow({})
|
||||
}
|
||||
|
||||
setModalOpen(false)
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
*/}
|
||||
<Button
|
||||
variant="contained"
|
||||
style={{}}
|
||||
disabled={name.length === 0 || submitLoading === true}
|
||||
onClick={() => {
|
||||
setSubmitLoading(true)
|
||||
|
||||
// Loop inputfields
|
||||
var validfields = []
|
||||
for (var i = 0; i < inputQuestions.length; i++) {
|
||||
if (inputQuestions[i].deleted === true) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (inputQuestions[i].value.length === 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
validfields.push(inputQuestions[i])
|
||||
}
|
||||
|
||||
innerWorkflow.input_questions = validfields
|
||||
|
||||
innerWorkflow.name = name
|
||||
innerWorkflow.description = description
|
||||
if (newWorkflowTags.length > 0) {
|
||||
innerWorkflow.tags = newWorkflowTags
|
||||
}
|
||||
|
||||
if (selectedUsecases.length > 0) {
|
||||
innerWorkflow.usecase_ids = selectedUsecases
|
||||
}
|
||||
|
||||
if (dueDate > 0) {
|
||||
innerWorkflow.due_date = new Date(`${dueDate["$y"]}-${dueDate["$M"]+1}-${dueDate["$D"]}`).getTime()/1000
|
||||
}
|
||||
|
||||
if (setNewWorkflow !== undefined) {
|
||||
setNewWorkflow(
|
||||
innerWorkflow.name,
|
||||
innerWorkflow.description,
|
||||
innerWorkflow.tags,
|
||||
innerWorkflow.default_return_value,
|
||||
innerWorkflow,
|
||||
newWorkflow,
|
||||
innerWorkflow.usecase_ids,
|
||||
innerWorkflow.blogpost,
|
||||
innerWorkflow.status,
|
||||
)
|
||||
setWorkflow({})
|
||||
} else {
|
||||
setWorkflow(innerWorkflow)
|
||||
console.log("editing workflow: ", innerWorkflow)
|
||||
}
|
||||
|
||||
setSubmitLoading(true)
|
||||
|
||||
// If new workflow, don't close it
|
||||
if (isEditing) {
|
||||
setModalOpen(false)
|
||||
}
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
{submitLoading ? <CircularProgress color="secondary" /> : "Done"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<DialogContent style={{paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, paddingBottom: 200, }}>
|
||||
<div style={{minWidth: newWorkflow ? 500 : 550, maxWidth: newWorkflow ? 450 : 500, }}>
|
||||
<TextField
|
||||
onChange={(event) => {
|
||||
@@ -477,41 +563,21 @@ const EditWorkflow = (props) => {
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
{/*
|
||||
<Typography variant="h6">
|
||||
<Typography variant="h6" style={{marginTop: 50, }}>
|
||||
Input fields
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
<Typography variant="body1" color="textSecondary" style={{marginBottom: 20, }}>
|
||||
Input fields are fields that will be used during the startup of the workflow. These will be formatted in JSON and is most commonly used from the <a href={`/workflows/${workflow.id}/run`} rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>workflow run page</a>.
|
||||
|
||||
|
||||
</Typography>
|
||||
|
||||
{inputFields.length === 0 ?
|
||||
<Button
|
||||
color="primary"
|
||||
style={{ maxWidth: 50, marginLeft: 15 }}
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
inputFields.push({
|
||||
"name": "",
|
||||
"required": false
|
||||
})
|
||||
setInputFields(inputFields)
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
>
|
||||
<AddIcon style={{}} />
|
||||
</Button>
|
||||
: null}
|
||||
|
||||
{inputFields.map((data, index) => {
|
||||
{inputQuestions.map((data, index) => {
|
||||
console.log("Inputfield: ", data)
|
||||
|
||||
return (
|
||||
<div style={{display: "flex", }}>
|
||||
<TextField
|
||||
required={data.required}
|
||||
disabled={data.deleted === true}
|
||||
style={{
|
||||
height: 50,
|
||||
flex: 2,
|
||||
@@ -521,14 +587,45 @@ const EditWorkflow = (props) => {
|
||||
marginRight: 5,
|
||||
}}
|
||||
fullWidth={true}
|
||||
placeholder="Name"
|
||||
placeholder="Question"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
defaultValue={data.name}
|
||||
onChange={(e) => {
|
||||
inputQuestions[index].name = e.target.value
|
||||
setInputQuestions(inputQuestions)
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style: {
|
||||
color: "white",
|
||||
minHeight: 50,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
disabled={data.deleted === true}
|
||||
style={{
|
||||
height: 50,
|
||||
flex: 2,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
marginRight: 5,
|
||||
}}
|
||||
fullWidth={true}
|
||||
placeholder="JSON key"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
defaultValue={data.value}
|
||||
onChange={(e) => {
|
||||
inputFields[index].name = e.target.value
|
||||
setInputFields(inputFields)
|
||||
inputQuestions[index].value = e.target.value
|
||||
setInputQuestions(inputQuestions)
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
InputProps={{
|
||||
@@ -544,28 +641,44 @@ const EditWorkflow = (props) => {
|
||||
<Button
|
||||
color="primary"
|
||||
style={{ maxWidth: 50, marginLeft: 15 }}
|
||||
disabled={data.deleted === true}
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
inputFields.push({
|
||||
"name": "",
|
||||
"required": false
|
||||
})
|
||||
setInputFields(inputFields)
|
||||
setUpdate(Math.random());
|
||||
// Remove current index
|
||||
console.log("Removing index: ", index)
|
||||
inputQuestions[index].deleted = true
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
>
|
||||
<AddIcon style={{}} />
|
||||
<RemoveIcon style={{}} />
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
*/}
|
||||
|
||||
<Button
|
||||
color="primary"
|
||||
style={{ maxWidth: 50, marginLeft: 15, marginTop: 20, }}
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
inputQuestions.push({
|
||||
"name": "",
|
||||
"value": "",
|
||||
"deleted": false,
|
||||
"required": false
|
||||
})
|
||||
setInputQuestions(inputQuestions)
|
||||
setUpdate(Math.random());
|
||||
}}
|
||||
>
|
||||
<AddIcon style={{}} />
|
||||
</Button>
|
||||
</span>
|
||||
: null}
|
||||
|
||||
<Tooltip color="primary" title={"Add more details"} placement="top">
|
||||
<IconButton
|
||||
style={{ color: "white", margin: "auto", marginTop: 10, textAlign: "center", width: 50,}}
|
||||
style={{ color: "white", margin: "auto", textAlign: "center", width: 50, marginTop: 50, }}
|
||||
onClick={() => {
|
||||
setShowMoreClicked(!showMoreClicked);
|
||||
}}
|
||||
@@ -577,71 +690,7 @@ const EditWorkflow = (props) => {
|
||||
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions style={{paddingRight: 100, marginBottom: 100, }}>
|
||||
<Button
|
||||
style={{}}
|
||||
onClick={() => {
|
||||
if (setNewWorkflow !== undefined) {
|
||||
setWorkflow({})
|
||||
}
|
||||
|
||||
setModalOpen(false)
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
style={{}}
|
||||
disabled={name.length === 0 || submitLoading === true}
|
||||
onClick={() => {
|
||||
setSubmitLoading(true)
|
||||
|
||||
innerWorkflow.name = name
|
||||
innerWorkflow.description = description
|
||||
if (newWorkflowTags.length > 0) {
|
||||
innerWorkflow.tags = newWorkflowTags
|
||||
}
|
||||
|
||||
if (selectedUsecases.length > 0) {
|
||||
innerWorkflow.usecase_ids = selectedUsecases
|
||||
}
|
||||
|
||||
if (dueDate > 0) {
|
||||
innerWorkflow.due_date = new Date(`${dueDate["$y"]}-${dueDate["$M"]+1}-${dueDate["$D"]}`).getTime()/1000
|
||||
}
|
||||
|
||||
if (setNewWorkflow !== undefined) {
|
||||
setNewWorkflow(
|
||||
innerWorkflow.name,
|
||||
innerWorkflow.description,
|
||||
innerWorkflow.tags,
|
||||
innerWorkflow.default_return_value,
|
||||
innerWorkflow,
|
||||
newWorkflow,
|
||||
innerWorkflow.usecase_ids,
|
||||
innerWorkflow.blogpost,
|
||||
innerWorkflow.status,
|
||||
)
|
||||
setWorkflow({})
|
||||
} else {
|
||||
setWorkflow(innerWorkflow)
|
||||
console.log("editing workflow: ", innerWorkflow)
|
||||
}
|
||||
|
||||
setSubmitLoading(true)
|
||||
|
||||
// If new workflow, don't close it
|
||||
if (isEditing) {
|
||||
setModalOpen(false)
|
||||
}
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
{submitLoading ? <CircularProgress color="secondary" /> : "Done"}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
{newWorkflow === true ?
|
||||
<span style={{marginTop: 30, }}>
|
||||
<Typography variant="h6" style={{marginLeft: 30, paddingBottom: 0, }}>
|
||||
|
||||
@@ -70,6 +70,7 @@ const Header = (props) => {
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
const [anchorElAvatar, setAnchorElAvatar] = React.useState(null);
|
||||
const [subAnchorEl, setSubAnchorEl] = React.useState(null);
|
||||
const [upgradeHovered, setUpgradeHovered] = React.useState(false);
|
||||
let navigate = useNavigate();
|
||||
|
||||
const handleClick = (event) => {
|
||||
@@ -1097,10 +1098,10 @@ const Header = (props) => {
|
||||
)}
|
||||
|
||||
{/* Show on cloud, if not suborg and if not customer/pov/internal */}
|
||||
{isCloud &&
|
||||
(userdata.org_status === undefined ||
|
||||
userdata.org_status === null ||
|
||||
userdata.org_status.length === 0) ? (
|
||||
{
|
||||
userdata.licensed !== undefined &&
|
||||
userdata.licensed !== null &&
|
||||
userdata.licensed === false ?
|
||||
<ListItem
|
||||
style={{
|
||||
textAlign: "center",
|
||||
@@ -1109,11 +1110,13 @@ const Header = (props) => {
|
||||
marginTop: 0,
|
||||
}}
|
||||
>
|
||||
<Link to="/pricing?tab=cloud&highlight=true" style={hrefStyle}>
|
||||
<Link to="/admin?tab=billing" style={hrefStyle}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
style={{ textTransform: "none" }}
|
||||
onMouseOver={() => {setUpgradeHovered(true)}}
|
||||
onMouseOut={() => {setUpgradeHovered(false)}}
|
||||
onClick={() => {
|
||||
if (isCloud) {
|
||||
ReactGA.event({
|
||||
@@ -1122,13 +1125,30 @@ const Header = (props) => {
|
||||
label: "",
|
||||
});
|
||||
}
|
||||
|
||||
if (window.drift !== undefined) {
|
||||
if (isCloud) {
|
||||
window.drift.api.startInteraction({
|
||||
interactionId: 386404,
|
||||
})
|
||||
} else {
|
||||
window.drift.api.startInteraction({
|
||||
interactionId: 386403,
|
||||
})
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
Upgrade
|
||||
{upgradeHovered ?
|
||||
isCloud ? "Upgrade License" : "Upgrade License"
|
||||
:
|
||||
isCloud ? "Upgrade" : "Upgrade"
|
||||
}
|
||||
|
||||
</Button>
|
||||
</Link>
|
||||
</ListItem>
|
||||
) : null}
|
||||
: null}
|
||||
|
||||
{userdata === undefined ||
|
||||
userdata.app_execution_limit === undefined ||
|
||||
@@ -1145,7 +1165,6 @@ const Header = (props) => {
|
||||
textAlign: "center",
|
||||
cursor: "pointer",
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
marginRight: 10,
|
||||
marginTop: 5,
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
minWidth: 60,
|
||||
@@ -1154,7 +1173,7 @@ const Header = (props) => {
|
||||
userdata.app_execution_usage /
|
||||
userdata.app_execution_limit >=
|
||||
0.9
|
||||
? "#f86a3e"
|
||||
? "2px solid #f86a3e"
|
||||
: null,
|
||||
}}
|
||||
onClick={() => {
|
||||
|
||||
@@ -3258,7 +3258,6 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("DID NAME REPLACE ACTUALLY WORK? - may be missing it in certain triggers");
|
||||
setWorkflow(workflow);
|
||||
setUpdate(Math.random());
|
||||
baselabel = name
|
||||
|
||||
Reference in New Issue
Block a user