Joe-ifying some of the work on webhooks to make it a bit easier to understand and finished up some testing around it.
This commit is contained in:
parent
a6c4e7fd04
commit
533e502143
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { backendUiStore, automationStore } from "builderStore"
|
import { backendUiStore, automationStore } from "builderStore"
|
||||||
import CreateWebookModal from "./CreateWebhookModal.svelte"
|
import CreateWebookModal from "../../Shared/CreateWebhookModal.svelte"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import { Modal } from "@budibase/bbui"
|
import { Modal } from "@budibase/bbui"
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
import RowSelector from "./ParamInputs/RowSelector.svelte"
|
import RowSelector from "./ParamInputs/RowSelector.svelte"
|
||||||
import { Button, Input, TextArea, Select, Label } from "@budibase/bbui"
|
import { Button, Input, TextArea, Select, Label } from "@budibase/bbui"
|
||||||
import { automationStore } from "builderStore"
|
import { automationStore } from "builderStore"
|
||||||
import WebhookDisplay from "../AutomationPanel/BlockList/WebhookDisplay.svelte"
|
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
|
||||||
import BindableInput from "../../userInterface/BindableInput.svelte"
|
import BindableInput from "../../userInterface/BindableInput.svelte"
|
||||||
|
|
||||||
export let block
|
export let block
|
||||||
|
export let webhookModal
|
||||||
$: inputs = Object.entries(block.schema?.inputs?.properties || {})
|
$: inputs = Object.entries(block.schema?.inputs?.properties || {})
|
||||||
|
$: stepId = block.stepId
|
||||||
$: bindings = getAvailableBindings(
|
$: bindings = getAvailableBindings(
|
||||||
block,
|
block,
|
||||||
$automationStore.selectedAutomation?.automation?.definition
|
$automationStore.selectedAutomation?.automation?.definition
|
||||||
|
@ -76,6 +78,11 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
{#if stepId === "WEBHOOK"}
|
||||||
|
<Button wide secondary on:click={() => webhookModal.show()}>
|
||||||
|
Setup webhook
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
import { backendUiStore, automationStore } from "builderStore"
|
import { backendUiStore, automationStore } from "builderStore"
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import AutomationBlockSetup from "./AutomationBlockSetup.svelte"
|
import AutomationBlockSetup from "./AutomationBlockSetup.svelte"
|
||||||
import { Button, Input, Label } from "@budibase/bbui"
|
import { Button, Input, Label, Modal } from "@budibase/bbui"
|
||||||
|
import CreateWebookModal from "../Shared/CreateWebhookModal.svelte"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
|
|
||||||
let selectedTab = "SETUP"
|
let selectedTab = "SETUP"
|
||||||
let confirmDeleteDialog
|
let confirmDeleteDialog
|
||||||
|
let webhookModal
|
||||||
|
|
||||||
$: instanceId = $backendUiStore.selectedDatabase._id
|
$: instanceId = $backendUiStore.selectedDatabase._id
|
||||||
$: automation = $automationStore.selectedAutomation?.automation
|
$: automation = $automationStore.selectedAutomation?.automation
|
||||||
|
@ -60,7 +62,7 @@
|
||||||
</header>
|
</header>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{#if $automationStore.selectedBlock}
|
{#if $automationStore.selectedBlock}
|
||||||
<AutomationBlockSetup bind:block={$automationStore.selectedBlock} />
|
<AutomationBlockSetup bind:block={$automationStore.selectedBlock} webhookModal={webhookModal} />
|
||||||
{:else if $automationStore.selectedAutomation}
|
{:else if $automationStore.selectedAutomation}
|
||||||
<div class="block-label">Automation <b>{automation.name}</b></div>
|
<div class="block-label">Automation <b>{automation.name}</b></div>
|
||||||
<Button secondary wide on:click={testAutomation}>Test Automation</Button>
|
<Button secondary wide on:click={testAutomation}>Test Automation</Button>
|
||||||
|
@ -102,6 +104,9 @@
|
||||||
body={`Are you sure you wish to delete the automation '${name}'?`}
|
body={`Are you sure you wish to delete the automation '${name}'?`}
|
||||||
okText="Delete Automation"
|
okText="Delete Automation"
|
||||||
onOk={deleteAutomation} />
|
onOk={deleteAutomation} />
|
||||||
|
<Modal bind:this={webhookModal} width="30%">
|
||||||
|
<CreateWebookModal />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
section {
|
section {
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
const DEFAULT_SCHEMA_OUTPUT = "Any input allowed"
|
const DEFAULT_SCHEMA_OUTPUT = "Any input allowed"
|
||||||
let name
|
let name
|
||||||
let interval
|
let interval
|
||||||
let valid = false
|
let finished = false
|
||||||
let schemaURL
|
let schemaURL
|
||||||
let schema = DEFAULT_SCHEMA_OUTPUT
|
let propCount = 0
|
||||||
|
|
||||||
$: instanceId = $backendUiStore.selectedDatabase._id
|
$: instanceId = $backendUiStore.selectedDatabase._id
|
||||||
$: appId = $store.appId
|
$: appId = $store.appId
|
||||||
|
@ -27,16 +27,10 @@
|
||||||
interval = setInterval(async () => {
|
interval = setInterval(async () => {
|
||||||
await automationStore.actions.fetch()
|
await automationStore.actions.fetch()
|
||||||
const outputs = automation?.definition?.trigger.schema.outputs?.properties
|
const outputs = automation?.definition?.trigger.schema.outputs?.properties
|
||||||
if (Object.keys(outputs).length !== 0) {
|
// always one prop for the "body"
|
||||||
schema = cloneDeep(outputs)
|
if (Object.keys(outputs).length > 1) {
|
||||||
// clear out the "description" properties
|
propCount = Object.keys(outputs).length - 1
|
||||||
for (let key of Object.keys(schema)) {
|
finished = true
|
||||||
delete schema[key].description
|
|
||||||
}
|
|
||||||
schema = JSON.stringify(schema, null, 2)
|
|
||||||
//schema = schema.replace(/(?:\r\n|\r|\n)/g, "<br />")
|
|
||||||
//console.log(schema)
|
|
||||||
valid = true
|
|
||||||
}
|
}
|
||||||
}, POLL_RATE_MS)
|
}, POLL_RATE_MS)
|
||||||
schemaURL = automation?.definition?.trigger?.inputs.schemaUrl
|
schemaURL = automation?.definition?.trigger?.inputs.schemaUrl
|
||||||
|
@ -50,17 +44,18 @@
|
||||||
<ModalContent
|
<ModalContent
|
||||||
title="Webhook Setup"
|
title="Webhook Setup"
|
||||||
confirmText="Finished"
|
confirmText="Finished"
|
||||||
cancelText="Skip"
|
showConfirmButton={finished}
|
||||||
disabled={!valid}>
|
cancelText="Skip">
|
||||||
<p class="webhook-exp">
|
<p>
|
||||||
To configure a webhook we need to create a schema for your webhook to
|
Webhooks are for receiving data. To make them easier please use the URL
|
||||||
validate against. Use the URL shown below and send a
|
shown below and send a <code>POST</code> request to it from your other application.
|
||||||
<b>POST</b>
|
If you're unable to do this now then you can skip this step, however we
|
||||||
request to it with a JSON body in the format that your webhook should use!
|
will not be able to configure bindings for your later actions!
|
||||||
</p>
|
</p>
|
||||||
<WebhookDisplay value={schemaURL} />
|
<WebhookDisplay value={schemaURL} />
|
||||||
<h5>Schema</h5>
|
{#if finished}
|
||||||
<code> {schema} </code>
|
<p class="finished-text">Request received! We found {propCount} bindable value{propCount > 1 ? "s" : ""}.</p>
|
||||||
|
{/if}
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
<a target="_blank" href="https://docs.budibase.com/automate/steps/triggers">
|
<a target="_blank" href="https://docs.budibase.com/automate/steps/triggers">
|
||||||
<i class="ri-information-line" />
|
<i class="ri-information-line" />
|
||||||
|
@ -91,16 +86,19 @@
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
.finished-text {
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
h5 {
|
h5 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
code {
|
code {
|
||||||
padding: 8px;
|
padding: 1px 4px 1px 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--grey-5);
|
color: var(--grey-7);
|
||||||
background-color: var(--grey-4);
|
background-color: var(--grey-4);
|
||||||
border-radius: 6px;
|
border-radius: 2px;
|
||||||
display: block;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -19,19 +19,23 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="copy-area">
|
<div>
|
||||||
<Input disabled="true" thin value={fullWebhookURL(value)} />
|
<Input disabled="true" thin value={fullWebhookURL(value)} />
|
||||||
<span class="copy-btn" on:click={() => copyToClipboard()}>
|
<span on:click={() => copyToClipboard()}>
|
||||||
<i class="ri-clipboard-line copy-icon" />
|
<i class="ri-clipboard-line copy-icon" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.copy-area {
|
div {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copy-btn {
|
div :global(input:disabled) {
|
||||||
|
color: var(--grey-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
@ -46,7 +50,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copy-btn:hover {
|
span:hover {
|
||||||
background-color: var(--grey-3);
|
background-color: var(--grey-3);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -87,7 +87,13 @@ exports.trigger = async ctx => {
|
||||||
validate(ctx.request.body, webhook.bodySchema)
|
validate(ctx.request.body, webhook.bodySchema)
|
||||||
const target = await db.get(webhook.action.target)
|
const target = await db.get(webhook.action.target)
|
||||||
if (webhook.action.type === exports.WebhookType.AUTOMATION) {
|
if (webhook.action.type === exports.WebhookType.AUTOMATION) {
|
||||||
await triggers.externalTrigger(target, ctx.request.body)
|
// trigger with both the pure request and then expand it
|
||||||
|
// incase the user has produced a schema to bind to
|
||||||
|
await triggers.externalTrigger(target, {
|
||||||
|
body: ctx.request.body,
|
||||||
|
...ctx.request.body,
|
||||||
|
instanceId: ctx.params.instance,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.body = "Webhook trigger fired successfully"
|
ctx.body = "Webhook trigger fired successfully"
|
||||||
|
|
|
@ -108,8 +108,13 @@ const BUILTIN_DEFINITIONS = {
|
||||||
required: ["schemaUrl", "triggerUrl"],
|
required: ["schemaUrl", "triggerUrl"],
|
||||||
},
|
},
|
||||||
outputs: {
|
outputs: {
|
||||||
properties: {},
|
properties: {
|
||||||
required: [],
|
body: {
|
||||||
|
type: "object",
|
||||||
|
description: "Body of the request which hit the webhook",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["body"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
type: "TRIGGER",
|
type: "TRIGGER",
|
||||||
|
|
Loading…
Reference in New Issue