200 lines
5.1 KiB
Svelte
200 lines
5.1 KiB
Svelte
<script>
|
|
import { tick } from "svelte"
|
|
import {
|
|
ModalContent,
|
|
TextArea,
|
|
notifications,
|
|
ActionButton,
|
|
} from "@budibase/bbui"
|
|
import { automationStore, selectedAutomation } from "@/stores/builder"
|
|
import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte"
|
|
import { cloneDeep } from "lodash/fp"
|
|
import { AutomationEventType } from "@budibase/types"
|
|
|
|
let failedParse = null
|
|
let trigger = {}
|
|
let schemaProperties = {}
|
|
|
|
const rowTriggers = [
|
|
AutomationEventType.ROW_DELETE,
|
|
AutomationEventType.ROW_UPDATE,
|
|
AutomationEventType.ROW_SAVE,
|
|
AutomationEventType.ROW_ACTION,
|
|
]
|
|
|
|
/**
|
|
* Parses the automation test data and ensures it is valid
|
|
* @param {object} testData contains all config for the test
|
|
* @returns {object} valid testData
|
|
* @todo Parse *all* data for each trigger type and relay adequate feedback
|
|
*/
|
|
const parseTestData = testData => {
|
|
const autoTrigger = $selectedAutomation.data?.definition?.trigger
|
|
const { tableId } = autoTrigger?.inputs || {}
|
|
|
|
// Ensure the tableId matches the trigger table for row trigger automations
|
|
if (
|
|
rowTriggers.includes(autoTrigger?.event) &&
|
|
testData?.row?.tableId !== tableId
|
|
) {
|
|
return {
|
|
// Reset Core fields
|
|
row: { tableId },
|
|
meta: {},
|
|
id: "",
|
|
revision: "",
|
|
}
|
|
} else {
|
|
// Leave the core data as it is
|
|
return cloneDeep(testData)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Before executing a test run, relay if an automation is in a valid state
|
|
* @param {object} trigger The automation trigger config
|
|
* @returns {boolean} validation status
|
|
* @todo Parse *all* trigger types relay adequate feedback
|
|
*/
|
|
const isTriggerValid = trigger => {
|
|
if (rowTriggers.includes(trigger?.event) && !trigger?.inputs?.tableId) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
$: currentTestData = $selectedAutomation.data.testData
|
|
|
|
// Can be updated locally to avoid race condition when testing
|
|
$: testData = parseTestData(currentTestData)
|
|
|
|
$: {
|
|
// clone the trigger so we're not mutating the reference
|
|
trigger = cloneDeep($selectedAutomation.data.definition.trigger)
|
|
|
|
// get the outputs so we can define the fields
|
|
let schema = Object.entries(trigger.schema?.outputs?.properties || {})
|
|
|
|
if (trigger?.event === AutomationEventType.APP_TRIGGER) {
|
|
schema = [["fields", { customType: "fields" }]]
|
|
}
|
|
schemaProperties = schema
|
|
}
|
|
|
|
// Check the schema to see if required fields have been entered
|
|
$: isError =
|
|
!isTriggerValid(trigger) ||
|
|
!(trigger.schema.outputs.required || []).every(
|
|
required => testData?.[required] || required !== "row"
|
|
)
|
|
|
|
async function parseTestJSON(e) {
|
|
let jsonUpdate
|
|
|
|
try {
|
|
jsonUpdate = JSON.parse(e.detail)
|
|
failedParse = null
|
|
} catch (e) {
|
|
failedParse = "Invalid JSON"
|
|
return false
|
|
}
|
|
|
|
if (rowTriggers.includes(trigger?.event)) {
|
|
const tableId = trigger?.inputs?.tableId
|
|
|
|
if (!jsonUpdate.row) {
|
|
jsonUpdate.row = {}
|
|
}
|
|
|
|
// Reset the tableId as it must match the trigger
|
|
if (jsonUpdate?.row?.tableId !== tableId) {
|
|
jsonUpdate.row.tableId = tableId
|
|
}
|
|
}
|
|
|
|
const updatedAuto =
|
|
automationStore.actions.addTestDataToAutomation(jsonUpdate)
|
|
await automationStore.actions.save(updatedAuto)
|
|
}
|
|
|
|
const testAutomation = async () => {
|
|
// Ensure testData reactiveness is processed
|
|
await tick()
|
|
try {
|
|
await automationStore.actions.test($selectedAutomation.data, testData)
|
|
$automationStore.showTestPanel = true
|
|
} catch (error) {
|
|
notifications.error(error)
|
|
}
|
|
}
|
|
|
|
const toggle = () => {
|
|
selectedValues = !selectedValues
|
|
selectedJSON = !selectedJSON
|
|
}
|
|
let selectedValues = true
|
|
let selectedJSON = false
|
|
</script>
|
|
|
|
<ModalContent
|
|
title="Add test data"
|
|
confirmText="Run test"
|
|
size="L"
|
|
showConfirmButton={true}
|
|
disabled={isError}
|
|
onConfirm={testAutomation}
|
|
cancelText="Cancel"
|
|
>
|
|
<div class="size">
|
|
<div class="options">
|
|
<ActionButton quiet selected={selectedValues} on:click={toggle}
|
|
>Use values</ActionButton
|
|
>
|
|
<ActionButton quiet selected={selectedJSON} on:click={toggle}
|
|
>Use JSON</ActionButton
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
{#if selectedValues}
|
|
<div class="tab-content-padding">
|
|
<AutomationBlockSetup
|
|
{schemaProperties}
|
|
isTestModal
|
|
{testData}
|
|
block={trigger}
|
|
on:update={e => {
|
|
const { testData: updatedTestData } = e.detail
|
|
testData = parseTestData(updatedTestData)
|
|
}}
|
|
/>
|
|
</div>
|
|
{/if}
|
|
{#if selectedJSON}
|
|
<div class="text-area-container">
|
|
<TextArea
|
|
value={JSON.stringify($selectedAutomation.data.testData, null, 2)}
|
|
error={failedParse}
|
|
on:change={async e => await parseTestJSON(e)}
|
|
/>
|
|
</div>
|
|
{/if}
|
|
</ModalContent>
|
|
|
|
<style>
|
|
.text-area-container :global(textarea) {
|
|
min-height: 300px;
|
|
height: 300px;
|
|
}
|
|
|
|
.tab-content-padding {
|
|
padding: 0 var(--spacing-s);
|
|
}
|
|
|
|
.options {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
</style>
|