1
0
Fork 0
mirror of synced 2024-07-09 08:16:34 +12:00

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 dataCy = null
export let size = "M" export let size = "M"
export let active = false export let active = false
export let fullWidth = false
function longPress(element) { function longPress(element) {
if (!longPressable) return if (!longPressable) return
@ -40,6 +41,7 @@
class:spectrum-ActionButton--quiet={quiet} class:spectrum-ActionButton--quiet={quiet}
class:spectrum-ActionButton--emphasized={emphasized} class:spectrum-ActionButton--emphasized={emphasized}
class:is-selected={selected} class:is-selected={selected}
class:fullWidth
class="spectrum-ActionButton spectrum-ActionButton--size{size}" class="spectrum-ActionButton spectrum-ActionButton--size{size}"
class:active class:active
{disabled} {disabled}
@ -71,6 +73,9 @@
</button> </button>
<style> <style>
.fullWidth {
width: 100%;
}
.active, .active,
.active svg { .active svg {
color: var(--spectrum-global-color-blue-600); color: var(--spectrum-global-color-blue-600);

View file

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

View file

@ -6,6 +6,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<path <path
stroke-dasharray="5,5"
d="M5.0625 70H9L4.5 75L0 70H3.9375V65H5.0625V70Z" d="M5.0625 70H9L4.5 75L0 70H3.9375V65H5.0625V70Z"
fill="var(--grey-5)" 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 Arrow from "./Arrow.svelte"
import { flip } from "svelte/animate" import { flip } from "svelte/animate"
import { fade, fly } from "svelte/transition" import { fade, fly } from "svelte/transition"
import { Body, Detail, Icon, Label, StatusLight } from "@budibase/bbui"
export let automation export let automation
export let onSelect export let onSelect
let blocks let blocks
// TODO: ADD LOGIC FOR SWITCHING THIS
let published = true
$: { $: {
blocks = [] blocks = []
if (automation) { if (automation) {
@ -20,6 +24,28 @@
</script> </script>
<section class="canvas"> <section class="canvas">
<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 blocks as block, idx (block.id)} {#each blocks as block, idx (block.id)}
<div <div
class="block" class="block"
@ -33,20 +59,18 @@
{/if} {/if}
</div> </div>
{/each} {/each}
</div>
</section> </section>
<style> <style>
section { .canvas {
margin: 0 -40px calc(-1 * var(--spacing-l)) -40px; margin: 0 -40px calc(-1 * var(--spacing-l)) -40px;
padding: var(--spacing-l) 40px 0 40px; padding: var(--spacing-l) 40px 0 40px;
display: flex;
align-items: center;
flex-direction: column;
overflow-y: auto; overflow-y: auto;
flex: 1 1 auto; text-align: center;
} }
/* Fix for firefox not respecting bottom padding in scrolling containers */ /* Fix for firefox not respecting bottom padding in scrolling containers */
section > *:last-child { .canvas > *:last-child {
padding-bottom: 40px; padding-bottom: 40px;
} }
@ -56,4 +80,24 @@
justify-content: flex-start; justify-content: flex-start;
align-items: center; 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> </style>

View file

@ -1,21 +1,83 @@
<script> <script>
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
import AutomationBlockTagline from "./AutomationBlockTagline.svelte" import {
import { Icon } from "@budibase/bbui" 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 onSelect
export let block export let block
let selected 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 $: selected = $automationStore.selectedBlock?.id === block.id
$: steps = $: steps =
$automationStore.selectedAutomation?.automation?.definition?.steps ?? [] $automationStore.selectedAutomation?.automation?.definition?.steps ?? []
$: blockIdx = steps.findIndex(step => step.id === block.id) $: blockIdx = steps.findIndex(step => step.id === block.id)
$: allowDeleteTrigger = !steps.length $: allowDeleteTrigger = !steps.length
function deleteStep() { function deleteStep() {
automationStore.actions.deleteAutomationBlock(block) 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> </script>
<div <div
@ -23,64 +85,124 @@
class:selected class:selected
on:click={() => onSelect(block)} on:click={() => onSelect(block)}
> >
<header> <div class="blockSection">
{#if block.type === "TRIGGER"} <div style="display: flex;">
<Icon name="Light" /> <svg
<span>When this happens...</span> width="35px"
{:else if block.type === "ACTION"} height="35px"
<Icon name="FlashOn" /> class="spectrum-Icon"
<span>Do this...</span> style="color:grey;"
{:else if block.type === "LOGIC"} focusable="false"
<Icon name="Branch2" /> >
<span>Only continue if...</span> <use xlink:href="#spectrum-icon-18-{block.icon}" />
{/if} </svg>
<div class="label"> <div class="iconAlign">
{#if block.type === "TRIGGER"}Trigger{:else}Step {blockIdx + 1}{/if} <Body size="XS">When this happens:</Body>
<Detail size="S">{block.name.toUpperCase()}</Detail>
</div> </div>
{#if block.type !== "TRIGGER" || allowDeleteTrigger} </div>
<div on:click|stopPropagation={deleteStep}><Icon name="Close" /></div> </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} {/if}
</header> <Detail size="S">Setup</Detail>
<hr /> </div>
<p> <div on:click={() => deleteStep()}>
<AutomationBlockTagline {block} /> <Icon name="DeleteOutline" />
</p> </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> </div>
<style> <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 { .block {
width: 360px; 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; font-size: 16px;
background-color: var(--spectrum-global-color-gray-50); background-color: var(--spectrum-alias-background-color-secondary);
color: var(--grey-9); color: var(--grey-9);
} border: 1px solid var(--spectrum-global-color-gray-300);
.block.selected, border-radius: 4px 4px 4px 4px;
.block:hover {
transform: scale(1.1);
box-shadow: 0 4px 30px 0 rgba(57, 60, 68, 0.15);
} }
header { .blockSection {
font-size: 16px; padding: var(--spacing-xl);
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);
} }
</style> </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 { database } from "stores/backend"
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
import { notifications } from "@budibase/bbui" 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" import analytics from "analytics"
let name let name
@ -18,17 +18,18 @@
name, name,
instanceId, instanceId,
}) })
const newBlock = await $automationStore.selectedAutomation.constructBlock( const newBlock = $automationStore.selectedAutomation.constructBlock(
"TRIGGER", "TRIGGER",
triggerVal.stepId, triggerVal.stepId,
triggerVal triggerVal
) )
automationStore.actions.addBlockToAutomation(newBlock) automationStore.actions.addBlockToAutomation(newBlock)
if (triggerVal.stepId === "WEBHOOK") { if (triggerVal.stepId === "WEBHOOK") {
webhookModal.show() webhookModal.show()
} }
notifications.success(`Automation ${name} created.`) notifications.success(`Automation ${name} created.`)
$goto(`./${$automationStore.selectedAutomation.automation._id}`) $goto(`./${$automationStore.selectedAutomation.automation._id}`)
analytics.captureEvent("Automation Created", { name }) analytics.captureEvent("Automation Created", { name })
} }
@ -56,16 +57,16 @@
<Layout noPadding> <Layout noPadding>
<Body size="S">Triggers</Body> <Body size="S">Triggers</Body>
<div class="integration-list"> <div class="item-list">
{#each triggers as [idx, trigger]} {#each triggers as [idx, trigger]}
<div <div
class="integration hoverable" class="item"
class:selected={selectedTrigger === trigger.name} class:selected={selectedTrigger === trigger.name}
on:click={() => selectTrigger(trigger)} on:click={() => selectTrigger(trigger)}
> >
<div style="display: flex; margin-left: 8%"> <div class="item-body">
<i class={trigger.icon} /> <Icon name={trigger.icon} />
<span style="margin-left:5px;"> <span class="icon-spacing">
<Body size="S">{trigger.name}</Body></span <Body size="S">{trigger.name}</Body></span
> >
</div> </div>
@ -76,13 +77,21 @@
</ModalContent> </ModalContent>
<style> <style>
.integration-list { .icon-spacing {
margin-left: var(--spacing-m);
}
.item-body {
display: flex;
margin-left: var(--spacing-m);
}
.item-list {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
grid-gap: var(--spectrum-alias-grid-baseline); grid-gap: var(--spectrum-alias-grid-baseline);
} }
.integration { .item {
cursor: pointer;
display: grid; display: grid;
grid-gap: var(--spectrum-alias-grid-margin-xsmall); grid-gap: var(--spectrum-alias-grid-margin-xsmall);
padding: var(--spectrum-alias-item-padding-s); padding: var(--spectrum-alias-item-padding-s);
@ -93,8 +102,6 @@
box-sizing: border-box; box-sizing: border-box;
border-width: 2px; border-width: 2px;
} }
.integration:hover,
.selected { .selected {
background: var(--spectrum-alias-background-color-tertiary); background: var(--spectrum-alias-background-color-tertiary);
} }

View file

@ -15,6 +15,7 @@
export let block export let block
export let webhookModal export let webhookModal
$: inputs = Object.entries(block.schema?.inputs?.properties || {}) $: inputs = Object.entries(block.schema?.inputs?.properties || {})
$: stepId = block.stepId $: stepId = block.stepId
$: bindings = getAvailableBindings( $: bindings = getAvailableBindings(
@ -55,7 +56,6 @@
</script> </script>
<div class="fields"> <div class="fields">
<div class="block-label">{block.name}</div>
{#each inputs as [key, value]} {#each inputs as [key, value]}
<div class="block-field"> <div class="block-field">
<Label>{value.title}</Label> <Label>{value.title}</Label>
@ -131,10 +131,4 @@
display: grid; display: grid;
grid-gap: 5px; grid-gap: 5px;
} }
.block-label {
font-weight: 600;
font-size: var(--font-size-s);
color: var(--grey-7);
}
</style> </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 />