Update flow chart styling and event handling

This commit is contained in:
Peter Clement 2021-09-06 14:31:55 +01:00
parent fd4c1c9929
commit 7fd79d3d4e
9 changed files with 273 additions and 104 deletions

View File

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

View File

@ -4,7 +4,6 @@
import BlockList from "./BlockList.svelte"
$: automation = $automationStore.selectedAutomation?.automation
function onSelect(block) {
automationStore.update(state => {
state.selectedBlock = block

View File

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

View File

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

View File

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

View File

@ -0,0 +1,12 @@
<script>
import { ModalContent } from "@budibase/bbui"
</script>
<ModalContent
title="Add test data"
confirmText="Save"
showConfirmButton={true}
cancelText="Cancel"
>
test
</ModalContent>

View File

@ -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);
}

View File

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

View File

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