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:
mike12345567 2020-10-26 16:04:02 +00:00
parent fdf0fdd145
commit c66541ad99
7 changed files with 63 additions and 38 deletions

View File

@ -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"

View File

@ -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>

View File

@ -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 {

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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",