Adding a modal on creation of a webhook automation to make sure the user can setup a schema.

This commit is contained in:
mike12345567 2020-10-23 17:17:53 +01:00
parent 653fb16c86
commit ec7a4d7f8b
6 changed files with 194 additions and 68 deletions

View File

@ -11,12 +11,18 @@ const automationActions = store => ({
])
const jsonResponses = await Promise.all(responses.map(x => x.json()))
store.update(state => {
let selected = state.selectedAutomation?.automation
state.automations = jsonResponses[0]
state.blockDefinitions = {
TRIGGER: jsonResponses[1].trigger,
ACTION: jsonResponses[1].action,
LOGIC: jsonResponses[1].logic,
}
// if previously selected find the new obj and select it
if (selected) {
selected = jsonResponses[0].filter(automation => automation._id === selected._id)
state.selectedAutomation = new Automation(selected[0])
}
return state
})
},

View File

@ -1,11 +1,15 @@
<script>
import { backendUiStore, automationStore } from "builderStore"
import CreateWebookModal from "./CreateWebhookModal.svelte"
import analytics from "analytics"
import { Modal } from "@budibase/bbui"
export let blockDefinition
export let stepId
export let blockType
let modal
$: blockDefinitions = $automationStore.blockDefinitions
$: instanceId = $backendUiStore.selectedDatabase._id
$: automation = $automationStore.selectedAutomation?.automation
@ -18,10 +22,7 @@
type: blockType,
})
if (stepId === blockDefinitions.TRIGGER["WEBHOOK"].stepId) {
automationStore.actions.save({
instanceId,
automation,
})
modal.show()
}
analytics.captureEvent("Added Automation Block", {
name: blockDefinition.name,
@ -39,6 +40,9 @@
<p>{blockDefinition.description}</p>
</div>
</div>
<Modal bind:this={modal} width="30%">
<CreateWebookModal />
</Modal>
<style>
.automation-block {

View File

@ -0,0 +1,107 @@
<script>
import { store, backendUiStore, automationStore } from "builderStore"
import WebhookDisplay from "./WebhookDisplay.svelte"
import { ModalContent } from "@budibase/bbui"
import { onMount, onDestroy } from "svelte"
import { cloneDeep } from "lodash/fp"
import analytics from "analytics"
const POLL_RATE_MS = 2500
const DEFAULT_SCHEMA_OUTPUT = "Any input allowed"
let name
let interval
let valid = false
let schemaURL
let schema = DEFAULT_SCHEMA_OUTPUT
$: instanceId = $backendUiStore.selectedDatabase._id
$: appId = $store.appId
$: automation = $automationStore.selectedAutomation?.automation
onMount(async () => {
// save the automation initially
await automationStore.actions.save({
instanceId,
automation,
})
interval = setInterval(async () => {
await automationStore.actions.fetch()
const outputs = automation?.definition?.trigger.schema.outputs?.properties
if (Object.keys(outputs).length !== 0) {
schema = cloneDeep(outputs)
// clear out the "description" properties
for (let key of Object.keys(schema)) {
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)
schemaURL = automation?.definition?.trigger?.inputs.schemaUrl
})
onDestroy(() => {
clearInterval(interval)
})
</script>
<ModalContent
title="Webhook Setup"
confirmText="Finished"
cancelText="Skip"
disabled={!valid}>
<p class="webhook-exp">To configure a webhook we need to create a schema for your webhook to validate against.
Use the URL shown below and send a <b>POST</b> request to it with a JSON body in the format that
your webhook should use!</p>
<WebhookDisplay value={schemaURL}/>
<h5>Schema</h5>
<code>
{schema}
</code>
<div slot="footer">
<a
target="_blank"
href="https://docs.budibase.com/automate/steps/triggers">
<i class="ri-information-line" />
<span>Learn about webhooks</span>
</a>
</div>
</ModalContent>
<style>
a {
color: var(--ink);
font-size: 14px;
vertical-align: middle;
display: flex;
align-items: center;
text-decoration: none;
}
a span {
text-decoration: underline;
}
i {
font-size: 20px;
margin-right: var(--spacing-m);
text-decoration: none;
}
p {
margin-top: 0;
padding-top: 0;
text-align: justify;
}
h5 {
margin: 0;
}
code {
padding: 8px;
font-size: 14px;
color: var(--grey-5);
background-color: var(--grey-4);
border-radius: 6px;
display: block;
white-space: pre-wrap;
}
</style>

View File

@ -0,0 +1,57 @@
<script>
import { notifier } from "builderStore/store/notifications"
import { Input } from "@budibase/bbui"
export let value
function fullWebhookURL(uri) {
return `http://localhost:4001/${uri}`
}
function copyToClipboard() {
const dummy = document.createElement("textarea")
document.body.appendChild(dummy)
dummy.value = fullWebhookURL(value)
dummy.select()
document.execCommand("copy")
document.body.removeChild(dummy)
notifier.success(`URL copied to clipboard`)
}
</script>
<div class="copy-area">
<Input
disabled="true"
thin
value={fullWebhookURL(value)}/>
<span
class="copy-btn"
on:click={() => copyToClipboard()}>
<i class="ri-clipboard-line copy-icon" />
</span>
</div>
<style>
.copy-area {
position: relative;
}
.copy-btn {
position: absolute;
border: none;
border-radius: 50%;
height: 24px;
width: 24px;
background: white;
right: var(--spacing-s);
bottom: 9px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.copy-btn:hover {
background-color: var(--grey-3);
}
</style>

View File

@ -3,7 +3,7 @@
import RowSelector from "./ParamInputs/RowSelector.svelte"
import { Button, Input, TextArea, Select, Label } from "@budibase/bbui"
import { automationStore } from "builderStore"
import { notifier } from "builderStore/store/notifications"
import WebhookDisplay from "../AutomationPanel/BlockList/WebhookDisplay.svelte"
import BindableInput from "../../userInterface/BindableInput.svelte"
export let block
@ -43,20 +43,6 @@
}
return bindings
}
function fullWebhookURL(uri) {
return `http://localhost:4001/${uri}`
}
function copyToClipboard(input) {
const dummy = document.createElement("textarea")
document.body.appendChild(dummy)
dummy.value = input
dummy.select()
document.execCommand("copy")
document.body.removeChild(dummy)
notifier.success(`URL copied to clipboard`)
}
</script>
<div class="container" data-cy="automation-block-setup">
@ -80,17 +66,7 @@
{:else if value.customType === 'row'}
<RowSelector bind:value={block.inputs[key]} {bindings} />
{:else if value.customType === 'webhookUrl'}
<div class="copy-area">
<Input
disabled="true"
thin
value={fullWebhookURL(block.inputs[key])} />
<span
class="copy-btn"
on:click={() => copyToClipboard(fullWebhookURL(block.inputs[key]))}>
<i class="ri-clipboard-line copy-icon" />
</span>
</div>
<WebhookDisplay value={block.inputs[key]}/>
{:else if value.type === 'string' || value.type === 'number'}
<BindableInput
type="string"
@ -119,27 +95,4 @@
padding: 12px;
margin-top: 8px;
}
.copy-area {
position: relative;
}
.copy-btn {
position: absolute;
border: none;
border-radius: 50%;
height: 24px;
width: 24px;
background: white;
right: var(--spacing-s);
bottom: 9px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.copy-btn:hover {
background-color: var(--grey-4);
}
</style>

View File

@ -41,6 +41,8 @@ function cleanAutomationInputs(automation) {
* written to DB (this does not write to DB as it would be wasteful to repeat).
*/
async function checkForWebhooks({ user, oldAuto, newAuto }) {
const oldTrigger = oldAuto ? oldAuto.definition.trigger : null
const newTrigger = newAuto ? newAuto.definition.trigger : null
function isWebhookTrigger(auto) {
return (
auto &&
@ -52,21 +54,19 @@ async function checkForWebhooks({ user, oldAuto, newAuto }) {
if (
isWebhookTrigger(oldAuto) &&
!isWebhookTrigger(newAuto) &&
oldAuto.definition.trigger.webhook
oldTrigger.webhookId
) {
let db = new CouchDB(user.instanceId)
// need to get the webhook to get the rev
const webhook = await db.get(oldTrigger.webhookId)
const ctx = {
user,
params: {
id: oldAuto.definition.trigger.webhook.id,
rev: oldAuto.definition.trigger.webhook.rev,
},
params: { id: webhook._id, rev: webhook._rev },
}
// reset the inputs to remove the URLs
if (newAuto && newAuto.definition.trigger) {
const trigger = newAuto.definition.trigger
delete trigger.webhook
delete trigger.inputs.schemaUrl
delete trigger.inputs.triggerUrl
// might be updating - reset the inputs to remove the URLs
if (newTrigger) {
delete newTrigger.webhookId
newTrigger.inputs = {}
}
await webhooks.destroy(ctx)
}
@ -83,10 +83,9 @@ async function checkForWebhooks({ user, oldAuto, newAuto }) {
},
}
await webhooks.save(ctx)
const id = ctx.body.webhook._id,
rev = ctx.body.webhook._rev
newAuto.definition.trigger.webhook = { id, rev }
newAuto.definition.trigger.inputs = {
const id = ctx.body.webhook._id
newTrigger.webhookId = id
newTrigger.inputs = {
schemaUrl: `api/webhooks/schema/${user.instanceId}/${id}`,
triggerUrl: `api/webhooks/trigger/${user.instanceId}/${id}`,
}