commit
72199f319e
|
@ -79,6 +79,7 @@
|
||||||
"posthog-js": "1.4.5",
|
"posthog-js": "1.4.5",
|
||||||
"remixicon": "2.5.0",
|
"remixicon": "2.5.0",
|
||||||
"shortid": "2.2.15",
|
"shortid": "2.2.15",
|
||||||
|
"svelte-dnd-action": "^0.8.9",
|
||||||
"svelte-loading-spinners": "^0.1.1",
|
"svelte-loading-spinners": "^0.1.1",
|
||||||
"svelte-portal": "0.1.0",
|
"svelte-portal": "0.1.0",
|
||||||
"uuid": "8.3.1",
|
"uuid": "8.3.1",
|
||||||
|
|
|
@ -120,7 +120,7 @@ const getContextBindings = (asset, componentId) => {
|
||||||
tableName = info.table?.name
|
tableName = info.table?.name
|
||||||
|
|
||||||
// Add _id and _rev fields for certain types
|
// Add _id and _rev fields for certain types
|
||||||
if (datasource.type === "table" || datasource.type === "link") {
|
if (schema && ["table", "link"].includes(datasource.type)) {
|
||||||
schema["_id"] = { type: "string" }
|
schema["_id"] = { type: "string" }
|
||||||
schema["_rev"] = { type: "string" }
|
schema["_rev"] = { type: "string" }
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,6 +285,7 @@ export const getFrontendStore = () => {
|
||||||
_id: uuid(),
|
_id: uuid(),
|
||||||
_component: definition.component,
|
_component: definition.component,
|
||||||
_styles: { normal: {}, hover: {}, active: {} },
|
_styles: { normal: {}, hover: {}, active: {} },
|
||||||
|
_transition: "",
|
||||||
_instanceName: `New ${definition.name}`,
|
_instanceName: `New ${definition.name}`,
|
||||||
...cloneDeep(props),
|
...cloneDeep(props),
|
||||||
...extras,
|
...extras,
|
||||||
|
@ -487,6 +488,15 @@ export const getFrontendStore = () => {
|
||||||
selected._styles = { normal: {}, hover: {}, active: {} }
|
selected._styles = { normal: {}, hover: {}, active: {} }
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
},
|
},
|
||||||
|
updateTransition: async transition => {
|
||||||
|
const selected = get(selectedComponent)
|
||||||
|
if (transition == null || transition === "") {
|
||||||
|
selected._transition = ""
|
||||||
|
} else {
|
||||||
|
selected._transition = transition
|
||||||
|
}
|
||||||
|
await store.actions.preview.saveSelected()
|
||||||
|
},
|
||||||
updateProp: async (name, value) => {
|
updateProp: async (name, value) => {
|
||||||
let component = get(selectedComponent)
|
let component = get(selectedComponent)
|
||||||
if (!name || !component) {
|
if (!name || !component) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ export class Component extends BaseStructure {
|
||||||
active: {},
|
active: {},
|
||||||
selected: {},
|
selected: {},
|
||||||
},
|
},
|
||||||
|
_transition: "",
|
||||||
_instanceName: "",
|
_instanceName: "",
|
||||||
_children: [],
|
_children: [],
|
||||||
}
|
}
|
||||||
|
@ -39,6 +40,11 @@ export class Component extends BaseStructure {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transition(transition) {
|
||||||
|
this._json._transition = transition
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
// Shorthand for custom props "type"
|
// Shorthand for custom props "type"
|
||||||
type(type) {
|
type(type) {
|
||||||
this._json.type = type
|
this._json.type = type
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
import AutomationList from "./AutomationList.svelte"
|
import AutomationList from "./AutomationList.svelte"
|
||||||
import CreateAutomationModal from "./CreateAutomationModal.svelte"
|
import CreateAutomationModal from "./CreateAutomationModal.svelte"
|
||||||
import { Modal } from "@budibase/bbui"
|
import { Modal } from "@budibase/bbui"
|
||||||
import { automationStore, backendUiStore } from "builderStore"
|
|
||||||
import { notifier } from "builderStore/store/notifications"
|
|
||||||
|
|
||||||
let selectedTab = "AUTOMATIONS"
|
|
||||||
let modal
|
let modal
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -40,12 +36,4 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
span:not(.selected) {
|
|
||||||
color: var(--grey-5);
|
|
||||||
}
|
|
||||||
|
|
||||||
span:not(.selected):hover {
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -8,13 +8,6 @@
|
||||||
|
|
||||||
$: valid = !!name
|
$: valid = !!name
|
||||||
$: instanceId = $backendUiStore.selectedDatabase._id
|
$: instanceId = $backendUiStore.selectedDatabase._id
|
||||||
$: appId = $store.appId
|
|
||||||
|
|
||||||
function sleep(ms) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(resolve, ms)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createAutomation() {
|
async function createAutomation() {
|
||||||
await automationStore.actions.create({
|
await automationStore.actions.create({
|
||||||
|
|
|
@ -60,29 +60,4 @@
|
||||||
div.icon i {
|
div.icon i {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: var(--spacing-s) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
display: flex;
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
color: var(--ink);
|
|
||||||
padding: var(--spacing-s) var(--spacing-m);
|
|
||||||
margin: auto 0;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
li:hover {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
li:active {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
<script>
|
||||||
|
import groupBy from "lodash/fp/groupBy"
|
||||||
|
import { Input, TextArea, Heading, Spacer, Label } from "@budibase/bbui"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import { isValid } from "@budibase/string-templates"
|
||||||
|
import { handlebarsCompletions } from "constants/completions"
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
export let value = ""
|
||||||
|
export let bindingDrawer
|
||||||
|
export let bindableProperties = []
|
||||||
|
|
||||||
|
let originalValue = value
|
||||||
|
let helpers = handlebarsCompletions()
|
||||||
|
let getCaretPosition
|
||||||
|
let search = ""
|
||||||
|
let validity = true
|
||||||
|
|
||||||
|
$: categories = Object.entries(groupBy("category", bindableProperties))
|
||||||
|
$: value && checkValid()
|
||||||
|
$: dispatch("update", value)
|
||||||
|
$: searchRgx = new RegExp(search, "ig")
|
||||||
|
|
||||||
|
function checkValid() {
|
||||||
|
validity = isValid(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToText(binding) {
|
||||||
|
const position = getCaretPosition()
|
||||||
|
const toAdd = `{{ ${binding.path} }}`
|
||||||
|
if (position.start) {
|
||||||
|
value =
|
||||||
|
value.substring(0, position.start) +
|
||||||
|
toAdd +
|
||||||
|
value.substring(position.end, value.length)
|
||||||
|
} else {
|
||||||
|
value += toAdd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function cancel() {
|
||||||
|
dispatch("update", originalValue)
|
||||||
|
bindingDrawer.close()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="list">
|
||||||
|
<Heading small>Available bindings</Heading>
|
||||||
|
<Spacer medium />
|
||||||
|
<Input extraThin placeholder="Search" bind:value={search} />
|
||||||
|
<Spacer medium />
|
||||||
|
{#each categories as [categoryName, bindings]}
|
||||||
|
<Heading extraSmall>{categoryName}</Heading>
|
||||||
|
<Spacer extraSmall />
|
||||||
|
{#each bindableProperties.filter(binding =>
|
||||||
|
binding.label.match(searchRgx)
|
||||||
|
) as binding}
|
||||||
|
<div class="binding" on:click={() => addToText(binding)}>
|
||||||
|
<span class="binding__label">{binding.label}</span>
|
||||||
|
<span class="binding__type">{binding.type}</span>
|
||||||
|
<br />
|
||||||
|
<div class="binding__description">
|
||||||
|
{binding.description || ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/each}
|
||||||
|
<Heading extraSmall>Helpers</Heading>
|
||||||
|
<Spacer extraSmall />
|
||||||
|
{#each helpers.filter(helper => helper.label.match(searchRgx) || helper.description.match(searchRgx)) as helper}
|
||||||
|
<div class="binding" on:click={() => addToText(helper)}>
|
||||||
|
<span class="binding__label">{helper.label}</span>
|
||||||
|
<br />
|
||||||
|
<div class="binding__description">
|
||||||
|
{@html helper.description || ''}
|
||||||
|
</div>
|
||||||
|
<pre>{helper.example || ''}</pre>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="text">
|
||||||
|
<TextArea
|
||||||
|
bind:getCaretPosition
|
||||||
|
thin
|
||||||
|
bind:value
|
||||||
|
placeholder="Add text, or click the objects on the left to add them to the textbox." />
|
||||||
|
{#if !validity}
|
||||||
|
<p class="syntax-error">
|
||||||
|
Current Handlebars syntax is invalid, please check the guide
|
||||||
|
<a href="https://handlebarsjs.com/guide/">here</a>
|
||||||
|
for more details.
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
height: 40vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 280px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
border-right: var(--border-light);
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.list {
|
||||||
|
border-right: var(--border-light);
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
}
|
||||||
|
.text :global(textarea) {
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
.text :global(p) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.binding {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: var(--spacing-s);
|
||||||
|
border-radius: var(--border-radius-m);
|
||||||
|
}
|
||||||
|
.binding:hover {
|
||||||
|
background-color: var(--grey-2);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.binding__label {
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
.binding__description {
|
||||||
|
color: var(--grey-8);
|
||||||
|
margin-top: 2px;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.binding__type {
|
||||||
|
font-family: monospace;
|
||||||
|
background-color: var(--grey-2);
|
||||||
|
border-radius: var(--border-radius-m);
|
||||||
|
padding: 2px;
|
||||||
|
margin-left: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor {
|
||||||
|
padding-left: var(--spacing-l);
|
||||||
|
}
|
||||||
|
.editor :global(textarea) {
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
grid-gap: var(--spacing-l);
|
||||||
|
align-items: center;
|
||||||
|
margin-top: var(--spacing-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.syntax-error {
|
||||||
|
color: var(--red);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.syntax-error a {
|
||||||
|
color: var(--red);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
import { Button, Input, Select, Label } from "@budibase/bbui"
|
import { Button, Input, Select, Label } from "@budibase/bbui"
|
||||||
import { automationStore } from "builderStore"
|
import { automationStore } from "builderStore"
|
||||||
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
|
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
|
||||||
import BindableInput from "../../common/BindableInput.svelte"
|
import DrawerBindableInput from "../../common/DrawerBindableInput.svelte"
|
||||||
|
import AutomationBindingPanel from './AutomationBindingPanel.svelte'
|
||||||
|
|
||||||
export let block
|
export let block
|
||||||
export let webhookModal
|
export let webhookModal
|
||||||
|
@ -64,10 +65,12 @@
|
||||||
{:else if value.customType === 'password'}
|
{:else if value.customType === 'password'}
|
||||||
<Input type="password" extraThin bind:value={block.inputs[key]} />
|
<Input type="password" extraThin bind:value={block.inputs[key]} />
|
||||||
{:else if value.customType === 'email'}
|
{:else if value.customType === 'email'}
|
||||||
<BindableInput
|
<DrawerBindableInput
|
||||||
|
panel={AutomationBindingPanel}
|
||||||
type={'email'}
|
type={'email'}
|
||||||
extraThin
|
extraThin
|
||||||
bind:value={block.inputs[key]}
|
value={block.inputs[key]}
|
||||||
|
on:change={e => block.inputs[key] = e.detail}
|
||||||
{bindings} />
|
{bindings} />
|
||||||
{:else if value.customType === 'table'}
|
{:else if value.customType === 'table'}
|
||||||
<TableSelector bind:value={block.inputs[key]} />
|
<TableSelector bind:value={block.inputs[key]} />
|
||||||
|
@ -78,10 +81,12 @@
|
||||||
{:else if value.customType === 'triggerSchema'}
|
{:else if value.customType === 'triggerSchema'}
|
||||||
<SchemaSetup bind:value={block.inputs[key]} />
|
<SchemaSetup bind:value={block.inputs[key]} />
|
||||||
{:else if value.type === 'string' || value.type === 'number'}
|
{:else if value.type === 'string' || value.type === 'number'}
|
||||||
<BindableInput
|
<DrawerBindableInput
|
||||||
|
panel={AutomationBindingPanel}
|
||||||
type={value.customType}
|
type={value.customType}
|
||||||
extraThin
|
extraThin
|
||||||
bind:value={block.inputs[key]}
|
value={block.inputs[key]}
|
||||||
|
on:change={e => block.inputs[key] = e.detail}
|
||||||
{bindings} />
|
{bindings} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -102,11 +107,4 @@
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
color: var(--grey-7);
|
color: var(--grey-7);
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
|
||||||
min-height: 150px;
|
|
||||||
font-family: inherit;
|
|
||||||
padding: 12px;
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,219 +0,0 @@
|
||||||
<script>
|
|
||||||
import groupBy from "lodash/fp/groupBy"
|
|
||||||
import {
|
|
||||||
TextArea,
|
|
||||||
Input,
|
|
||||||
Heading,
|
|
||||||
Body,
|
|
||||||
Spacer,
|
|
||||||
Button,
|
|
||||||
Popover,
|
|
||||||
} from "@budibase/bbui"
|
|
||||||
import { createEventDispatcher } from "svelte"
|
|
||||||
import { isValid } from "@budibase/string-templates"
|
|
||||||
import { handlebarsCompletions } from "constants/completions"
|
|
||||||
import { readableToRuntimeBinding } from "builderStore/dataBinding"
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
export let value = ""
|
|
||||||
export let bindings = []
|
|
||||||
export let anchor
|
|
||||||
export let align
|
|
||||||
export let popover = null
|
|
||||||
|
|
||||||
let helpers = handlebarsCompletions()
|
|
||||||
let getCaretPosition
|
|
||||||
let validity = true
|
|
||||||
let search = ""
|
|
||||||
|
|
||||||
$: categories = Object.entries(groupBy("category", bindings))
|
|
||||||
$: value && checkValid()
|
|
||||||
$: searchRgx = new RegExp(search, "ig")
|
|
||||||
|
|
||||||
function onClickBinding(binding) {
|
|
||||||
const position = getCaretPosition()
|
|
||||||
const toAdd = `{{ ${binding.path} }}`
|
|
||||||
if (position.start) {
|
|
||||||
value =
|
|
||||||
value.substring(0, position.start) +
|
|
||||||
toAdd +
|
|
||||||
value.substring(position.end, value.length)
|
|
||||||
} else {
|
|
||||||
value += toAdd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkValid() {
|
|
||||||
const runtimeValue = readableToRuntimeBinding(bindings, value)
|
|
||||||
validity = isValid(runtimeValue)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Popover {anchor} {align} bind:this={popover}>
|
|
||||||
<div class="container">
|
|
||||||
<div class="bindings">
|
|
||||||
<Heading small>Available bindings</Heading>
|
|
||||||
<Spacer medium />
|
|
||||||
<Input extraThin placeholder="Search" bind:value={search} />
|
|
||||||
<Spacer medium />
|
|
||||||
<div class="bindings__wrapper">
|
|
||||||
<div class="bindings__list">
|
|
||||||
{#each categories as [categoryName, bindings]}
|
|
||||||
<Heading extraSmall>{categoryName}</Heading>
|
|
||||||
<Spacer extraSmall />
|
|
||||||
{#each bindings.filter(binding =>
|
|
||||||
binding.label.match(searchRgx)
|
|
||||||
) as binding}
|
|
||||||
<div class="binding" on:click={() => onClickBinding(binding)}>
|
|
||||||
<span class="binding__label">{binding.label}</span>
|
|
||||||
<span class="binding__type">{binding.type}</span>
|
|
||||||
<br />
|
|
||||||
<div class="binding__description">
|
|
||||||
{binding.description || ''}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
{/each}
|
|
||||||
<Heading extraSmall>Helpers</Heading>
|
|
||||||
<Spacer extraSmall />
|
|
||||||
{#each helpers.filter(helper => helper.label.match(searchRgx) || helper.description.match(searchRgx)) as helper}
|
|
||||||
<div class="binding" on:click={() => onClickBinding(helper)}>
|
|
||||||
<span class="binding__label">{helper.label}</span>
|
|
||||||
<br />
|
|
||||||
<div class="binding__description">
|
|
||||||
{@html helper.description || ''}
|
|
||||||
</div>
|
|
||||||
<pre>{helper.example || ''}</pre>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="editor">
|
|
||||||
<Heading small>Data binding</Heading>
|
|
||||||
<Body small lh black>
|
|
||||||
Binding connects one piece of data to another and makes it dynamic.
|
|
||||||
Click the objects on the left to add them to the textbox.
|
|
||||||
</Body>
|
|
||||||
<TextArea
|
|
||||||
thin
|
|
||||||
bind:getCaretPosition
|
|
||||||
bind:value
|
|
||||||
placeholder="Add options from the left, type text, or do both" />
|
|
||||||
{#if !validity}
|
|
||||||
<p class="syntax-error">
|
|
||||||
Current Handlebars syntax is invalid, please check the guide
|
|
||||||
<a href="https://handlebarsjs.com/guide/">here</a>
|
|
||||||
for more details.
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
<div class="controls">
|
|
||||||
<a href="https://docs.budibase.com/design/binding">
|
|
||||||
<Body small>Learn more about binding</Body>
|
|
||||||
</a>
|
|
||||||
<Button on:click={popover.hide} disabled={!validity} primary>
|
|
||||||
Done
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 280px 1fr;
|
|
||||||
width: 800px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bindings {
|
|
||||||
border-right: 1px solid var(--grey-4);
|
|
||||||
flex: 0 0 240px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: stretch;
|
|
||||||
padding-right: var(--spacing-l);
|
|
||||||
}
|
|
||||||
.bindings :global(label) {
|
|
||||||
margin: var(--spacing-m) 0;
|
|
||||||
}
|
|
||||||
.bindings :global(label:first-child) {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
.bindings__wrapper {
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
position: relative;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
-ms-overflow-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bindings__wrapper::-webkit-scrollbar {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bindings__list {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.binding {
|
|
||||||
font-size: 12px;
|
|
||||||
padding: var(--spacing-s);
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
}
|
|
||||||
.binding:hover {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.binding__label {
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
.binding__description {
|
|
||||||
color: var(--grey-8);
|
|
||||||
margin-top: 2px;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.binding__type {
|
|
||||||
font-family: monospace;
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
padding: 2px;
|
|
||||||
margin-left: 2px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor {
|
|
||||||
padding-left: var(--spacing-l);
|
|
||||||
}
|
|
||||||
.editor :global(textarea) {
|
|
||||||
min-height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.controls {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr auto;
|
|
||||||
grid-gap: var(--spacing-l);
|
|
||||||
align-items: center;
|
|
||||||
margin-top: var(--spacing-m);
|
|
||||||
}
|
|
||||||
|
|
||||||
.syntax-error {
|
|
||||||
color: var(--red);
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.syntax-error a {
|
|
||||||
color: var(--red);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,7 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { Select } from "@budibase/bbui"
|
import { Select } from "@budibase/bbui"
|
||||||
import BindableInput from "../../common/BindableInput.svelte"
|
import DrawerBindableInput from "../../common/DrawerBindableInput.svelte"
|
||||||
|
import AutomationBindingPanel from './AutomationBindingPanel.svelte'
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
export let bindings
|
export let bindings
|
||||||
|
@ -39,9 +40,11 @@
|
||||||
{/each}
|
{/each}
|
||||||
</Select>
|
</Select>
|
||||||
{:else if schema.type === 'string' || schema.type === 'number'}
|
{:else if schema.type === 'string' || schema.type === 'number'}
|
||||||
<BindableInput
|
<DrawerBindableInput
|
||||||
|
panel={AutomationBindingPanel}
|
||||||
extraThin
|
extraThin
|
||||||
bind:value={value[field]}
|
value={value[field]}
|
||||||
|
on:change={e => value[field] = e.detail}
|
||||||
label={field}
|
label={field}
|
||||||
type="string"
|
type="string"
|
||||||
{bindings} />
|
{bindings} />
|
||||||
|
|
|
@ -92,9 +92,6 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
h5 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
code {
|
code {
|
||||||
padding: 1px 4px 1px 4px;
|
padding: 1px 4px 1px 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
|
@ -246,10 +246,6 @@
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody tr:hover {
|
|
||||||
background: var(--grey-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.ag-filter) {
|
:global(.ag-filter) {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
padding: var(--spacing-s);
|
padding: var(--spacing-s);
|
||||||
|
|
|
@ -28,10 +28,6 @@
|
||||||
title="Confirm Deletion" />
|
title="Confirm Deletion" />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.ri-delete-bin-line:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
div {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Input, Select } from "@budibase/bbui"
|
import { Button, Select } from "@budibase/bbui"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Input, Select } from "@budibase/bbui"
|
import { Button, Input } from "@budibase/bbui"
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script>
|
<script>
|
||||||
import api from "builderStore/api"
|
|
||||||
import { Button, Select } from "@budibase/bbui"
|
import { Button, Select } from "@budibase/bbui"
|
||||||
import download from "downloadjs"
|
import download from "downloadjs"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Input, Select } from "@budibase/bbui"
|
import { Button, Select } from "@budibase/bbui"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { Roles } from "constants/backend"
|
|
||||||
import api from "builderStore/api"
|
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import { Button, Label, Input, Select, Spacer } from "@budibase/bbui"
|
import { Button, Label, Input, Select, Spacer } from "@budibase/bbui"
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,11 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { TableNames } from "constants"
|
|
||||||
import CreateDatasourceModal from "./modals/CreateDatasourceModal.svelte"
|
|
||||||
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
|
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
|
||||||
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
|
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
|
||||||
import { Modal, Switcher } from "@budibase/bbui"
|
|
||||||
import NavItem from "components/common/NavItem.svelte"
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
import ICONS from "./icons"
|
import ICONS from "./icons"
|
||||||
|
|
||||||
$: selectedView =
|
|
||||||
$backendUiStore.selectedView && $backendUiStore.selectedView.name
|
|
||||||
|
|
||||||
function selectDatasource(datasource) {
|
function selectDatasource(datasource) {
|
||||||
backendUiStore.actions.datasources.select(datasource._id)
|
backendUiStore.actions.datasources.select(datasource._id)
|
||||||
$goto(`./datasource/${datasource._id}`)
|
$goto(`./datasource/${datasource._id}`)
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { backendUiStore } from "builderStore"
|
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
import { Input, Label, TextArea, Spacer } from "@budibase/bbui"
|
|
||||||
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
|
|
||||||
import ICONS from "../icons"
|
import ICONS from "../icons"
|
||||||
|
|
||||||
export let integration = {}
|
export let integration = {}
|
||||||
|
|
|
@ -6,13 +6,10 @@
|
||||||
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte"
|
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
|
|
||||||
let modal
|
|
||||||
let error = ""
|
let error = ""
|
||||||
|
|
||||||
let name
|
let name
|
||||||
let source
|
|
||||||
let integration
|
let integration
|
||||||
let datasource
|
|
||||||
|
|
||||||
function checkValid(evt) {
|
function checkValid(evt) {
|
||||||
const datasourceName = evt.target.value
|
const datasourceName = evt.target.value
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
let templateScreens
|
let templateScreens
|
||||||
let willBeDeleted
|
let willBeDeleted
|
||||||
|
|
||||||
$: fields = Object.keys(table.schema)
|
|
||||||
|
|
||||||
function showEditor() {
|
function showEditor() {
|
||||||
editing = true
|
editing = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
<script>
|
|
||||||
import { createEventDispatcher } from "svelte"
|
|
||||||
import GenericBindingPopover from "../automation/SetupPanel/GenericBindingPopover.svelte"
|
|
||||||
import { Input, Icon } from "@budibase/bbui"
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
export let bindings = []
|
|
||||||
export let value
|
|
||||||
|
|
||||||
let anchor
|
|
||||||
let popover = undefined
|
|
||||||
let enrichedValue
|
|
||||||
let inputProps
|
|
||||||
|
|
||||||
// Extract all other props to pass to input component
|
|
||||||
$: {
|
|
||||||
let { bindings, ...otherProps } = $$props
|
|
||||||
inputProps = otherProps
|
|
||||||
}
|
|
||||||
$: value && dispatch("change", value)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container" bind:this={anchor}>
|
|
||||||
<Input {...inputProps} bind:value />
|
|
||||||
<div class="icon" on:click={popover.show}>
|
|
||||||
<Icon name="lightning" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<GenericBindingPopover
|
|
||||||
{anchor}
|
|
||||||
{bindings}
|
|
||||||
bind:value
|
|
||||||
bind:popover
|
|
||||||
align="right" />
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
right: 2px;
|
|
||||||
top: 5px;
|
|
||||||
bottom: 2px;
|
|
||||||
position: absolute;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding-left: var(--spacing-xs);
|
|
||||||
border-left: 1px solid var(--grey-4);
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
border-top-right-radius: var(--border-radius-m);
|
|
||||||
border-bottom-right-radius: var(--border-radius-m);
|
|
||||||
color: var(--grey-7);
|
|
||||||
font-size: 16px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
.icon:hover {
|
|
||||||
color: var(--ink);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -8,6 +8,7 @@
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
export let panel = BindingPanel
|
||||||
export let value = ""
|
export let value = ""
|
||||||
export let bindings = []
|
export let bindings = []
|
||||||
export let thin = true
|
export let thin = true
|
||||||
|
@ -49,7 +50,8 @@
|
||||||
<Button thin blue on:click={handleClose}>Save</Button>
|
<Button thin blue on:click={handleClose}>Save</Button>
|
||||||
</heading>
|
</heading>
|
||||||
<div slot="body">
|
<div slot="body">
|
||||||
<BindingPanel
|
<svelte:component
|
||||||
|
this={panel}
|
||||||
value={readableValue}
|
value={readableValue}
|
||||||
close={handleClose}
|
close={handleClose}
|
||||||
on:update={event => (tempValue = event.detail)}
|
on:update={event => (tempValue = event.detail)}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"fieldgroup",
|
"fieldgroup",
|
||||||
"stringfield",
|
"stringfield",
|
||||||
"numberfield",
|
"numberfield",
|
||||||
|
"passwordfield",
|
||||||
"optionsfield",
|
"optionsfield",
|
||||||
"booleanfield",
|
"booleanfield",
|
||||||
"longformfield",
|
"longformfield",
|
||||||
|
@ -49,6 +50,7 @@
|
||||||
"heading",
|
"heading",
|
||||||
"text",
|
"text",
|
||||||
"image",
|
"image",
|
||||||
|
"backgroundimage",
|
||||||
"link",
|
"link",
|
||||||
"icon",
|
"icon",
|
||||||
"embed"
|
"embed"
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store, currentAsset } from "builderStore"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
import { last } from "lodash/fp"
|
|
||||||
import { findComponentParent } from "builderStore/storeUtils"
|
import { findComponentParent } from "builderStore/storeUtils"
|
||||||
import { DropdownMenu } from "@budibase/bbui"
|
import { DropdownMenu } from "@budibase/bbui"
|
||||||
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
|
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
|
||||||
|
@ -17,16 +16,10 @@
|
||||||
$: noChildrenAllowed = !component || !definition?.hasChildren
|
$: noChildrenAllowed = !component || !definition?.hasChildren
|
||||||
$: noPaste = !$store.componentToPaste
|
$: noPaste = !$store.componentToPaste
|
||||||
|
|
||||||
const lastPartOfName = c => (c ? last(c._component.split("/")) : "")
|
|
||||||
|
|
||||||
const hideDropdown = () => {
|
const hideDropdown = () => {
|
||||||
dropdown.hide()
|
dropdown.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectComponent = component => {
|
|
||||||
store.actions.components.select(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
const moveUpComponent = () => {
|
const moveUpComponent = () => {
|
||||||
const asset = get(currentAsset)
|
const asset = get(currentAsset)
|
||||||
const parent = findComponentParent(asset.props, component._id)
|
const parent = findComponentParent(asset.props, component._id)
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@sveltech/routify"
|
|
||||||
import { store, backendUiStore, allScreens } from "builderStore"
|
import { store, backendUiStore, allScreens } from "builderStore"
|
||||||
import { Input, Select, ModalContent, Toggle } from "@budibase/bbui"
|
import { Input, Select, ModalContent, Toggle } from "@budibase/bbui"
|
||||||
import getTemplates from "builderStore/store/screenTemplates"
|
import getTemplates from "builderStore/store/screenTemplates"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import { onMount } from "svelte"
|
|
||||||
import api from "builderStore/api"
|
|
||||||
|
|
||||||
const CONTAINER = "@budibase/standard-components/container"
|
const CONTAINER = "@budibase/standard-components/container"
|
||||||
|
|
||||||
|
@ -19,9 +16,6 @@
|
||||||
|
|
||||||
$: templates = getTemplates($store, $backendUiStore.tables)
|
$: templates = getTemplates($store, $backendUiStore.tables)
|
||||||
$: route = !route && $allScreens.length === 0 ? "*" : route
|
$: route = !route && $allScreens.length === 0 ? "*" : route
|
||||||
$: baseComponents = Object.values($store.components)
|
|
||||||
.filter(componentDefinition => componentDefinition.baseComponent)
|
|
||||||
.map(c => c._component)
|
|
||||||
$: {
|
$: {
|
||||||
if (templates && templateIndex === undefined) {
|
if (templates && templateIndex === undefined) {
|
||||||
templateIndex = 0
|
templateIndex = 0
|
||||||
|
@ -31,7 +25,6 @@
|
||||||
|
|
||||||
const templateChanged = newTemplateIndex => {
|
const templateChanged = newTemplateIndex => {
|
||||||
if (newTemplateIndex === undefined) return
|
if (newTemplateIndex === undefined) return
|
||||||
const template = templates[newTemplateIndex]
|
|
||||||
draftScreen = templates[newTemplateIndex].create()
|
draftScreen = templates[newTemplateIndex].create()
|
||||||
if (draftScreen.props._instanceName) {
|
if (draftScreen.props._instanceName) {
|
||||||
name = draftScreen.props._instanceName
|
name = draftScreen.props._instanceName
|
||||||
|
@ -60,6 +53,7 @@
|
||||||
if (routeError) return false
|
if (routeError) return false
|
||||||
|
|
||||||
draftScreen.props._instanceName = name
|
draftScreen.props._instanceName = name
|
||||||
|
draftScreen.props._transition = "fade"
|
||||||
draftScreen.props._component = baseComponent
|
draftScreen.props._component = baseComponent
|
||||||
draftScreen.routing = { route, roleId }
|
draftScreen.routing = { route, roleId }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { TextArea, DetailSummary, Button } from "@budibase/bbui"
|
import { TextArea, DetailSummary, Button, Select } from "@budibase/bbui"
|
||||||
import PropertyGroup from "./PropertyControls/PropertyGroup.svelte"
|
import PropertyGroup from "./PropertyControls/PropertyGroup.svelte"
|
||||||
import FlatButtonGroup from "./PropertyControls/FlatButtonGroup"
|
import FlatButtonGroup from "./PropertyControls/FlatButtonGroup"
|
||||||
import { allStyles } from "./componentStyles"
|
import { allStyles } from "./componentStyles"
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let onStyleChanged = () => {}
|
export let onStyleChanged = () => {}
|
||||||
export let onCustomStyleChanged = () => {}
|
export let onCustomStyleChanged = () => {}
|
||||||
|
export let onUpdateTransition = () => {}
|
||||||
export let onResetStyles = () => {}
|
export let onResetStyles = () => {}
|
||||||
|
|
||||||
let selectedCategory = "normal"
|
let selectedCategory = "normal"
|
||||||
|
@ -23,16 +24,22 @@
|
||||||
{ value: "active", text: "Active" },
|
{ value: "active", text: "Active" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const transitions = [
|
||||||
|
'none', 'fade', 'blur', 'fly', 'scale' // slide is hidden because it does not seem to result in any effect
|
||||||
|
]
|
||||||
|
|
||||||
|
const capitalize = ([first,...rest]) => first.toUpperCase() + rest.join('');
|
||||||
|
|
||||||
$: groups = componentDefinition?.styleable ? Object.keys(allStyles) : []
|
$: groups = componentDefinition?.styleable ? Object.keys(allStyles) : []
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="design-view-container">
|
<div class="container">
|
||||||
<div class="design-view-state-categories">
|
<div class="state-categories">
|
||||||
<FlatButtonGroup value={selectedCategory} {buttonProps} {onChange} />
|
<FlatButtonGroup value={selectedCategory} {buttonProps} {onChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="positioned-wrapper">
|
<div class="positioned-wrapper">
|
||||||
<div class="design-view-property-groups">
|
<div class="property-groups">
|
||||||
{#if groups.length > 0}
|
{#if groups.length > 0}
|
||||||
{#each groups as groupName}
|
{#each groups as groupName}
|
||||||
<PropertyGroup
|
<PropertyGroup
|
||||||
|
@ -64,10 +71,19 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{#if componentDefinition?.transitionable}
|
||||||
|
<div class="transitions">
|
||||||
|
<Select value={componentInstance._transition} on:change={event => onUpdateTransition(event.target.value)} name="transition" label="Transition" secondary thin>
|
||||||
|
{#each transitions as transition}
|
||||||
|
<option value={transition}>{capitalize(transition)}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.design-view-container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -81,7 +97,7 @@
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.design-view-property-groups {
|
.property-groups {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
@ -104,4 +120,8 @@
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -24,29 +24,9 @@
|
||||||
|
|
||||||
const onStyleChanged = store.actions.components.updateStyle
|
const onStyleChanged = store.actions.components.updateStyle
|
||||||
const onCustomStyleChanged = store.actions.components.updateCustomStyle
|
const onCustomStyleChanged = store.actions.components.updateCustomStyle
|
||||||
|
const onUpdateTransition = store.actions.components.updateTransition
|
||||||
const onResetStyles = store.actions.components.resetStyles
|
const onResetStyles = store.actions.components.resetStyles
|
||||||
|
|
||||||
function walkProps(component, action) {
|
|
||||||
action(component)
|
|
||||||
if (component.children) {
|
|
||||||
for (let child of component.children) {
|
|
||||||
walkProps(child, action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function flattenComponents(props) {
|
|
||||||
const components = []
|
|
||||||
props.forEach(comp =>
|
|
||||||
walkProps(comp, c => {
|
|
||||||
if ("_component" in c) {
|
|
||||||
components.push(c)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
return components
|
|
||||||
}
|
|
||||||
|
|
||||||
function setAssetProps(name, value) {
|
function setAssetProps(name, value) {
|
||||||
const selectedAsset = get(currentAsset)
|
const selectedAsset = get(currentAsset)
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -62,10 +42,6 @@
|
||||||
})
|
})
|
||||||
store.actions.preview.saveSelected()
|
store.actions.preview.saveSelected()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProps(obj, keys) {
|
|
||||||
return keys.map((key, i) => [key, obj[key], obj.props._id + i])
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CategoryTab
|
<CategoryTab
|
||||||
|
@ -84,6 +60,7 @@
|
||||||
componentDefinition={definition}
|
componentDefinition={definition}
|
||||||
{onStyleChanged}
|
{onStyleChanged}
|
||||||
{onCustomStyleChanged}
|
{onCustomStyleChanged}
|
||||||
|
{onUpdateTransition}
|
||||||
{onResetStyles} />
|
{onResetStyles} />
|
||||||
{:else if selectedCategory.value === 'settings'}
|
{:else if selectedCategory.value === 'settings'}
|
||||||
<SettingsView
|
<SettingsView
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
<script>
|
<script>
|
||||||
|
import {flip} from "svelte/animate";
|
||||||
|
import {dndzone} from "svelte-dnd-action";
|
||||||
import { Button, DropdownMenu, Spacer } from "@budibase/bbui"
|
import { Button, DropdownMenu, Spacer } from "@budibase/bbui"
|
||||||
import actionTypes from "./actions"
|
import actionTypes from "./actions"
|
||||||
|
|
||||||
|
const flipDurationMs = 150;
|
||||||
|
|
||||||
const EVENT_TYPE_KEY = "##eventHandlerType"
|
const EVENT_TYPE_KEY = "##eventHandlerType"
|
||||||
|
|
||||||
export let actions
|
export let actions
|
||||||
|
|
||||||
|
// dndzone needs an id on the array items, so this adds some temporary ones.
|
||||||
|
if (actions) {
|
||||||
|
actions = actions.map((action, i) => {
|
||||||
|
return {...action, id: i}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let addActionButton
|
let addActionButton
|
||||||
let addActionDropdown
|
let addActionDropdown
|
||||||
let selectedAction = actions?.length ? actions[0] : null
|
let selectedAction = actions?.length ? actions[0] : null
|
||||||
|
@ -30,19 +41,26 @@
|
||||||
const newAction = {
|
const newAction = {
|
||||||
parameters: {},
|
parameters: {},
|
||||||
[EVENT_TYPE_KEY]: actionType.name,
|
[EVENT_TYPE_KEY]: actionType.name,
|
||||||
|
id: actions ? actions.length + 1 : 0
|
||||||
}
|
}
|
||||||
if (!actions) {
|
if (!actions) {
|
||||||
actions = []
|
actions = []
|
||||||
}
|
}
|
||||||
actions.push(newAction)
|
actions = [...actions, newAction]
|
||||||
selectedAction = newAction
|
selectedAction = newAction
|
||||||
actions = actions
|
|
||||||
addActionDropdown.hide()
|
addActionDropdown.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectAction = action => () => {
|
const selectAction = action => () => {
|
||||||
selectedAction = action
|
selectedAction = action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleDndConsider(e) {
|
||||||
|
actions = e.detail.items;
|
||||||
|
}
|
||||||
|
function handleDndFinalize(e) {
|
||||||
|
actions = e.detail.items;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="actions-container">
|
<div class="actions-container">
|
||||||
|
@ -69,8 +87,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if actions && actions.length > 0}
|
{#if actions && actions.length > 0}
|
||||||
{#each actions as action, index}
|
<div class="action-dnd-container" use:dndzone={{items: actions, flipDurationMs, dropTargetStyle: { outline: 'none'}}} on:consider={handleDndConsider} on:finalize={handleDndFinalize}>
|
||||||
<div class="action-container">
|
{#each actions as action, index (action.id)}
|
||||||
|
<div class="action-container" animate:flip={{duration: flipDurationMs}}>
|
||||||
<div
|
<div
|
||||||
class="action-header"
|
class="action-header"
|
||||||
class:selected={action === selectedAction}
|
class:selected={action === selectedAction}
|
||||||
|
@ -84,6 +103,7 @@
|
||||||
on:click={() => deleteAction(index)} />
|
on:click={() => deleteAction(index)} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="action-config">
|
<div class="action-config">
|
||||||
|
@ -156,17 +176,6 @@
|
||||||
padding: var(--spacing-l);
|
padding: var(--spacing-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
flex: 1;
|
|
||||||
color: var(--grey-5);
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
i:hover {
|
i:hover {
|
||||||
color: var(--red);
|
color: var(--red);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<script>
|
||||||
|
import { Label } from "@budibase/bbui"
|
||||||
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
|
import { currentAsset, store } from "builderStore"
|
||||||
|
import DrawerBindableInput from "components/common/DrawerBindableInput.svelte"
|
||||||
|
|
||||||
|
export let parameters
|
||||||
|
|
||||||
|
let bindingDrawer
|
||||||
|
$: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="root">
|
||||||
|
<Label small>Email</Label>
|
||||||
|
<DrawerBindableInput
|
||||||
|
title="Email"
|
||||||
|
value={parameters.email}
|
||||||
|
on:change={value => (parameters.email = value.detail)}
|
||||||
|
{bindings} />
|
||||||
|
<Label small>Password</Label>
|
||||||
|
<DrawerBindableInput
|
||||||
|
title="Password"
|
||||||
|
value={parameters.password}
|
||||||
|
on:change={value => (parameters.password = value.detail)}
|
||||||
|
{bindings} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.root {
|
||||||
|
display: grid;
|
||||||
|
column-gap: var(--spacing-l);
|
||||||
|
row-gap: var(--spacing-s);
|
||||||
|
grid-template-columns: auto 1fr auto 1fr;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div class="root">This action doesn't require any additional settings.</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.root {
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,6 +4,8 @@ import DeleteRow from "./DeleteRow.svelte"
|
||||||
import ExecuteQuery from "./ExecuteQuery.svelte"
|
import ExecuteQuery from "./ExecuteQuery.svelte"
|
||||||
import TriggerAutomation from "./TriggerAutomation.svelte"
|
import TriggerAutomation from "./TriggerAutomation.svelte"
|
||||||
import ValidateForm from "./ValidateForm.svelte"
|
import ValidateForm from "./ValidateForm.svelte"
|
||||||
|
import LogIn from "./LogIn.svelte"
|
||||||
|
import LogOut from "./LogOut.svelte"
|
||||||
|
|
||||||
// defines what actions are available, when adding a new one
|
// defines what actions are available, when adding a new one
|
||||||
// the component is the setup panel for the action
|
// the component is the setup panel for the action
|
||||||
|
@ -35,4 +37,12 @@ export default [
|
||||||
name: "Validate Form",
|
name: "Validate Form",
|
||||||
component: ValidateForm,
|
component: ValidateForm,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Log In",
|
||||||
|
component: LogIn,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Log Out",
|
||||||
|
component: LogOut,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script context="module">
|
<script context="module">
|
||||||
import iconData from "./icons.js"
|
import iconData from "./icons.js"
|
||||||
|
|
||||||
const categories = Object.keys(iconData)
|
|
||||||
const icons = Object.keys(iconData).reduce(
|
const icons = Object.keys(iconData).reduce(
|
||||||
(acc, cat) => [...acc, ...Object.keys(iconData[cat])],
|
(acc, cat) => [...acc, ...Object.keys(iconData[cat])],
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
|
|
||||||
let roles = []
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Select bind:value extraThin secondary on:change>
|
<Select bind:value extraThin secondary on:change>
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import { Label, Spacer } from "@budibase/bbui"
|
import { Label, Spacer } from "@budibase/bbui"
|
||||||
import { onMount, createEventDispatcher } from "svelte"
|
import { onMount, createEventDispatcher } from "svelte"
|
||||||
import { themeStore } from "builderStore"
|
import { themeStore } from "builderStore"
|
||||||
import { handlebarsCompletions } from "constants/completions"
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
@ -21,13 +20,6 @@
|
||||||
export let editorHeight = 500
|
export let editorHeight = 500
|
||||||
// export let parameters = []
|
// export let parameters = []
|
||||||
|
|
||||||
let completions = handlebarsCompletions()
|
|
||||||
|
|
||||||
// $: completions = parameters.map(param => ({
|
|
||||||
// text: `{{ ${param.name} }}`,
|
|
||||||
// displayText: param.name,
|
|
||||||
// }))
|
|
||||||
|
|
||||||
let width
|
let width
|
||||||
let height
|
let height
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,6 @@
|
||||||
export let schema
|
export let schema
|
||||||
export let editable
|
export let editable
|
||||||
|
|
||||||
let draftField = {}
|
|
||||||
|
|
||||||
$: fieldKeys = Object.keys(fields)
|
|
||||||
$: schemaKeys = Object.keys(schema.fields)
|
$: schemaKeys = Object.keys(schema.fields)
|
||||||
|
|
||||||
function updateCustomFields({ detail }) {
|
function updateCustomFields({ detail }) {
|
||||||
|
|
|
@ -44,11 +44,6 @@
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
|
||||||
margin: 0;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,11 +61,4 @@
|
||||||
.card-footer {
|
.card-footer {
|
||||||
margin-top: var(--spacing-m);
|
margin-top: var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: var(--font-size-l);
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--ink);
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -130,11 +130,6 @@
|
||||||
border-bottom: 1px solid var(--grey-2);
|
border-bottom: 1px solid var(--grey-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content > div {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toprightnav {
|
.toprightnav {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { params } from "@sveltech/routify"
|
import { params } from "@sveltech/routify"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { Switcher } from "@budibase/bbui"
|
|
||||||
import QueryInterface from "components/integration/QueryViewer.svelte"
|
import QueryInterface from "components/integration/QueryViewer.svelte"
|
||||||
|
|
||||||
let query
|
|
||||||
|
|
||||||
async function fetchQueryConfig() {
|
async function fetchQueryConfig() {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`/api/integrations/${datasource.source}`)
|
const response = await api.get(`/api/integrations/${datasource.source}`)
|
||||||
|
|
|
@ -135,11 +135,6 @@
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
|
||||||
margin: 0 !important;
|
|
||||||
font-size: var(--font-size-l);
|
|
||||||
}
|
|
||||||
|
|
||||||
.query-header {
|
.query-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
@ -202,31 +202,4 @@
|
||||||
gap: var(--spacing-l);
|
gap: var(--spacing-l);
|
||||||
padding: var(--spacing-l) var(--spacing-xl);
|
padding: var(--spacing-l) var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.binding-drawer-container {
|
|
||||||
height: 50vh;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
background: var(--background);
|
|
||||||
padding: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-group-header > div:nth-child(1) {
|
|
||||||
padding: 0rem 0.5rem 0rem 0rem;
|
|
||||||
vertical-align: bottom;
|
|
||||||
grid-column-start: icon;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-group-header > div:nth-child(3) {
|
|
||||||
vertical-align: bottom;
|
|
||||||
grid-column-start: button;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-group-header > div:nth-child(3):hover {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
import TemplateList from "components/start/TemplateList.svelte"
|
import TemplateList from "components/start/TemplateList.svelte"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
|
|
||||||
let promise = getApps()
|
|
||||||
let hasKey
|
let hasKey
|
||||||
let template
|
let template
|
||||||
let modal
|
let modal
|
||||||
|
|
|
@ -6686,6 +6686,11 @@ supports-color@^7.0.0, supports-color@^7.1.0, supports-color@^7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
|
svelte-dnd-action@^0.8.9:
|
||||||
|
version "0.8.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte-dnd-action/-/svelte-dnd-action-0.8.9.tgz#90fa211057a5d9e832d5521511f9c1b87242d2ae"
|
||||||
|
integrity sha512-4WaLRvERr2JoX6Lh9GnlEZRzFF5eY3h2q0n5+lS4/+nqqQjTIpCwTrncMf9tJNa+M4AGy43I5aq5F+Ohl/nxLg==
|
||||||
|
|
||||||
svelte-flatpickr@^2.4.0:
|
svelte-flatpickr@^2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-2.4.0.tgz#190871fc3305956c8c8fd3601cd036b8ac71ef49"
|
resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-2.4.0.tgz#190871fc3305956c8c8fd3601cd036b8ac71ef49"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
screenStore,
|
screenStore,
|
||||||
authStore,
|
authStore,
|
||||||
} from "../store"
|
} from "../store"
|
||||||
|
import { TableNames, ActionTypes } from "../constants"
|
||||||
|
|
||||||
// Provide contexts
|
// Provide contexts
|
||||||
setContext("sdk", SDK)
|
setContext("sdk", SDK)
|
||||||
|
@ -25,10 +26,20 @@
|
||||||
await authStore.actions.fetchUser()
|
await authStore.actions.fetchUser()
|
||||||
loaded = true
|
loaded = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Register this as a refreshable datasource so that user changes cause
|
||||||
|
// the user object to be refreshed
|
||||||
|
$: actions = [
|
||||||
|
{
|
||||||
|
type: ActionTypes.RefreshDatasource,
|
||||||
|
callback: () => authStore.actions.fetchUser(),
|
||||||
|
metadata: { datasource: { type: "table", tableId: TableNames.USERS } },
|
||||||
|
},
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loaded && $screenStore.activeLayout}
|
{#if loaded && $screenStore.activeLayout}
|
||||||
<Provider key="user" data={$authStore}>
|
<Provider key="user" data={$authStore} {actions}>
|
||||||
<Component definition={$screenStore.activeLayout.props} />
|
<Component definition={$screenStore.activeLayout.props} />
|
||||||
<NotificationDisplay />
|
<NotificationDisplay />
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|
|
@ -34,12 +34,14 @@
|
||||||
$: id = definition._id
|
$: id = definition._id
|
||||||
$: updateComponentProps(definition, $context)
|
$: updateComponentProps(definition, $context)
|
||||||
$: styles = definition._styles
|
$: styles = definition._styles
|
||||||
|
$: transition = definition._transition
|
||||||
|
|
||||||
// Update component context
|
// Update component context
|
||||||
$: componentStore.set({
|
$: componentStore.set({
|
||||||
id,
|
id,
|
||||||
children: children.length,
|
children: children.length,
|
||||||
styles: { ...styles, id },
|
styles: { ...styles, id },
|
||||||
|
transition
|
||||||
})
|
})
|
||||||
|
|
||||||
// Gets the component constructor for the specified component
|
// Gets the component constructor for the specified component
|
||||||
|
|
|
@ -18,19 +18,6 @@
|
||||||
<!-- Ensure to fully remount when screen changes -->
|
<!-- Ensure to fully remount when screen changes -->
|
||||||
{#key screenDefinition?._id}
|
{#key screenDefinition?._id}
|
||||||
<Provider key="url" data={params}>
|
<Provider key="url" data={params}>
|
||||||
<div in:fade>
|
|
||||||
<Component definition={screenDefinition} />
|
<Component definition={screenDefinition} />
|
||||||
</div>
|
|
||||||
</Provider>
|
</Provider>
|
||||||
{/key}
|
{/key}
|
||||||
|
|
||||||
<style>
|
|
||||||
div {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
align-self: stretch;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
builderStore,
|
builderStore,
|
||||||
} from "./store"
|
} from "./store"
|
||||||
import { styleable } from "./utils/styleable"
|
import { styleable } from "./utils/styleable"
|
||||||
|
import transition from "./utils/transition"
|
||||||
import { linkable } from "./utils/linkable"
|
import { linkable } from "./utils/linkable"
|
||||||
import Provider from "./components/Provider.svelte"
|
import Provider from "./components/Provider.svelte"
|
||||||
import { ActionTypes } from "./constants"
|
import { ActionTypes } from "./constants"
|
||||||
|
@ -19,6 +20,7 @@ export default {
|
||||||
screenStore,
|
screenStore,
|
||||||
builderStore,
|
builderStore,
|
||||||
styleable,
|
styleable,
|
||||||
|
transition,
|
||||||
linkable,
|
linkable,
|
||||||
Provider,
|
Provider,
|
||||||
ActionTypes,
|
ActionTypes,
|
||||||
|
|
|
@ -21,7 +21,7 @@ const createAuthStore = () => {
|
||||||
const logIn = async ({ email, password }) => {
|
const logIn = async ({ email, password }) => {
|
||||||
const user = await API.logIn({ email, password })
|
const user = await API.logIn({ email, password })
|
||||||
if (!user.error) {
|
if (!user.error) {
|
||||||
store.set(user)
|
await fetchUser()
|
||||||
await initialise()
|
await initialise()
|
||||||
goToDefaultRoute()
|
goToDefaultRoute()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,33 @@
|
||||||
import { writable, derived } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import { generate } from "shortid"
|
|
||||||
|
|
||||||
const NOTIFICATION_TIMEOUT = 3000
|
const NOTIFICATION_TIMEOUT = 3000
|
||||||
|
|
||||||
const createNotificationStore = () => {
|
const createNotificationStore = () => {
|
||||||
const _notifications = writable([])
|
const timeoutIds = new Set()
|
||||||
let block = false
|
const _notifications = writable([], () => {
|
||||||
|
return () => {
|
||||||
|
// clear all the timers
|
||||||
|
timeoutIds.forEach(timeoutId => {
|
||||||
|
clearTimeout(timeoutId)
|
||||||
|
})
|
||||||
|
_notifications.set([])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const send = (message, type = "default") => {
|
const send = (message, type = "default") => {
|
||||||
if (block) {
|
let _id = id()
|
||||||
return
|
|
||||||
}
|
|
||||||
_notifications.update(state => {
|
_notifications.update(state => {
|
||||||
return [...state, { id: generate(), type, message }]
|
return [...state, { id: _id, type, message }]
|
||||||
})
|
})
|
||||||
}
|
const timeoutId = setTimeout(() => {
|
||||||
|
|
||||||
const blockNotifications = (timeout = 1000) => {
|
|
||||||
block = true
|
|
||||||
setTimeout(() => (block = false), timeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
const notifications = derived(_notifications, ($_notifications, set) => {
|
|
||||||
set($_notifications)
|
|
||||||
if ($_notifications.length > 0) {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
_notifications.update(state => {
|
_notifications.update(state => {
|
||||||
state.shift()
|
return state.filter(({ id }) => id !== _id)
|
||||||
return state
|
|
||||||
})
|
})
|
||||||
set($_notifications)
|
|
||||||
}, NOTIFICATION_TIMEOUT)
|
}, NOTIFICATION_TIMEOUT)
|
||||||
return () => {
|
timeoutIds.add(timeoutId)
|
||||||
clearTimeout(timeout)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
const { subscribe } = _notifications
|
||||||
const { subscribe } = notifications
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
|
@ -45,8 +36,16 @@ const createNotificationStore = () => {
|
||||||
warning: msg => send(msg, "warning"),
|
warning: msg => send(msg, "warning"),
|
||||||
info: msg => send(msg, "info"),
|
info: msg => send(msg, "info"),
|
||||||
success: msg => send(msg, "success"),
|
success: msg => send(msg, "success"),
|
||||||
blockNotifications,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function id() {
|
||||||
|
return (
|
||||||
|
"_" +
|
||||||
|
Math.random()
|
||||||
|
.toString(36)
|
||||||
|
.substr(2, 9)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export const notificationStore = createNotificationStore()
|
export const notificationStore = createNotificationStore()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { routeStore, builderStore } from "../store"
|
import { routeStore, builderStore, authStore } from "../store"
|
||||||
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
|
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
|
||||||
import { ActionTypes } from "../constants"
|
import { ActionTypes } from "../constants"
|
||||||
|
|
||||||
|
@ -68,6 +68,15 @@ const refreshDatasourceHandler = async (action, context) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loginHandler = async action => {
|
||||||
|
const { email, password } = action.parameters
|
||||||
|
await authStore.actions.logIn({ email, password })
|
||||||
|
}
|
||||||
|
|
||||||
|
const logoutHandler = async () => {
|
||||||
|
await authStore.actions.logOut()
|
||||||
|
}
|
||||||
|
|
||||||
const handlerMap = {
|
const handlerMap = {
|
||||||
["Save Row"]: saveRowHandler,
|
["Save Row"]: saveRowHandler,
|
||||||
["Delete Row"]: deleteRowHandler,
|
["Delete Row"]: deleteRowHandler,
|
||||||
|
@ -76,6 +85,8 @@ const handlerMap = {
|
||||||
["Trigger Automation"]: triggerAutomationHandler,
|
["Trigger Automation"]: triggerAutomationHandler,
|
||||||
["Validate Form"]: validateFormHandler,
|
["Validate Form"]: validateFormHandler,
|
||||||
["Refresh Datasource"]: refreshDatasourceHandler,
|
["Refresh Datasource"]: refreshDatasourceHandler,
|
||||||
|
["Log In"]: loginHandler,
|
||||||
|
["Log Out"]: logoutHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { fade, blur, scale, fly } from "svelte/transition"
|
||||||
|
|
||||||
|
// Default options
|
||||||
|
const transitions = new Map([
|
||||||
|
["fade", { tn: fade, opt: {} }],
|
||||||
|
["blur", { tn: blur, opt: {} }],
|
||||||
|
// This one seems to not result in any effect
|
||||||
|
// ["slide", { tn: slide, opt: {} }],
|
||||||
|
["scale", { tn: scale, opt: {} }],
|
||||||
|
["fly", { tn: fly, opt: { y: 80 } }],
|
||||||
|
])
|
||||||
|
|
||||||
|
export default function transition(node, { type, options = {} }) {
|
||||||
|
const { tn, opt } = transitions.get(type) || { tn: () => {}, opt: {} }
|
||||||
|
return tn(node, { ...opt, ...options })
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ exports.createHomeScreen = () => ({
|
||||||
active: {},
|
active: {},
|
||||||
selected: {},
|
selected: {},
|
||||||
},
|
},
|
||||||
|
_transition: "fade",
|
||||||
type: "div",
|
type: "div",
|
||||||
_children: [
|
_children: [
|
||||||
{
|
{
|
||||||
|
@ -69,6 +70,7 @@ exports.createLoginScreen = app => ({
|
||||||
active: {},
|
active: {},
|
||||||
selected: {},
|
selected: {},
|
||||||
},
|
},
|
||||||
|
_transition: "fade",
|
||||||
type: "div",
|
type: "div",
|
||||||
_children: [
|
_children: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"icon": "ri-layout-column-line",
|
"icon": "ri-layout-column-line",
|
||||||
"hasChildren": true,
|
"hasChildren": true,
|
||||||
"styleable": true,
|
"styleable": true,
|
||||||
|
"transitionable": true,
|
||||||
"settings": []
|
"settings": []
|
||||||
},
|
},
|
||||||
"datagrid": {
|
"datagrid": {
|
||||||
|
@ -272,6 +273,63 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"backgroundimage": {
|
||||||
|
"name": "Background Image",
|
||||||
|
"description": "A background image",
|
||||||
|
"icon": "ri-image-line",
|
||||||
|
"styleable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "URL",
|
||||||
|
"key": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "Position",
|
||||||
|
"key": "position",
|
||||||
|
"defaultValue": "center center",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"label": "Center Top",
|
||||||
|
"value": "center top"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Center",
|
||||||
|
"value": "center center"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Center Bottom",
|
||||||
|
"value": "center bottom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Left Top",
|
||||||
|
"value": "left top"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Left Center",
|
||||||
|
"value": "left center"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Left Bottom",
|
||||||
|
"value": "left bottom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Right Top",
|
||||||
|
"value": "right top"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Right Center",
|
||||||
|
"value": "right center"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Right Bottom",
|
||||||
|
"value": "right bottom"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"icon": {
|
"icon": {
|
||||||
"name": "Icon",
|
"name": "Icon",
|
||||||
"description": "A basic component for displaying icons",
|
"description": "A basic component for displaying icons",
|
||||||
|
@ -372,6 +430,11 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"label": "New Tab",
|
"label": "New Tab",
|
||||||
"key": "openInNewTab"
|
"key": "openInNewTab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "External",
|
||||||
|
"key": "external"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1211,6 +1274,34 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"passwordfield": {
|
||||||
|
"name": "Password Field",
|
||||||
|
"icon": "ri-lock-password-line",
|
||||||
|
"styleable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "field/string",
|
||||||
|
"label": "Field",
|
||||||
|
"key": "field"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Label",
|
||||||
|
"key": "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Placeholder",
|
||||||
|
"key": "placeholder"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Disabled",
|
||||||
|
"key": "disabled",
|
||||||
|
"defaultValue": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"optionsfield": {
|
"optionsfield": {
|
||||||
"name": "Options Picker",
|
"name": "Options Picker",
|
||||||
"icon": "ri-file-list-line",
|
"icon": "ri-file-list-line",
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
|
const { styleable } = getContext("sdk")
|
||||||
|
const component = getContext("component")
|
||||||
|
|
||||||
|
export let url
|
||||||
|
export let position
|
||||||
|
|
||||||
|
let style = ""
|
||||||
|
$: {
|
||||||
|
if (url) {
|
||||||
|
style += `background-image: url("${url}");`
|
||||||
|
}
|
||||||
|
if (position) {
|
||||||
|
style += `background-position: ${position};`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="outer" use:styleable={$component.styles}>
|
||||||
|
<div class="inner" {style} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.outer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,62 +1,62 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
const { styleable } = getContext("sdk")
|
const { styleable, transition } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
|
||||||
export let type = "div"
|
export let type = "div"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if type === 'div'}
|
{#if type === 'div'}
|
||||||
<div use:styleable={$component.styles}>
|
<div in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
{:else if type === 'header'}
|
{:else if type === 'header'}
|
||||||
<header use:styleable={$component.styles}>
|
<header in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</header>
|
</header>
|
||||||
{:else if type === 'main'}
|
{:else if type === 'main'}
|
||||||
<main use:styleable={$component.styles}>
|
<main in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
{:else if type === 'footer'}
|
{:else if type === 'footer'}
|
||||||
<footer use:styleable={$component.styles}>
|
<footer in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</footer>
|
</footer>
|
||||||
{:else if type === 'aside'}
|
{:else if type === 'aside'}
|
||||||
<aside use:styleable={$component.styles}>
|
<aside in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</aside>
|
</aside>
|
||||||
{:else if type === 'summary'}
|
{:else if type === 'summary'}
|
||||||
<summary use:styleable={$component.styles}>
|
<summary in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</summary>
|
</summary>
|
||||||
{:else if type === 'details'}
|
{:else if type === 'details'}
|
||||||
<details use:styleable={$component.styles}>
|
<details in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</details>
|
</details>
|
||||||
{:else if type === 'article'}
|
{:else if type === 'article'}
|
||||||
<article use:styleable={$component.styles}>
|
<article in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</article>
|
</article>
|
||||||
{:else if type === 'nav'}
|
{:else if type === 'nav'}
|
||||||
<nav use:styleable={$component.styles}>
|
<nav in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</nav>
|
</nav>
|
||||||
{:else if type === 'mark'}
|
{:else if type === 'mark'}
|
||||||
<mark use:styleable={$component.styles}>
|
<mark in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</mark>
|
</mark>
|
||||||
{:else if type === 'figure'}
|
{:else if type === 'figure'}
|
||||||
<figure use:styleable={$component.styles}>
|
<figure in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</figure>
|
</figure>
|
||||||
{:else if type === 'figcaption'}
|
{:else if type === 'figcaption'}
|
||||||
<figcaption use:styleable={$component.styles}>
|
<figcaption in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</figcaption>
|
</figcaption>
|
||||||
{:else if type === 'paragraph'}
|
{:else if type === 'paragraph'}
|
||||||
<p use:styleable={$component.styles}>
|
<p in:transition={{type: $component.transition}} use:styleable={$component.styles}>
|
||||||
<slot />
|
<slot />
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -7,11 +7,19 @@
|
||||||
export let url = ""
|
export let url = ""
|
||||||
export let text = ""
|
export let text = ""
|
||||||
export let openInNewTab = false
|
export let openInNewTab = false
|
||||||
|
export let external = false
|
||||||
|
|
||||||
$: target = openInNewTab ? "_blank" : "_self"
|
$: target = openInNewTab ? "_blank" : "_self"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a href={url || '/'} use:linkable {target} use:styleable={$component.styles}>
|
{#if external}
|
||||||
|
<a href={url || '/'} {target} use:styleable={$component.styles}>
|
||||||
{text}
|
{text}
|
||||||
<slot />
|
<slot />
|
||||||
</a>
|
</a>
|
||||||
|
{:else}
|
||||||
|
<a href={url || '/'} use:linkable {target} use:styleable={$component.styles}>
|
||||||
|
{text}
|
||||||
|
<slot />
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
import StringField from "./StringField.svelte"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<StringField {...$$props} type="password" />
|
|
@ -8,3 +8,4 @@ export { default as longformfield } from "./LongFormField.svelte"
|
||||||
export { default as datetimefield } from "./DateTimeField.svelte"
|
export { default as datetimefield } from "./DateTimeField.svelte"
|
||||||
export { default as attachmentfield } from "./AttachmentField.svelte"
|
export { default as attachmentfield } from "./AttachmentField.svelte"
|
||||||
export { default as relationshipfield } from "./RelationshipField.svelte"
|
export { default as relationshipfield } from "./RelationshipField.svelte"
|
||||||
|
export { default as passwordfield } from "./PasswordField.svelte"
|
||||||
|
|
|
@ -31,5 +31,6 @@ export { default as cardhorizontal } from "./CardHorizontal.svelte"
|
||||||
export { default as cardstat } from "./CardStat.svelte"
|
export { default as cardstat } from "./CardStat.svelte"
|
||||||
export { default as icon } from "./Icon.svelte"
|
export { default as icon } from "./Icon.svelte"
|
||||||
export { default as search } from "./Search.svelte"
|
export { default as search } from "./Search.svelte"
|
||||||
|
export { default as backgroundimage } from "./BackgroundImage.svelte"
|
||||||
export * from "./charts"
|
export * from "./charts"
|
||||||
export * from "./forms"
|
export * from "./forms"
|
||||||
|
|
Loading…
Reference in New Issue