Many small fixes :)
This commit is contained in:
@@ -5,7 +5,7 @@ go 1.24.0
|
|||||||
toolchain go1.24.3
|
toolchain go1.24.3
|
||||||
|
|
||||||
//replace github.com/frikky/schemaless => ../../../schemaless
|
//replace github.com/frikky/schemaless => ../../../schemaless
|
||||||
//replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared
|
replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared
|
||||||
|
|
||||||
//replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi
|
//replace github.com/frikky/kin-openapi => ../../../../git/kin-openapi
|
||||||
|
|
||||||
|
|||||||
@@ -4099,8 +4099,9 @@ func runInitEs(ctx context.Context) {
|
|||||||
time.Sleep(30 * time.Second)
|
time.Sleep(30 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This should ONLY run on one backend instance
|
shuffle.InitOpensearchIndexes()
|
||||||
|
|
||||||
|
// FIXME: This should ONLY run on one backend instance. This may cause interference.
|
||||||
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
|
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
|
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ import {
|
|||||||
Add as AddIcon,
|
Add as AddIcon,
|
||||||
Remove as RemoveIcon,
|
Remove as RemoveIcon,
|
||||||
EditNote as EditNoteIcon,
|
EditNote as EditNoteIcon,
|
||||||
|
AutoAwesome as AutoAwesomeIcon
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
|
|
||||||
const EditWorkflow = (props) => {
|
const EditWorkflow = (props) => {
|
||||||
@@ -72,6 +73,7 @@ const EditWorkflow = (props) => {
|
|||||||
const {themeMode, brandColor} = useContext(Context)
|
const {themeMode, brandColor} = useContext(Context)
|
||||||
const theme = getTheme(themeMode, brandColor)
|
const theme = getTheme(themeMode, brandColor)
|
||||||
const [submitLoading, setSubmitLoading] = React.useState(false);
|
const [submitLoading, setSubmitLoading] = React.useState(false);
|
||||||
|
const [aiGenerateLoading, setAiGenerateLoading] = React.useState(false);
|
||||||
const [showMoreClicked, setShowMoreClicked] = React.useState(isEditing !== false ? true : false);
|
const [showMoreClicked, setShowMoreClicked] = React.useState(isEditing !== false ? true : false);
|
||||||
|
|
||||||
const [innerWorkflow, setInnerWorkflow] = React.useState(workflow)
|
const [innerWorkflow, setInnerWorkflow] = React.useState(workflow)
|
||||||
@@ -220,7 +222,7 @@ const EditWorkflow = (props) => {
|
|||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<div style={{ flex: 1, color: theme.palette.textColor }}>
|
<div style={{ flex: 1, color: theme.palette.textColor }}>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<Typography variant="h4" style={{ flex: 9, marginTop: 25, }}>
|
<Typography variant="h4" style={{ flex: 9, marginTop: newWorkflow ? 50 : 25, }}>
|
||||||
{newWorkflow ? "New" : "Editing"} Workflow
|
{newWorkflow ? "New" : "Editing"} Workflow
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -298,93 +300,316 @@ const EditWorkflow = (props) => {
|
|||||||
paddingLeft: 30,
|
paddingLeft: 30,
|
||||||
backgroundColor: themeMode === "dark" ? "#262626" : theme.palette.DialogStyle.backgroundColor,
|
backgroundColor: themeMode === "dark" ? "#262626" : theme.palette.DialogStyle.backgroundColor,
|
||||||
}}>
|
}}>
|
||||||
<Button
|
{newWorkflow === true ? (
|
||||||
variant="contained"
|
<div style={{ display: "flex", gap: 10 }}>
|
||||||
style={{}}
|
|
||||||
id="save_workflow_button"
|
|
||||||
disabled={name.length === 0 || submitLoading === true}
|
<Button
|
||||||
onClick={() => {
|
variant="contained"
|
||||||
setSubmitLoading(true)
|
style={{}}
|
||||||
|
id="save_workflow_button"
|
||||||
|
disabled={name.length === 0 || submitLoading === true || aiGenerateLoading === true}
|
||||||
|
onClick={() => {
|
||||||
|
setSubmitLoading(true)
|
||||||
|
|
||||||
// Loop inputfields
|
// Loop inputfields
|
||||||
var validfields = []
|
var validfields = []
|
||||||
for (var i = 0; i < inputQuestions.length; i++) {
|
for (var i = 0; i < inputQuestions.length; i++) {
|
||||||
if (inputQuestions[i].deleted === true) {
|
if (inputQuestions[i].deleted === true) {
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputQuestions[i].value.length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
validfields.push(inputQuestions[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
innerWorkflow.input_questions = validfields
|
||||||
|
|
||||||
|
if (innerWorkflow.form_control === undefined || innerWorkflow.form_control === null) {
|
||||||
|
innerWorkflow.form_control = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
innerWorkflow.form_control.input_markdown = inputMarkdown
|
||||||
|
innerWorkflow.form_control.output_yields = selectedYieldActions
|
||||||
|
innerWorkflow.form_control.form_width = formWidth
|
||||||
|
innerWorkflow.form_control.cleanup_actions = selectedCleanupActions
|
||||||
|
|
||||||
|
innerWorkflow.name = name
|
||||||
|
innerWorkflow.description = description
|
||||||
|
|
||||||
|
if (newWorkflowTags.length > 0) {
|
||||||
|
innerWorkflow.tags = newWorkflowTags
|
||||||
|
} else {
|
||||||
|
innerWorkflow.tags = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedUsecases.length > 0) {
|
||||||
|
innerWorkflow.usecase_ids = selectedUsecases
|
||||||
|
} else {
|
||||||
|
innerWorkflow.usecase_ids = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dueDate > 0) {
|
||||||
|
innerWorkflow.due_date = new Date(`${dueDate["$y"]}-${dueDate["$M"] + 1}-${dueDate["$D"]}`).getTime() / 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saveWorkflow !== undefined) {
|
||||||
|
saveWorkflow(innerWorkflow)
|
||||||
|
|
||||||
|
if (setWorkflow !== undefined) {
|
||||||
|
setWorkflow(innerWorkflow)
|
||||||
|
}
|
||||||
|
} else if (setNewWorkflow !== undefined) {
|
||||||
|
setNewWorkflow(
|
||||||
|
innerWorkflow.name,
|
||||||
|
innerWorkflow.description,
|
||||||
|
innerWorkflow.tags,
|
||||||
|
innerWorkflow.default_return_value,
|
||||||
|
innerWorkflow,
|
||||||
|
newWorkflow,
|
||||||
|
innerWorkflow.usecase_ids,
|
||||||
|
innerWorkflow.blogpost,
|
||||||
|
innerWorkflow.status,
|
||||||
|
workflowAsCode
|
||||||
|
)
|
||||||
|
setWorkflow({})
|
||||||
|
} else {
|
||||||
|
setWorkflow(innerWorkflow)
|
||||||
|
}
|
||||||
|
|
||||||
|
setSubmitLoading(true)
|
||||||
|
|
||||||
|
// If new workflow, don't close it
|
||||||
|
if (isEditing) {
|
||||||
|
setModalOpen(false)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{submitLoading ? <CircularProgress color="secondary" /> : "Create from scratch"}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Tooltip placement="top" arrow
|
||||||
|
title={
|
||||||
|
<Typography variant="body1" style={{padding: 10, }}>
|
||||||
|
Generate using the name, description, usecases and tags provided. Required: Name + Description
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<Button
|
||||||
|
disabled={name.length === 0 || innerWorkflow?.default_return_value?.length === 0 || aiGenerateLoading === true || submitLoading === true}
|
||||||
|
variant="aiButton"
|
||||||
|
onClick={async () => {
|
||||||
|
// Check if description is provided in the visible field for new workflows
|
||||||
|
if (!innerWorkflow.default_return_value || innerWorkflow.default_return_value.trim().length === 0) {
|
||||||
|
toast.error("You need to describe what you want to generate so the AI can auto generate the entire workflow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAiGenerateLoading(true);
|
||||||
|
toast.info("Creating workflow...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Step 1: Create basic workflow WITHOUT using setNewWorkflow (to avoid modal closing)
|
||||||
|
const workflowData = {
|
||||||
|
name: name.length > 0 ? name : "AI Generated Workflow",
|
||||||
|
description: innerWorkflow.default_return_value,
|
||||||
|
tags: newWorkflowTags,
|
||||||
|
default_return_value: innerWorkflow.default_return_value,
|
||||||
|
usecase_ids: selectedUsecases,
|
||||||
|
blogpost: innerWorkflow.blogpost || "",
|
||||||
|
status: innerWorkflow.status || ""
|
||||||
|
};
|
||||||
|
|
||||||
|
const workflowResponse = await fetch(`${globalUrl}/api/v1/workflows`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(workflowData),
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (workflowResponse.status !== 200) {
|
||||||
|
toast.error("Failed to create workflow");
|
||||||
|
setAiGenerateLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workflowJson = await workflowResponse.json();
|
||||||
|
|
||||||
|
if (workflowJson.success === false) {
|
||||||
|
toast.error("Failed to create workflow: " + (workflowJson.reason || "Unknown error"));
|
||||||
|
setAiGenerateLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!workflowJson || !workflowJson.id) {
|
||||||
|
toast.error("Failed to create workflow - no ID returned");
|
||||||
|
setAiGenerateLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workflowId = workflowJson.id;
|
||||||
|
console.log("Created workflow with ID:", workflowId);
|
||||||
|
|
||||||
|
// Step 2: Generate AI content for the workflow
|
||||||
|
const data = {
|
||||||
|
query: innerWorkflow.default_return_value,
|
||||||
|
workflow_id: workflowId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const aiResponse = await fetch(globalUrl + "/api/v2/workflows/generate/llm", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = await aiResponse.json();
|
||||||
|
|
||||||
|
// Handle AI response and provide feedback
|
||||||
|
if (aiResponse.status !== 200) {
|
||||||
|
console.log("AI generation failed, but workflow created:", json.message || "Unexpected response");
|
||||||
|
toast.warning("Workflow created successfully, but AI generation failed. Opening workflow editor...");
|
||||||
|
} else if (json.success === true && typeof json.message === "string") {
|
||||||
|
// AI "rejection" message
|
||||||
|
console.log("AI rejected request:", json.message);
|
||||||
|
toast.warning(`AI: ${json.message}. Opening empty workflow editor...`);
|
||||||
|
} else if (json.success === false) {
|
||||||
|
console.log("AI generation failed:", json.message || "Operation failed");
|
||||||
|
toast.warning("AI generation failed. Opening empty workflow editor...");
|
||||||
|
} else if (!json || Object.keys(json).length === 0) {
|
||||||
|
console.log("Empty AI response");
|
||||||
|
toast.warning("AI returned empty response. Opening workflow editor...");
|
||||||
|
} else {
|
||||||
|
toast.success("Workflow generated successfully! Opening editor...");
|
||||||
|
console.log("AI generation successful");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Now close modal and redirect (only after everything is complete)
|
||||||
|
setTimeout(() => {
|
||||||
|
setModalOpen(false);
|
||||||
|
setAiGenerateLoading(false);
|
||||||
|
window.location.href = `/workflows/${workflowId}`;
|
||||||
|
}, 1500); // Give user time to read the final message
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in AI workflow generation:", error);
|
||||||
|
toast.error("Failed to generate. Please try again later: " + error.message);
|
||||||
|
setAiGenerateLoading(false);
|
||||||
|
// Don't close modal on error so user can try again
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{aiGenerateLoading ? (
|
||||||
|
<CircularProgress color="secondary" size={20} style={{ marginRight: 8 }} />
|
||||||
|
) : (
|
||||||
|
<AutoAwesomeIcon style={{ marginRight: 8 }} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
AI Generate
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
style={{}}
|
||||||
|
id="save_workflow_button"
|
||||||
|
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])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputQuestions[i].value.length === 0) {
|
innerWorkflow.input_questions = validfields
|
||||||
continue
|
|
||||||
|
if (innerWorkflow.form_control === undefined || innerWorkflow.form_control === null) {
|
||||||
|
innerWorkflow.form_control = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
validfields.push(inputQuestions[i])
|
innerWorkflow.form_control.input_markdown = inputMarkdown
|
||||||
}
|
innerWorkflow.form_control.output_yields = selectedYieldActions
|
||||||
|
innerWorkflow.form_control.form_width = formWidth
|
||||||
|
innerWorkflow.form_control.cleanup_actions = selectedCleanupActions
|
||||||
|
|
||||||
innerWorkflow.input_questions = validfields
|
innerWorkflow.name = name
|
||||||
|
innerWorkflow.description = description
|
||||||
|
|
||||||
if (innerWorkflow.form_control === undefined || innerWorkflow.form_control === null) {
|
if (newWorkflowTags.length > 0) {
|
||||||
innerWorkflow.form_control = {}
|
innerWorkflow.tags = newWorkflowTags
|
||||||
}
|
} else {
|
||||||
|
innerWorkflow.tags = []
|
||||||
|
}
|
||||||
|
|
||||||
innerWorkflow.form_control.input_markdown = inputMarkdown
|
if (selectedUsecases.length > 0) {
|
||||||
innerWorkflow.form_control.output_yields = selectedYieldActions
|
innerWorkflow.usecase_ids = selectedUsecases
|
||||||
innerWorkflow.form_control.form_width = formWidth
|
} else {
|
||||||
innerWorkflow.form_control.cleanup_actions = selectedCleanupActions
|
innerWorkflow.usecase_ids = []
|
||||||
|
}
|
||||||
|
|
||||||
innerWorkflow.name = name
|
if (dueDate > 0) {
|
||||||
innerWorkflow.description = description
|
innerWorkflow.due_date = new Date(`${dueDate["$y"]}-${dueDate["$M"] + 1}-${dueDate["$D"]}`).getTime() / 1000
|
||||||
|
}
|
||||||
|
|
||||||
if (newWorkflowTags.length > 0) {
|
if (saveWorkflow !== undefined) {
|
||||||
innerWorkflow.tags = newWorkflowTags
|
saveWorkflow(innerWorkflow)
|
||||||
} else {
|
|
||||||
innerWorkflow.tags = []
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedUsecases.length > 0) {
|
if (setWorkflow !== undefined) {
|
||||||
innerWorkflow.usecase_ids = selectedUsecases
|
setWorkflow(innerWorkflow)
|
||||||
} else {
|
}
|
||||||
innerWorkflow.usecase_ids = []
|
} else if (setNewWorkflow !== undefined) {
|
||||||
}
|
setNewWorkflow(
|
||||||
|
innerWorkflow.name,
|
||||||
if (dueDate > 0) {
|
innerWorkflow.description,
|
||||||
innerWorkflow.due_date = new Date(`${dueDate["$y"]}-${dueDate["$M"] + 1}-${dueDate["$D"]}`).getTime() / 1000
|
innerWorkflow.tags,
|
||||||
}
|
innerWorkflow.default_return_value,
|
||||||
|
innerWorkflow,
|
||||||
if (saveWorkflow !== undefined) {
|
newWorkflow,
|
||||||
saveWorkflow(innerWorkflow)
|
innerWorkflow.usecase_ids,
|
||||||
|
innerWorkflow.blogpost,
|
||||||
if (setWorkflow !== undefined) {
|
innerWorkflow.status,
|
||||||
|
workflowAsCode
|
||||||
|
)
|
||||||
|
setWorkflow({})
|
||||||
|
} else {
|
||||||
setWorkflow(innerWorkflow)
|
setWorkflow(innerWorkflow)
|
||||||
}
|
}
|
||||||
} else if (setNewWorkflow !== undefined) {
|
|
||||||
setNewWorkflow(
|
|
||||||
innerWorkflow.name,
|
|
||||||
innerWorkflow.description,
|
|
||||||
innerWorkflow.tags,
|
|
||||||
innerWorkflow.default_return_value,
|
|
||||||
innerWorkflow,
|
|
||||||
newWorkflow,
|
|
||||||
innerWorkflow.usecase_ids,
|
|
||||||
innerWorkflow.blogpost,
|
|
||||||
innerWorkflow.status,
|
|
||||||
workflowAsCode
|
|
||||||
)
|
|
||||||
setWorkflow({})
|
|
||||||
} else {
|
|
||||||
setWorkflow(innerWorkflow)
|
|
||||||
}
|
|
||||||
|
|
||||||
setSubmitLoading(true)
|
setSubmitLoading(true)
|
||||||
|
|
||||||
// If new workflow, don't close it
|
// If new workflow, don't close it
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
setModalOpen(false)
|
setModalOpen(false)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
{submitLoading ? <CircularProgress color="secondary" /> : "Save Changes"}
|
{submitLoading ? <CircularProgress color="secondary" /> : "Save Changes"}
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogContent style={{ paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, paddingBottom: 400, paddingLeft: 50, }}>
|
<DialogContent style={{ paddingTop: 10, display: "flex", minHeight: 300, zIndex: 1001, paddingBottom: 400, paddingLeft: 50, }}>
|
||||||
@@ -409,6 +634,29 @@ const EditWorkflow = (props) => {
|
|||||||
id="Enter-Workflow-Name"
|
id="Enter-Workflow-Name"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{newWorkflow === true ?
|
||||||
|
<TextField
|
||||||
|
onBlur={(event) => {
|
||||||
|
innerWorkflow.default_return_value = event.target.value
|
||||||
|
setInnerWorkflow(innerWorkflow)
|
||||||
|
setUpdate(Math.random())
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
defaultValue={innerWorkflow.default_return_value}
|
||||||
|
placeholder="Please describe your workflow below so the AI can generate it."
|
||||||
|
rows="3"
|
||||||
|
multiline
|
||||||
|
label="Description"
|
||||||
|
margin="dense"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
: null}
|
||||||
|
|
||||||
<div style={{ display: "flex", marginTop: 10, }}>
|
<div style={{ display: "flex", marginTop: 10, }}>
|
||||||
{usecases !== null && usecases !== undefined && usecases.length > 0 ?
|
{usecases !== null && usecases !== undefined && usecases.length > 0 ?
|
||||||
<FormControl style={{ flex: 1, marginRight: 5, }}>
|
<FormControl style={{ flex: 1, marginRight: 5, }}>
|
||||||
@@ -1285,7 +1533,7 @@ const EditWorkflow = (props) => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
|
|
||||||
{newWorkflow === true ?
|
{/*newWorkflow === true ?
|
||||||
<span style={{ paddingTop: 30 }}>
|
<span style={{ paddingTop: 30 }}>
|
||||||
<Typography variant="h6" style={{ marginLeft: 30, paddingBottom: 0, }}>
|
<Typography variant="h6" style={{ marginLeft: 30, paddingBottom: 0, }}>
|
||||||
Relevant Workflows
|
Relevant Workflows
|
||||||
@@ -1311,9 +1559,8 @@ const EditWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
: null}
|
: null*/}
|
||||||
|
{/*newWorkflow === true && name.length > 2 ?
|
||||||
{/*newWorkflow === true && name.length > 2 ?
|
|
||||||
<div style={{marginLeft: 30, }}>
|
<div style={{marginLeft: 30, }}>
|
||||||
<WorkflowGrid
|
<WorkflowGrid
|
||||||
maxRows={1}
|
maxRows={1}
|
||||||
|
|||||||
@@ -383,38 +383,36 @@ const EnvironmentTab = memo((props) => {
|
|||||||
//toast("No Orborus necessary for environment cloud. Create and use a different environment to run executions on-premises.",)
|
//toast("No Orborus necessary for environment cloud. Create and use a different environment to run executions on-premises.",)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
props.userdata.active_org === undefined ||
|
props.userdata.active_org === undefined ||
|
||||||
props.userdata.active_org === null
|
props.userdata.active_org === null
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const elementName = "copy_element_shuffle";
|
const elementName = "copy_element_shuffle";
|
||||||
var auth =
|
var auth =
|
||||||
environment.auth === ""
|
environment.auth === ""
|
||||||
? "cb5st3d3Z!3X3zaJ*Pc"
|
? "cb5st3d3Z!3X3zaJ*Pc"
|
||||||
: environment.auth
|
: environment.auth
|
||||||
|
// Escape exclamation marks for copying
|
||||||
// Escape exclamation marks for copying
|
auth = auth.replace("\\!", "!").replace(/!/g, "\\!")
|
||||||
auth = auth.replace("\\!", "!").replace(/!/g, "\\!")
|
|
||||||
|
|
||||||
const newUrl =
|
const newUrl =
|
||||||
globalUrl === "https://shuffler.io"
|
globalUrl === "https://shuffler.io"
|
||||||
? "https://shuffle-backend-stbuwivzoq-nw.a.run.app"
|
? "https://shuffle-backend-stbuwivzoq-nw.a.run.app"
|
||||||
: globalUrl;
|
: globalUrl;
|
||||||
|
|
||||||
var skipPipeline = false
|
var skipPipeline = false
|
||||||
if (commandController.pipelines === true) {
|
if (commandController.pipelines === true) {
|
||||||
skipPipeline = true
|
skipPipeline = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var addProxy = false
|
var addProxy = false
|
||||||
if (commandController.proxies === true) {
|
if (commandController.proxies === true) {
|
||||||
addProxy = true
|
addProxy = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (installationTab === 1) {
|
if (installationTab === 1) {
|
||||||
return (`docker run -d \\
|
return (`docker run -d \\
|
||||||
--restart=always \\
|
--restart=always \\
|
||||||
@@ -428,14 +426,32 @@ const EnvironmentTab = memo((props) => {
|
|||||||
-e SHUFFLE_SWARM_CONFIG=run \\
|
-e SHUFFLE_SWARM_CONFIG=run \\
|
||||||
-e SHUFFLE_LOGS_DISABLED=true \\
|
-e SHUFFLE_LOGS_DISABLED=true \\
|
||||||
-e BASE_URL="${newUrl}" \\${addProxy ? `
|
-e BASE_URL="${newUrl}" \\${addProxy ? `
|
||||||
-e HTTPS_PROXY=IP:PORT \\` : ""}${skipPipeline ? `
|
-e HTTPS_PROXY=IP:PORT \\` : ""}${skipPipeline ? `
|
||||||
-e SHUFFLE_SKIP_PIPELINES=true \\` : ""}
|
-e SHUFFLE_SKIP_PIPELINES=true \\` : ""}
|
||||||
ghcr.io/shuffle/shuffle-orborus:latest
|
ghcr.io/shuffle/shuffle-orborus:latest
|
||||||
`)
|
`)
|
||||||
} else if (installationTab === 2) {
|
} else if (installationTab === 2) {
|
||||||
return `https://shuffler.io/docs/configuration#kubernetes`
|
return `helm install shuffle-orborus oci://ghcr.io/shuffle/charts/shuffle \\
|
||||||
|
--namespace shuffle --create-namespace \\
|
||||||
|
--set opensearch.enabled=false \\
|
||||||
|
--set backend.replicaCount=0 \\
|
||||||
|
--set frontend.replicaCount=0 \\
|
||||||
|
--set 'orborus.extraEnvVars[0].name=AUTH' \\
|
||||||
|
--set 'orborus.extraEnvVars[0].value=${auth}' \\
|
||||||
|
--set 'orborus.extraEnvVars[1].name=BASE_URL' \\
|
||||||
|
--set 'orborus.extraEnvVars[1].value=${newUrl}' \\
|
||||||
|
--set 'orborus.extraEnvVars[2].name=ENVIRONMENT_NAME' \\
|
||||||
|
--set 'orborus.extraEnvVars[2].value=${environment.Name}' \\
|
||||||
|
--set 'orborus.extraEnvVars[3].name=ORG' \\
|
||||||
|
--set 'orborus.extraEnvVars[3].value=${environment.org_id}' \\
|
||||||
|
--set shuffle.org="${environment.org_id}"${addProxy ? ` \\
|
||||||
|
--set 'orborus.extraEnvVars[4].name=HTTPS_PROXY' \\
|
||||||
|
--set 'orborus.extraEnvVars[4].value=IP:PORT'` : ""}${skipPipeline ? ` \\
|
||||||
|
--set 'orborus.extraEnvVars[${addProxy ? 5 : 4}].name=SHUFFLE_SKIP_PIPELINES' \\
|
||||||
|
--set 'orborus.extraEnvVars[${addProxy ? 5 : 4}].value=true'` : ""} \\
|
||||||
|
--set persistence.storageClass=standard`
|
||||||
}
|
}
|
||||||
|
|
||||||
const commandData = `docker rm shuffle-orborus --force; \\\ndocker run -d \\
|
const commandData = `docker rm shuffle-orborus --force; \\\ndocker run -d \\
|
||||||
--restart=always \\
|
--restart=always \\
|
||||||
--name="shuffle-orborus" \\
|
--name="shuffle-orborus" \\
|
||||||
@@ -445,12 +461,13 @@ const EnvironmentTab = memo((props) => {
|
|||||||
-e ENVIRONMENT_NAME="${environment.Name}" \\
|
-e ENVIRONMENT_NAME="${environment.Name}" \\
|
||||||
-e ORG="${props.userdata.active_org.id}" \\
|
-e ORG="${props.userdata.active_org.id}" \\
|
||||||
-e BASE_URL="${newUrl}" \\${addProxy ? `
|
-e BASE_URL="${newUrl}" \\${addProxy ? `
|
||||||
-e HTTPS_PROXY=IP:PORT \\` : ""}${skipPipeline ? `
|
-e HTTPS_PROXY=IP:PORT \\` : ""}${skipPipeline ? `
|
||||||
-e SHUFFLE_SKIP_PIPELINES=true \\` : ""}
|
-e SHUFFLE_SKIP_PIPELINES=true \\` : ""}
|
||||||
ghcr.io/shuffle/shuffle-orborus:latest`
|
ghcr.io/shuffle/shuffle-orborus:latest`
|
||||||
|
|
||||||
return commandData
|
return commandData
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const submitEnvironment = (data) => {
|
const submitEnvironment = (data) => {
|
||||||
// FIXME - add some check here ROFL
|
// FIXME - add some check here ROFL
|
||||||
@@ -1475,7 +1492,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
||||||
{installationTab === 2 ?
|
{installationTab === 2 ?
|
||||||
<Typography variant='body2' color="textSecondary">
|
<Typography variant='body2' color="textSecondary">
|
||||||
Check our <a href="https://docs.docker.com/get-started/get-docker/" target="_blank" rel="noopener noreferrer" style={{textDecoration: "none", color: "#f85a3e",}}>Kubernetes documentation</a> for more information on how to run Shuffle on Kubernetes. The status of the node will change when connected.
|
Simply connect to your Kubernetes cluster and run the following command:
|
||||||
</Typography>
|
</Typography>
|
||||||
:
|
:
|
||||||
<Typography variant='body2' color="textSecondary">
|
<Typography variant='body2' color="textSecondary">
|
||||||
@@ -1489,7 +1506,6 @@ const EnvironmentTab = memo((props) => {
|
|||||||
"2. Run this command on the server you want to run workflows or store Pipeline data on"}
|
"2. Run this command on the server you want to run workflows or store Pipeline data on"}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{installationTab === 2 ? null :
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
@@ -1571,8 +1587,7 @@ const EnvironmentTab = memo((props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
|
|
||||||
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
<Typography variant="body1" color="textSecondary" style={{marginTop: 15, }}>
|
||||||
{installationTab === 2 ? null :
|
{installationTab === 2 ? null :
|
||||||
|
|||||||
@@ -741,7 +741,7 @@ const PartnerHeader = (props) => {
|
|||||||
<div >
|
<div >
|
||||||
<Button
|
<Button
|
||||||
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 128, height: 40 }}
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 128, height: 40 }}
|
||||||
variant="contained"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={isDisabled || isPublishing}
|
disabled={isDisabled || isPublishing}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -812,7 +812,7 @@ const PartnerHeader = (props) => {
|
|||||||
<div >
|
<div >
|
||||||
<Button
|
<Button
|
||||||
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 128, height: 40 }}
|
style={{ fontSize: 16, textTransform: 'capitalize', boxShadow: "none", borderRadius: 4, width: 128, height: 40 }}
|
||||||
variant="contained"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={isDisabled || isPublishing}
|
disabled={isDisabled || isPublishing}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
+82
-10
@@ -391,6 +391,78 @@ export const getTheme = (themeMode, brandColor) =>
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
props: { variant: 'aiButton' },
|
||||||
|
style: {
|
||||||
|
background: 'linear-gradient(90deg, #ff8544 0%, #ec517c 50%, #9c5af2 100%)',
|
||||||
|
color: '#ffffff',
|
||||||
|
borderRadius: '4px',
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
textWrap: "normal",
|
||||||
|
border: 'none',
|
||||||
|
boxShadow: 'none',
|
||||||
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
'&:hover': {
|
||||||
|
color: '#ffffff',
|
||||||
|
textShadow: '0 0 1px currentColor',
|
||||||
|
},
|
||||||
|
'&:active': {
|
||||||
|
background: 'linear-gradient(90deg, #e6743a 0%, #d4456e 50%, #8a4de8 100%)',
|
||||||
|
},
|
||||||
|
'&:disabled': {
|
||||||
|
background: themeMode === "dark" ? '#494949' : '#C9C9C9',
|
||||||
|
color: themeMode === "dark" ? '#9E9E9E' : '#616161',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
props: { variant: 'aiButtonGhost' },
|
||||||
|
style: {
|
||||||
|
background: 'transparent',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '4px',
|
||||||
|
color: '#ffffff',
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
textWrap: "normal",
|
||||||
|
boxShadow: 'none',
|
||||||
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
position: 'relative',
|
||||||
|
'&::before': {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
borderRadius: '4px',
|
||||||
|
padding: '2px',
|
||||||
|
background: 'linear-gradient(90deg, #ff8544 0%, #ec517c 50%, #9c5af2 100%)',
|
||||||
|
mask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
|
||||||
|
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
|
||||||
|
maskComposite: 'exclude',
|
||||||
|
WebkitMaskComposite: 'xor',
|
||||||
|
transition: 'opacity 0.2s ease-in-out',
|
||||||
|
zIndex: -1,
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
background: 'linear-gradient(90deg, #ff8544 0%, #ec517c 50%, #9c5af2 100%)',
|
||||||
|
color: '#ffffff',
|
||||||
|
'&::before': {
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'&:active': {
|
||||||
|
background: 'linear-gradient(90deg, #e6743a 0%, #d4456e 50%, #8a4de8 100%)',
|
||||||
|
},
|
||||||
|
'&:disabled': {
|
||||||
|
background: 'transparent',
|
||||||
|
color: themeMode === "dark" ? '#9E9E9E' : '#616161',
|
||||||
|
'&::before': {
|
||||||
|
background: themeMode === "dark" ? '#494949' : '#C9C9C9',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
MuiTab: {
|
MuiTab: {
|
||||||
@@ -412,39 +484,39 @@ export const getTheme = (themeMode, brandColor) =>
|
|||||||
MuiCssBaseline: {
|
MuiCssBaseline: {
|
||||||
styleOverrides: `
|
styleOverrides: `
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Roboto';
|
font-family: 'Inter';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light');
|
src: local('Inter Light'), local('Inter-Light');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Roboto';
|
font-family: 'Inter';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Roboto'), local('Roboto-Regular');
|
src: local('Inter Regular'), local('Inter-Regular');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Roboto';
|
font-family: 'Inter';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium');
|
src: local('Inter Medium'), local('Inter-Medium');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Roboto';
|
font-family: 'Inter';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
src: local('Roboto SemiBold'), local('Roboto-SemiBold');
|
src: local('Inter SemiBold'), local('Inter-SemiBold');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Roboto';
|
font-family: 'Inter';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold');
|
src: local('Inter Bold'), local('Inter-Bold');
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useNavigate, Link, useParams } from "react-router-dom";
|
|||||||
import { isMobile } from "react-device-detect";
|
import { isMobile } from "react-device-detect";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useInterval } from "react-powerhooks";
|
import { useInterval } from "react-powerhooks";
|
||||||
|
import ReactGA from 'react-ga4';
|
||||||
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
|
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
|
||||||
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||||
import {
|
import {
|
||||||
@@ -157,7 +158,7 @@ const FreePlanCard = ({ classes }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MarketplaceCard = ({ classes }) => {
|
const MarketplaceCard = ({ classes, isCloud }) => {
|
||||||
const marketplaceOptions = [
|
const marketplaceOptions = [
|
||||||
{
|
{
|
||||||
name: "Open Source Install",
|
name: "Open Source Install",
|
||||||
@@ -216,6 +217,15 @@ const MarketplaceCard = ({ classes }) => {
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
// Track marketplace click
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: "click_marketplace_option",
|
||||||
|
label: option.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (option.valid === true) {
|
if (option.valid === true) {
|
||||||
window.open(option.link, "_blank")
|
window.open(option.link, "_blank")
|
||||||
}
|
}
|
||||||
@@ -512,6 +522,15 @@ const LoginPage = props => {
|
|||||||
const onSubmit = (e) => {
|
const onSubmit = (e) => {
|
||||||
//toast("Testing from login page")
|
//toast("Testing from login page")
|
||||||
|
|
||||||
|
// Track form submission attempt
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: register ? "submit_login_form" : "submit_register_form",
|
||||||
|
label: register ? (loginWithSSO ? "SSO Login Form" : "Email Login Form") : "Email Registration Form",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setMessage("")
|
setMessage("")
|
||||||
setLoginLoading(true)
|
setLoginLoading(true)
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -556,6 +575,14 @@ const LoginPage = props => {
|
|||||||
setLoginLoading(false)
|
setLoginLoading(false)
|
||||||
|
|
||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
|
// Track failed login event
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: loginWithSSO ? "login_sso_failed" : "login_failed",
|
||||||
|
label: loginWithSSO ? "SSO Login Failed" : "Email Login Failed",
|
||||||
|
});
|
||||||
|
}
|
||||||
setLoginInfo(responseJson["reason"])
|
setLoginInfo(responseJson["reason"])
|
||||||
} else {
|
} else {
|
||||||
if (responseJson?.region_url !== undefined && responseJson?.region_url !== null && responseJson?.region_url !== "") {
|
if (responseJson?.region_url !== undefined && responseJson?.region_url !== null && responseJson?.region_url !== "") {
|
||||||
@@ -583,6 +610,14 @@ const LoginPage = props => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track successful login event
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: loginWithSSO ? "login_sso_success" : "login_success",
|
||||||
|
label: loginWithSSO ? "SSO Login" : "Email Login",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setLoginInfo("Successful login! Redirecting you in 3 seconds...")
|
setLoginInfo("Successful login! Redirecting you in 3 seconds...")
|
||||||
for (var key in responseJson["cookies"]) {
|
for (var key in responseJson["cookies"]) {
|
||||||
@@ -643,6 +678,14 @@ const LoginPage = props => {
|
|||||||
.then(response =>
|
.then(response =>
|
||||||
response.json().then(responseJson => {
|
response.json().then(responseJson => {
|
||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
|
// Track failed registration event
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: "register_failed",
|
||||||
|
label: "Email Registration Failed",
|
||||||
|
});
|
||||||
|
}
|
||||||
setLoginInfo(responseJson["reason"])
|
setLoginInfo(responseJson["reason"])
|
||||||
} else {
|
} else {
|
||||||
if (responseJson["reason"] === "shuffle_account") {
|
if (responseJson["reason"] === "shuffle_account") {
|
||||||
@@ -659,6 +702,16 @@ const LoginPage = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setLoginLoading(false)
|
setLoginLoading(false)
|
||||||
|
|
||||||
|
// Track successful registration event
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: "register_success",
|
||||||
|
label: "Email Registration",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setLoginInfo("Successful registration! Redirecting in 3 seconds...")
|
setLoginInfo("Successful registration! Redirecting in 3 seconds...")
|
||||||
|
|
||||||
|
|
||||||
@@ -707,15 +760,40 @@ const LoginPage = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const HandleLoginWithSSO = () => {
|
const HandleLoginWithSSO = () => {
|
||||||
|
// Track SSO login attempt
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: "click_sso_login",
|
||||||
|
label: "SSO Login Attempt",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setPassword("")
|
setPassword("")
|
||||||
setLoginInfo("")
|
setLoginInfo("")
|
||||||
setLoginWithSSO(true)
|
setLoginWithSSO(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
var formtitle = register ? <div>Welcome Back!</div> : <div>Create your account</div>
|
var formtitle = register ? <div>Welcome Back!</div> : <div>Create your account</div>
|
||||||
var formButton = !isCloud ? "" : register ? <div style={{ display: "flex" }}> <div style={{ fontSize: "14px", paddingRight: "7px", textDecoration: "none", }}>Don’t have an account yet?</div> <Link style={hrefStyle} to={`/register${parsedsearch}`}><div>Register here</div></Link></div> : <>
|
var formButton = !isCloud ? "" : register ? <div style={{ display: "flex" }}> <div style={{ fontSize: "14px", paddingRight: "7px", textDecoration: "none", }}>Don’t have an account yet?</div> <Link style={hrefStyle} to={`/register${parsedsearch}`} onClick={() => {
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: "click_register_link",
|
||||||
|
label: "Switch to Register",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}><div>Register here</div></Link></div> : <>
|
||||||
|
|
||||||
<div style={{ display: "flex", marginTop: 40, marginBottom: -10 }}> <div style={{ fontSize: "14px", paddingRight: "7px", textDecoration: "none", }}>Already have an account?</div> <Link style={hrefStyle} to={`/login${parsedsearch}`}><div>Login here</div></Link></div>
|
<div style={{ display: "flex", marginTop: 40, marginBottom: -10 }}> <div style={{ fontSize: "14px", paddingRight: "7px", textDecoration: "none", }}>Already have an account?</div> <Link style={hrefStyle} to={`/login${parsedsearch}`} onClick={() => {
|
||||||
|
if (isCloud) {
|
||||||
|
ReactGA.event({
|
||||||
|
category: "authentication",
|
||||||
|
action: "click_login_link",
|
||||||
|
label: "Switch to Login",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}><div>Login here</div></Link></div>
|
||||||
</>
|
</>
|
||||||
//<Link to={`/login${parsedsearch}`} style={hrefStyle}><div>Click here to Login</div></Link>
|
//<Link to={`/login${parsedsearch}`} style={hrefStyle}><div>Click here to Login</div></Link>
|
||||||
|
|
||||||
@@ -1025,7 +1103,7 @@ const LoginPage = props => {
|
|||||||
<div className={classes.divider}>
|
<div className={classes.divider}>
|
||||||
<span>OR</span>
|
<span>OR</span>
|
||||||
</div>
|
</div>
|
||||||
<MarketplaceCard classes={classes} />
|
<MarketplaceCard classes={classes} isCloud={isCloud} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user