Merge pull request #1372 from satti-hari-krishna-reddy/pipelines

added webhooks to the trigger view
This commit is contained in:
Frikky
2024-04-29 14:36:23 +02:00
committed by GitHub
3 changed files with 589 additions and 103 deletions
+1 -1
View File
@@ -4908,7 +4908,7 @@ func initHandlers() {
r.HandleFunc("/api/v1/triggers/outlook/{key}", shuffle.HandleGetSpecificTrigger).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/triggers/gmail/register", shuffle.HandleNewGmailRegister).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/triggers/gmail/getFolders", shuffle.HandleGetGmailFolders).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/triggers", shuffle.HandleGetTriggers).Methods("GET", "OPTIONS")
//r.HandleFunc("/api/v1/triggers/gmail/routing", handleGmailRouting).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/triggers/gmail/{key}", shuffle.HandleGetSpecificTrigger).Methods("GET", "OPTIONS")
+572 -88
View File
@@ -201,7 +201,9 @@ const Admin = (props) => {
const [showApiKey, setShowApiKey] = useState(false);
const [billingInfo, setBillingInfo] = React.useState({});
const [selectedStatus, setSelectedStatus] = React.useState([]);
const [webHooks, setWebHooks] = React.useState([]);
const [allSchedules, setAllSchedules] = React.useState([]);
const [pipelines, setPipelines] = React.useState([]);
const [, forceUpdate] = React.useState();
const [showDeleteAccountTextbox, setShowDeleteAccountTextbox] =
@@ -247,7 +249,11 @@ const Admin = (props) => {
) {
handleGetSubOrgs(userdata.active_org.id);
} else console.log("error in user data");
}, [userdata]);
}, [userdata]);
useEffect(() => {
handleGetAllTriggers()
}, []);
const isCloud =
window.location.host === "localhost:3002" ||
@@ -731,6 +737,32 @@ If you're interested, please let me know a time that works for you, or set up a
});
};
const handleGetAllTriggers = () => {
fetch(globalUrl + "/api/v1/triggers", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for getting all triggers");
}
return response.json();
})
.then((responseJson) => {
setWebHooks(responseJson.webhooks || []); // Handling the case where the result is null or undefined
setAllSchedules(responseJson.schedules || []);
// setPipelines(responseJson.pipelines || []);
})
.catch((error) => {
toast(error.toString());
});
};
const deleteSchedule = (data) => {
// FIXME - add some check here ROFL
console.log("INPUT: ", data);
@@ -756,11 +788,11 @@ If you're interested, please let me know a time that works for you, or set up a
if (responseJson["success"] === false) {
toast("Failed stopping schedule");
} else {
setTimeout(() => {
getSchedules();
}, 1500);
//toast("Successfully stopped schedule!")
toast("Successfully stopped schedule!");
}
setTimeout(handleGetAllTriggers, 1000);
}),
)
.catch((error) => {
@@ -768,6 +800,189 @@ If you're interested, please let me know a time that works for you, or set up a
});
};
const startSchedule = (trigger) => {
if (trigger.name.length <= 0) {
toast("Error: name can't be empty");
return;
}
toast("Creating schedule");
const data = {
name: trigger.name,
frequency: trigger.frequency,
execution_argument: trigger.argument,
environment: trigger.environment,
id: trigger.id,
start: trigger.start_node,
};
fetch(`${globalUrl}/api/v1/workflows/${trigger.workflow_id}/schedule`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for stream results :O!");
}
return response.json();
})
.then((responseJson) => {
if (!responseJson.success) {
toast("Failed to set schedule: " + responseJson.reason);
} else {
toast("Successfully created schedule");
}
setTimeout(handleGetAllTriggers, 1000);
})
.catch((error) => {
//toast(error.toString());
console.log("Get schedule error: ", error.toString());
});
};
const deleteWebhook = (trigger) => {
if (trigger === undefined) {
return;
}
fetch(globalUrl + "/api/v1/hooks/" + trigger.id + "/delete", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for stream results :O!");
}
return response.json();
})
.then((responseJson) => {
if (responseJson.success) {
toast("Successfully stopped webhook");
} else {
if (responseJson.reason !== undefined) {
toast("Failed stopping webhook: " + responseJson.reason);
}
}
setTimeout(handleGetAllTriggers, 1000);
})
.catch((error) => {
toast(
"Delete webhook error. Contact support or check logs if this persists.",
);
});
};
const startWebHook = (trigger) => {
const hookname = trigger.info.name;
if (hookname.length === 0) {
toast("Missing name");
return;
}
if (trigger.id.length !== 36) {
toast("Missing id");
return;
}
toast("Starting webhook");
const data = {
name: hookname,
type: "webhook",
id: trigger.id,
workflow: trigger.workflows[0],
start: trigger.start,
environment: trigger.environment,
auth: trigger.auth,
custom_response: trigger.custom_response,
version: trigger.version,
version_timeout: 15,
};
console.log("Trigger data: ", data);
fetch(globalUrl + "/api/v1/hooks/new", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(data),
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
if (responseJson.success) {
// Set the status
toast("Successfully started webhook");
} else {
toast("Failed starting webhook: " + responseJson.reason);
}
setTimeout(handleGetAllTriggers, 1000);
})
.catch((error) => {
//console.log(error.toString());
console.log("New webhook error: ", error.toString());
});
};
const changePipelineState = (pipeline, state) => {
if (state.trim() === "") {
toast("state is not defined");
return;
}
const data = {
name: pipeline.name,
type: state,
environment: pipeline.environment,
workflow_id: pipeline.workflow_id,
trigger_id: pipeline.trigger_id,
};
if (state === "start") toast("starting the pipeline");
else toast("stopping the pipeline");
const url = `${globalUrl}/api/v1/triggers/pipeline`;
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for stream results :O!");
toast("Failed to update the pipeline state");
}
return response.json();
})
.then((responseJson) => {
if (!responseJson.success) {
toast("Failed to update the pipeline: " + responseJson.reason);
} else {
if (state === "start") toast("Successfully created pipeline");
else toast("Sucessfully stopped the pipeline");
}
})
.catch((error) => {
//toast(error.toString());
console.log("Get schedule error: ", error.toString());
});
};
if (
userdata.support === true &&
selectedOrganization.id !== "" &&
@@ -4384,7 +4599,7 @@ If you're interested, please let me know a time that works for you, or set up a
/>
);
const schedulesView =
const schedulesView =
curTab === 5 ? (
<div>
<div style={{ marginTop: 20, marginBottom: 20 }}>
@@ -4408,88 +4623,357 @@ If you're interested, please let me know a time that works for you, or set up a
backgroundColor: theme.palette.inputColor,
}}
/>
<List>
<ListItem>
<ListItemText
primary="Interval"
style={{ maxWidth: 200, minWidth: 200 }}
/>
<ListItemText
primary="Environment"
style={{ maxWidth: 150, minWidth: 150 }}
/>
<ListItemText
primary="Workflow"
style={{ maxWidth: 315, minWidth: 315 }}
/>
<ListItemText
primary="Argument"
style={{ minWidth: 300, maxWidth: 300, overflow: "hidden" }}
/>
<ListItemText primary="Actions" />
<ListItemText primary="Delegation" />
</ListItem>
{schedules === undefined || schedules === null
? null
: schedules.map((schedule, index) => {
var bgColor = "#27292d";
if (index % 2 === 0) {
bgColor = "#1f2023";
}
return (
<ListItem key={index} style={{ backgroundColor: bgColor }}>
<ListItemText
style={{ maxWidth: 200, minWidth: 200 }}
primary={
schedule.environment === "cloud" ||
schedule.environment === "" ||
schedule.frequency.length > 0 ? (
schedule.frequency
) : (
<span>{schedule.seconds} seconds</span>
)
}
/>
<ListItemText
style={{ maxWidth: 150, minWidth: 150 }}
primary={schedule.environment}
/>
<ListItemText
style={{ maxWidth: 315, minWidth: 315 }}
primary={
<a
style={{ textDecoration: "none", color: "#f85a3e" }}
href={`/workflows/${schedule.workflow_id}`}
target="_blank"
rel="noopener noreferrer"
>
{schedule.workflow_id}
</a>
}
/>
<ListItemText
primary={schedule.argument.replaceAll('\\"', '"')}
style={{
minWidth: 300,
maxWidth: 300,
overflow: "hidden",
}}
/>
<ListItemText>
<Button
style={{}}
variant="contained"
color="primary"
onClick={() => deleteSchedule(schedule)}
{allSchedules === undefined ||
allSchedules === null ||
allSchedules.length === 0 ? (
<div
style={{
textAlign: "center",
padding: "20px",
color: "#666",
borderRadius: "5px",
}}
>
No schedules found.
</div>
) : (
<List>
<ListItem>
<ListItemText
primary="Interval"
style={{ maxWidth: 200, minWidth: 200 }}
/>
<ListItemText
primary="Environment"
style={{ maxWidth: 150, minWidth: 150 }}
/>
<ListItemText
primary="Workflow"
style={{ maxWidth: 315, minWidth: 315 }}
/>
<ListItemText
primary="Argument"
style={{ minWidth: 300, maxWidth: 300, overflow: "hidden" }}
/>
<ListItemText primary="Actions" />
<ListItemText primary="Delegation" />
</ListItem>
{allSchedules.map((schedule, index) => {
var bgColor = "#27292d";
if (index % 2 === 0) {
bgColor = "#1f2023";
}
return (
<ListItem key={index} style={{ backgroundColor: bgColor }}>
<ListItemText
style={{ maxWidth: 200, minWidth: 200 }}
primary={
schedule.environment === "cloud" ||
schedule.environment === "" ||
schedule.frequency.length > 0 ? (
schedule.frequency
) : (
<span>{schedule.seconds} seconds</span>
)
}
/>
<ListItemText
style={{ maxWidth: 150, minWidth: 150 }}
primary={schedule.environment}
/>
<ListItemText
style={{ maxWidth: 315, minWidth: 315 }}
primary={
<a
style={{ textDecoration: "none", color: "#f85a3e" }}
href={`/workflows/${schedule.workflow_id}`}
target="_blank"
rel="noopener noreferrer"
>
Stop schedule
</Button>
</ListItemText>
</ListItem>
);
})}
</List>
{schedule.workflow_id}
</a>
}
/>
<ListItemText
primary={schedule.wrapped_argument.replaceAll('\\"', '"')}
style={{
minWidth: 300,
maxWidth: 300,
overflow: "hidden",
}}
/>
<ListItemText>
<Button
style={{}}
variant={
schedule.status === "running" ? "contained" : "outlined"
}
disabled={schedule.status === "uninitialized"}
onClick={() => {
if (schedule.status === "running") {
deleteSchedule(schedule);
} else startSchedule(schedule);
}}
>
{schedule.status === "running"
? "Stop Schedule"
: "Start Schedule"}
</Button>
</ListItemText>
</ListItem>
);
})}
</List>
)}
<div style={{ marginTop: 20, marginBottom: 20 }}>
<h2 style={{ display: "inline" }}>WebHooks</h2>
</div>
<Divider
style={{
marginTop: 20,
marginBottom: 20,
backgroundColor: theme.palette.inputColor,
}}
/>
{webHooks === undefined || webHooks === null || webHooks.length === 0 ? (
<div
style={{
textAlign: "center",
padding: "20px",
color: "#666",
borderRadius: "5px",
}}
>
No webhooks found.
</div>
) : (
<List>
<ListItem>
<ListItemText
primary="Name"
style={{ maxWidth: 200, minWidth: 200 }}
/>
<ListItemText
primary="Environment"
style={{ maxWidth: 150, minWidth: 150 }}
/>
<ListItemText
primary="Workflow"
style={{ maxWidth: 315, minWidth: 315 }}
/>
<ListItemText
primary="Url"
style={{ minWidth: 300, maxWidth: 300, overflow: "hidden" }}
/>
<ListItemText primary="Actions" />
</ListItem>
{webHooks.map((webhook, index) => {
var bgColor = "#27292d";
if (index % 2 === 0) {
bgColor = "#1f2023";
}
return (
<ListItem key={index} style={{ backgroundColor: bgColor }}>
<ListItemText
style={{ maxWidth: 200, minWidth: 200 }}
primary={webhook.info.name}
/>
<ListItemText
style={{ maxWidth: 150, minWidth: 150 }}
primary={webhook.environment}
/>
<ListItemText
style={{ maxWidth: 315, minWidth: 315 }}
primary={
<a
style={{ textDecoration: "none", color: "#f85a3e" }}
href={`/workflows/${webhook.workflows[0]}`}
target="_blank"
rel="noopener noreferrer"
>
{webhook.workflows[0]}
</a>
}
/>
<ListItemText
style={{ marginLeft: 10, maxWidth: 100, minWidth: 100 }}
primary={
webhook.info.url === undefined || webhook.info.url === 0 ? (
""
) : (
<Tooltip
title={"Copy URL"}
style={{}}
aria-label={"Copy URL"}
>
<IconButton
style={{}}
onClick={() => {
const elementName = "copy_element_shuffle";
var copyText = document.getElementById(elementName);
if (copyText !== null && copyText !== undefined) {
const clipboard = navigator.clipboard;
if (clipboard === undefined) {
toast("Can only copy over HTTPS (port 3443)");
return;
}
navigator.clipboard.writeText(webhook.info.url);
copyText.select();
copyText.setSelectionRange(
0,
99999,
); /* For mobile devices */
/* Copy the text inside the text field */
document.execCommand("copy");
toast("URL copied to clipboard");
}
}}
>
<FileCopyIcon
style={{ color: "rgba(255,255,255,0.8)" }}
/>
</IconButton>
</Tooltip>
)
}
/>
<ListItemText>
<Button
style={{ marginLeft: "18%" }}
variant={
webhook.status === "running" ? "contained" : "outlined"
}
disabled={webhook.status === "uninitialized"}
onClick={() => {
if (webhook.status === "running") {
deleteWebhook(webhook);
} else startWebHook(webhook);
}}
>
{webhook.status === "running"
? "Stop webhook"
: "Start Webhook"}
</Button>
</ListItemText>
</ListItem>
);
})}
</List>
)}
{/* <div style={{ marginTop: 20, marginBottom: 20 }}>
<h2 style={{ display: "inline" }}>Tenzir Pipelines</h2>
<span style={{ marginLeft: 25 }}>
Controls a pipeline to run things.{" "}
<a
target="_blank"
rel="noopener noreferrer"
href="/docs/triggers#pipelines"
style={{ textDecoration: "none", color: "#f85a3e" }}
>
Learn more
</a>
</span>
</div>
<Divider
style={{
marginTop: 20,
marginBottom: 20,
backgroundColor: theme.palette.inputColor,
}}
/>
{pipelines === undefined ||
pipelines === null ||
pipelines.length === 0 ? (
<div
style={{
textAlign: "center",
padding: "20px",
color: "#666",
borderRadius: "5px",
}}
>
No pipelines found.
</div>
) : (
<List>
<ListItem>
<ListItemText
primary="Name"
style={{ maxWidth: 200, minWidth: 200 }}
/>
<ListItemText
primary="Environment"
style={{ maxWidth: 150, minWidth: 150 }}
/>
<ListItemText
primary="Workflow"
style={{ maxWidth: 315, minWidth: 315 }}
/>
<ListItemText primary="Actions" />
</ListItem>
{pipelines.map((pipeline, index) => {
var bgColor = "#27292d";
if (index % 2 === 0) {
bgColor = "#1f2023";
}
return (
<ListItem key={index} style={{ backgroundColor: bgColor }}>
<ListItemText
style={{ maxWidth: 200, minWidth: 200 }}
primary={pipeline.name}
/>
<ListItemText
style={{ maxWidth: 150, minWidth: 150 }}
primary={pipeline.environment}
/>
<ListItemText
style={{ maxWidth: 315, minWidth: 315 }}
primary={
<a
style={{ textDecoration: "none", color: "#f85a3e" }}
href={`/workflows/${pipeline.workflow_id}`}
target="_blank"
rel="noopener noreferrer"
>
{pipeline.workflow_id}
</a>
}
/>
<ListItemText>
<Button
style={{ marginLeft: "18%" }}
variant={
pipeline.status === "running" ? "contained" : "outlined"
}
disabled={pipeline.status === "uninitialized"}
onClick={() => {
if (pipeline.status === "running") {
changePipelineState(pipeline, "stop");
} else changePipelineState(pipeline, "start");
}}
>
{pipeline.status === "running"
? "Stop pipeline"
: "Start pipeline"}
</Button>
</ListItemText>
</ListItem>
);
})}
</List>
)}*/}
</div>
) : null;
+16 -14
View File
@@ -13124,7 +13124,7 @@ const AngularWorkflow = (defaultprops) => {
if (trigger.id === undefined) {
return;
}
fetch(globalUrl + "/api/v1/hooks/" + trigger.id + "/delete", {
method: "DELETE",
headers: {
@@ -13137,32 +13137,34 @@ const AngularWorkflow = (defaultprops) => {
if (response.status !== 200) {
console.log("Status not 200 for stream results :O!");
}
return response.json();
})
.then((responseJson) => {
if (!responseJson.success) {
if (responseJson.reason !== undefined) {
toast("Failed to stop webhook: " + responseJson.reason);
}
} else {
toast("Successfully stopped webhook");
}
if (workflow.triggers[triggerindex] !== undefined) {
workflow.triggers[triggerindex].status = "stopped";
}
if (responseJson.success) {
// Set the status
saveWorkflow(workflow);
} else {
if (responseJson.reason !== undefined) {
toast("Failed stopping webhook: " + responseJson.reason);
}
}
trigger.status = "stopped";
setWorkflow(workflow);
setSelectedTrigger(trigger);
setWorkflow(workflow);
saveWorkflow(workflow);
})
.catch((error) => {
//toast(error.toString());
toast("Delete webhook error. Contact support or check logs if this persists.")
toast(
"Delete webhook error. Contact support or check logs if this persists.",
);
});
};
// POST to /api/v1/workflows
const createWorkflow = (workflow, trigger_index) => {