Merge branch 'master' into fix/csp-worker-signature-component
This commit is contained in:
commit
0c49f192c4
12 changed files with 99 additions and 19 deletions
|
@ -71,8 +71,8 @@ const handleMouseDown = e => {
|
|||
|
||||
// Clear any previous listeners in case of multiple down events, and register
|
||||
// a single mouse up listener
|
||||
document.removeEventListener("mouseup", handleMouseUp)
|
||||
document.addEventListener("mouseup", handleMouseUp, true)
|
||||
document.removeEventListener("click", handleMouseUp)
|
||||
document.addEventListener("click", handleMouseUp, true)
|
||||
}
|
||||
|
||||
// Global singleton listeners for our events
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import TestDataModal from "./TestDataModal.svelte"
|
||||
import { flip } from "svelte/animate"
|
||||
import { fly } from "svelte/transition"
|
||||
import { Icon, notifications, Modal } from "@budibase/bbui"
|
||||
import { Icon, notifications, Modal, Toggle } from "@budibase/bbui"
|
||||
import { ActionStepID } from "constants/backend/automations"
|
||||
import UndoRedoControl from "components/common/UndoRedoControl.svelte"
|
||||
|
||||
|
@ -73,6 +73,16 @@
|
|||
Test details
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-spacing">
|
||||
<Toggle
|
||||
text={automation.disabled ? "Paused" : "Activated"}
|
||||
on:change={automationStore.actions.toggleDisabled(
|
||||
automation._id,
|
||||
automation.disabled
|
||||
)}
|
||||
value={!automation.disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="canvas" on:scroll={handleScroll}>
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
selected={automation._id === selectedAutomationId}
|
||||
on:click={() => selectAutomation(automation._id)}
|
||||
selectedBy={$userSelectedResourceMap[automation._id]}
|
||||
disabled={automation.disabled}
|
||||
>
|
||||
<EditAutomationPopover {automation} />
|
||||
</NavItem>
|
||||
|
|
|
@ -39,6 +39,15 @@
|
|||
>Duplicate</MenuItem
|
||||
>
|
||||
<MenuItem icon="Edit" on:click={updateAutomationDialog.show}>Edit</MenuItem>
|
||||
<MenuItem
|
||||
icon={automation.disabled ? "CheckmarkCircle" : "Cancel"}
|
||||
on:click={automationStore.actions.toggleDisabled(
|
||||
automation._id,
|
||||
automation.disabled
|
||||
)}
|
||||
>
|
||||
{automation.disabled ? "Activate" : "Pause"}
|
||||
</MenuItem>
|
||||
<MenuItem icon="Delete" on:click={confirmDeleteDialog.show}>Delete</MenuItem>
|
||||
</ActionMenu>
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
export let selectedBy = null
|
||||
export let compact = false
|
||||
export let hovering = false
|
||||
export let disabled = false
|
||||
|
||||
const scrollApi = getContext("scroll")
|
||||
const dispatch = createEventDispatcher()
|
||||
|
@ -74,6 +75,7 @@
|
|||
class:scrollable
|
||||
class:highlighted
|
||||
class:selectedBy
|
||||
class:disabled
|
||||
on:dragend
|
||||
on:dragstart
|
||||
on:dragover
|
||||
|
@ -165,6 +167,9 @@
|
|||
--avatars-background: var(--spectrum-global-color-gray-300);
|
||||
color: var(--ink);
|
||||
}
|
||||
.nav-item.disabled span {
|
||||
color: var(--spectrum-global-color-gray-700);
|
||||
}
|
||||
.nav-item:hover,
|
||||
.hovering {
|
||||
background-color: var(--spectrum-global-color-gray-200);
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
parameters
|
||||
}
|
||||
$: automations = $automationStore.automations
|
||||
.filter(a => a.definition.trigger?.stepId === TriggerStepID.APP)
|
||||
.filter(
|
||||
a => a.definition.trigger?.stepId === TriggerStepID.APP && !a.disabled
|
||||
)
|
||||
.map(automation => {
|
||||
const schema = Object.entries(
|
||||
automation.definition.trigger.inputs.fields || {}
|
||||
|
|
|
@ -82,6 +82,7 @@ const automationActions = store => ({
|
|||
steps: [],
|
||||
trigger,
|
||||
},
|
||||
disabled: false,
|
||||
}
|
||||
const response = await store.actions.save(automation)
|
||||
await store.actions.fetch()
|
||||
|
@ -134,6 +135,28 @@ const automationActions = store => ({
|
|||
})
|
||||
await store.actions.fetch()
|
||||
},
|
||||
toggleDisabled: async automationId => {
|
||||
let automation
|
||||
try {
|
||||
automation = store.actions.getDefinition(automationId)
|
||||
if (!automation) {
|
||||
return
|
||||
}
|
||||
automation.disabled = !automation.disabled
|
||||
await store.actions.save(automation)
|
||||
notifications.success(
|
||||
`Automation ${
|
||||
automation.disabled ? "enabled" : "disabled"
|
||||
} successfully`
|
||||
)
|
||||
} catch (error) {
|
||||
notifications.error(
|
||||
`Error ${
|
||||
automation && automation.disabled ? "enabling" : "disabling"
|
||||
} automation`
|
||||
)
|
||||
}
|
||||
},
|
||||
updateBlockInputs: async (block, data) => {
|
||||
// Create new modified block
|
||||
let newBlock = {
|
||||
|
|
|
@ -274,20 +274,28 @@ export async function trigger(ctx: UserCtx) {
|
|||
|
||||
let hasCollectStep = sdk.automations.utils.checkForCollectStep(automation)
|
||||
if (hasCollectStep && (await features.isSyncAutomationsEnabled())) {
|
||||
const response: AutomationResults = await triggers.externalTrigger(
|
||||
automation,
|
||||
{
|
||||
fields: ctx.request.body.fields,
|
||||
timeout:
|
||||
ctx.request.body.timeout * 1000 || env.AUTOMATION_THREAD_TIMEOUT,
|
||||
},
|
||||
{ getResponses: true }
|
||||
)
|
||||
try {
|
||||
const response: AutomationResults = await triggers.externalTrigger(
|
||||
automation,
|
||||
{
|
||||
fields: ctx.request.body.fields,
|
||||
timeout:
|
||||
ctx.request.body.timeout * 1000 || env.AUTOMATION_THREAD_TIMEOUT,
|
||||
},
|
||||
{ getResponses: true }
|
||||
)
|
||||
|
||||
let collectedValue = response.steps.find(
|
||||
step => step.stepId === AutomationActionStepId.COLLECT
|
||||
)
|
||||
ctx.body = collectedValue?.outputs
|
||||
let collectedValue = response.steps.find(
|
||||
step => step.stepId === AutomationActionStepId.COLLECT
|
||||
)
|
||||
ctx.body = collectedValue?.outputs
|
||||
} catch (err: any) {
|
||||
if (err.message) {
|
||||
ctx.throw(400, err.message)
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ctx.appId && !dbCore.isProdAppID(ctx.appId)) {
|
||||
ctx.throw(400, "Only apps in production support this endpoint")
|
||||
|
|
|
@ -206,6 +206,23 @@ describe("/automations", () => {
|
|||
expect(res.body.value).toEqual([1, 2, 3])
|
||||
})
|
||||
|
||||
it("should throw an error when attempting to trigger a disabled automation", async () => {
|
||||
mocks.licenses.useSyncAutomations()
|
||||
let automation = collectAutomation()
|
||||
automation = await config.createAutomation({
|
||||
...automation,
|
||||
disabled: true,
|
||||
})
|
||||
|
||||
const res = await request
|
||||
.post(`/api/automations/${automation._id}/trigger`)
|
||||
.set(config.defaultHeaders())
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(400)
|
||||
|
||||
expect(res.body.message).toEqual("Automation is disabled")
|
||||
})
|
||||
|
||||
it("triggers an asynchronous automation", async () => {
|
||||
let automation = newAutomation()
|
||||
automation = await config.createAutomation(automation)
|
||||
|
|
|
@ -36,10 +36,10 @@ async function queueRelevantRowAutomations(
|
|||
await context.doInAppContext(event.appId, async () => {
|
||||
let automations = await getAllAutomations()
|
||||
|
||||
// filter down to the correct event type
|
||||
// filter down to the correct event type and enabled automations
|
||||
automations = automations.filter(automation => {
|
||||
const trigger = automation.definition.trigger
|
||||
return trigger && trigger.event === eventType
|
||||
return trigger && trigger.event === eventType && !automation.disabled
|
||||
})
|
||||
|
||||
for (let automation of automations) {
|
||||
|
@ -94,6 +94,9 @@ export async function externalTrigger(
|
|||
params: { fields: Record<string, any>; timeout?: number },
|
||||
{ getResponses }: { getResponses?: boolean } = {}
|
||||
): Promise<any> {
|
||||
if (automation.disabled) {
|
||||
throw new Error("Automation is disabled")
|
||||
}
|
||||
if (
|
||||
automation.definition != null &&
|
||||
automation.definition.trigger != null &&
|
||||
|
|
|
@ -196,6 +196,7 @@ export async function enableCronTrigger(appId: any, automation: Automation) {
|
|||
if (
|
||||
isCronTrigger(automation) &&
|
||||
!isRebootTrigger(automation) &&
|
||||
!automation.disabled &&
|
||||
trigger?.inputs.cron
|
||||
) {
|
||||
const cronExp = trigger.inputs.cron
|
||||
|
|
|
@ -125,6 +125,7 @@ export interface Automation extends Document {
|
|||
name: string
|
||||
internal?: boolean
|
||||
type?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
interface BaseIOStructure {
|
||||
|
|
Loading…
Reference in a new issue