Merge branch 'develop' of github.com:Budibase/budibase into default-field-values
This commit is contained in:
commit
d98fcb33b8
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
name: Feature Request
|
||||||
|
about: Request a new budibase feature or enhancement
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the feature request**
|
||||||
|
A clear and concise description of what the feature request.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
|
@ -57,7 +57,7 @@
|
||||||
|
|
||||||
- **Open source and extensible.** Budibase is open-source - licensed as GPL v3. This should fill you with confidence that Budibase will always be around. You can also code against Budibase or fork it and make changes as you please, providing a developer-friendly experience.
|
- **Open source and extensible.** Budibase is open-source - licensed as GPL v3. This should fill you with confidence that Budibase will always be around. You can also code against Budibase or fork it and make changes as you please, providing a developer-friendly experience.
|
||||||
|
|
||||||
- **Load data or start from scratch.** Budibase pulls in data from multiple sources, including MongoDB, CouchDB, PostgreSQL, mySQL, Airtable, S3, DyanmoDB, or a REST API. And unlike other platforms, with Budibase you can start from scratch and create business apps with no data sources. [Request new data sources](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
|
- **Load data or start from scratch.** Budibase pulls in data from multiple sources, including MongoDB, CouchDB, PostgreSQL, MySQL, Airtable, S3, DynamoDB, or a REST API. And unlike other platforms, with Budibase you can start from scratch and create business apps with no data sources. [Request new data sources](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
|
||||||
|
|
||||||
- **Design and build apps with powerful pre-made components.** Budibase comes out of the box with beautifully designed, powerful components which you can use like building blocks to build your UI. We also expose a lot of your favourite CSS styling options so you can go that extra creative mile. [Request new component](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
|
- **Design and build apps with powerful pre-made components.** Budibase comes out of the box with beautifully designed, powerful components which you can use like building blocks to build your UI. We also expose a lot of your favourite CSS styling options so you can go that extra creative mile. [Request new component](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/auth",
|
"name": "@budibase/auth",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"description": "Authentication middlewares for budibase builder and apps",
|
"description": "Authentication middlewares for budibase builder and apps",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
|
|
|
@ -66,6 +66,7 @@ module.exports = (noAuthPatterns = [], opts) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
|
console.error("Auth Error", error)
|
||||||
// remove the cookie as the user does not exist anymore
|
// remove the cookie as the user does not exist anymore
|
||||||
clearCookie(ctx, Cookies.Auth)
|
clearCookie(ctx, Cookies.Auth)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,7 +6,6 @@ const { authError } = require("./utils")
|
||||||
const { newid } = require("../../hashing")
|
const { newid } = require("../../hashing")
|
||||||
const { createASession } = require("../../security/sessions")
|
const { createASession } = require("../../security/sessions")
|
||||||
const { getGlobalUserByEmail } = require("../../utils")
|
const { getGlobalUserByEmail } = require("../../utils")
|
||||||
const fetch = require("node-fetch")
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common authentication logic for third parties. e.g. OAuth, OIDC.
|
* Common authentication logic for third parties. e.g. OAuth, OIDC.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/bbui",
|
"name": "@budibase/bbui",
|
||||||
"description": "A UI solution used in the different Budibase projects.",
|
"description": "A UI solution used in the different Budibase projects.",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"svelte": "src/index.js",
|
"svelte": "src/index.js",
|
||||||
"module": "dist/bbui.es.js",
|
"module": "dist/bbui.es.js",
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
>
|
>
|
||||||
<div class="modal-wrapper" on:mousedown|self={cancel}>
|
<div class="modal-wrapper" on:mousedown|self={cancel}>
|
||||||
<div class="modal-inner-wrapper" on:mousedown|self={cancel}>
|
<div class="modal-inner-wrapper" on:mousedown|self={cancel}>
|
||||||
|
<slot name="outside" />
|
||||||
<div
|
<div
|
||||||
use:focusFirstInput
|
use:focusFirstInput
|
||||||
class="spectrum-Modal is-open"
|
class="spectrum-Modal is-open"
|
||||||
|
@ -93,6 +94,7 @@
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
background: rgba(0, 0, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-wrapper {
|
.modal-wrapper {
|
||||||
|
@ -112,6 +114,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
width: 0;
|
width: 0;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spectrum-Modal {
|
.spectrum-Modal {
|
||||||
|
@ -122,6 +125,7 @@
|
||||||
--spectrum-dialog-confirm-border-radius: var(
|
--spectrum-dialog-confirm-border-radius: var(
|
||||||
--spectrum-global-dimension-size-100
|
--spectrum-global-dimension-size-100
|
||||||
);
|
);
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
:global(.spectrum--lightest .spectrum-Modal.inline) {
|
:global(.spectrum--lightest .spectrum-Modal.inline) {
|
||||||
border: var(--border-light);
|
border: var(--border-light);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
export let showCloseIcon = true
|
export let showCloseIcon = true
|
||||||
export let onConfirm = undefined
|
export let onConfirm = undefined
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
export let showDivider = true
|
||||||
|
|
||||||
const { hide, cancel } = getContext(Context.Modal)
|
const { hide, cancel } = getContext(Context.Modal)
|
||||||
let loading = false
|
let loading = false
|
||||||
|
@ -41,11 +42,17 @@
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
>
|
>
|
||||||
<div class="spectrum-Dialog-grid">
|
<div class="spectrum-Dialog-grid">
|
||||||
<h1 class="spectrum-Dialog-heading spectrum-Dialog-heading--noHeader">
|
{#if title}
|
||||||
{title}
|
<h1
|
||||||
</h1>
|
class="spectrum-Dialog-heading spectrum-Dialog-heading--noHeader"
|
||||||
|
class:noDivider={!showDivider}
|
||||||
<Divider size="M" />
|
>
|
||||||
|
{title}
|
||||||
|
</h1>
|
||||||
|
{#if showDivider}
|
||||||
|
<Divider size="M" />
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
<!-- TODO: Remove content-grid class once Layout components are in bbui -->
|
<!-- TODO: Remove content-grid class once Layout components are in bbui -->
|
||||||
<section class="spectrum-Dialog-content content-grid">
|
<section class="spectrum-Dialog-content content-grid">
|
||||||
<slot />
|
<slot />
|
||||||
|
@ -72,8 +79,8 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if showCloseIcon}
|
{#if showCloseIcon}
|
||||||
<div class="close-icon" on:click={hide}>
|
<div class="close-icon">
|
||||||
<Icon hoverable name="Close" />
|
<Icon hoverable name="Close" on:click={cancel} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,6 +103,9 @@
|
||||||
.spectrum-Dialog-heading {
|
.spectrum-Dialog-heading {
|
||||||
font-family: var(--font-sans);
|
font-family: var(--font-sans);
|
||||||
}
|
}
|
||||||
|
.spectrum-Dialog-heading.noDivider {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.spectrum-Dialog-buttonGroup {
|
.spectrum-Dialog-buttonGroup {
|
||||||
gap: var(--spectrum-global-dimension-static-size-200);
|
gap: var(--spectrum-global-dimension-static-size-200);
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<script>
|
||||||
|
export let type = "info"
|
||||||
|
export let icon = "Info"
|
||||||
|
export let message = ""
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="spectrum-Toast spectrum-Toast--{type}">
|
||||||
|
{#if icon}
|
||||||
|
<svg
|
||||||
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
|
||||||
|
focusable="false"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
<div class="spectrum-Toast-body">
|
||||||
|
<div class="spectrum-Toast-content">{message || ""}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -2,30 +2,16 @@
|
||||||
import "@spectrum-css/toast/dist/index-vars.css"
|
import "@spectrum-css/toast/dist/index-vars.css"
|
||||||
import Portal from "svelte-portal"
|
import Portal from "svelte-portal"
|
||||||
import { flip } from "svelte/animate"
|
import { flip } from "svelte/animate"
|
||||||
import { fly } from "svelte/transition"
|
|
||||||
import { notifications } from "../Stores/notifications"
|
import { notifications } from "../Stores/notifications"
|
||||||
|
import Notification from "./Notification.svelte"
|
||||||
|
import { fly } from "svelte/transition"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Portal target=".modal-container">
|
<Portal target=".modal-container">
|
||||||
<div class="notifications">
|
<div class="notifications">
|
||||||
{#each $notifications as { type, icon, message, id } (id)}
|
{#each $notifications as { type, icon, message, id } (id)}
|
||||||
<div
|
<div animate:flip transition:fly={{ y: -30 }}>
|
||||||
animate:flip
|
<Notification {type} {icon} {message} />
|
||||||
transition:fly={{ y: -30 }}
|
|
||||||
class="spectrum-Toast spectrum-Toast--{type} notification-offset"
|
|
||||||
>
|
|
||||||
{#if icon}
|
|
||||||
<svg
|
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
|
|
||||||
focusable="false"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
|
||||||
</svg>
|
|
||||||
{/if}
|
|
||||||
<div class="spectrum-Toast-body">
|
|
||||||
<div class="spectrum-Toast-content">{message}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,7 +20,7 @@
|
||||||
<style>
|
<style>
|
||||||
.notifications {
|
.notifications {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 10px;
|
top: 20px;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
@ -45,8 +31,6 @@
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
gap: 10px;
|
||||||
.notification-offset {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -38,6 +38,7 @@ export { default as MenuItem } from "./Menu/Item.svelte"
|
||||||
export { default as Modal } from "./Modal/Modal.svelte"
|
export { default as Modal } from "./Modal/Modal.svelte"
|
||||||
export { default as ModalContent } from "./Modal/ModalContent.svelte"
|
export { default as ModalContent } from "./Modal/ModalContent.svelte"
|
||||||
export { default as NotificationDisplay } from "./Notification/NotificationDisplay.svelte"
|
export { default as NotificationDisplay } from "./Notification/NotificationDisplay.svelte"
|
||||||
|
export { default as Notification } from "./Notification/Notification.svelte"
|
||||||
export { default as SideNavigation } from "./SideNavigation/Navigation.svelte"
|
export { default as SideNavigation } from "./SideNavigation/Navigation.svelte"
|
||||||
export { default as SideNavigationItem } from "./SideNavigation/Item.svelte"
|
export { default as SideNavigationItem } from "./SideNavigation/Item.svelte"
|
||||||
export { default as DatePicker } from "./Form/DatePicker.svelte"
|
export { default as DatePicker } from "./Form/DatePicker.svelte"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -65,10 +65,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^0.9.87-alpha.7",
|
"@budibase/bbui": "^0.9.96",
|
||||||
"@budibase/client": "^0.9.87-alpha.7",
|
"@budibase/client": "^0.9.96",
|
||||||
"@budibase/colorpicker": "1.1.2",
|
"@budibase/colorpicker": "1.1.2",
|
||||||
"@budibase/string-templates": "^0.9.87-alpha.7",
|
"@budibase/string-templates": "^0.9.96",
|
||||||
"@sentry/browser": "5.19.1",
|
"@sentry/browser": "5.19.1",
|
||||||
"@spectrum-css/page": "^3.0.1",
|
"@spectrum-css/page": "^3.0.1",
|
||||||
"@spectrum-css/vars": "^3.0.1",
|
"@spectrum-css/vars": "^3.0.1",
|
||||||
|
|
|
@ -70,7 +70,7 @@ export const getFrontendStore = () => {
|
||||||
url: application.url,
|
url: application.url,
|
||||||
layouts,
|
layouts,
|
||||||
screens,
|
screens,
|
||||||
theme: application.theme,
|
theme: application.theme || "spectrum--light",
|
||||||
hasAppPackage: true,
|
hasAppPackage: true,
|
||||||
appInstance: application.instance,
|
appInstance: application.instance,
|
||||||
clientLibPath,
|
clientLibPath,
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let bindingDrawer
|
let bindingDrawer
|
||||||
$: tempValue = Array.isArray(value) ? value : []
|
|
||||||
$: readableValue = runtimeToReadableBinding(bindings, value)
|
$: readableValue = runtimeToReadableBinding(bindings, value)
|
||||||
|
$: tempValue = readableValue
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onChange(tempValue)
|
onChange(tempValue)
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
slot="body"
|
slot="body"
|
||||||
value={readableValue}
|
value={readableValue}
|
||||||
close={handleClose}
|
close={handleClose}
|
||||||
on:update={event => (tempValue = event.detail)}
|
on:change={event => (tempValue = event.detail)}
|
||||||
bindableProperties={bindings}
|
bindableProperties={bindings}
|
||||||
/>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Select
|
<Select
|
||||||
value={$store.theme || "spectrum--light"}
|
value={$store.theme}
|
||||||
options={themeOptions}
|
options={themeOptions}
|
||||||
placeholder={null}
|
placeholder={null}
|
||||||
on:change={e => store.actions.theme.save(e.detail)}
|
on:change={e => store.actions.theme.save(e.detail)}
|
||||||
|
|
|
@ -47,6 +47,18 @@ export default `
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse received message
|
||||||
|
// If parsing fails, just ignore and wait for the next message
|
||||||
|
let parsed
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(event.data)
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
if (!parsed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Extract data from message
|
// Extract data from message
|
||||||
const {
|
const {
|
||||||
selectedComponentId,
|
selectedComponentId,
|
||||||
|
@ -55,7 +67,7 @@ export default `
|
||||||
previewType,
|
previewType,
|
||||||
appId,
|
appId,
|
||||||
theme
|
theme
|
||||||
} = JSON.parse(event.data)
|
} = parsed
|
||||||
|
|
||||||
// Set some flags so the app knows we're in the builder
|
// Set some flags so the app knows we're in the builder
|
||||||
window["##BUDIBASE_IN_BUILDER##"] = true
|
window["##BUDIBASE_IN_BUILDER##"] = true
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
export let componentDefinition
|
export let componentDefinition
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
export let assetInstance
|
export let assetInstance
|
||||||
|
export let bindings
|
||||||
|
|
||||||
const layoutDefinition = []
|
const layoutDefinition = []
|
||||||
const screenDefinition = [
|
const screenDefinition = [
|
||||||
|
@ -65,6 +66,7 @@
|
||||||
options: setting.options,
|
options: setting.options,
|
||||||
placeholder: setting.placeholder,
|
placeholder: setting.placeholder,
|
||||||
}}
|
}}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
import ConditionalUIDrawer from "./PropertyControls/ConditionalUIDrawer.svelte"
|
import ConditionalUIDrawer from "./PropertyControls/ConditionalUIDrawer.svelte"
|
||||||
|
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
export let bindings
|
||||||
|
|
||||||
let tempValue
|
let tempValue
|
||||||
let drawer
|
let drawer
|
||||||
|
@ -32,5 +33,5 @@
|
||||||
Show, hide and update components in response to conditions being met.
|
Show, hide and update components in response to conditions being met.
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<Button cta slot="buttons" on:click={() => save()}>Save</Button>
|
<Button cta slot="buttons" on:click={() => save()}>Save</Button>
|
||||||
<ConditionalUIDrawer slot="body" bind:conditions={tempValue} />
|
<ConditionalUIDrawer slot="body" bind:conditions={tempValue} {bindings} />
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
export let componentDefinition
|
export let componentDefinition
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
export let bindings
|
||||||
|
|
||||||
const getStyles = def => {
|
const getStyles = def => {
|
||||||
if (!def?.styles?.length) {
|
if (!def?.styles?.length) {
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
columns={style.columns}
|
columns={style.columns}
|
||||||
properties={style.settings}
|
properties={style.settings}
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,27 +1,45 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, selectedComponent } from "builderStore"
|
import { store, selectedComponent, currentAsset } from "builderStore"
|
||||||
import { Tabs, Tab } from "@budibase/bbui"
|
import { Tabs, Tab } from "@budibase/bbui"
|
||||||
import ScreenSettingsSection from "./ScreenSettingsSection.svelte"
|
import ScreenSettingsSection from "./ScreenSettingsSection.svelte"
|
||||||
import ComponentSettingsSection from "./ComponentSettingsSection.svelte"
|
import ComponentSettingsSection from "./ComponentSettingsSection.svelte"
|
||||||
import DesignSection from "./DesignSection.svelte"
|
import DesignSection from "./DesignSection.svelte"
|
||||||
import CustomStylesSection from "./CustomStylesSection.svelte"
|
import CustomStylesSection from "./CustomStylesSection.svelte"
|
||||||
import ConditionalUISection from "./ConditionalUISection.svelte"
|
import ConditionalUISection from "./ConditionalUISection.svelte"
|
||||||
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
|
|
||||||
$: componentInstance = $selectedComponent
|
$: componentInstance = $selectedComponent
|
||||||
$: componentDefinition = store.actions.components.getDefinition(
|
$: componentDefinition = store.actions.components.getDefinition(
|
||||||
$selectedComponent?._component
|
$selectedComponent?._component
|
||||||
)
|
)
|
||||||
|
$: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Tabs selected="Settings" noPadding>
|
<Tabs selected="Settings" noPadding>
|
||||||
<Tab title="Settings">
|
<Tab title="Settings">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{#key componentInstance?._id}
|
{#key componentInstance?._id}
|
||||||
<ScreenSettingsSection {componentInstance} {componentDefinition} />
|
<ScreenSettingsSection
|
||||||
<ComponentSettingsSection {componentInstance} {componentDefinition} />
|
{componentInstance}
|
||||||
<DesignSection {componentInstance} {componentDefinition} />
|
{componentDefinition}
|
||||||
<CustomStylesSection {componentInstance} {componentDefinition} />
|
{bindings}
|
||||||
<ConditionalUISection {componentInstance} {componentDefinition} />
|
/>
|
||||||
|
<ComponentSettingsSection
|
||||||
|
{componentInstance}
|
||||||
|
{componentDefinition}
|
||||||
|
{bindings}
|
||||||
|
/>
|
||||||
|
<DesignSection {componentInstance} {componentDefinition} {bindings} />
|
||||||
|
<CustomStylesSection
|
||||||
|
{componentInstance}
|
||||||
|
{componentDefinition}
|
||||||
|
{bindings}
|
||||||
|
/>
|
||||||
|
<ConditionalUISection
|
||||||
|
{componentInstance}
|
||||||
|
{componentDefinition}
|
||||||
|
{bindings}
|
||||||
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
|
@ -13,12 +13,12 @@
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
|
import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
import { selectedComponent, store } from "builderStore"
|
||||||
import { currentAsset, selectedComponent, store } from "builderStore"
|
|
||||||
import { getComponentForSettingType } from "./componentSettings"
|
import { getComponentForSettingType } from "./componentSettings"
|
||||||
import PropertyControl from "./PropertyControl.svelte"
|
import PropertyControl from "./PropertyControl.svelte"
|
||||||
|
|
||||||
export let conditions = []
|
export let conditions = []
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
const flipDurationMs = 150
|
const flipDurationMs = 150
|
||||||
const actionOptions = [
|
const actionOptions = [
|
||||||
|
@ -64,10 +64,6 @@
|
||||||
value: setting.key,
|
value: setting.key,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
$: bindableProperties = getBindableProperties(
|
|
||||||
$currentAsset,
|
|
||||||
$store.selectedComponentId
|
|
||||||
)
|
|
||||||
$: conditions.forEach(link => {
|
$: conditions.forEach(link => {
|
||||||
if (!link.id) {
|
if (!link.id) {
|
||||||
link.id = generate()
|
link.id = generate()
|
||||||
|
@ -194,6 +190,7 @@
|
||||||
placeholder: getSettingDefinition(condition.setting)
|
placeholder: getSettingDefinition(condition.setting)
|
||||||
.placeholder,
|
.placeholder,
|
||||||
}}
|
}}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<Select disabled placeholder=" " />
|
<Select disabled placeholder=" " />
|
||||||
|
@ -201,7 +198,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<div>IF</div>
|
<div>IF</div>
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
bindings={bindableProperties}
|
{bindings}
|
||||||
placeholder="Value"
|
placeholder="Value"
|
||||||
value={condition.newValue}
|
value={condition.newValue}
|
||||||
on:change={e => (condition.newValue = e.detail)}
|
on:change={e => (condition.newValue = e.detail)}
|
||||||
|
@ -222,7 +219,7 @@
|
||||||
{#if ["string", "number"].includes(condition.valueType)}
|
{#if ["string", "number"].includes(condition.valueType)}
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
disabled={condition.noValue}
|
disabled={condition.noValue}
|
||||||
bindings={bindableProperties}
|
{bindings}
|
||||||
placeholder="Value"
|
placeholder="Value"
|
||||||
value={condition.referenceValue}
|
value={condition.referenceValue}
|
||||||
on:change={e => (condition.referenceValue = e.detail)}
|
on:change={e => (condition.referenceValue = e.detail)}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { getDataProviderComponents } from "builderStore/dataBinding"
|
||||||
getBindableProperties,
|
|
||||||
getDataProviderComponents,
|
|
||||||
} from "builderStore/dataBinding"
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Popover,
|
Popover,
|
||||||
|
@ -31,6 +28,7 @@
|
||||||
export let value = {}
|
export let value = {}
|
||||||
export let otherSources
|
export let otherSources
|
||||||
export let showAllQueries
|
export let showAllQueries
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
$: text = value?.label ?? "Choose an option"
|
$: text = value?.label ?? "Choose an option"
|
||||||
$: tables = $tablesStore.list.map(m => ({
|
$: tables = $tablesStore.list.map(m => ({
|
||||||
|
@ -60,10 +58,6 @@
|
||||||
parameters: query.parameters,
|
parameters: query.parameters,
|
||||||
type: "query",
|
type: "query",
|
||||||
}))
|
}))
|
||||||
$: bindableProperties = getBindableProperties(
|
|
||||||
$currentAsset,
|
|
||||||
$store.selectedComponentId
|
|
||||||
)
|
|
||||||
$: dataProviders = getDataProviderComponents(
|
$: dataProviders = getDataProviderComponents(
|
||||||
$currentAsset,
|
$currentAsset,
|
||||||
$store.selectedComponentId
|
$store.selectedComponentId
|
||||||
|
@ -75,13 +69,13 @@
|
||||||
type: "provider",
|
type: "provider",
|
||||||
schema: provider.schema,
|
schema: provider.schema,
|
||||||
}))
|
}))
|
||||||
$: queryBindableProperties = bindableProperties.map(property => ({
|
$: queryBindableProperties = bindings.map(property => ({
|
||||||
...property,
|
...property,
|
||||||
category: property.type === "instance" ? "Component" : "Table",
|
category: property.type === "instance" ? "Component" : "Table",
|
||||||
label: property.readableBinding,
|
label: property.readableBinding,
|
||||||
path: property.readableBinding,
|
path: property.readableBinding,
|
||||||
}))
|
}))
|
||||||
$: links = bindableProperties
|
$: links = bindings
|
||||||
.filter(x => x.fieldSchema?.type === "link")
|
.filter(x => x.fieldSchema?.type === "link")
|
||||||
.map(property => {
|
.map(property => {
|
||||||
return {
|
return {
|
||||||
|
@ -138,7 +132,7 @@
|
||||||
bind:customParams={value.queryParams}
|
bind:customParams={value.queryParams}
|
||||||
parameters={queries.find(query => query._id === value._id)
|
parameters={queries.find(query => query._id === value._id)
|
||||||
.parameters}
|
.parameters}
|
||||||
bindings={queryBindableProperties}
|
{bindings}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<IntegrationQueryEditor
|
<IntegrationQueryEditor
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
|
|
||||||
const flipDurationMs = 150
|
const flipDurationMs = 150
|
||||||
|
|
||||||
const EVENT_TYPE_KEY = "##eventHandlerType"
|
const EVENT_TYPE_KEY = "##eventHandlerType"
|
||||||
|
|
||||||
export let actions
|
export let actions
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
// dndzone needs an id on the array items, so this adds some temporary ones.
|
// dndzone needs an id on the array items, so this adds some temporary ones.
|
||||||
$: {
|
$: {
|
||||||
|
@ -121,6 +121,7 @@
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={selectedActionComponent}
|
this={selectedActionComponent}
|
||||||
parameters={selectedAction.parameters}
|
parameters={selectedAction.parameters}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
export let value = []
|
export let value = []
|
||||||
export let name
|
export let name
|
||||||
|
export let bindings
|
||||||
|
|
||||||
let drawer
|
let drawer
|
||||||
|
|
||||||
|
@ -57,5 +58,5 @@
|
||||||
Define what actions to run.
|
Define what actions to run.
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<Button cta slot="buttons" on:click={saveEventData}>Save</Button>
|
<Button cta slot="buttons" on:click={saveEventData}>Save</Button>
|
||||||
<EventEditor slot="body" bind:actions={value} eventType={name} />
|
<EventEditor slot="body" bind:actions={value} eventType={name} {bindings} />
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script>
|
||||||
|
import { Body } from "@budibase/bbui"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="root">
|
||||||
|
<Body size="S">This action doesn't require any additional settings.</Body>
|
||||||
|
<Body size="S">
|
||||||
|
This action won't do anything if there isn't a screen modal open.
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.root {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,14 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select, Label, Checkbox, Input } from "@budibase/bbui"
|
import { Select, Label, Checkbox, Input } from "@budibase/bbui"
|
||||||
import { store, currentAsset } from "builderStore"
|
|
||||||
import { tables } from "stores/backend"
|
import { tables } from "stores/backend"
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
|
||||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
$: tableOptions = $tables.list || []
|
$: tableOptions = $tables.list || []
|
||||||
$: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select, Layout, Input, Checkbox } from "@budibase/bbui"
|
import { Select, Layout, Input, Checkbox } from "@budibase/bbui"
|
||||||
import { store, currentAsset } from "builderStore"
|
|
||||||
import { datasources, integrations, queries } from "stores/backend"
|
import { datasources, integrations, queries } from "stores/backend"
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
|
||||||
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
|
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
|
||||||
import IntegrationQueryEditor from "components/integration/index.svelte"
|
import IntegrationQueryEditor from "components/integration/index.svelte"
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
$: query = $queries.list.find(q => q._id === parameters.queryId)
|
$: query = $queries.list.find(q => q._id === parameters.queryId)
|
||||||
$: datasource = $datasources.list.find(
|
$: datasource = $datasources.list.find(
|
||||||
ds => ds._id === parameters.datasourceId
|
ds => ds._id === parameters.datasourceId
|
||||||
)
|
)
|
||||||
$: bindableProperties = getBindableProperties(
|
|
||||||
$currentAsset,
|
|
||||||
$store.selectedComponentId
|
|
||||||
)
|
|
||||||
|
|
||||||
function fetchQueryDefinition(query) {
|
function fetchQueryDefinition(query) {
|
||||||
const source = $datasources.list.find(
|
const source = $datasources.list.find(
|
||||||
|
@ -61,7 +56,7 @@
|
||||||
<ParameterBuilder
|
<ParameterBuilder
|
||||||
bind:customParams={parameters.queryParams}
|
bind:customParams={parameters.queryParams}
|
||||||
parameters={query.parameters}
|
parameters={query.parameters}
|
||||||
bindings={bindableProperties}
|
{bindings}
|
||||||
/>
|
/>
|
||||||
<IntegrationQueryEditor
|
<IntegrationQueryEditor
|
||||||
height={200}
|
height={200}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
import { Label } from "@budibase/bbui"
|
import { Label } from "@budibase/bbui"
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
|
||||||
import { currentAsset, store } from "builderStore"
|
|
||||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
|
export let bindings = []
|
||||||
$: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
@ -18,19 +15,17 @@
|
||||||
on:change={value => (parameters.url = value.detail)}
|
on:change={value => (parameters.url = value.detail)}
|
||||||
{bindings}
|
{bindings}
|
||||||
/>
|
/>
|
||||||
|
<div />
|
||||||
|
<Checkbox text="Open screen in modal" bind:value={parameters.peek} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.root {
|
.root {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: row;
|
align-items: center;
|
||||||
align-items: baseline;
|
gap: var(--spacing-m);
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root :global(> div) {
|
|
||||||
flex: 1;
|
|
||||||
margin-left: var(--spacing-l);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Label, ActionButton, Button, Select, Input } from "@budibase/bbui"
|
import { Label, ActionButton, Button, Select, Input } from "@budibase/bbui"
|
||||||
import { store, currentAsset } from "builderStore"
|
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
|
|
||||||
|
@ -11,13 +9,10 @@
|
||||||
export let schemaFields
|
export let schemaFields
|
||||||
export let fieldLabel = "Column"
|
export let fieldLabel = "Column"
|
||||||
export let valueLabel = "Value"
|
export let valueLabel = "Value"
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
let fields = Object.entries(parameterFields || {})
|
let fields = Object.entries(parameterFields || {})
|
||||||
$: onChange(fields)
|
$: onChange(fields)
|
||||||
$: bindableProperties = getBindableProperties(
|
|
||||||
$currentAsset,
|
|
||||||
$store.selectedComponentId
|
|
||||||
)
|
|
||||||
|
|
||||||
const addField = () => {
|
const addField = () => {
|
||||||
fields = [...fields.filter(field => field[0]), ["", ""]]
|
fields = [...fields.filter(field => field[0]), ["", ""]]
|
||||||
|
@ -69,7 +64,7 @@
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
title={`Value for "${field[0]}"`}
|
title={`Value for "${field[0]}"`}
|
||||||
value={field[1]}
|
value={field[1]}
|
||||||
bindings={bindableProperties}
|
{bindings}
|
||||||
on:change={event => updateFieldValue(idx, event.detail)}
|
on:change={event => updateFieldValue(idx, event.detail)}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import SaveFields from "./SaveFields.svelte"
|
import SaveFields from "./SaveFields.svelte"
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
$: dataProviderComponents = getDataProviderComponents(
|
$: dataProviderComponents = getDataProviderComponents(
|
||||||
$currentAsset,
|
$currentAsset,
|
||||||
|
@ -70,6 +71,7 @@
|
||||||
parameterFields={parameters.fields}
|
parameterFields={parameters.fields}
|
||||||
{schemaFields}
|
{schemaFields}
|
||||||
on:change={onFieldsChanged}
|
on:change={onFieldsChanged}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
import { automationStore } from "builderStore"
|
import { automationStore } from "builderStore"
|
||||||
import SaveFields from "./SaveFields.svelte"
|
import SaveFields from "./SaveFields.svelte"
|
||||||
|
|
||||||
|
export let parameters = {}
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
const AUTOMATION_STATUS = {
|
const AUTOMATION_STATUS = {
|
||||||
NEW: "new",
|
NEW: "new",
|
||||||
EXISTING: "existing",
|
EXISTING: "existing",
|
||||||
}
|
}
|
||||||
|
|
||||||
export let parameters = {}
|
|
||||||
|
|
||||||
let automationStatus = parameters.automationId
|
let automationStatus = parameters.automationId
|
||||||
? AUTOMATION_STATUS.EXISTING
|
? AUTOMATION_STATUS.EXISTING
|
||||||
: AUTOMATION_STATUS.NEW
|
: AUTOMATION_STATUS.NEW
|
||||||
|
@ -109,6 +110,7 @@
|
||||||
parameterFields={parameters.fields}
|
parameterFields={parameters.fields}
|
||||||
fieldLabel="Field"
|
fieldLabel="Field"
|
||||||
on:change={onFieldsChanged}
|
on:change={onFieldsChanged}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import TriggerAutomation from "./TriggerAutomation.svelte"
|
||||||
import ValidateForm from "./ValidateForm.svelte"
|
import ValidateForm from "./ValidateForm.svelte"
|
||||||
import LogOut from "./LogOut.svelte"
|
import LogOut from "./LogOut.svelte"
|
||||||
import ClearForm from "./ClearForm.svelte"
|
import ClearForm from "./ClearForm.svelte"
|
||||||
|
import CloseScreenModal from "./CloseScreenModal.svelte"
|
||||||
|
|
||||||
// Defines which actions are available to configure in the front end.
|
// Defines which actions are available to configure in the front end.
|
||||||
// Unfortunately the "name" property is used as the identifier so please don't
|
// Unfortunately the "name" property is used as the identifier so please don't
|
||||||
|
@ -47,4 +48,8 @@ export default [
|
||||||
name: "Clear Form",
|
name: "Clear Form",
|
||||||
component: ClearForm,
|
component: ClearForm,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Close Screen Modal",
|
||||||
|
component: CloseScreenModal,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
export let value = []
|
export let value = []
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
let drawer
|
let drawer
|
||||||
let tempValue = value || []
|
let tempValue = value || []
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@
|
||||||
constraints.
|
constraints.
|
||||||
{/if}
|
{/if}
|
||||||
</Body>
|
</Body>
|
||||||
<LuceneFilterBuilder bind:value={tempValue} {schemaFields} />
|
<LuceneFilterBuilder bind:value={tempValue} {schemaFields} {bindings} />
|
||||||
</Layout>
|
</Layout>
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
|
@ -7,20 +7,15 @@
|
||||||
Combobox,
|
Combobox,
|
||||||
Input,
|
Input,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { store, currentAsset } from "builderStore"
|
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
|
||||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
|
import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
|
||||||
|
|
||||||
export let schemaFields
|
export let schemaFields
|
||||||
export let value
|
export let value
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
const BannedTypes = ["link", "attachment"]
|
const BannedTypes = ["link", "attachment"]
|
||||||
$: bindableProperties = getBindableProperties(
|
|
||||||
$currentAsset,
|
|
||||||
$store.selectedComponentId
|
|
||||||
)
|
|
||||||
$: fieldOptions = (schemaFields ?? [])
|
$: fieldOptions = (schemaFields ?? [])
|
||||||
.filter(field => !BannedTypes.includes(field.type))
|
.filter(field => !BannedTypes.includes(field.type))
|
||||||
.map(field => field.name)
|
.map(field => field.name)
|
||||||
|
@ -101,7 +96,7 @@
|
||||||
title={`Value for "${expression.field}"`}
|
title={`Value for "${expression.field}"`}
|
||||||
value={expression.value}
|
value={expression.value}
|
||||||
placeholder="Value"
|
placeholder="Value"
|
||||||
bindings={bindableProperties}
|
{bindings}
|
||||||
on:change={event => (expression.value = event.detail)}
|
on:change={event => (expression.value = event.detail)}
|
||||||
/>
|
/>
|
||||||
{:else if ["string", "longform", "number"].includes(expression.type)}
|
{:else if ["string", "longform", "number"].includes(expression.type)}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Icon, Drawer, Label } from "@budibase/bbui"
|
import { Button, Icon, Drawer, Label } from "@budibase/bbui"
|
||||||
import { store, currentAsset } from "builderStore"
|
|
||||||
import {
|
import {
|
||||||
getBindableProperties,
|
|
||||||
readableToRuntimeBinding,
|
readableToRuntimeBinding,
|
||||||
runtimeToReadableBinding,
|
runtimeToReadableBinding,
|
||||||
} from "builderStore/dataBinding"
|
} from "builderStore/dataBinding"
|
||||||
|
@ -18,18 +16,15 @@
|
||||||
export let value = null
|
export let value = null
|
||||||
export let props = {}
|
export let props = {}
|
||||||
export let onChange = () => {}
|
export let onChange = () => {}
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
let bindingDrawer
|
let bindingDrawer
|
||||||
let anchor
|
let anchor
|
||||||
let valid
|
let valid
|
||||||
|
|
||||||
$: bindableProperties = getBindableProperties(
|
$: safeValue = getSafeValue(value, props.defaultValue, bindings)
|
||||||
$currentAsset,
|
|
||||||
$store.selectedComponentId
|
|
||||||
)
|
|
||||||
$: safeValue = getSafeValue(value, props.defaultValue, bindableProperties)
|
|
||||||
$: tempValue = safeValue
|
$: tempValue = safeValue
|
||||||
$: replaceBindings = val => readableToRuntimeBinding(bindableProperties, val)
|
$: replaceBindings = val => readableToRuntimeBinding(bindings, val)
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
handleChange(tempValue)
|
handleChange(tempValue)
|
||||||
|
@ -61,8 +56,8 @@
|
||||||
|
|
||||||
// The "safe" value is the value with any bindings made readable
|
// The "safe" value is the value with any bindings made readable
|
||||||
// If there is no value set, any default value is used
|
// If there is no value set, any default value is used
|
||||||
const getSafeValue = (value, defaultValue, bindableProperties) => {
|
const getSafeValue = (value, defaultValue, bindings) => {
|
||||||
const enriched = runtimeToReadableBinding(bindableProperties, value)
|
const enriched = runtimeToReadableBinding(bindings, value)
|
||||||
return enriched == null && defaultValue !== undefined
|
return enriched == null && defaultValue !== undefined
|
||||||
? defaultValue
|
? defaultValue
|
||||||
: enriched
|
: enriched
|
||||||
|
@ -83,6 +78,7 @@
|
||||||
updateOnChange={false}
|
updateOnChange={false}
|
||||||
on:change={handleChange}
|
on:change={handleChange}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
{bindings}
|
||||||
name={key}
|
name={key}
|
||||||
text={label}
|
text={label}
|
||||||
{type}
|
{type}
|
||||||
|
@ -108,7 +104,7 @@
|
||||||
bind:valid
|
bind:valid
|
||||||
value={safeValue}
|
value={safeValue}
|
||||||
on:change={e => (tempValue = e.detail)}
|
on:change={e => (tempValue = e.detail)}
|
||||||
{bindableProperties}
|
bindableProperties={bindings}
|
||||||
/>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte"
|
import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte"
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
|
export let bindings
|
||||||
|
|
||||||
$: urlOptions = $store.screens
|
$: urlOptions = $store.screens
|
||||||
.map(screen => screen.routing?.route)
|
.map(screen => screen.routing?.route)
|
||||||
.filter(x => x != null)
|
.filter(x => x != null)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DrawerBindableCombobox {value} on:change options={urlOptions} />
|
<DrawerBindableCombobox {value} {bindings} on:change options={urlOptions} />
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
|
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
export let bindings
|
||||||
|
|
||||||
function setAssetProps(name, value) {
|
function setAssetProps(name, value) {
|
||||||
const selectedAsset = get(currentAsset)
|
const selectedAsset = get(currentAsset)
|
||||||
|
@ -44,6 +45,7 @@
|
||||||
key={def.key}
|
key={def.key}
|
||||||
value={deepGet($currentAsset, def.key)}
|
value={deepGet($currentAsset, def.key)}
|
||||||
onChange={val => setAssetProps(def.key, val)}
|
onChange={val => setAssetProps(def.key, val)}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</DetailSummary>
|
</DetailSummary>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
export let columns
|
export let columns
|
||||||
export let properties
|
export let properties
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
export let bindings = []
|
||||||
|
|
||||||
$: style = componentInstance._styles.normal || {}
|
$: style = componentInstance._styles.normal || {}
|
||||||
$: changed = properties?.some(prop => hasPropChanged(style, prop)) ?? false
|
$: changed = properties?.some(prop => hasPropChanged(style, prop)) ?? false
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
value={style[prop.key]}
|
value={style[prop.key]}
|
||||||
onChange={val => store.actions.components.updateStyle(prop.key, val)}
|
onChange={val => store.actions.components.updateStyle(prop.key, val)}
|
||||||
props={getControlProps(prop)}
|
props={getControlProps(prop)}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -158,10 +158,16 @@
|
||||||
fieldName: fromTable.primary[0],
|
fieldName: fromTable.primary[0],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// the relateFrom.fieldName should remain the same, as it is the foreignKey in the other
|
||||||
|
// table, this is due to the way that budibase represents relationships, the fieldName in a
|
||||||
|
// link column schema is the column linked to (FK in this case). The foreignKey column is
|
||||||
|
// essentially what is linked to in the from table, this is unique to SQL as this isn't a feature
|
||||||
|
// of Budibase internal tables.
|
||||||
|
// Essentially this means the fieldName is what we are linking to in the other table, and the
|
||||||
|
// foreignKey is what is linking out of the current table.
|
||||||
relateFrom = {
|
relateFrom = {
|
||||||
...relateFrom,
|
...relateFrom,
|
||||||
foreignKey: relateFrom.fieldName,
|
foreignKey: fromTable.primary[0],
|
||||||
fieldName: fromTable.primary[0],
|
|
||||||
}
|
}
|
||||||
relateTo = {
|
relateTo = {
|
||||||
...relateTo,
|
...relateTo,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/cli",
|
"name": "@budibase/cli",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/client",
|
"name": "@budibase/client",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"module": "dist/budibase-client.js",
|
"module": "dist/budibase-client.js",
|
||||||
"main": "dist/budibase-client.js",
|
"main": "dist/budibase-client.js",
|
||||||
|
@ -18,9 +18,9 @@
|
||||||
"dev:builder": "rollup -cw"
|
"dev:builder": "rollup -cw"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^0.9.87-alpha.7",
|
"@budibase/bbui": "^0.9.96",
|
||||||
"@budibase/standard-components": "^0.9.87-alpha.7",
|
"@budibase/standard-components": "^0.9.96",
|
||||||
"@budibase/string-templates": "^0.9.87-alpha.7",
|
"@budibase/string-templates": "^0.9.96",
|
||||||
"regexparam": "^1.3.0",
|
"regexparam": "^1.3.0",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
"svelte-spa-router": "^3.0.5"
|
"svelte-spa-router": "^3.0.5"
|
||||||
|
|
|
@ -38,15 +38,15 @@ const makeApiCall = async ({ method, url, body, json = true }) => {
|
||||||
case 200:
|
case 200:
|
||||||
return response.json()
|
return response.json()
|
||||||
case 401:
|
case 401:
|
||||||
notificationStore.danger("Invalid credentials")
|
notificationStore.actions.error("Invalid credentials")
|
||||||
return handleError(`Invalid credentials`)
|
return handleError(`Invalid credentials`)
|
||||||
case 404:
|
case 404:
|
||||||
notificationStore.danger("Not found")
|
notificationStore.actions.warning("Not found")
|
||||||
return handleError(`${url}: Not Found`)
|
return handleError(`${url}: Not Found`)
|
||||||
case 400:
|
case 400:
|
||||||
return handleError(`${url}: Bad Request`)
|
return handleError(`${url}: Bad Request`)
|
||||||
case 403:
|
case 403:
|
||||||
notificationStore.danger(
|
notificationStore.actions.error(
|
||||||
"Your session has expired, or you don't have permission to access that data"
|
"Your session has expired, or you don't have permission to access that data"
|
||||||
)
|
)
|
||||||
return handleError(`${url}: Forbidden`)
|
return handleError(`${url}: Forbidden`)
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const triggerAutomation = async (automationId, fields) => {
|
||||||
body: { fields },
|
body: { fields },
|
||||||
})
|
})
|
||||||
res.error
|
res.error
|
||||||
? notificationStore.danger("An error has occurred")
|
? notificationStore.actions.error("An error has occurred")
|
||||||
: notificationStore.success("Automation triggered")
|
: notificationStore.actions.success("Automation triggered")
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import API from "./api"
|
||||||
export const executeQuery = async ({ queryId, parameters }) => {
|
export const executeQuery = async ({ queryId, parameters }) => {
|
||||||
const query = await API.get({ url: `/api/queries/${queryId}` })
|
const query = await API.get({ url: `/api/queries/${queryId}` })
|
||||||
if (query?.datasourceId == null) {
|
if (query?.datasourceId == null) {
|
||||||
notificationStore.danger("That query couldn't be found")
|
notificationStore.actions.error("That query couldn't be found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const res = await API.post({
|
const res = await API.post({
|
||||||
|
@ -17,9 +17,9 @@ export const executeQuery = async ({ queryId, parameters }) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
notificationStore.danger("An error has occurred")
|
notificationStore.actions.error("An error has occurred")
|
||||||
} else if (!query.readable) {
|
} else if (!query.readable) {
|
||||||
notificationStore.success("Query executed successfully")
|
notificationStore.actions.success("Query executed successfully")
|
||||||
dataSourceStore.actions.invalidateDataSource(query.datasourceId)
|
dataSourceStore.actions.invalidateDataSource(query.datasourceId)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -27,8 +27,8 @@ export const saveRow = async row => {
|
||||||
body: row,
|
body: row,
|
||||||
})
|
})
|
||||||
res.error
|
res.error
|
||||||
? notificationStore.danger("An error has occurred")
|
? notificationStore.actions.error("An error has occurred")
|
||||||
: notificationStore.success("Row saved")
|
: notificationStore.actions.success("Row saved")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
||||||
|
@ -48,8 +48,8 @@ export const updateRow = async row => {
|
||||||
body: row,
|
body: row,
|
||||||
})
|
})
|
||||||
res.error
|
res.error
|
||||||
? notificationStore.danger("An error has occurred")
|
? notificationStore.actions.error("An error has occurred")
|
||||||
: notificationStore.success("Row updated")
|
: notificationStore.actions.success("Row updated")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
||||||
|
@ -72,8 +72,8 @@ export const deleteRow = async ({ tableId, rowId, revId }) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
res.error
|
res.error
|
||||||
? notificationStore.danger("An error has occurred")
|
? notificationStore.actions.error("An error has occurred")
|
||||||
: notificationStore.success("Row deleted")
|
: notificationStore.actions.success("Row deleted")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(tableId)
|
dataSourceStore.actions.invalidateDataSource(tableId)
|
||||||
|
@ -95,8 +95,8 @@ export const deleteRows = async ({ tableId, rows }) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
res.error
|
res.error
|
||||||
? notificationStore.danger("An error has occurred")
|
? notificationStore.actions.error("An error has occurred")
|
||||||
: notificationStore.success(`${rows.length} row(s) deleted`)
|
: notificationStore.actions.success(`${rows.length} row(s) deleted`)
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(tableId)
|
dataSourceStore.actions.invalidateDataSource(tableId)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
import Component from "./Component.svelte"
|
import Component from "./Component.svelte"
|
||||||
import NotificationDisplay from "./NotificationDisplay.svelte"
|
import NotificationDisplay from "./NotificationDisplay.svelte"
|
||||||
import ConfirmationDisplay from "./ConfirmationDisplay.svelte"
|
import ConfirmationDisplay from "./ConfirmationDisplay.svelte"
|
||||||
|
import PeekScreenDisplay from "./PeekScreenDisplay.svelte"
|
||||||
import Provider from "./Provider.svelte"
|
import Provider from "./Provider.svelte"
|
||||||
import SDK from "../sdk"
|
import SDK from "../sdk"
|
||||||
import {
|
import {
|
||||||
|
@ -93,13 +94,14 @@
|
||||||
</div>
|
</div>
|
||||||
{:else if $screenStore.activeLayout}
|
{:else if $screenStore.activeLayout}
|
||||||
<Provider key="user" data={$authStore} {actions}>
|
<Provider key="user" data={$authStore} {actions}>
|
||||||
<div id="app-root">
|
<div id="app-root" class:preview={$builderStore.inBuilder}>
|
||||||
{#key $screenStore.activeLayout._id}
|
{#key $screenStore.activeLayout._id}
|
||||||
<Component instance={$screenStore.activeLayout.props} />
|
<Component instance={$screenStore.activeLayout.props} />
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
<NotificationDisplay />
|
<NotificationDisplay />
|
||||||
<ConfirmationDisplay />
|
<ConfirmationDisplay />
|
||||||
|
<PeekScreenDisplay />
|
||||||
<!-- Key block needs to be outside the if statement or it breaks -->
|
<!-- Key block needs to be outside the if statement or it breaks -->
|
||||||
{#key $builderStore.selectedComponentId}
|
{#key $builderStore.selectedComponentId}
|
||||||
{#if $builderStore.inBuilder}
|
{#if $builderStore.inBuilder}
|
||||||
|
@ -131,6 +133,9 @@
|
||||||
#app-root {
|
#app-root {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
#app-root.preview {
|
||||||
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
|
}
|
||||||
|
|
||||||
/* Custom scrollbars */
|
/* Custom scrollbars */
|
||||||
:global(::-webkit-scrollbar) {
|
:global(::-webkit-scrollbar) {
|
||||||
|
|
|
@ -1,36 +1,34 @@
|
||||||
<script>
|
<script>
|
||||||
import { flip } from "svelte/animate"
|
import { notificationStore } from "../store"
|
||||||
|
import { Notification } from "@budibase/bbui"
|
||||||
import { fly } from "svelte/transition"
|
import { fly } from "svelte/transition"
|
||||||
import { getContext } from "svelte"
|
|
||||||
const { notifications } = getContext("sdk")
|
|
||||||
|
|
||||||
export let themes = {
|
|
||||||
danger: "#E26D69",
|
|
||||||
success: "#84C991",
|
|
||||||
warning: "#f0ad4e",
|
|
||||||
info: "#5bc0de",
|
|
||||||
default: "#aaaaaa",
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="notifications">
|
<div class="notifications">
|
||||||
{#each $notifications as notification (notification.id)}
|
{#if $notificationStore}
|
||||||
<div
|
{#key $notificationStore.id}
|
||||||
animate:flip
|
<div
|
||||||
class="toast"
|
in:fly={{
|
||||||
style="background: {themes[notification.type]};"
|
duration: 300,
|
||||||
transition:fly={{ y: -30 }}
|
y: -20,
|
||||||
>
|
delay: $notificationStore.delay ? 300 : 0,
|
||||||
<div class="content">{notification.message}</div>
|
}}
|
||||||
{#if notification.icon}<i class={notification.icon} />{/if}
|
out:fly={{ y: -20, duration: 150 }}
|
||||||
</div>
|
>
|
||||||
{/each}
|
<Notification
|
||||||
|
type={$notificationStore.type}
|
||||||
|
message={$notificationStore.message}
|
||||||
|
icon={$notificationStore.icon}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/key}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.notifications {
|
.notifications {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 10px;
|
top: 20px;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
@ -42,19 +40,4 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toast {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
/* The toasts now support being auto sized, so this static width could be removed */
|
|
||||||
width: 40vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
padding: 10px;
|
|
||||||
display: block;
|
|
||||||
color: white;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
peekStore,
|
||||||
|
dataSourceStore,
|
||||||
|
notificationStore,
|
||||||
|
routeStore,
|
||||||
|
} from "../store"
|
||||||
|
import { Modal, ModalContent, ActionButton } from "@budibase/bbui"
|
||||||
|
import { onDestroy } from "svelte"
|
||||||
|
|
||||||
|
let iframe
|
||||||
|
let listenersAttached = false
|
||||||
|
|
||||||
|
const invalidateDataSource = event => {
|
||||||
|
const { dataSourceId } = event.detail
|
||||||
|
dataSourceStore.actions.invalidateDataSource(dataSourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
const proxyNotification = event => {
|
||||||
|
const { message, type, icon } = event.detail
|
||||||
|
notificationStore.actions.send(message, type, icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachListeners = () => {
|
||||||
|
// Mirror datasource invalidation to keep the parent window up to date
|
||||||
|
iframe.contentWindow.addEventListener(
|
||||||
|
"invalidate-datasource",
|
||||||
|
invalidateDataSource
|
||||||
|
)
|
||||||
|
// Listen for a close event to close the screen peek
|
||||||
|
iframe.contentWindow.addEventListener(
|
||||||
|
"close-screen-modal",
|
||||||
|
peekStore.actions.hidePeek
|
||||||
|
)
|
||||||
|
// Proxy notifications back to the parent window instead of iframe
|
||||||
|
iframe.contentWindow.addEventListener("notification", proxyNotification)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
peekStore.actions.hidePeek()
|
||||||
|
iframe.contentWindow.removeEventListener(
|
||||||
|
"invalidate-datasource",
|
||||||
|
invalidateDataSource
|
||||||
|
)
|
||||||
|
iframe.contentWindow.removeEventListener(
|
||||||
|
"close-screen-modal",
|
||||||
|
peekStore.actions.hidePeek
|
||||||
|
)
|
||||||
|
iframe.contentWindow.removeEventListener("notification", proxyNotification)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFullscreen = () => {
|
||||||
|
if ($peekStore.external) {
|
||||||
|
window.location = $peekStore.href
|
||||||
|
} else {
|
||||||
|
routeStore.actions.navigate($peekStore.url)
|
||||||
|
handleCancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (iframe && !listenersAttached) {
|
||||||
|
attachListeners()
|
||||||
|
listenersAttached = true
|
||||||
|
} else if (!iframe) {
|
||||||
|
listenersAttached = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (iframe) {
|
||||||
|
handleCancel()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $peekStore.showPeek}
|
||||||
|
<Modal fixed on:cancel={handleCancel}>
|
||||||
|
<div class="actions spectrum--darkest" slot="outside">
|
||||||
|
<ActionButton size="S" quiet icon="OpenIn" on:click={handleFullscreen}>
|
||||||
|
Full screen
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton size="S" quiet icon="Close" on:click={handleCancel}>
|
||||||
|
Close
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
<ModalContent
|
||||||
|
showCancelButton={false}
|
||||||
|
showConfirmButton={false}
|
||||||
|
size="L"
|
||||||
|
showDivider={false}
|
||||||
|
showCloseIcon={false}
|
||||||
|
>
|
||||||
|
<iframe title="Peek" bind:this={iframe} src={$peekStore.href} />
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
iframe {
|
||||||
|
margin: -40px;
|
||||||
|
border: none;
|
||||||
|
width: calc(100% + 80px);
|
||||||
|
height: 640px;
|
||||||
|
max-height: calc(100vh - 120px);
|
||||||
|
transition: width 1s ease, height 1s ease, top 1s ease, left 1s ease;
|
||||||
|
border-radius: var(--spectrum-global-dimension-size-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 640px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { setContext, getContext } from "svelte"
|
import { setContext, getContext } from "svelte"
|
||||||
import Router from "svelte-spa-router"
|
import Router, { querystring } from "svelte-spa-router"
|
||||||
import { routeStore } from "../store"
|
import { routeStore } from "../store"
|
||||||
import Screen from "./Screen.svelte"
|
import Screen from "./Screen.svelte"
|
||||||
|
|
||||||
|
@ -16,6 +16,18 @@
|
||||||
id: $routeStore.routeSessionId,
|
id: $routeStore.routeSessionId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep query params up to date
|
||||||
|
$: {
|
||||||
|
let queryParams = {}
|
||||||
|
if ($querystring) {
|
||||||
|
const urlSearchParams = new URLSearchParams($querystring)
|
||||||
|
for (const [key, value] of urlSearchParams) {
|
||||||
|
queryParams[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
routeStore.actions.setQueryParams(queryParams)
|
||||||
|
}
|
||||||
|
|
||||||
const getRouterConfig = routes => {
|
const getRouterConfig = routes => {
|
||||||
let config = {}
|
let config = {}
|
||||||
routes.forEach(route => {
|
routes.forEach(route => {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { ActionTypes } from "./constants"
|
||||||
export default {
|
export default {
|
||||||
API,
|
API,
|
||||||
authStore,
|
authStore,
|
||||||
notifications: notificationStore,
|
notificationStore,
|
||||||
routeStore,
|
routeStore,
|
||||||
screenStore,
|
screenStore,
|
||||||
builderStore,
|
builderStore,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { notificationStore } from "./notification"
|
|
||||||
|
|
||||||
export const createDataSourceStore = () => {
|
export const createDataSourceStore = () => {
|
||||||
const store = writable([])
|
const store = writable([])
|
||||||
|
@ -67,12 +66,17 @@ export const createDataSourceStore = () => {
|
||||||
const relatedInstances = get(store).filter(instance => {
|
const relatedInstances = get(store).filter(instance => {
|
||||||
return instance.dataSourceId === dataSourceId
|
return instance.dataSourceId === dataSourceId
|
||||||
})
|
})
|
||||||
if (relatedInstances?.length) {
|
|
||||||
notificationStore.blockNotifications(1000)
|
|
||||||
}
|
|
||||||
relatedInstances?.forEach(instance => {
|
relatedInstances?.forEach(instance => {
|
||||||
instance.refresh()
|
instance.refresh()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Emit this as a window event, so parent screens which are iframing us in
|
||||||
|
// can also invalidate the same datasource
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("invalidate-datasource", {
|
||||||
|
detail: { dataSourceId },
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -6,6 +6,7 @@ export { screenStore } from "./screens"
|
||||||
export { builderStore } from "./builder"
|
export { builderStore } from "./builder"
|
||||||
export { dataSourceStore } from "./dataSource"
|
export { dataSourceStore } from "./dataSource"
|
||||||
export { confirmationStore } from "./confirmation"
|
export { confirmationStore } from "./confirmation"
|
||||||
|
export { peekStore } from "./peek"
|
||||||
|
|
||||||
// Context stores are layered and duplicated, so it is not a singleton
|
// Context stores are layered and duplicated, so it is not a singleton
|
||||||
export { createContextStore } from "./context"
|
export { createContextStore } from "./context"
|
||||||
|
|
|
@ -1,56 +1,63 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
|
import { generate } from "shortid"
|
||||||
|
import { routeStore } from "./routes"
|
||||||
|
|
||||||
const NOTIFICATION_TIMEOUT = 3000
|
const NOTIFICATION_TIMEOUT = 3000
|
||||||
|
|
||||||
const createNotificationStore = () => {
|
const createNotificationStore = () => {
|
||||||
const timeoutIds = new Set()
|
let timeout
|
||||||
const _notifications = writable([], () => {
|
let block = false
|
||||||
|
|
||||||
|
const store = writable(null, () => {
|
||||||
return () => {
|
return () => {
|
||||||
// clear all the timers
|
clearTimeout(timeout)
|
||||||
timeoutIds.forEach(timeoutId => {
|
|
||||||
clearTimeout(timeoutId)
|
|
||||||
})
|
|
||||||
_notifications.set([])
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let block = false
|
|
||||||
|
|
||||||
const blockNotifications = (timeout = 1000) => {
|
const blockNotifications = (timeout = 1000) => {
|
||||||
block = true
|
block = true
|
||||||
setTimeout(() => (block = false), timeout)
|
setTimeout(() => (block = false), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
const send = (message, type = "default") => {
|
const send = (message, type = "info", icon) => {
|
||||||
if (block) {
|
if (block) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _id = id()
|
|
||||||
_notifications.update(state => {
|
|
||||||
return [...state, { id: _id, type, message }]
|
|
||||||
})
|
|
||||||
const timeoutId = setTimeout(() => {
|
|
||||||
_notifications.update(state => {
|
|
||||||
return state.filter(({ id }) => id !== _id)
|
|
||||||
})
|
|
||||||
}, NOTIFICATION_TIMEOUT)
|
|
||||||
timeoutIds.add(timeoutId)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { subscribe } = _notifications
|
// If peeking, pass notifications back to parent window
|
||||||
|
if (get(routeStore).queryParams?.peek) {
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("notification", {
|
||||||
|
detail: { message, type, icon },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
store.set({
|
||||||
|
id: generate(),
|
||||||
|
type,
|
||||||
|
message,
|
||||||
|
icon,
|
||||||
|
delay: get(store) != null,
|
||||||
|
})
|
||||||
|
clearTimeout(timeout)
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
store.set(null)
|
||||||
|
}, NOTIFICATION_TIMEOUT)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe: store.subscribe,
|
||||||
send,
|
actions: {
|
||||||
danger: msg => send(msg, "danger"),
|
send,
|
||||||
warning: msg => send(msg, "warning"),
|
info: msg => send(msg, "info", "Info"),
|
||||||
info: msg => send(msg, "info"),
|
success: msg => send(msg, "success", "CheckmarkCircle"),
|
||||||
success: msg => send(msg, "success"),
|
warning: msg => send(msg, "warning", "Alert"),
|
||||||
blockNotifications,
|
error: msg => send(msg, "error", "Alert"),
|
||||||
|
blockNotifications,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function id() {
|
|
||||||
return "_" + Math.random().toString(36).substr(2, 9)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const notificationStore = createNotificationStore()
|
export const notificationStore = createNotificationStore()
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
showPeek: false,
|
||||||
|
url: null,
|
||||||
|
href: null,
|
||||||
|
external: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const createPeekStore = () => {
|
||||||
|
const store = writable(initialState)
|
||||||
|
|
||||||
|
const showPeek = url => {
|
||||||
|
let href = url
|
||||||
|
let external = !url.startsWith("/")
|
||||||
|
if (!external) {
|
||||||
|
href = `${window.location.href.split("#")[0]}#${url}?peek=true`
|
||||||
|
}
|
||||||
|
store.set({
|
||||||
|
showPeek: true,
|
||||||
|
url,
|
||||||
|
href,
|
||||||
|
external,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const hidePeek = () => {
|
||||||
|
store.set(initialState)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe: store.subscribe,
|
||||||
|
actions: { showPeek, hidePeek },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const peekStore = createPeekStore()
|
|
@ -9,6 +9,7 @@ const createRouteStore = () => {
|
||||||
activeRoute: null,
|
activeRoute: null,
|
||||||
routeSessionId: Math.random(),
|
routeSessionId: Math.random(),
|
||||||
routerLoaded: false,
|
routerLoaded: false,
|
||||||
|
queryParams: {},
|
||||||
}
|
}
|
||||||
const store = writable(initialState)
|
const store = writable(initialState)
|
||||||
|
|
||||||
|
@ -41,6 +42,17 @@ const createRouteStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const setQueryParams = queryParams => {
|
||||||
|
store.update(state => {
|
||||||
|
state.queryParams = {
|
||||||
|
...queryParams,
|
||||||
|
// Never unset the peek param - screen peek modals should always be
|
||||||
|
// in a peek state, even if they navigate to a different page
|
||||||
|
peek: queryParams.peek || state.queryParams?.peek,
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
const setActiveRoute = route => {
|
const setActiveRoute = route => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.activeRoute = state.routes.find(x => x.path === route)
|
state.activeRoute = state.routes.find(x => x.path === route)
|
||||||
|
@ -58,6 +70,7 @@ const createRouteStore = () => {
|
||||||
fetchRoutes,
|
fetchRoutes,
|
||||||
navigate,
|
navigate,
|
||||||
setRouteParams,
|
setRouteParams,
|
||||||
|
setQueryParams,
|
||||||
setActiveRoute,
|
setActiveRoute,
|
||||||
setRouterLoaded,
|
setRouterLoaded,
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
builderStore,
|
builderStore,
|
||||||
confirmationStore,
|
confirmationStore,
|
||||||
authStore,
|
authStore,
|
||||||
|
peekStore,
|
||||||
} from "../store"
|
} from "../store"
|
||||||
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
|
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
|
||||||
import { ActionTypes } from "../constants"
|
import { ActionTypes } from "../constants"
|
||||||
|
@ -39,13 +40,17 @@ const triggerAutomationHandler = async action => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigationHandler = action => {
|
const navigationHandler = action => {
|
||||||
const { url } = action.parameters
|
const { url, peek } = action.parameters
|
||||||
if (url) {
|
if (url) {
|
||||||
const external = !url.startsWith("/")
|
if (peek) {
|
||||||
if (external) {
|
peekStore.actions.showPeek(url)
|
||||||
window.location.href = url
|
|
||||||
} else {
|
} else {
|
||||||
routeStore.actions.navigate(action.parameters.url)
|
const external = !url.startsWith("/")
|
||||||
|
if (external) {
|
||||||
|
window.location.href = url
|
||||||
|
} else {
|
||||||
|
routeStore.actions.navigate(action.parameters.url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +99,12 @@ const clearFormHandler = async (action, context) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const closeScreenModalHandler = () => {
|
||||||
|
// Emit this as a window event, so parent screens which are iframing us in
|
||||||
|
// can close the modal
|
||||||
|
window.dispatchEvent(new Event("close-screen-modal"))
|
||||||
|
}
|
||||||
|
|
||||||
const handlerMap = {
|
const handlerMap = {
|
||||||
["Save Row"]: saveRowHandler,
|
["Save Row"]: saveRowHandler,
|
||||||
["Delete Row"]: deleteRowHandler,
|
["Delete Row"]: deleteRowHandler,
|
||||||
|
@ -104,6 +115,7 @@ const handlerMap = {
|
||||||
["Refresh Datasource"]: refreshDatasourceHandler,
|
["Refresh Datasource"]: refreshDatasourceHandler,
|
||||||
["Log Out"]: logoutHandler,
|
["Log Out"]: logoutHandler,
|
||||||
["Clear Form"]: clearFormHandler,
|
["Clear Form"]: clearFormHandler,
|
||||||
|
["Close Screen Modal"]: closeScreenModalHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmTextMap = {
|
const confirmTextMap = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"description": "Budibase Web Server",
|
"description": "Budibase Web Server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -60,9 +60,9 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/auth": "^0.9.87-alpha.7",
|
"@budibase/auth": "^0.9.96",
|
||||||
"@budibase/client": "^0.9.87-alpha.7",
|
"@budibase/client": "^0.9.96",
|
||||||
"@budibase/string-templates": "^0.9.87-alpha.7",
|
"@budibase/string-templates": "^0.9.96",
|
||||||
"@elastic/elasticsearch": "7.10.0",
|
"@elastic/elasticsearch": "7.10.0",
|
||||||
"@koa/router": "8.0.0",
|
"@koa/router": "8.0.0",
|
||||||
"@sendgrid/mail": "7.1.1",
|
"@sendgrid/mail": "7.1.1",
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.3",
|
"@babel/core": "^7.14.3",
|
||||||
"@babel/preset-env": "^7.14.4",
|
"@babel/preset-env": "^7.14.4",
|
||||||
"@budibase/standard-components": "^0.9.87-alpha.7",
|
"@budibase/standard-components": "^0.9.96",
|
||||||
"@jest/test-sequencer": "^24.8.0",
|
"@jest/test-sequencer": "^24.8.0",
|
||||||
"@types/bull": "^3.15.1",
|
"@types/bull": "^3.15.1",
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
|
|
|
@ -165,6 +165,10 @@ module External {
|
||||||
if (!row[key] || newRow[key] || field.autocolumn) {
|
if (!row[key] || newRow[key] || field.autocolumn) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// parse floats/numbers
|
||||||
|
if (field.type === FieldTypes.NUMBER && !isNaN(parseFloat(row[key]))) {
|
||||||
|
newRow[key] = parseFloat(row[key])
|
||||||
|
}
|
||||||
// if its not a link then just copy it over
|
// if its not a link then just copy it over
|
||||||
if (field.type !== FieldTypes.LINK) {
|
if (field.type !== FieldTypes.LINK) {
|
||||||
newRow[key] = row[key]
|
newRow[key] = row[key]
|
||||||
|
|
|
@ -19,8 +19,6 @@ function parseBody(body: any) {
|
||||||
}
|
}
|
||||||
if (isIsoDateString(value)) {
|
if (isIsoDateString(value)) {
|
||||||
body[key] = new Date(value)
|
body[key] = new Date(value)
|
||||||
} else if (!isNaN(parseFloat(value))) {
|
|
||||||
body[key] = parseFloat(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return body
|
return body
|
||||||
|
|
|
@ -29,13 +29,12 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"svelte"
|
"svelte"
|
||||||
],
|
],
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
|
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^0.9.87-alpha.7",
|
"@budibase/bbui": "^0.9.96",
|
||||||
"@spectrum-css/card": "^3.0.3",
|
"@spectrum-css/card": "^3.0.3",
|
||||||
"@spectrum-css/divider": "^1.0.3",
|
|
||||||
"@spectrum-css/link": "^3.1.3",
|
"@spectrum-css/link": "^3.1.3",
|
||||||
"@spectrum-css/page": "^3.0.1",
|
"@spectrum-css/page": "^3.0.1",
|
||||||
"@spectrum-css/typography": "^3.0.2",
|
"@spectrum-css/typography": "^3.0.2",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { Heading, Icon } from "@budibase/bbui"
|
import { Heading, Icon } from "@budibase/bbui"
|
||||||
|
import { routeStore } from "../../client/src/store"
|
||||||
|
|
||||||
const { styleable, linkable, builderStore } = getContext("sdk")
|
const { styleable, linkable, builderStore } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
@ -26,6 +27,14 @@
|
||||||
Small: "s",
|
Small: "s",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Permanently go into peek mode if we ever get the peek flag
|
||||||
|
let isPeeking = false
|
||||||
|
$: {
|
||||||
|
if ($routeStore.queryParams?.peek) {
|
||||||
|
isPeeking = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$: validLinks = links?.filter(link => link.text && link.url) || []
|
$: validLinks = links?.filter(link => link.text && link.url) || []
|
||||||
$: typeClass = navigationClasses[navigation] || "none"
|
$: typeClass = navigationClasses[navigation] || "none"
|
||||||
$: widthClass = widthClasses[width] || "l"
|
$: widthClass = widthClasses[width] || "l"
|
||||||
|
@ -51,7 +60,7 @@
|
||||||
|
|
||||||
<div class="layout layout--{typeClass}" use:styleable={$component.styles}>
|
<div class="layout layout--{typeClass}" use:styleable={$component.styles}>
|
||||||
{#if typeClass !== "none"}
|
{#if typeClass !== "none"}
|
||||||
<div class="nav-wrapper" class:sticky>
|
<div class="nav-wrapper" class:sticky class:hidden={isPeeking}>
|
||||||
<div class="nav nav--{typeClass} size--{widthClass}">
|
<div class="nav nav--{typeClass} size--{widthClass}">
|
||||||
<div class="nav-header">
|
<div class="nav-header">
|
||||||
{#if validLinks?.length}
|
{#if validLinks?.length}
|
||||||
|
@ -139,6 +148,9 @@
|
||||||
border-bottom: 1px solid var(--spectrum-global-color-gray-300);
|
border-bottom: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.05);
|
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
.nav-wrapper.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.layout--top .nav-wrapper.sticky {
|
.layout--top .nav-wrapper.sticky {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
export let underline
|
export let underline
|
||||||
export let size
|
export let size
|
||||||
|
|
||||||
$: external = url && !url.startsWith("/")
|
$: external = url && typeof url === "string" && !url.startsWith("/")
|
||||||
$: target = openInNewTab ? "_blank" : "_self"
|
$: target = openInNewTab ? "_blank" : "_self"
|
||||||
$: placeholder = $builderStore.inBuilder && !text
|
$: placeholder = $builderStore.inBuilder && !text
|
||||||
$: componentText = $builderStore.inBuilder
|
$: componentText = $builderStore.inBuilder
|
||||||
|
|
|
@ -10,12 +10,12 @@
|
||||||
let fieldState
|
let fieldState
|
||||||
let fieldApi
|
let fieldApi
|
||||||
|
|
||||||
const { API, notifications } = getContext("sdk")
|
const { API, notificationStore } = getContext("sdk")
|
||||||
const formContext = getContext("form")
|
const formContext = getContext("form")
|
||||||
const BYTES_IN_MB = 1000000
|
const BYTES_IN_MB = 1000000
|
||||||
|
|
||||||
const handleFileTooLarge = fileSizeLimit => {
|
const handleFileTooLarge = fileSizeLimit => {
|
||||||
notifications.warning(
|
notificationStore.actions.warning(
|
||||||
`Files cannot exceed ${
|
`Files cannot exceed ${
|
||||||
fileSizeLimit / BYTES_IN_MB
|
fileSizeLimit / BYTES_IN_MB
|
||||||
} MB. Please try again with smaller files.`
|
} MB. Please try again with smaller files.`
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/string-templates",
|
"name": "@budibase/string-templates",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"description": "Handlebars wrapper for Budibase templating.",
|
"description": "Handlebars wrapper for Budibase templating.",
|
||||||
"main": "src/index.cjs",
|
"main": "src/index.cjs",
|
||||||
"module": "dist/bundle.mjs",
|
"module": "dist/bundle.mjs",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/worker",
|
"name": "@budibase/worker",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "0.9.87-alpha.7",
|
"version": "0.9.96",
|
||||||
"description": "Budibase background service",
|
"description": "Budibase background service",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -21,8 +21,8 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/auth": "^0.9.87-alpha.7",
|
"@budibase/auth": "^0.9.96",
|
||||||
"@budibase/string-templates": "^0.9.87-alpha.7",
|
"@budibase/string-templates": "^0.9.96",
|
||||||
"@koa/router": "^8.0.0",
|
"@koa/router": "^8.0.0",
|
||||||
"@techpass/passport-openidconnect": "^0.3.0",
|
"@techpass/passport-openidconnect": "^0.3.0",
|
||||||
"aws-sdk": "^2.811.0",
|
"aws-sdk": "^2.811.0",
|
||||||
|
|
Loading…
Reference in New Issue