Update flow chart styling and event handling
This commit is contained in:
parent
fd4c1c9929
commit
7fd79d3d4e
|
@ -12,6 +12,7 @@
|
|||
export let dataCy = null
|
||||
export let size = "M"
|
||||
export let active = false
|
||||
export let fullWidth = false
|
||||
|
||||
function longPress(element) {
|
||||
if (!longPressable) return
|
||||
|
@ -40,6 +41,7 @@
|
|||
class:spectrum-ActionButton--quiet={quiet}
|
||||
class:spectrum-ActionButton--emphasized={emphasized}
|
||||
class:is-selected={selected}
|
||||
class:fullWidth
|
||||
class="spectrum-ActionButton spectrum-ActionButton--size{size}"
|
||||
class:active
|
||||
{disabled}
|
||||
|
@ -71,6 +73,9 @@
|
|||
</button>
|
||||
|
||||
<style>
|
||||
.fullWidth {
|
||||
width: 100%;
|
||||
}
|
||||
.active,
|
||||
.active svg {
|
||||
color: var(--spectrum-global-color-blue-600);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
import BlockList from "./BlockList.svelte"
|
||||
|
||||
$: automation = $automationStore.selectedAutomation?.automation
|
||||
|
||||
function onSelect(block) {
|
||||
automationStore.update(state => {
|
||||
state.selectedBlock = block
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
stroke-dasharray="5,5"
|
||||
d="M5.0625 70H9L4.5 75L0 70H3.9375V65H5.0625V70Z"
|
||||
fill="var(--grey-5)"
|
||||
/>
|
||||
|
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 353 B |
|
@ -3,11 +3,15 @@
|
|||
import Arrow from "./Arrow.svelte"
|
||||
import { flip } from "svelte/animate"
|
||||
import { fade, fly } from "svelte/transition"
|
||||
import { Body, Detail, Icon, Label, StatusLight } from "@budibase/bbui"
|
||||
|
||||
export let automation
|
||||
export let onSelect
|
||||
let blocks
|
||||
|
||||
// TODO: ADD LOGIC FOR SWITCHING THIS
|
||||
let published = true
|
||||
|
||||
$: {
|
||||
blocks = []
|
||||
if (automation) {
|
||||
|
@ -20,33 +24,53 @@
|
|||
</script>
|
||||
|
||||
<section class="canvas">
|
||||
{#each blocks as block, idx (block.id)}
|
||||
<div
|
||||
class="block"
|
||||
animate:flip={{ duration: 600 }}
|
||||
in:fade|local
|
||||
out:fly|local={{ x: 100 }}
|
||||
>
|
||||
<FlowItem {onSelect} {block} />
|
||||
{#if idx !== blocks.length - 1}
|
||||
<Arrow />
|
||||
{/if}
|
||||
<div class="content">
|
||||
<div class="title">
|
||||
<div class="subtitle">
|
||||
<Detail size="L">{automation.name}</Detail>
|
||||
<div
|
||||
style="display:flex;
|
||||
color: var(--spectrum-global-color-gray-400);"
|
||||
>
|
||||
<span class="iconPadding">
|
||||
<Icon name="DeleteOutline" />
|
||||
</span>
|
||||
<Label>Delete</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: calc(-1 * var(--spacing-s))">
|
||||
<StatusLight positive={published} notice={!published}
|
||||
>{#if published}
|
||||
<Body size="XS">Automation is published</Body>{:else}
|
||||
<Body size="XS">Automation is not published</Body>{/if}</StatusLight
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{#each blocks as block, idx (block.id)}
|
||||
<div
|
||||
class="block"
|
||||
animate:flip={{ duration: 600 }}
|
||||
in:fade|local
|
||||
out:fly|local={{ x: 100 }}
|
||||
>
|
||||
<FlowItem {onSelect} {block} />
|
||||
{#if idx !== blocks.length - 1}
|
||||
<Arrow />
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
section {
|
||||
.canvas {
|
||||
margin: 0 -40px calc(-1 * var(--spacing-l)) -40px;
|
||||
padding: var(--spacing-l) 40px 0 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
flex: 1 1 auto;
|
||||
text-align: center;
|
||||
}
|
||||
/* Fix for firefox not respecting bottom padding in scrolling containers */
|
||||
section > *:last-child {
|
||||
.canvas > *:last-child {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
|
@ -56,4 +80,24 @@
|
|||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.title {
|
||||
padding-bottom: var(--spacing-xl);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
padding-bottom: var(--spacing-xl);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.iconPadding {
|
||||
display: flex;
|
||||
padding-right: var(--spacing-m);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,21 +1,83 @@
|
|||
<script>
|
||||
import { automationStore } from "builderStore"
|
||||
import AutomationBlockTagline from "./AutomationBlockTagline.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
import {
|
||||
Icon,
|
||||
Divider,
|
||||
Layout,
|
||||
Body,
|
||||
Detail,
|
||||
Modal,
|
||||
Button,
|
||||
ActionButton,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte"
|
||||
import CreateWebhookModal from "components/automation/shared/CreateWebhookModal.svelte"
|
||||
import TestDataModal from "./TestDataModal.svelte"
|
||||
import ActionModal from "./ActionModal.svelte"
|
||||
import { database } from "stores/backend"
|
||||
|
||||
export let onSelect
|
||||
export let block
|
||||
|
||||
let selected
|
||||
let webhookModal
|
||||
let testDataModal
|
||||
let actionModal
|
||||
let setupComplete
|
||||
let testToggled
|
||||
|
||||
$: setupToggled = !setupComplete || false
|
||||
|
||||
$: instanceId = $database._id
|
||||
$: schemaKey = Object.keys(block.schema?.inputs?.properties || {})
|
||||
|
||||
$: selected = $automationStore.selectedBlock?.id === block.id
|
||||
$: steps =
|
||||
$automationStore.selectedAutomation?.automation?.definition?.steps ?? []
|
||||
|
||||
$: blockIdx = steps.findIndex(step => step.id === block.id)
|
||||
$: allowDeleteTrigger = !steps.length
|
||||
|
||||
function deleteStep() {
|
||||
automationStore.actions.deleteAutomationBlock(block)
|
||||
}
|
||||
|
||||
async function testAutomation() {
|
||||
const result = await automationStore.actions.trigger({
|
||||
automation: $automationStore.selectedAutomation.automation,
|
||||
})
|
||||
if (result.status === 200) {
|
||||
notifications.success(
|
||||
`Automation ${$automationStore.selectedAutomation.automation.name} triggered successfully.`
|
||||
)
|
||||
} else {
|
||||
notifications.error(
|
||||
`Failed to trigger automation ${$automationStore.selectedAutomation.automation.name}.`
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async function saveAutomation() {
|
||||
await automationStore.actions.save({
|
||||
instanceId,
|
||||
automation: $automationStore.selectedAutomation.automation,
|
||||
})
|
||||
notifications.success(
|
||||
`Automation ${$automationStore.selectedAutomation.automation.name} saved.`
|
||||
)
|
||||
}
|
||||
|
||||
function onContinue() {
|
||||
const testResult = testAutomation()
|
||||
const saveResult = saveAutomation()
|
||||
|
||||
if (testResult && saveResult) {
|
||||
setupComplete = true
|
||||
testToggled = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
@ -23,64 +85,124 @@
|
|||
class:selected
|
||||
on:click={() => onSelect(block)}
|
||||
>
|
||||
<header>
|
||||
{#if block.type === "TRIGGER"}
|
||||
<Icon name="Light" />
|
||||
<span>When this happens...</span>
|
||||
{:else if block.type === "ACTION"}
|
||||
<Icon name="FlashOn" />
|
||||
<span>Do this...</span>
|
||||
{:else if block.type === "LOGIC"}
|
||||
<Icon name="Branch2" />
|
||||
<span>Only continue if...</span>
|
||||
{/if}
|
||||
<div class="label">
|
||||
{#if block.type === "TRIGGER"}Trigger{:else}Step {blockIdx + 1}{/if}
|
||||
<div class="blockSection">
|
||||
<div style="display: flex;">
|
||||
<svg
|
||||
width="35px"
|
||||
height="35px"
|
||||
class="spectrum-Icon"
|
||||
style="color:grey;"
|
||||
focusable="false"
|
||||
>
|
||||
<use xlink:href="#spectrum-icon-18-{block.icon}" />
|
||||
</svg>
|
||||
<div class="iconAlign">
|
||||
<Body size="XS">When this happens:</Body>
|
||||
|
||||
<Detail size="S">{block.name.toUpperCase()}</Detail>
|
||||
</div>
|
||||
</div>
|
||||
{#if block.type !== "TRIGGER" || allowDeleteTrigger}
|
||||
<div on:click|stopPropagation={deleteStep}><Icon name="Close" /></div>
|
||||
{/if}
|
||||
</header>
|
||||
<hr />
|
||||
<p>
|
||||
<AutomationBlockTagline {block} />
|
||||
</p>
|
||||
</div>
|
||||
<Divider noMargin />
|
||||
<div class="blockSection">
|
||||
<Layout noPadding gap="S">
|
||||
<div class="setup">
|
||||
<div
|
||||
on:click={() => {
|
||||
if (!setupComplete) {
|
||||
setupToggled = !setupToggled
|
||||
}
|
||||
}}
|
||||
class="toggle"
|
||||
>
|
||||
{#if setupToggled}
|
||||
<Icon size="M" name="ChevronDown" />
|
||||
{:else}
|
||||
<Icon size="M" name="ChevronRight" />
|
||||
{/if}
|
||||
<Detail size="S">Setup</Detail>
|
||||
</div>
|
||||
<div on:click={() => deleteStep()}>
|
||||
<Icon name="DeleteOutline" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if setupToggled}
|
||||
<AutomationBlockSetup {block} {webhookModal} />
|
||||
{#if block.inputs[schemaKey]}
|
||||
<Button on:click={() => onContinue()} cta
|
||||
>Continue and test trigger</Button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
</Layout>
|
||||
</div>
|
||||
|
||||
<Divider noMargin />
|
||||
<div class="blockSection">
|
||||
<Layout noPadding gap="S">
|
||||
<div
|
||||
on:click={() => {
|
||||
if (setupComplete) {
|
||||
testToggled = !testToggled
|
||||
}
|
||||
}}
|
||||
class="toggle"
|
||||
>
|
||||
{#if testToggled}
|
||||
<Icon size="M" name="ChevronDown" />
|
||||
{:else}
|
||||
<Icon size="M" name="ChevronRight" />
|
||||
{/if}
|
||||
<Detail size="S">Test</Detail>
|
||||
</div>
|
||||
{#if testToggled}
|
||||
<ActionButton on:click={testDataModal.show()} fullWidth icon="Add"
|
||||
>Add test data</ActionButton
|
||||
>
|
||||
<Button on:click={() => actionModal.show()} cta
|
||||
>Save trigger and continue to action</Button
|
||||
>
|
||||
{/if}
|
||||
</Layout>
|
||||
</div>
|
||||
|
||||
<Modal bind:this={actionModal} width="30%">
|
||||
<ActionModal />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={webhookModal} width="30%">
|
||||
<CreateWebhookModal />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={testDataModal} width="30%">
|
||||
<TestDataModal />
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.setup {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.iconAlign {
|
||||
padding: 0 0 0 var(--spacing-m);
|
||||
display: inline-block;
|
||||
}
|
||||
.block {
|
||||
width: 360px;
|
||||
padding: 20px;
|
||||
border-radius: var(--border-radius-m);
|
||||
transition: 0.3s all ease;
|
||||
box-shadow: 0 4px 30px 0 rgba(57, 60, 68, 0.08);
|
||||
font-size: 16px;
|
||||
background-color: var(--spectrum-global-color-gray-50);
|
||||
background-color: var(--spectrum-alias-background-color-secondary);
|
||||
color: var(--grey-9);
|
||||
}
|
||||
.block.selected,
|
||||
.block:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 4px 30px 0 rgba(57, 60, 68, 0.15);
|
||||
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
}
|
||||
|
||||
header {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
header span {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
header .label {
|
||||
font-size: 14px;
|
||||
padding: var(--spacing-s);
|
||||
border-radius: var(--border-radius-m);
|
||||
background-color: var(--grey-2);
|
||||
color: var(--grey-8);
|
||||
.blockSection {
|
||||
padding: var(--spacing-xl);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<script>
|
||||
import { ModalContent } from "@budibase/bbui"
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
title="Add test data"
|
||||
confirmText="Save"
|
||||
showConfirmButton={true}
|
||||
cancelText="Cancel"
|
||||
>
|
||||
test
|
||||
</ModalContent>
|
|
@ -3,7 +3,7 @@
|
|||
import { database } from "stores/backend"
|
||||
import { automationStore } from "builderStore"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
import { Input, ModalContent, Layout, Body } from "@budibase/bbui"
|
||||
import { Input, ModalContent, Layout, Body, Icon } from "@budibase/bbui"
|
||||
import analytics from "analytics"
|
||||
|
||||
let name
|
||||
|
@ -18,17 +18,18 @@
|
|||
name,
|
||||
instanceId,
|
||||
})
|
||||
const newBlock = await $automationStore.selectedAutomation.constructBlock(
|
||||
const newBlock = $automationStore.selectedAutomation.constructBlock(
|
||||
"TRIGGER",
|
||||
triggerVal.stepId,
|
||||
triggerVal
|
||||
)
|
||||
|
||||
automationStore.actions.addBlockToAutomation(newBlock)
|
||||
if (triggerVal.stepId === "WEBHOOK") {
|
||||
webhookModal.show()
|
||||
}
|
||||
|
||||
notifications.success(`Automation ${name} created.`)
|
||||
|
||||
$goto(`./${$automationStore.selectedAutomation.automation._id}`)
|
||||
analytics.captureEvent("Automation Created", { name })
|
||||
}
|
||||
|
@ -56,16 +57,16 @@
|
|||
<Layout noPadding>
|
||||
<Body size="S">Triggers</Body>
|
||||
|
||||
<div class="integration-list">
|
||||
<div class="item-list">
|
||||
{#each triggers as [idx, trigger]}
|
||||
<div
|
||||
class="integration hoverable"
|
||||
class="item"
|
||||
class:selected={selectedTrigger === trigger.name}
|
||||
on:click={() => selectTrigger(trigger)}
|
||||
>
|
||||
<div style="display: flex; margin-left: 8%">
|
||||
<i class={trigger.icon} />
|
||||
<span style="margin-left:5px;">
|
||||
<div class="item-body">
|
||||
<Icon name={trigger.icon} />
|
||||
<span class="icon-spacing">
|
||||
<Body size="S">{trigger.name}</Body></span
|
||||
>
|
||||
</div>
|
||||
|
@ -76,13 +77,21 @@
|
|||
</ModalContent>
|
||||
|
||||
<style>
|
||||
.integration-list {
|
||||
.icon-spacing {
|
||||
margin-left: var(--spacing-m);
|
||||
}
|
||||
.item-body {
|
||||
display: flex;
|
||||
margin-left: var(--spacing-m);
|
||||
}
|
||||
.item-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
grid-gap: var(--spectrum-alias-grid-baseline);
|
||||
}
|
||||
|
||||
.integration {
|
||||
.item {
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
grid-gap: var(--spectrum-alias-grid-margin-xsmall);
|
||||
padding: var(--spectrum-alias-item-padding-s);
|
||||
|
@ -93,8 +102,6 @@
|
|||
box-sizing: border-box;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.integration:hover,
|
||||
.selected {
|
||||
background: var(--spectrum-alias-background-color-tertiary);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
export let block
|
||||
export let webhookModal
|
||||
|
||||
$: inputs = Object.entries(block.schema?.inputs?.properties || {})
|
||||
$: stepId = block.stepId
|
||||
$: bindings = getAvailableBindings(
|
||||
|
@ -55,7 +56,6 @@
|
|||
</script>
|
||||
|
||||
<div class="fields">
|
||||
<div class="block-label">{block.name}</div>
|
||||
{#each inputs as [key, value]}
|
||||
<div class="block-field">
|
||||
<Label>{value.title}</Label>
|
||||
|
@ -131,10 +131,4 @@
|
|||
display: grid;
|
||||
grid-gap: 5px;
|
||||
}
|
||||
|
||||
.block-label {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-s);
|
||||
color: var(--grey-7);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<script>
|
||||
import { automationStore } from "builderStore"
|
||||
import { params } from "@roxi/routify"
|
||||
|
||||
if ($params.automation) {
|
||||
const automation = $automationStore.automations.find(
|
||||
m => m._id === $params.automation
|
||||
)
|
||||
if (automation) {
|
||||
automationStore.actions.select(automation)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<slot />
|
Loading…
Reference in New Issue