commit
e6548a6c92
|
@ -10,6 +10,7 @@
|
||||||
import CodeEditorModal from "./CodeEditorModal.svelte"
|
import CodeEditorModal from "./CodeEditorModal.svelte"
|
||||||
import QuerySelector from "./QuerySelector.svelte"
|
import QuerySelector from "./QuerySelector.svelte"
|
||||||
import QueryParamSelector from "./QueryParamSelector.svelte"
|
import QueryParamSelector from "./QueryParamSelector.svelte"
|
||||||
|
import CronBuilder from "./CronBuilder.svelte"
|
||||||
import Editor from "components/integration/QueryEditor.svelte"
|
import Editor from "components/integration/QueryEditor.svelte"
|
||||||
|
|
||||||
export let block
|
export let block
|
||||||
|
@ -76,6 +77,8 @@
|
||||||
/>
|
/>
|
||||||
{:else if value.customType === "query"}
|
{:else if value.customType === "query"}
|
||||||
<QuerySelector bind:value={block.inputs[key]} />
|
<QuerySelector bind:value={block.inputs[key]} />
|
||||||
|
{:else if value.customType === "cron"}
|
||||||
|
<CronBuilder bind:value={block.inputs[key]} />
|
||||||
{:else if value.customType === "queryParams"}
|
{:else if value.customType === "queryParams"}
|
||||||
<QueryParamSelector bind:value={block.inputs[key]} {bindings} />
|
<QueryParamSelector bind:value={block.inputs[key]} {bindings} />
|
||||||
{:else if value.customType === "table"}
|
{:else if value.customType === "table"}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<script>
|
||||||
|
import { Button, Select, Label, Heading, Input } from "@budibase/bbui"
|
||||||
|
|
||||||
|
export let value
|
||||||
|
|
||||||
|
let presets = false
|
||||||
|
|
||||||
|
const CRON_EXPRESSIONS = [
|
||||||
|
{
|
||||||
|
label: "Every Minute",
|
||||||
|
value: "* * * * *",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Every Hour",
|
||||||
|
value: "0 * * * *",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Every Morning at 8AM",
|
||||||
|
value: "0 8 * * *",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Every Night at Midnight",
|
||||||
|
value: "0 0 * * *",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Every Budibase Reboot",
|
||||||
|
value: "@reboot",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="block-field">
|
||||||
|
<Input bind:value />
|
||||||
|
|
||||||
|
<div class="presets">
|
||||||
|
<Button on:click={() => (presets = !presets)}
|
||||||
|
>{presets ? "Hide" : "Show"} Presets</Button
|
||||||
|
>
|
||||||
|
{#if presets}
|
||||||
|
<Select
|
||||||
|
bind:value
|
||||||
|
secondary
|
||||||
|
extraThin
|
||||||
|
label="Presets"
|
||||||
|
options={CRON_EXPRESSIONS}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.presets {
|
||||||
|
margin-top: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.block-field {
|
||||||
|
padding-top: var(--spacing-s);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -61,7 +61,6 @@
|
||||||
|
|
||||||
// Required to check any updated deployment statuses between polls
|
// Required to check any updated deployment statuses between polls
|
||||||
function checkIncomingDeploymentStatus(current, incoming) {
|
function checkIncomingDeploymentStatus(current, incoming) {
|
||||||
console.log(current, incoming)
|
|
||||||
for (let incomingDeployment of incoming) {
|
for (let incomingDeployment of incoming) {
|
||||||
if (
|
if (
|
||||||
incomingDeployment.status === DeploymentStatus.FAILURE ||
|
incomingDeployment.status === DeploymentStatus.FAILURE ||
|
||||||
|
|
|
@ -6,6 +6,8 @@ const webhooks = require("./webhook")
|
||||||
const { getAutomationParams, generateAutomationID } = require("../../db/utils")
|
const { getAutomationParams, generateAutomationID } = require("../../db/utils")
|
||||||
|
|
||||||
const WH_STEP_ID = triggers.BUILTIN_DEFINITIONS.WEBHOOK.stepId
|
const WH_STEP_ID = triggers.BUILTIN_DEFINITIONS.WEBHOOK.stepId
|
||||||
|
const CRON_STEP_ID = triggers.BUILTIN_DEFINITIONS.CRON.stepId
|
||||||
|
|
||||||
/*************************
|
/*************************
|
||||||
* *
|
* *
|
||||||
* BUILDER FUNCTIONS *
|
* BUILDER FUNCTIONS *
|
||||||
|
@ -32,6 +34,46 @@ function cleanAutomationInputs(automation) {
|
||||||
return automation
|
return automation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function handles checking of any cron jobs need to be created or deleted for automations.
|
||||||
|
* @param {string} appId The ID of the app in which we are checking for webhooks
|
||||||
|
* @param {object|undefined} oldAuto The old automation object if updating/deleting
|
||||||
|
* @param {object|undefined} newAuto The new automation object if creating/updating
|
||||||
|
*/
|
||||||
|
async function checkForCronTriggers({ appId, oldAuto, newAuto }) {
|
||||||
|
const oldTrigger = oldAuto ? oldAuto.definition.trigger : null
|
||||||
|
const newTrigger = newAuto ? newAuto.definition.trigger : null
|
||||||
|
function isCronTrigger(auto) {
|
||||||
|
return (
|
||||||
|
auto &&
|
||||||
|
auto.definition.trigger &&
|
||||||
|
auto.definition.trigger.stepId === CRON_STEP_ID
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLive = auto => auto && auto.live
|
||||||
|
|
||||||
|
const cronTriggerRemoved =
|
||||||
|
isCronTrigger(oldAuto) && !isCronTrigger(newAuto) && oldTrigger.cronJobId
|
||||||
|
const cronTriggerDeactivated = !isLive(newAuto) && isLive(oldAuto)
|
||||||
|
|
||||||
|
const cronTriggerActivated = isLive(newAuto) && !isLive(oldAuto)
|
||||||
|
|
||||||
|
if (cronTriggerRemoved || cronTriggerDeactivated) {
|
||||||
|
await triggers.automationQueue.removeRepeatableByKey(oldTrigger.cronJobId)
|
||||||
|
}
|
||||||
|
// need to create cron job
|
||||||
|
else if (isCronTrigger(newAuto) && cronTriggerActivated) {
|
||||||
|
const job = await triggers.automationQueue.add(
|
||||||
|
{ automation: newAuto, event: { appId } },
|
||||||
|
{ repeat: { cron: newTrigger.inputs.cron } }
|
||||||
|
)
|
||||||
|
// Assign cron job ID from bull so we can remove it later if the cron trigger is removed
|
||||||
|
newTrigger.cronJobId = job.id
|
||||||
|
}
|
||||||
|
return newAuto
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function handles checking if any webhooks need to be created or deleted for automations.
|
* This function handles checking if any webhooks need to be created or deleted for automations.
|
||||||
* @param {string} appId The ID of the app in which we are checking for webhooks
|
* @param {string} appId The ID of the app in which we are checking for webhooks
|
||||||
|
@ -111,6 +153,10 @@ exports.create = async function (ctx) {
|
||||||
appId: ctx.appId,
|
appId: ctx.appId,
|
||||||
newAuto: automation,
|
newAuto: automation,
|
||||||
})
|
})
|
||||||
|
automation = await checkForCronTriggers({
|
||||||
|
appId: ctx.appId,
|
||||||
|
newAuto: automation,
|
||||||
|
})
|
||||||
const response = await db.put(automation)
|
const response = await db.put(automation)
|
||||||
automation._rev = response.rev
|
automation._rev = response.rev
|
||||||
|
|
||||||
|
@ -135,6 +181,11 @@ exports.update = async function (ctx) {
|
||||||
oldAuto: oldAutomation,
|
oldAuto: oldAutomation,
|
||||||
newAuto: automation,
|
newAuto: automation,
|
||||||
})
|
})
|
||||||
|
automation = await checkForCronTriggers({
|
||||||
|
appId: ctx.appId,
|
||||||
|
oldAuto: oldAutomation,
|
||||||
|
newAuto: automation,
|
||||||
|
})
|
||||||
const response = await db.put(automation)
|
const response = await db.put(automation)
|
||||||
automation._rev = response.rev
|
automation._rev = response.rev
|
||||||
|
|
||||||
|
@ -171,6 +222,10 @@ exports.destroy = async function (ctx) {
|
||||||
appId: ctx.appId,
|
appId: ctx.appId,
|
||||||
oldAuto: oldAutomation,
|
oldAuto: oldAutomation,
|
||||||
})
|
})
|
||||||
|
await checkForCronTriggers({
|
||||||
|
appId: ctx.appId,
|
||||||
|
oldAuto: oldAutomation,
|
||||||
|
})
|
||||||
ctx.body = await db.remove(ctx.params.id, ctx.params.rev)
|
ctx.body = await db.remove(ctx.params.id, ctx.params.rev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ const FILTER_STEP_ID = logic.BUILTIN_DEFINITIONS.FILTER.stepId
|
||||||
* inputs and handles any outputs.
|
* inputs and handles any outputs.
|
||||||
*/
|
*/
|
||||||
class Orchestrator {
|
class Orchestrator {
|
||||||
constructor(automation, triggerOutput) {
|
constructor(automation, triggerOutput = {}) {
|
||||||
this._metadata = triggerOutput.metadata
|
this._metadata = triggerOutput.metadata
|
||||||
this._chainCount = this._metadata ? this._metadata.automationChainCount : 0
|
this._chainCount = this._metadata ? this._metadata.automationChainCount : 0
|
||||||
this._appId = triggerOutput.appId
|
this._appId = triggerOutput.appId
|
||||||
|
|
|
@ -7,9 +7,10 @@ const Queue = env.isTest()
|
||||||
const { getAutomationParams } = require("../db/utils")
|
const { getAutomationParams } = require("../db/utils")
|
||||||
const { coerce } = require("../utilities/rowProcessor")
|
const { coerce } = require("../utilities/rowProcessor")
|
||||||
const { utils } = require("@budibase/auth/redis")
|
const { utils } = require("@budibase/auth/redis")
|
||||||
|
const { JobQueues } = require("../constants")
|
||||||
|
|
||||||
const { opts } = utils.getRedisOptions()
|
const { opts } = utils.getRedisOptions()
|
||||||
let automationQueue = new Queue("automationQueue", { redis: opts })
|
let automationQueue = new Queue(JobQueues.AUTOMATIONS, { redis: opts })
|
||||||
|
|
||||||
const FAKE_STRING = "TEST"
|
const FAKE_STRING = "TEST"
|
||||||
const FAKE_BOOL = false
|
const FAKE_BOOL = false
|
||||||
|
@ -196,6 +197,29 @@ const BUILTIN_DEFINITIONS = {
|
||||||
},
|
},
|
||||||
type: "TRIGGER",
|
type: "TRIGGER",
|
||||||
},
|
},
|
||||||
|
CRON: {
|
||||||
|
name: "Cron Trigger",
|
||||||
|
event: "cron:trigger",
|
||||||
|
icon: "ri-timer-line",
|
||||||
|
tagline: "Cron Trigger (<b>{{inputs.cron}}</b>)",
|
||||||
|
description: "Triggers automation on a cron schedule.",
|
||||||
|
stepId: "CRON",
|
||||||
|
inputs: {},
|
||||||
|
schema: {
|
||||||
|
inputs: {
|
||||||
|
properties: {
|
||||||
|
cron: {
|
||||||
|
type: "string",
|
||||||
|
customType: "cron",
|
||||||
|
title: "Expression",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["cron"],
|
||||||
|
},
|
||||||
|
outputs: {},
|
||||||
|
},
|
||||||
|
type: "TRIGGER",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
async function queueRelevantRowAutomations(event, eventType) {
|
async function queueRelevantRowAutomations(event, eventType) {
|
||||||
|
|
|
@ -5,6 +5,10 @@ const { ObjectStoreBuckets } = require("@budibase/auth").objectStore
|
||||||
exports.LOGO_URL =
|
exports.LOGO_URL =
|
||||||
"https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"
|
"https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"
|
||||||
|
|
||||||
|
exports.JobQueues = {
|
||||||
|
AUTOMATIONS: "automationQueue",
|
||||||
|
}
|
||||||
|
|
||||||
exports.FieldTypes = {
|
exports.FieldTypes = {
|
||||||
STRING: "string",
|
STRING: "string",
|
||||||
LONGFORM: "longform",
|
LONGFORM: "longform",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue