Merge branch 'develop' of github.com:Budibase/budibase into feature/query-variables
This commit is contained in:
commit
85858ff6b1
|
@ -12,6 +12,12 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 14.x
|
||||||
|
- run: yarn
|
||||||
|
- run: yarn bootstrap
|
||||||
|
|
||||||
- name: 'Get Previous tag'
|
- name: 'Get Previous tag'
|
||||||
id: previoustag
|
id: previoustag
|
||||||
uses: "WyriHaximus/github-action-get-previous-tag@v1"
|
uses: "WyriHaximus/github-action-get-previous-tag@v1"
|
||||||
|
|
|
@ -11,8 +11,8 @@ sources:
|
||||||
- https://github.com/Budibase/budibase
|
- https://github.com/Budibase/budibase
|
||||||
- https://budibase.com
|
- https://budibase.com
|
||||||
type: application
|
type: application
|
||||||
version: 0.2.6
|
version: 1.0.0
|
||||||
appVersion: 1.0.10
|
appVersion: 1.0.20
|
||||||
dependencies:
|
dependencies:
|
||||||
- name: couchdb
|
- name: couchdb
|
||||||
version: 3.3.4
|
version: 3.3.4
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/auth",
|
"name": "@budibase/auth",
|
||||||
"version": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"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",
|
||||||
|
|
|
@ -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": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"svelte": "src/index.js",
|
"svelte": "src/index.js",
|
||||||
"module": "dist/bbui.es.js",
|
"module": "dist/bbui.es.js",
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let id = null
|
export let id = null
|
||||||
export let updateOnChange = true
|
export let updateOnChange = true
|
||||||
|
export let quiet = false
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let focus = false
|
let focus = false
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@
|
||||||
<div class="spectrum-Search" class:is-disabled={disabled}>
|
<div class="spectrum-Search" class:is-disabled={disabled}>
|
||||||
<div
|
<div
|
||||||
class="spectrum-Textfield"
|
class="spectrum-Textfield"
|
||||||
|
class:spectrum-Textfield--quiet={quiet}
|
||||||
class:is-focused={focus}
|
class:is-focused={focus}
|
||||||
class:is-disabled={disabled}
|
class:is-disabled={disabled}
|
||||||
>
|
>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
export let placeholder = null
|
export let placeholder = null
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let updateOnChange = true
|
export let updateOnChange = true
|
||||||
|
export let quiet = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const onChange = e => {
|
const onChange = e => {
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
{disabled}
|
{disabled}
|
||||||
{value}
|
{value}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
|
{quiet}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
on:click
|
on:click
|
||||||
on:input
|
on:input
|
||||||
|
|
|
@ -10,7 +10,7 @@ it("should rename an unpublished application", () => {
|
||||||
cy.get(".home-logo").click()
|
cy.get(".home-logo").click()
|
||||||
renameApp(appRename)
|
renameApp(appRename)
|
||||||
cy.searchForApplication(appRename)
|
cy.searchForApplication(appRename)
|
||||||
cy.get(".appGrid").find(".wrapper").should("have.length", 1)
|
cy.get(".appTable").find(".title").should("have.length", 1)
|
||||||
cy.deleteApp(appRename)
|
cy.deleteApp(appRename)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ xit("Should rename a published application", () => {
|
||||||
cy.get(".home-logo").click()
|
cy.get(".home-logo").click()
|
||||||
renameApp(appRename, true)
|
renameApp(appRename, true)
|
||||||
cy.searchForApplication(appRename)
|
cy.searchForApplication(appRename)
|
||||||
cy.get(".appGrid").find(".wrapper").should("have.length", 1)
|
cy.get(".appTable").find(".title").should("have.length", 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("Should try to rename an application to have no name", () => {
|
it("Should try to rename an application to have no name", () => {
|
||||||
|
@ -38,7 +38,7 @@ it("Should try to rename an application to have no name", () => {
|
||||||
// Close modal and confirm name has not been changed
|
// Close modal and confirm name has not been changed
|
||||||
cy.get(".spectrum-Dialog-grid").contains("Cancel").click()
|
cy.get(".spectrum-Dialog-grid").contains("Cancel").click()
|
||||||
cy.searchForApplication("Cypress Tests")
|
cy.searchForApplication("Cypress Tests")
|
||||||
cy.get(".appGrid").find(".wrapper").should("have.length", 1)
|
cy.get(".appTable").find(".title").should("have.length", 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
xit("Should create two applications with the same name", () => {
|
xit("Should create two applications with the same name", () => {
|
||||||
|
@ -64,7 +64,7 @@ it("should validate application names", () => {
|
||||||
cy.get(".home-logo").click()
|
cy.get(".home-logo").click()
|
||||||
renameApp(numberName)
|
renameApp(numberName)
|
||||||
cy.searchForApplication(numberName)
|
cy.searchForApplication(numberName)
|
||||||
cy.get(".appGrid").find(".wrapper").should("have.length", 1)
|
cy.get(".appTable").find(".title").should("have.length", 1)
|
||||||
renameApp(specialCharName)
|
renameApp(specialCharName)
|
||||||
cy.get(".error").should("have.text", "App name must be letters, numbers and spaces only")
|
cy.get(".error").should("have.text", "App name must be letters, numbers and spaces only")
|
||||||
})
|
})
|
||||||
|
@ -74,14 +74,14 @@ it("should validate application names", () => {
|
||||||
.its("body")
|
.its("body")
|
||||||
.then(val => {
|
.then(val => {
|
||||||
if (val.length > 0) {
|
if (val.length > 0) {
|
||||||
cy.get(".title > :nth-child(3) > .spectrum-Icon").click()
|
cy.get(".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon").click()
|
||||||
// Check for when an app is published
|
// Check for when an app is published
|
||||||
if (published == true){
|
if (published == true){
|
||||||
// Should not have Edit as option, will unpublish app
|
// Should not have Edit as option, will unpublish app
|
||||||
cy.should("not.have.value", "Edit")
|
cy.should("not.have.value", "Edit")
|
||||||
cy.get(".spectrum-Menu").contains("Unpublish").click()
|
cy.get(".spectrum-Menu").contains("Unpublish").click()
|
||||||
cy.get(".spectrum-Dialog-grid").contains("Unpublish app").click()
|
cy.get(".spectrum-Dialog-grid").contains("Unpublish app").click()
|
||||||
cy.get(".title > :nth-child(3) > .spectrum-Icon").click()
|
cy.get(".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon").click()
|
||||||
}
|
}
|
||||||
cy.contains("Edit").click()
|
cy.contains("Edit").click()
|
||||||
cy.get(".spectrum-Modal")
|
cy.get(".spectrum-Modal")
|
||||||
|
|
|
@ -50,7 +50,9 @@ Cypress.Commands.add("deleteApp", appName => {
|
||||||
.its("body")
|
.its("body")
|
||||||
.then(val => {
|
.then(val => {
|
||||||
if (val.length > 0) {
|
if (val.length > 0) {
|
||||||
cy.get(".title > :nth-child(3) > .spectrum-Icon").click()
|
cy.get(
|
||||||
|
".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon"
|
||||||
|
).click()
|
||||||
cy.contains("Delete").click()
|
cy.contains("Delete").click()
|
||||||
cy.get(".spectrum-Modal").within(() => {
|
cy.get(".spectrum-Modal").within(() => {
|
||||||
cy.get("input").type(appName)
|
cy.get("input").type(appName)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -65,10 +65,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^1.0.19-alpha.2",
|
"@budibase/bbui": "^1.0.22",
|
||||||
"@budibase/client": "^1.0.19-alpha.2",
|
"@budibase/client": "^1.0.22",
|
||||||
"@budibase/colorpicker": "1.1.2",
|
"@budibase/colorpicker": "1.1.2",
|
||||||
"@budibase/string-templates": "^1.0.19-alpha.2",
|
"@budibase/string-templates": "^1.0.22",
|
||||||
"@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",
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
name: "javascript",
|
name: "javascript",
|
||||||
json: true,
|
json: true,
|
||||||
},
|
},
|
||||||
|
XML: {
|
||||||
|
name: "xml",
|
||||||
|
},
|
||||||
SQL: {
|
SQL: {
|
||||||
name: "sql",
|
name: "sql",
|
||||||
},
|
},
|
||||||
|
@ -40,11 +43,12 @@
|
||||||
let editor
|
let editor
|
||||||
|
|
||||||
// Keep editor up to date with value
|
// Keep editor up to date with value
|
||||||
|
$: editor?.setOption("mode", mode)
|
||||||
$: editor?.setValue(value || "")
|
$: editor?.setValue(value || "")
|
||||||
|
|
||||||
// Creates an instance of a code mirror editor
|
// Creates an instance of a code mirror editor
|
||||||
async function createEditor(mode, value) {
|
async function createEditor(mode, value) {
|
||||||
if (!CodeMirror || !textarea || editor) {
|
if (!CodeMirror || !textarea) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import "codemirror/lib/codemirror.css"
|
||||||
// Modes
|
// Modes
|
||||||
import "codemirror/mode/javascript/javascript"
|
import "codemirror/mode/javascript/javascript"
|
||||||
import "codemirror/mode/sql/sql"
|
import "codemirror/mode/sql/sql"
|
||||||
|
import "codemirror/mode/xml/xml"
|
||||||
import "codemirror/mode/css/css"
|
import "codemirror/mode/css/css"
|
||||||
import "codemirror/mode/handlebars/handlebars"
|
import "codemirror/mode/handlebars/handlebars"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script>
|
<script>
|
||||||
import { gradient } from "actions"
|
|
||||||
import {
|
import {
|
||||||
Heading,
|
Heading,
|
||||||
Button,
|
Button,
|
||||||
|
@ -18,14 +17,19 @@
|
||||||
export let deleteApp
|
export let deleteApp
|
||||||
export let unpublishApp
|
export let unpublishApp
|
||||||
export let releaseLock
|
export let releaseLock
|
||||||
|
export let editIcon
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="preview" use:gradient={{ seed: app.name }} />
|
<div style="display: flex;">
|
||||||
<div class="name" on:click={() => editApp(app)}>
|
<div style="color: {app.icon?.color || ''}">
|
||||||
<Heading size="XS">
|
<Icon size="XL" name={app.icon?.name || "Apps"} />
|
||||||
{app.name}
|
</div>
|
||||||
</Heading>
|
<div class="name" on:click={() => editApp(app)}>
|
||||||
|
<Heading size="XS">
|
||||||
|
{app.name}
|
||||||
|
</Heading>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="desktop">
|
<div class="desktop">
|
||||||
|
@ -62,6 +66,7 @@
|
||||||
disabled={app.lockedOther}
|
disabled={app.lockedOther}
|
||||||
on:click={() => editApp(app)}
|
on:click={() => editApp(app)}
|
||||||
size="S"
|
size="S"
|
||||||
|
quiet
|
||||||
secondary>Open</Button
|
secondary>Open</Button
|
||||||
>
|
>
|
||||||
<ActionMenu align="right">
|
<ActionMenu align="right">
|
||||||
|
@ -86,15 +91,11 @@
|
||||||
<MenuItem on:click={() => updateApp(app)} icon="Edit">Edit</MenuItem>
|
<MenuItem on:click={() => updateApp(app)} icon="Edit">Edit</MenuItem>
|
||||||
<MenuItem on:click={() => deleteApp(app)} icon="Delete">Delete</MenuItem>
|
<MenuItem on:click={() => deleteApp(app)} icon="Delete">Delete</MenuItem>
|
||||||
{/if}
|
{/if}
|
||||||
|
<MenuItem on:click={() => editIcon(app)} icon="Brush">Edit Icon</MenuItem>
|
||||||
</ActionMenu>
|
</ActionMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.preview {
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
}
|
|
||||||
.name {
|
.name {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -103,6 +104,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
margin-left: calc(1.5 * var(--spacing-xl));
|
||||||
}
|
}
|
||||||
.title :global(h1:hover) {
|
.title :global(h1:hover) {
|
||||||
color: var(--spectrum-global-color-blue-600);
|
color: var(--spectrum-global-color-blue-600);
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
<script>
|
||||||
|
import { ModalContent, Modal, Icon, ColorPicker, Label } from "@budibase/bbui"
|
||||||
|
import { apps } from "stores/portal"
|
||||||
|
|
||||||
|
export let app
|
||||||
|
let modal
|
||||||
|
$: selectedIcon = app?.icon?.name
|
||||||
|
$: selectedColor = app?.icon?.color
|
||||||
|
|
||||||
|
let iconsList = [
|
||||||
|
"Actions",
|
||||||
|
"ConversionFunnel",
|
||||||
|
"App",
|
||||||
|
"Briefcase",
|
||||||
|
"Money",
|
||||||
|
"ShoppingCart",
|
||||||
|
"Form",
|
||||||
|
"Help",
|
||||||
|
"Monitoring",
|
||||||
|
"Sandbox",
|
||||||
|
"Project",
|
||||||
|
"Organisations",
|
||||||
|
"Magnify",
|
||||||
|
"Launch",
|
||||||
|
"Car",
|
||||||
|
"Camera",
|
||||||
|
"Bug",
|
||||||
|
"Channel",
|
||||||
|
"Calculator",
|
||||||
|
"Calendar",
|
||||||
|
"GraphDonut",
|
||||||
|
"GraphBarHorizontal",
|
||||||
|
"Demographic",
|
||||||
|
"Apps",
|
||||||
|
]
|
||||||
|
export const show = () => {
|
||||||
|
modal.show()
|
||||||
|
}
|
||||||
|
export const hide = () => {
|
||||||
|
modal.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCancel = () => {
|
||||||
|
selectedIcon = ""
|
||||||
|
selectedColor = ""
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeColor = val => {
|
||||||
|
selectedColor = val
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = async () => {
|
||||||
|
await apps.update(app.instance._id, {
|
||||||
|
icon: {
|
||||||
|
name: selectedIcon,
|
||||||
|
color: selectedColor,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal bind:this={modal} on:hide={onCancel}>
|
||||||
|
<ModalContent
|
||||||
|
title={"Edit Icon"}
|
||||||
|
confirmText={"Save"}
|
||||||
|
onConfirm={() => save()}
|
||||||
|
>
|
||||||
|
<div class="scrollable-icons">
|
||||||
|
<div class="title-spacing">
|
||||||
|
<Label>Select an Icon</Label>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
{#each iconsList as item}
|
||||||
|
<div
|
||||||
|
class="icon-item"
|
||||||
|
style="color: {item === selectedIcon ? selectedColor : ''}"
|
||||||
|
on:click={() => (selectedIcon = item)}
|
||||||
|
>
|
||||||
|
<Icon name={item} />
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="color-selection">
|
||||||
|
<div>
|
||||||
|
<Label>Select a Color</Label>
|
||||||
|
</div>
|
||||||
|
<div class="color-selection-item">
|
||||||
|
<ColorPicker
|
||||||
|
bind:value={selectedColor}
|
||||||
|
on:change={e => changeColor(e.detail)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.scrollable-icons {
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 230px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 20px;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-selection {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-selection-item {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-spacing {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,13 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { writable, get as svelteGet } from "svelte/store"
|
import { writable, get as svelteGet } from "svelte/store"
|
||||||
import {
|
|
||||||
notifications,
|
import { notifications, Input, ModalContent, Dropzone } from "@budibase/bbui"
|
||||||
Input,
|
|
||||||
ModalContent,
|
|
||||||
Dropzone,
|
|
||||||
Body,
|
|
||||||
Checkbox,
|
|
||||||
} from "@budibase/bbui"
|
|
||||||
import { store, automationStore, hostingStore } from "builderStore"
|
import { store, automationStore, hostingStore } from "builderStore"
|
||||||
import { admin, auth } from "stores/portal"
|
import { admin, auth } from "stores/portal"
|
||||||
import { string, mixed, object } from "yup"
|
import { string, mixed, object } from "yup"
|
||||||
|
@ -147,16 +141,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getModalTitle() {
|
|
||||||
let title = "Create App"
|
|
||||||
if (template.fromFile) {
|
|
||||||
title = "Import App"
|
|
||||||
} else if (template.key) {
|
|
||||||
title = "Create app from template"
|
|
||||||
}
|
|
||||||
return title
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onCancel() {
|
async function onCancel() {
|
||||||
template = null
|
template = null
|
||||||
await auth.setInitInfo({})
|
await auth.setInitInfo({})
|
||||||
|
@ -187,7 +171,7 @@
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
{:else}
|
{:else}
|
||||||
<ModalContent
|
<ModalContent
|
||||||
title={getModalTitle()}
|
title={"Name your app"}
|
||||||
confirmText={template?.fromFile ? "Import app" : "Create app"}
|
confirmText={template?.fromFile ? "Import app" : "Create app"}
|
||||||
onConfirm={createNewApp}
|
onConfirm={createNewApp}
|
||||||
onCancel={inline ? onCancel : null}
|
onCancel={inline ? onCancel : null}
|
||||||
|
@ -207,16 +191,14 @@
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<Body size="S">
|
|
||||||
Give your new app a name, and choose which groups have access (paid plans
|
|
||||||
only).
|
|
||||||
</Body>
|
|
||||||
<Input
|
<Input
|
||||||
bind:value={$values.name}
|
bind:value={$values.name}
|
||||||
error={$touched.name && $errors.name}
|
error={$touched.name && $errors.name}
|
||||||
on:blur={() => ($touched.name = true)}
|
on:blur={() => ($touched.name = true)}
|
||||||
label="Name"
|
label="Name"
|
||||||
|
placeholder={$auth.user.firstName
|
||||||
|
? `${$auth.user.firstName}'s app`
|
||||||
|
: "My app"}
|
||||||
/>
|
/>
|
||||||
<Checkbox label="Group access" disabled value={true} text="All users" />
|
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,46 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
import { Heading, Layout, Icon, Body } from "@budibase/bbui"
|
import { Heading, Layout, Icon } from "@budibase/bbui"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
|
||||||
import api from "builderStore/api"
|
|
||||||
|
|
||||||
export let onSelect
|
export let onSelect
|
||||||
|
|
||||||
async function fetchTemplates() {
|
|
||||||
const response = await api.get("/api/templates?type=app")
|
|
||||||
return await response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
let templatesPromise = fetchTemplates()
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Layout gap="XS" noPadding>
|
<Layout gap="XS" noPadding>
|
||||||
{#await templatesPromise}
|
|
||||||
<div class="spinner-container">
|
|
||||||
<Spinner size="30" />
|
|
||||||
</div>
|
|
||||||
{:then templates}
|
|
||||||
{#if templates?.length > 0}
|
|
||||||
<Body size="M">Select a template below, or start from scratch.</Body>
|
|
||||||
{:else}
|
|
||||||
<Body size="M">Start your app from scratch below.</Body>
|
|
||||||
{/if}
|
|
||||||
<div class="templates">
|
|
||||||
{#each templates as template}
|
|
||||||
<div class="template" on:click={() => onSelect(template)}>
|
|
||||||
<div
|
|
||||||
class="background-icon"
|
|
||||||
style={`background: ${template.background};`}
|
|
||||||
>
|
|
||||||
<Icon name={template.icon} />
|
|
||||||
</div>
|
|
||||||
<Heading size="XS">{template.name}</Heading>
|
|
||||||
<p class="detail">{template?.category?.toUpperCase()}</p>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{:catch err}
|
|
||||||
<h1 style="color:red">{err}</h1>
|
|
||||||
{/await}
|
|
||||||
<div class="template start-from-scratch" on:click={() => onSelect(null)}>
|
<div class="template start-from-scratch" on:click={() => onSelect(null)}>
|
||||||
<div
|
<div
|
||||||
class="background-icon"
|
class="background-icon"
|
||||||
|
@ -67,15 +31,6 @@
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.templates {
|
|
||||||
display: grid;
|
|
||||||
width: 100%;
|
|
||||||
grid-gap: var(--spacing-m);
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
justify-content: start;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.background-icon {
|
.background-icon {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
async function updateApp() {
|
async function updateApp() {
|
||||||
try {
|
try {
|
||||||
// Update App
|
// Update App
|
||||||
await apps.update(app.instance._id, $values.name.trim())
|
await apps.update(app.instance._id, { name: $values.name.trim() })
|
||||||
hide()
|
hide()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
|
@ -200,6 +200,7 @@ export const RawRestBodyTypes = {
|
||||||
ENCODED: "encoded",
|
ENCODED: "encoded",
|
||||||
JSON: "json",
|
JSON: "json",
|
||||||
TEXT: "text",
|
TEXT: "text",
|
||||||
|
XML: "xml",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RestBodyTypes = [
|
export const RestBodyTypes = [
|
||||||
|
@ -207,5 +208,6 @@ export const RestBodyTypes = [
|
||||||
{ name: "form-data", value: "form" },
|
{ name: "form-data", value: "form" },
|
||||||
{ name: "x-www-form-encoded", value: "encoded" },
|
{ name: "x-www-form-encoded", value: "encoded" },
|
||||||
{ name: "raw (JSON)", value: "json" },
|
{ name: "raw (JSON)", value: "json" },
|
||||||
|
{ name: "raw (XML)", value: "xml" },
|
||||||
{ name: "raw (Text)", value: "text" },
|
{ name: "raw (Text)", value: "text" },
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
} from "components/common/CodeMirrorEditor.svelte"
|
} from "components/common/CodeMirrorEditor.svelte"
|
||||||
|
|
||||||
const objectTypes = [RawRestBodyTypes.FORM, RawRestBodyTypes.ENCODED]
|
const objectTypes = [RawRestBodyTypes.FORM, RawRestBodyTypes.ENCODED]
|
||||||
const textTypes = [RawRestBodyTypes.JSON, RawRestBodyTypes.TEXT]
|
const textTypes = [
|
||||||
|
RawRestBodyTypes.JSON,
|
||||||
|
RawRestBodyTypes.XML,
|
||||||
|
RawRestBodyTypes.TEXT,
|
||||||
|
]
|
||||||
|
|
||||||
export let query
|
export let query
|
||||||
export let bodyType
|
export let bodyType
|
||||||
|
@ -25,6 +29,18 @@
|
||||||
query.fields.requestBody = ""
|
query.fields.requestBody = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function editorMode(type) {
|
||||||
|
switch (type) {
|
||||||
|
case RawRestBodyTypes.JSON:
|
||||||
|
return EditorModes.JSON
|
||||||
|
case RawRestBodyTypes.XML:
|
||||||
|
return EditorModes.XML
|
||||||
|
default:
|
||||||
|
case RawRestBodyTypes.TEXT:
|
||||||
|
return EditorModes.Text
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="margin">
|
<div class="margin">
|
||||||
|
@ -41,9 +57,7 @@
|
||||||
{:else if textTypes.includes(bodyType)}
|
{:else if textTypes.includes(bodyType)}
|
||||||
<CodeMirrorEditor
|
<CodeMirrorEditor
|
||||||
height={200}
|
height={200}
|
||||||
mode={bodyType === RawRestBodyTypes.JSON
|
mode={editorMode(bodyType)}
|
||||||
? EditorModes.JSON
|
|
||||||
: EditorModes.Text}
|
|
||||||
value={query.fields.requestBody}
|
value={query.fields.requestBody}
|
||||||
resize="vertical"
|
resize="vertical"
|
||||||
on:change={e => (query.fields.requestBody = e.detail)}
|
on:change={e => (query.fields.requestBody = e.detail)}
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
let breakQs = {},
|
let breakQs = {},
|
||||||
bindings = {}
|
bindings = {}
|
||||||
let url = ""
|
let url = ""
|
||||||
let saveId
|
let saveId, isGet
|
||||||
let response, schema, enabledHeaders
|
let response, schema, enabledHeaders
|
||||||
let datasourceType, integrationInfo, queryConfig, responseSuccess
|
let datasourceType, integrationInfo, queryConfig, responseSuccess
|
||||||
let authConfigId
|
let authConfigId
|
||||||
|
@ -60,6 +60,7 @@
|
||||||
$: url = buildUrl(url, breakQs)
|
$: url = buildUrl(url, breakQs)
|
||||||
$: checkQueryName(url)
|
$: checkQueryName(url)
|
||||||
$: responseSuccess = response?.info?.code >= 200 && response?.info?.code < 400
|
$: responseSuccess = response?.info?.code >= 200 && response?.info?.code < 400
|
||||||
|
$: isGet = query?.queryVerb === "read"
|
||||||
$: authConfigs = buildAuthConfigs(datasource)
|
$: authConfigs = buildAuthConfigs(datasource)
|
||||||
$: schemaReadOnly = !responseSuccess
|
$: schemaReadOnly = !responseSuccess
|
||||||
$: variablesReadOnly = !responseSuccess
|
$: variablesReadOnly = !responseSuccess
|
||||||
|
@ -327,7 +328,7 @@
|
||||||
<Tab title="Body">
|
<Tab title="Body">
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
bind:value={query.fields.bodyType}
|
bind:value={query.fields.bodyType}
|
||||||
options={bodyTypes}
|
options={isGet ? [bodyTypes[0]] : bodyTypes}
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
getOptionLabel={option => option.name}
|
getOptionLabel={option => option.name}
|
||||||
getOptionValue={option => option.value}
|
getOptionValue={option => option.value}
|
||||||
|
|
|
@ -2,33 +2,33 @@
|
||||||
import {
|
import {
|
||||||
Heading,
|
Heading,
|
||||||
Layout,
|
Layout,
|
||||||
|
Detail,
|
||||||
Button,
|
Button,
|
||||||
ActionButton,
|
|
||||||
ActionGroup,
|
|
||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
Input,
|
Input,
|
||||||
Select,
|
Select,
|
||||||
Modal,
|
Modal,
|
||||||
Page,
|
Page,
|
||||||
notifications,
|
notifications,
|
||||||
|
Body,
|
||||||
Search,
|
Search,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||||
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
||||||
|
import ChooseIconModal from "components/start/ChooseIconModal.svelte"
|
||||||
|
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import api, { del, post, get } from "builderStore/api"
|
import api, { del, post, get } from "builderStore/api"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { apps, auth, admin } from "stores/portal"
|
import { apps, auth, admin, templates } from "stores/portal"
|
||||||
import download from "downloadjs"
|
import download from "downloadjs"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
import AppCard from "components/start/AppCard.svelte"
|
|
||||||
import AppRow from "components/start/AppRow.svelte"
|
import AppRow from "components/start/AppRow.svelte"
|
||||||
import { AppStatus } from "constants"
|
import { AppStatus } from "constants"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
|
|
||||||
let layout = "grid"
|
|
||||||
let sortBy = "name"
|
let sortBy = "name"
|
||||||
let template
|
let template
|
||||||
let selectedApp
|
let selectedApp
|
||||||
|
@ -36,13 +36,13 @@
|
||||||
let updatingModal
|
let updatingModal
|
||||||
let deletionModal
|
let deletionModal
|
||||||
let unpublishModal
|
let unpublishModal
|
||||||
|
let iconModal
|
||||||
let creatingApp = false
|
let creatingApp = false
|
||||||
let loaded = false
|
let loaded = false
|
||||||
let searchTerm = ""
|
let searchTerm = ""
|
||||||
let cloud = $admin.cloud
|
let cloud = $admin.cloud
|
||||||
let appName = ""
|
let appName = ""
|
||||||
let creatingFromTemplate = false
|
let creatingFromTemplate = false
|
||||||
|
|
||||||
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
||||||
$: filteredApps = enrichedApps.filter(app =>
|
$: filteredApps = enrichedApps.filter(app =>
|
||||||
app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
@ -172,6 +172,11 @@
|
||||||
$goto(`../../app/${app.devId}`)
|
$goto(`../../app/${app.devId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const editIcon = app => {
|
||||||
|
selectedApp = app
|
||||||
|
iconModal.show()
|
||||||
|
}
|
||||||
|
|
||||||
const exportApp = app => {
|
const exportApp = app => {
|
||||||
const id = app.deployed ? app.prodId : app.devId
|
const id = app.deployed ? app.prodId : app.devId
|
||||||
const appName = encodeURIComponent(app.name)
|
const appName = encodeURIComponent(app.name)
|
||||||
|
@ -262,6 +267,7 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await apps.load()
|
await apps.load()
|
||||||
|
await templates.load()
|
||||||
// if the portal is loaded from an external URL with a template param
|
// if the portal is loaded from an external URL with a template param
|
||||||
const initInfo = await auth.getInitInfo()
|
const initInfo = await auth.getInitInfo()
|
||||||
if (initInfo?.init_template) {
|
if (initInfo?.init_template) {
|
||||||
|
@ -274,21 +280,66 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Page wide>
|
<Page wide>
|
||||||
{#if loaded && enrichedApps.length}
|
<Layout noPadding>
|
||||||
<Layout noPadding>
|
<div class="title">
|
||||||
|
<Heading size="S">Welcome to Budibase</Heading>
|
||||||
|
|
||||||
|
<ButtonGroup>
|
||||||
|
{#if cloud}
|
||||||
|
<Button secondary on:click={initiateAppsExport}>Export apps</Button>
|
||||||
|
{/if}
|
||||||
|
<Button icon="Import" quiet secondary on:click={initiateAppImport}
|
||||||
|
>Import app</Button
|
||||||
|
>
|
||||||
|
<Button icon="Add" cta on:click={initiateAppCreation}>Create app</Button
|
||||||
|
>
|
||||||
|
</ButtonGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="title-text">
|
||||||
|
<Body size="S">Manage your apps and get a head start with templates</Body>
|
||||||
|
</div>
|
||||||
|
<Detail>Quick Start Templates</Detail>
|
||||||
|
<div class="grid">
|
||||||
|
{#each $templates as item}
|
||||||
|
<div
|
||||||
|
on:click={() => {
|
||||||
|
template = item
|
||||||
|
creationModal.show()
|
||||||
|
creatingApp = true
|
||||||
|
}}
|
||||||
|
class="template-card"
|
||||||
|
>
|
||||||
|
<div class="card-body">
|
||||||
|
<div style="color: {item.background}" class="iconAlign">
|
||||||
|
<svg
|
||||||
|
width="26px"
|
||||||
|
height="26px"
|
||||||
|
class="spectrum-Icon"
|
||||||
|
style="color:{item.background};"
|
||||||
|
focusable="false"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-{item.icon}" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="iconAlign">
|
||||||
|
<Body weight="900" size="S">{item.name}</Body>
|
||||||
|
<div style="font-size: 10px;">
|
||||||
|
<Body size="S">{item.category.toUpperCase()}</Body>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{#if loaded && enrichedApps.length}
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<Heading>Apps</Heading>
|
<Detail>My Apps</Detail>
|
||||||
<ButtonGroup>
|
|
||||||
{#if cloud}
|
|
||||||
<Button secondary on:click={initiateAppsExport}>Export apps</Button>
|
|
||||||
{/if}
|
|
||||||
<Button secondary on:click={initiateAppImport}>Import app</Button>
|
|
||||||
<Button cta on:click={initiateAppCreation}>Create app</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
<div class="select">
|
<div class="select">
|
||||||
<Select
|
<Select
|
||||||
|
quiet
|
||||||
autoWidth
|
autoWidth
|
||||||
bind:value={sortBy}
|
bind:value={sortBy}
|
||||||
placeholder={null}
|
placeholder={null}
|
||||||
|
@ -299,35 +350,18 @@
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<div class="desktop-search">
|
<div class="desktop-search">
|
||||||
<Search placeholder="Search" bind:value={searchTerm} />
|
<Search quiet placeholder="Search" bind:value={searchTerm} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ActionGroup>
|
|
||||||
<ActionButton
|
|
||||||
on:click={() => (layout = "grid")}
|
|
||||||
selected={layout === "grid"}
|
|
||||||
quiet
|
|
||||||
icon="ClassicGridView"
|
|
||||||
/>
|
|
||||||
<ActionButton
|
|
||||||
on:click={() => (layout = "table")}
|
|
||||||
selected={layout === "table"}
|
|
||||||
quiet
|
|
||||||
icon="ViewRow"
|
|
||||||
/>
|
|
||||||
</ActionGroup>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mobile-search">
|
<div class="mobile-search">
|
||||||
<Search placeholder="Search" bind:value={searchTerm} />
|
<Search placeholder="Search" bind:value={searchTerm} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="appTable">
|
||||||
class:appGrid={layout === "grid"}
|
|
||||||
class:appTable={layout === "table"}
|
|
||||||
>
|
|
||||||
{#each filteredApps as app (app.appId)}
|
{#each filteredApps as app (app.appId)}
|
||||||
<svelte:component
|
<AppRow
|
||||||
this={layout === "grid" ? AppCard : AppRow}
|
|
||||||
{releaseLock}
|
{releaseLock}
|
||||||
|
{editIcon}
|
||||||
{app}
|
{app}
|
||||||
{unpublishApp}
|
{unpublishApp}
|
||||||
{viewApp}
|
{viewApp}
|
||||||
|
@ -338,22 +372,23 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
{/if}
|
||||||
{/if}
|
{#if !enrichedApps.length && !creatingApp && loaded}
|
||||||
{#if !enrichedApps.length && !creatingApp && loaded}
|
<div class="empty-wrapper">
|
||||||
<div class="empty-wrapper">
|
<Modal inline>
|
||||||
<Modal inline>
|
<CreateAppModal {template} inline={true} />
|
||||||
<CreateAppModal {template} inline={true} />
|
</Modal>
|
||||||
</Modal>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
{#if creatingFromTemplate}
|
||||||
{#if creatingFromTemplate}
|
<div class="empty-wrapper">
|
||||||
<div class="empty-wrapper">
|
<p>Creating your Budibase app from your selected template...</p>
|
||||||
<p>Creating your Budibase app from your selected template...</p>
|
<Spinner size="10" />
|
||||||
<Spinner size="10" />
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</Layout>
|
||||||
</Page>
|
</Page>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
bind:this={creationModal}
|
bind:this={creationModal}
|
||||||
padding={false}
|
padding={false}
|
||||||
|
@ -389,6 +424,7 @@
|
||||||
</ConfirmDialog>
|
</ConfirmDialog>
|
||||||
|
|
||||||
<UpdateAppModal app={selectedApp} bind:this={updatingModal} />
|
<UpdateAppModal app={selectedApp} bind:this={updatingModal} />
|
||||||
|
<ChooseIconModal app={selectedApp} bind:this={iconModal} />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.title,
|
.title,
|
||||||
|
@ -397,7 +433,7 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 560px) {
|
@media only screen and (max-width: 560px) {
|
||||||
|
@ -405,12 +441,48 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconAlign {
|
||||||
|
padding: 0 0 0 var(--spacing-m);
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.template-card {
|
||||||
|
height: 80px;
|
||||||
|
width: 270px;
|
||||||
|
border-radius: var(--border-radius-s);
|
||||||
|
margin-bottom: var(--spacing-m);
|
||||||
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-text {
|
||||||
|
margin-top: calc(var(--spacing-xl) * -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 5px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 200px) {
|
||||||
}
|
}
|
||||||
|
|
||||||
.select {
|
.select {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: auto auto;
|
||||||
grid-gap: 10px;
|
grid-gap: 30px;
|
||||||
}
|
}
|
||||||
.filter :global(.spectrum-ActionGroup) {
|
.filter :global(.spectrum-ActionGroup) {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
|
@ -419,11 +491,6 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.appGrid {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 50px;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
||||||
}
|
|
||||||
.appTable {
|
.appTable {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto;
|
grid-template-rows: auto;
|
||||||
|
@ -464,4 +531,8 @@
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.template-card:hover {
|
||||||
|
background: var(--spectrum-alias-background-color-tertiary);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -65,16 +65,17 @@ export function createAppStore() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function update(appId, name) {
|
async function update(appId, value) {
|
||||||
const response = await api.put(`/api/applications/${appId}`, { name })
|
console.log({ value })
|
||||||
|
const response = await api.put(`/api/applications/${appId}`, { ...value })
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const updatedAppIndex = state.findIndex(
|
const updatedAppIndex = state.findIndex(
|
||||||
app => app.instance._id === appId
|
app => app.instance._id === appId
|
||||||
)
|
)
|
||||||
if (updatedAppIndex !== -1) {
|
if (updatedAppIndex !== -1) {
|
||||||
const updatedApp = state[updatedAppIndex]
|
let updatedApp = state[updatedAppIndex]
|
||||||
updatedApp.name = name
|
updatedApp = { ...updatedApp, ...value }
|
||||||
state.apps = state.splice(updatedAppIndex, 1, updatedApp)
|
state.apps = state.splice(updatedAppIndex, 1, updatedApp)
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
|
|
@ -5,3 +5,4 @@ export { apps } from "./apps"
|
||||||
export { email } from "./email"
|
export { email } from "./email"
|
||||||
export { auth } from "./auth"
|
export { auth } from "./auth"
|
||||||
export { oidc } from "./oidc"
|
export { oidc } from "./oidc"
|
||||||
|
export { templates } from "./templates"
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
export function templatesStore() {
|
||||||
|
const { subscribe, set } = writable([])
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
const response = await api.get("/api/templates?type=app")
|
||||||
|
const json = await response.json()
|
||||||
|
set(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
load,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const templates = templatesStore()
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/cli",
|
"name": "@budibase/cli",
|
||||||
"version": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"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": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"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",
|
||||||
|
@ -19,9 +19,9 @@
|
||||||
"dev:builder": "rollup -cw"
|
"dev:builder": "rollup -cw"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^1.0.19-alpha.2",
|
"@budibase/bbui": "^1.0.22",
|
||||||
"@budibase/standard-components": "^0.9.139",
|
"@budibase/standard-components": "^0.9.139",
|
||||||
"@budibase/string-templates": "^1.0.19-alpha.2",
|
"@budibase/string-templates": "^1.0.22",
|
||||||
"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"
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
import { setContext, getContext } from "svelte"
|
import { setContext, getContext, onMount } from "svelte"
|
||||||
import Router, { querystring } from "svelte-spa-router"
|
import Router, { querystring } from "svelte-spa-router"
|
||||||
import { routeStore } from "stores"
|
import { routeStore, stateStore } from "stores"
|
||||||
import Screen from "./Screen.svelte"
|
import Screen from "./Screen.svelte"
|
||||||
|
import { get } from "svelte/store"
|
||||||
|
|
||||||
const { styleable } = getContext("sdk")
|
const { styleable } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
@ -17,15 +18,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep query params up to date
|
// Keep query params up to date
|
||||||
$: {
|
$: routeStore.actions.setQueryParams(parseQueryString($querystring))
|
||||||
|
|
||||||
|
const parseQueryString = query => {
|
||||||
let queryParams = {}
|
let queryParams = {}
|
||||||
if ($querystring) {
|
if (query) {
|
||||||
const urlSearchParams = new URLSearchParams($querystring)
|
const urlSearchParams = new URLSearchParams(query)
|
||||||
for (const [key, value] of urlSearchParams) {
|
for (const [key, value] of urlSearchParams) {
|
||||||
queryParams[key] = value
|
queryParams[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
routeStore.actions.setQueryParams(queryParams)
|
return queryParams
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRouterConfig = routes => {
|
const getRouterConfig = routes => {
|
||||||
|
@ -42,6 +45,19 @@
|
||||||
const onRouteLoading = ({ detail }) => {
|
const onRouteLoading = ({ detail }) => {
|
||||||
routeStore.actions.setActiveRoute(detail.route)
|
routeStore.actions.setActiveRoute(detail.route)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialise state store from query string on initial load
|
||||||
|
onMount(() => {
|
||||||
|
const queryParams = parseQueryString(get(querystring))
|
||||||
|
if (queryParams.state) {
|
||||||
|
try {
|
||||||
|
const state = JSON.parse(atob(queryParams.state))
|
||||||
|
stateStore.actions.initialise(state)
|
||||||
|
} catch (error) {
|
||||||
|
// Swallow error and do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#key config.id}
|
{#key config.id}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
dataSourceStore,
|
dataSourceStore,
|
||||||
notificationStore,
|
notificationStore,
|
||||||
routeStore,
|
routeStore,
|
||||||
|
stateStore,
|
||||||
} from "stores"
|
} from "stores"
|
||||||
import { Modal, ModalContent, ActionButton } from "@budibase/bbui"
|
import { Modal, ModalContent, ActionButton } from "@budibase/bbui"
|
||||||
import { onDestroy } from "svelte"
|
import { onDestroy } from "svelte"
|
||||||
|
@ -12,12 +13,13 @@
|
||||||
NOTIFICATION: "notification",
|
NOTIFICATION: "notification",
|
||||||
CLOSE_SCREEN_MODAL: "close-screen-modal",
|
CLOSE_SCREEN_MODAL: "close-screen-modal",
|
||||||
INVALIDATE_DATASOURCE: "invalidate-datasource",
|
INVALIDATE_DATASOURCE: "invalidate-datasource",
|
||||||
|
UPDATE_STATE: "update-state",
|
||||||
}
|
}
|
||||||
|
|
||||||
let iframe
|
let iframe
|
||||||
let listenersAttached = false
|
let listenersAttached = false
|
||||||
|
|
||||||
const invalidateDataSource = event => {
|
const proxyInvalidation = event => {
|
||||||
const { dataSourceId } = event.detail
|
const { dataSourceId } = event.detail
|
||||||
dataSourceStore.actions.invalidateDataSource(dataSourceId)
|
dataSourceStore.actions.invalidateDataSource(dataSourceId)
|
||||||
}
|
}
|
||||||
|
@ -27,14 +29,28 @@
|
||||||
notificationStore.actions.send(message, type, icon)
|
notificationStore.actions.send(message, type, icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const proxyStateUpdate = event => {
|
||||||
|
const { type, key, value, persist } = event.detail
|
||||||
|
if (type === "set") {
|
||||||
|
stateStore.actions.setValue(key, value, persist)
|
||||||
|
} else if (type === "delete") {
|
||||||
|
stateStore.actions.deleteValue(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function receiveMessage(message) {
|
function receiveMessage(message) {
|
||||||
const handlers = {
|
const handlers = {
|
||||||
[MessageTypes.NOTIFICATION]: () => {
|
[MessageTypes.NOTIFICATION]: () => {
|
||||||
proxyNotification(message.data)
|
proxyNotification(message.data)
|
||||||
},
|
},
|
||||||
[MessageTypes.CLOSE_SCREEN_MODAL]: peekStore.actions.hidePeek,
|
[MessageTypes.CLOSE_SCREEN_MODAL]: () => {
|
||||||
|
peekStore.actions.hidePeek()
|
||||||
|
},
|
||||||
[MessageTypes.INVALIDATE_DATASOURCE]: () => {
|
[MessageTypes.INVALIDATE_DATASOURCE]: () => {
|
||||||
invalidateDataSource(message.data)
|
proxyInvalidation(message.data)
|
||||||
|
},
|
||||||
|
[MessageTypes.UPDATE_STATE]: () => {
|
||||||
|
proxyStateUpdate(message.data)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { fetchTableDefinition } from "../api"
|
import { fetchTableDefinition } from "../api"
|
||||||
import { FieldTypes } from "../constants"
|
import { FieldTypes } from "../constants"
|
||||||
|
import { routeStore } from "./routes"
|
||||||
|
|
||||||
export const createDataSourceStore = () => {
|
export const createDataSourceStore = () => {
|
||||||
const store = writable([])
|
const store = writable([])
|
||||||
|
@ -60,10 +61,12 @@ export const createDataSourceStore = () => {
|
||||||
|
|
||||||
// Emit this as a window event, so parent screens which are iframing us in
|
// Emit this as a window event, so parent screens which are iframing us in
|
||||||
// can also invalidate the same datasource
|
// can also invalidate the same datasource
|
||||||
window.parent.postMessage({
|
if (get(routeStore).queryParams?.peek) {
|
||||||
type: "close-screen-modal",
|
window.parent.postMessage({
|
||||||
detail: { dataSourceId },
|
type: "invalidate-datasource",
|
||||||
})
|
detail: { dataSourceId },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let invalidations = [dataSourceId]
|
let invalidations = [dataSourceId]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
|
import { stateStore } from "./state.js"
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
showPeek: false,
|
showPeek: false,
|
||||||
|
@ -14,7 +15,10 @@ const createPeekStore = () => {
|
||||||
let href = url
|
let href = url
|
||||||
let external = !url.startsWith("/")
|
let external = !url.startsWith("/")
|
||||||
if (!external) {
|
if (!external) {
|
||||||
href = `${window.location.href.split("#")[0]}#${url}?peek=true`
|
const state = get(stateStore)
|
||||||
|
const serialised = encodeURIComponent(btoa(JSON.stringify(state)))
|
||||||
|
const query = `peek=true&state=${serialised}`
|
||||||
|
href = `${window.location.href.split("#")[0]}#${url}?${query}`
|
||||||
}
|
}
|
||||||
store.set({
|
store.set({
|
||||||
showPeek: true,
|
showPeek: true,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { writable, get, derived } from "svelte/store"
|
import { writable, get, derived } from "svelte/store"
|
||||||
import { localStorageStore } from "builder/src/builderStore/store/localStorage"
|
import { localStorageStore } from "builder/src/builderStore/store/localStorage"
|
||||||
import { appStore } from "./app"
|
|
||||||
|
|
||||||
const createStateStore = () => {
|
const createStateStore = () => {
|
||||||
const localStorageKey = `${get(appStore).appId}.state`
|
const appId = window["##BUDIBASE_APP_ID##"] || "app"
|
||||||
|
const localStorageKey = `${appId}.state`
|
||||||
const persistentStore = localStorageStore(localStorageKey, {})
|
const persistentStore = localStorageStore(localStorageKey, {})
|
||||||
|
|
||||||
// Initialise the temp store to mirror the persistent store
|
// Initialise the temp store to mirror the persistent store
|
||||||
|
@ -34,6 +34,9 @@ const createStateStore = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialises the temporary state store with a certain value
|
||||||
|
const initialise = tempStore.set
|
||||||
|
|
||||||
// Derive the combination of both persisted and non persisted stores
|
// Derive the combination of both persisted and non persisted stores
|
||||||
const store = derived(
|
const store = derived(
|
||||||
[tempStore, persistentStore],
|
[tempStore, persistentStore],
|
||||||
|
@ -47,7 +50,7 @@ const createStateStore = () => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe: store.subscribe,
|
subscribe: store.subscribe,
|
||||||
actions: { setValue, deleteValue },
|
actions: { setValue, deleteValue, initialise },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,15 @@ const updateStateHandler = action => {
|
||||||
} else if (type === "delete") {
|
} else if (type === "delete") {
|
||||||
stateStore.actions.deleteValue(key)
|
stateStore.actions.deleteValue(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit this as an event so that parent windows which are iframing us in
|
||||||
|
// can also update their state
|
||||||
|
if (get(routeStore).queryParams?.peek) {
|
||||||
|
window.parent.postMessage({
|
||||||
|
type: "update-state",
|
||||||
|
detail: { type, key, value, persist },
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlerMap = {
|
const handlerMap = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"description": "Budibase Web Server",
|
"description": "Budibase Web Server",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -70,9 +70,9 @@
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apidevtools/swagger-parser": "^10.0.3",
|
"@apidevtools/swagger-parser": "^10.0.3",
|
||||||
"@budibase/auth": "^1.0.19-alpha.2",
|
"@budibase/auth": "^1.0.22",
|
||||||
"@budibase/client": "^1.0.19-alpha.2",
|
"@budibase/client": "^1.0.22",
|
||||||
"@budibase/string-templates": "^1.0.19-alpha.2",
|
"@budibase/string-templates": "^1.0.22",
|
||||||
"@bull-board/api": "^3.7.0",
|
"@bull-board/api": "^3.7.0",
|
||||||
"@bull-board/koa": "^3.7.0",
|
"@bull-board/koa": "^3.7.0",
|
||||||
"@elastic/elasticsearch": "7.10.0",
|
"@elastic/elasticsearch": "7.10.0",
|
||||||
|
@ -90,6 +90,7 @@
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
"download": "8.0.0",
|
"download": "8.0.0",
|
||||||
"fix-path": "3.0.0",
|
"fix-path": "3.0.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
"fs-extra": "8.1.0",
|
"fs-extra": "8.1.0",
|
||||||
"jimp": "0.16.1",
|
"jimp": "0.16.1",
|
||||||
"joi": "17.2.1",
|
"joi": "17.2.1",
|
||||||
|
@ -126,6 +127,7 @@
|
||||||
"validate.js": "0.13.1",
|
"validate.js": "0.13.1",
|
||||||
"vm2": "^3.9.3",
|
"vm2": "^3.9.3",
|
||||||
"worker-farm": "^1.7.0",
|
"worker-farm": "^1.7.0",
|
||||||
|
"xml2js": "^0.4.23",
|
||||||
"yargs": "13.2.4",
|
"yargs": "13.2.4",
|
||||||
"zlib": "1.0.5"
|
"zlib": "1.0.5"
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,11 +5,15 @@ const { getAutomationParams, generateAutomationID } = require("../../db/utils")
|
||||||
const {
|
const {
|
||||||
checkForWebhooks,
|
checkForWebhooks,
|
||||||
updateTestHistory,
|
updateTestHistory,
|
||||||
|
removeDeprecated,
|
||||||
} = require("../../automations/utils")
|
} = require("../../automations/utils")
|
||||||
const { deleteEntityMetadata } = require("../../utilities")
|
const { deleteEntityMetadata } = require("../../utilities")
|
||||||
const { MetadataTypes } = require("../../constants")
|
const { MetadataTypes } = require("../../constants")
|
||||||
const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
|
const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
|
||||||
|
|
||||||
|
const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
|
||||||
|
const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
||||||
|
|
||||||
/*************************
|
/*************************
|
||||||
* *
|
* *
|
||||||
* BUILDER FUNCTIONS *
|
* BUILDER FUNCTIONS *
|
||||||
|
@ -155,17 +159,17 @@ exports.destroy = async function (ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getActionList = async function (ctx) {
|
exports.getActionList = async function (ctx) {
|
||||||
ctx.body = actions.ACTION_DEFINITIONS
|
ctx.body = ACTION_DEFS
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getTriggerList = async function (ctx) {
|
exports.getTriggerList = async function (ctx) {
|
||||||
ctx.body = triggers.TRIGGER_DEFINITIONS
|
ctx.body = TRIGGER_DEFS
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.getDefinitionList = async function (ctx) {
|
module.exports.getDefinitionList = async function (ctx) {
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
trigger: triggers.TRIGGER_DEFINITIONS,
|
trigger: TRIGGER_DEFS,
|
||||||
action: actions.ACTION_DEFINITIONS,
|
action: ACTION_DEFS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,11 @@ const RequestType = {
|
||||||
const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH]
|
const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note, there is some functionality in this that is not currently exposed as it
|
* NOTE: this functionality is deprecated - it no longer should be used.
|
||||||
* is complex and maybe better to be opinionated here.
|
|
||||||
* GET/DELETE requests cannot handle body elements so they will not be sent if configured.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.definition = {
|
exports.definition = {
|
||||||
|
deprecated: true,
|
||||||
name: "Outgoing webhook",
|
name: "Outgoing webhook",
|
||||||
tagline: "Send a {{inputs.requestMethod}} request",
|
tagline: "Send a {{inputs.requestMethod}} request",
|
||||||
icon: "Send",
|
icon: "Send",
|
||||||
|
|
|
@ -7,6 +7,7 @@ const newid = require("../db/newid")
|
||||||
const { updateEntityMetadata } = require("../utilities")
|
const { updateEntityMetadata } = require("../utilities")
|
||||||
const { MetadataTypes } = require("../constants")
|
const { MetadataTypes } = require("../constants")
|
||||||
const { getDeployedAppID } = require("@budibase/auth/db")
|
const { getDeployedAppID } = require("@budibase/auth/db")
|
||||||
|
const { cloneDeep } = require("lodash/fp")
|
||||||
|
|
||||||
const WH_STEP_ID = definitions.WEBHOOK.stepId
|
const WH_STEP_ID = definitions.WEBHOOK.stepId
|
||||||
const CRON_STEP_ID = definitions.CRON.stepId
|
const CRON_STEP_ID = definitions.CRON.stepId
|
||||||
|
@ -42,6 +43,16 @@ exports.updateTestHistory = async (appId, automation, history) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.removeDeprecated = definitions => {
|
||||||
|
const base = cloneDeep(definitions)
|
||||||
|
for (let key of Object.keys(base)) {
|
||||||
|
if (base[key].deprecated) {
|
||||||
|
delete base[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
|
||||||
// end the repetition and the job itself
|
// end the repetition and the job itself
|
||||||
exports.disableAllCrons = async appId => {
|
exports.disableAllCrons = async appId => {
|
||||||
const promises = []
|
const promises = []
|
||||||
|
|
|
@ -6,13 +6,14 @@ import {
|
||||||
RestQueryFields as RestQuery,
|
RestQueryFields as RestQuery,
|
||||||
AuthType,
|
AuthType,
|
||||||
BasicAuthConfig,
|
BasicAuthConfig,
|
||||||
BearerAuthConfig
|
BearerAuthConfig,
|
||||||
} from "../definitions/datasource"
|
} from "../definitions/datasource"
|
||||||
import { IntegrationBase } from "./base/IntegrationBase"
|
import { IntegrationBase } from "./base/IntegrationBase"
|
||||||
|
|
||||||
const BodyTypes = {
|
const BodyTypes = {
|
||||||
NONE: "none",
|
NONE: "none",
|
||||||
FORM_DATA: "form",
|
FORM_DATA: "form",
|
||||||
|
XML: "xml",
|
||||||
ENCODED: "encoded",
|
ENCODED: "encoded",
|
||||||
JSON: "json",
|
JSON: "json",
|
||||||
TEXT: "text",
|
TEXT: "text",
|
||||||
|
@ -45,6 +46,9 @@ module RestModule {
|
||||||
const fetch = require("node-fetch")
|
const fetch = require("node-fetch")
|
||||||
const { formatBytes } = require("../utilities")
|
const { formatBytes } = require("../utilities")
|
||||||
const { performance } = require("perf_hooks")
|
const { performance } = require("perf_hooks")
|
||||||
|
const FormData = require("form-data")
|
||||||
|
const { URLSearchParams } = require("url")
|
||||||
|
const { parseStringPromise: xmlParser, Builder: XmlBuilder } = require("xml2js")
|
||||||
|
|
||||||
const SCHEMA: Integration = {
|
const SCHEMA: Integration = {
|
||||||
docs: "https://github.com/node-fetch/node-fetch",
|
docs: "https://github.com/node-fetch/node-fetch",
|
||||||
|
@ -110,15 +114,38 @@ module RestModule {
|
||||||
|
|
||||||
async parseResponse(response: any) {
|
async parseResponse(response: any) {
|
||||||
let data, raw, headers
|
let data, raw, headers
|
||||||
const contentType = response.headers.get("content-type")
|
const contentType = response.headers.get("content-type") || ""
|
||||||
if (contentType && contentType.indexOf("application/json") !== -1) {
|
try {
|
||||||
data = await response.json()
|
if (contentType.includes("application/json")) {
|
||||||
raw = JSON.stringify(data)
|
data = await response.json()
|
||||||
} else {
|
raw = JSON.stringify(data)
|
||||||
data = await response.text()
|
} else if (
|
||||||
raw = data
|
contentType.includes("text/xml") ||
|
||||||
|
contentType.includes("application/xml")
|
||||||
|
) {
|
||||||
|
const rawXml = await response.text()
|
||||||
|
data =
|
||||||
|
(await xmlParser(rawXml, {
|
||||||
|
explicitArray: false,
|
||||||
|
trim: true,
|
||||||
|
explicitRoot: false,
|
||||||
|
})) || {}
|
||||||
|
// there is only one structure, its an array, return the array so it appears as rows
|
||||||
|
const keys = Object.keys(data)
|
||||||
|
if (keys.length === 1 && Array.isArray(data[keys[0]])) {
|
||||||
|
data = data[keys[0]]
|
||||||
|
}
|
||||||
|
raw = rawXml
|
||||||
|
} else {
|
||||||
|
data = await response.text()
|
||||||
|
raw = data
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw "Failed to parse response body."
|
||||||
}
|
}
|
||||||
const size = formatBytes(response.headers.get("content-length") || Buffer.byteLength(raw, "utf8"))
|
const size = formatBytes(
|
||||||
|
response.headers.get("content-length") || Buffer.byteLength(raw, "utf8")
|
||||||
|
)
|
||||||
const time = `${Math.round(performance.now() - this.startTimeMs)}ms`
|
const time = `${Math.round(performance.now() - this.startTimeMs)}ms`
|
||||||
headers = response.headers.raw()
|
headers = response.headers.raw()
|
||||||
for (let [key, value] of Object.entries(headers)) {
|
for (let [key, value] of Object.entries(headers)) {
|
||||||
|
@ -150,7 +177,59 @@ module RestModule {
|
||||||
return complete
|
return complete
|
||||||
}
|
}
|
||||||
|
|
||||||
getAuthHeaders(authConfigId: string): { [key: string]: any }{
|
addBody(bodyType: string, body: string | any, input: any) {
|
||||||
|
let error, object, string
|
||||||
|
try {
|
||||||
|
string = typeof body !== "string" ? JSON.stringify(body) : body
|
||||||
|
object = typeof body === "object" ? body : JSON.parse(body)
|
||||||
|
} catch (err) {
|
||||||
|
error = err
|
||||||
|
}
|
||||||
|
if (!input.headers) {
|
||||||
|
input.headers = {}
|
||||||
|
}
|
||||||
|
switch (bodyType) {
|
||||||
|
case BodyTypes.NONE:
|
||||||
|
break
|
||||||
|
case BodyTypes.TEXT:
|
||||||
|
// content type defaults to plaintext
|
||||||
|
input.body = string
|
||||||
|
break
|
||||||
|
case BodyTypes.ENCODED:
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
for (let [key, value] of Object.entries(object)) {
|
||||||
|
params.append(key, value)
|
||||||
|
}
|
||||||
|
input.body = params
|
||||||
|
break
|
||||||
|
case BodyTypes.FORM_DATA:
|
||||||
|
const form = new FormData()
|
||||||
|
for (let [key, value] of Object.entries(object)) {
|
||||||
|
form.append(key, value)
|
||||||
|
}
|
||||||
|
input.body = form
|
||||||
|
break
|
||||||
|
case BodyTypes.XML:
|
||||||
|
if (object != null) {
|
||||||
|
string = (new XmlBuilder()).buildObject(object)
|
||||||
|
}
|
||||||
|
input.body = string
|
||||||
|
input.headers["Content-Type"] = "application/xml"
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
case BodyTypes.JSON:
|
||||||
|
// if JSON error, throw it
|
||||||
|
if (error) {
|
||||||
|
throw "Invalid JSON for request body"
|
||||||
|
}
|
||||||
|
input.body = string
|
||||||
|
input.headers["Content-Type"] = "application/json"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
getAuthHeaders(authConfigId: string): { [key: string]: any } {
|
||||||
let headers: any = {}
|
let headers: any = {}
|
||||||
|
|
||||||
if (this.config.authConfigs && authConfigId) {
|
if (this.config.authConfigs && authConfigId) {
|
||||||
|
@ -180,7 +259,16 @@ module RestModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _req(query: RestQuery) {
|
async _req(query: RestQuery) {
|
||||||
const { path = "", queryString = "", headers = {}, method = "GET", disabledHeaders, bodyType, requestBody, authConfigId } = query
|
const {
|
||||||
|
path = "",
|
||||||
|
queryString = "",
|
||||||
|
headers = {},
|
||||||
|
method = "GET",
|
||||||
|
disabledHeaders,
|
||||||
|
bodyType,
|
||||||
|
requestBody,
|
||||||
|
authConfigId,
|
||||||
|
} = query
|
||||||
const authHeaders = this.getAuthHeaders(authConfigId)
|
const authHeaders = this.getAuthHeaders(authConfigId)
|
||||||
|
|
||||||
this.headers = {
|
this.headers = {
|
||||||
|
@ -197,18 +285,9 @@ module RestModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let json
|
let input: any = { method, headers: this.headers }
|
||||||
if (bodyType === BodyTypes.JSON && requestBody) {
|
if (requestBody) {
|
||||||
try {
|
input = this.addBody(bodyType, requestBody, input)
|
||||||
json = JSON.parse(requestBody)
|
|
||||||
} catch (err) {
|
|
||||||
throw "Invalid JSON for request body"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const input: any = { method, headers: this.headers }
|
|
||||||
if (json && typeof json === "object" && Object.keys(json).length > 0) {
|
|
||||||
input.body = JSON.stringify(json)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.startTimeMs = performance.now()
|
this.startTimeMs = performance.now()
|
||||||
|
|
|
@ -14,6 +14,11 @@ const fetch = require("node-fetch")
|
||||||
const RestIntegration = require("../rest")
|
const RestIntegration = require("../rest")
|
||||||
const { AuthType } = require("../rest")
|
const { AuthType } = require("../rest")
|
||||||
|
|
||||||
|
const HEADERS = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
class TestConfiguration {
|
class TestConfiguration {
|
||||||
constructor(config = {}) {
|
constructor(config = {}) {
|
||||||
this.integration = new RestIntegration.integration(config)
|
this.integration = new RestIntegration.integration(config)
|
||||||
|
@ -35,9 +40,7 @@ describe("REST Integration", () => {
|
||||||
const query = {
|
const query = {
|
||||||
path: "api",
|
path: "api",
|
||||||
queryString: "test=1",
|
queryString: "test=1",
|
||||||
headers: {
|
headers: HEADERS,
|
||||||
Accept: "application/json",
|
|
||||||
},
|
|
||||||
bodyType: "json",
|
bodyType: "json",
|
||||||
requestBody: JSON.stringify({
|
requestBody: JSON.stringify({
|
||||||
name: "test",
|
name: "test",
|
||||||
|
@ -47,9 +50,7 @@ describe("REST Integration", () => {
|
||||||
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
|
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: '{"name":"test"}',
|
body: '{"name":"test"}',
|
||||||
headers: {
|
headers: HEADERS,
|
||||||
Accept: "application/json",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -86,9 +87,7 @@ describe("REST Integration", () => {
|
||||||
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
|
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
body: '{"name":"test"}',
|
body: '{"name":"test"}',
|
||||||
headers: {
|
headers: HEADERS,
|
||||||
Accept: "application/json",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -107,13 +106,98 @@ describe("REST Integration", () => {
|
||||||
const response = await config.integration.delete(query)
|
const response = await config.integration.delete(query)
|
||||||
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
|
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: HEADERS,
|
||||||
Accept: "application/json",
|
|
||||||
},
|
|
||||||
body: '{"name":"test"}',
|
body: '{"name":"test"}',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("request body", () => {
|
||||||
|
const input = { a: 1, b: 2 }
|
||||||
|
|
||||||
|
it("should allow no body", () => {
|
||||||
|
const output = config.integration.addBody("none", null, {})
|
||||||
|
expect(output.body).toBeUndefined()
|
||||||
|
expect(Object.keys(output.headers).length).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow text body", () => {
|
||||||
|
const output = config.integration.addBody("text", "hello world", {})
|
||||||
|
expect(output.body).toEqual("hello world")
|
||||||
|
// gets added by fetch
|
||||||
|
expect(Object.keys(output.headers).length).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow form data", () => {
|
||||||
|
const FormData = require("form-data")
|
||||||
|
const output = config.integration.addBody("form", input, {})
|
||||||
|
expect(output.body instanceof FormData).toEqual(true)
|
||||||
|
expect(output.body._valueLength).toEqual(2)
|
||||||
|
// gets added by fetch
|
||||||
|
expect(Object.keys(output.headers).length).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow encoded form data", () => {
|
||||||
|
const { URLSearchParams } = require("url")
|
||||||
|
const output = config.integration.addBody("encoded", input, {})
|
||||||
|
expect(output.body instanceof URLSearchParams).toEqual(true)
|
||||||
|
expect(output.body.toString()).toEqual("a=1&b=2")
|
||||||
|
// gets added by fetch
|
||||||
|
expect(Object.keys(output.headers).length).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow JSON", () => {
|
||||||
|
const output = config.integration.addBody("json", input, {})
|
||||||
|
expect(output.body).toEqual(JSON.stringify(input))
|
||||||
|
expect(output.headers["Content-Type"]).toEqual("application/json")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow XML", () => {
|
||||||
|
const output = config.integration.addBody("xml", input, {})
|
||||||
|
expect(output.body.includes("<a>1</a>")).toEqual(true)
|
||||||
|
expect(output.body.includes("<b>2</b>")).toEqual(true)
|
||||||
|
expect(output.headers["Content-Type"]).toEqual("application/xml")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("response", () => {
|
||||||
|
function buildInput(json, text, header) {
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
json: json ? async () => json : undefined,
|
||||||
|
text: text ? async () => text : undefined,
|
||||||
|
headers: { get: key => key === "content-length" ? 100 : header, raw: () => ({ "content-type": header }) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should be able to parse JSON response", async () => {
|
||||||
|
const input = buildInput({a: 1}, null, "application/json")
|
||||||
|
const output = await config.integration.parseResponse(input)
|
||||||
|
expect(output.data).toEqual({a: 1})
|
||||||
|
expect(output.info.code).toEqual(200)
|
||||||
|
expect(output.info.size).toEqual("100B")
|
||||||
|
expect(output.extra.raw).toEqual(JSON.stringify({a: 1}))
|
||||||
|
expect(output.extra.headers["content-type"]).toEqual("application/json")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to parse text response", async () => {
|
||||||
|
const text = "hello world"
|
||||||
|
const input = buildInput(null, text, "text/plain")
|
||||||
|
const output = await config.integration.parseResponse(input)
|
||||||
|
expect(output.data).toEqual(text)
|
||||||
|
expect(output.extra.raw).toEqual(text)
|
||||||
|
expect(output.extra.headers["content-type"]).toEqual("text/plain")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to parse XML response", async () => {
|
||||||
|
const text = "<root><a>1</a><b>2</b></root>"
|
||||||
|
const input = buildInput(null, text, "application/xml")
|
||||||
|
const output = await config.integration.parseResponse(input)
|
||||||
|
expect(output.data).toEqual({a: "1", b: "2"})
|
||||||
|
expect(output.extra.raw).toEqual(text)
|
||||||
|
expect(output.extra.headers["content-type"]).toEqual("application/xml")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("authentication", () => {
|
describe("authentication", () => {
|
||||||
const basicAuth = {
|
const basicAuth = {
|
||||||
_id: "c59c14bd1898a43baa08da68959b24686",
|
_id: "c59c14bd1898a43baa08da68959b24686",
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// when thread starts, make sure it is recorded
|
require("./utils").threadSetup()
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
env.setInThread()
|
|
||||||
const actions = require("../automations/actions")
|
const actions = require("../automations/actions")
|
||||||
const automationUtils = require("../automations/automationUtils")
|
const automationUtils = require("../automations/automationUtils")
|
||||||
const AutomationEmitter = require("../events/AutomationEmitter")
|
const AutomationEmitter = require("../events/AutomationEmitter")
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// when thread starts, make sure it is recorded
|
require("./utils").threadSetup()
|
||||||
const env = require("../environment")
|
|
||||||
env.setInThread()
|
|
||||||
const ScriptRunner = require("../utilities/scriptRunner")
|
const ScriptRunner = require("../utilities/scriptRunner")
|
||||||
const { integrations } = require("../integrations")
|
const { integrations } = require("../integrations")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
const env = require("../environment")
|
||||||
|
const CouchDB = require("../db")
|
||||||
|
const { init } = require("@budibase/auth")
|
||||||
|
|
||||||
|
exports.threadSetup = () => {
|
||||||
|
// don't run this if not threading
|
||||||
|
if (env.isTest() || env.DISABLE_THREADING) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// when thread starts, make sure it is recorded
|
||||||
|
env.setInThread()
|
||||||
|
init(CouchDB)
|
||||||
|
}
|
|
@ -983,10 +983,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@budibase/auth@^1.0.18":
|
"@budibase/auth@^1.0.19-alpha.1":
|
||||||
version "1.0.19"
|
version "1.0.22"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-1.0.19.tgz#b5a8ad51170443d2136d244f51cfe7dbcc0db116"
|
resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-1.0.22.tgz#a93ea2fea46e00138ad3fa129c9ea19b056654e2"
|
||||||
integrity sha512-6H1K80KX8RUseLXD307tKRc+b0B7/b2SZmAYYGq5qrUSdUotydZaZ90pt5pXVdE754duxyc8DlrwmRfri5xu+A==
|
integrity sha512-eHCNEzGl6HxYlMpfRTXBokq2ALTK5f+CDSgJmGaL/jfPc2NlzCI5NoigZUkSrdwDiYZnnWLfDDR4dArYyLlFuA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@techpass/passport-openidconnect" "^0.3.0"
|
"@techpass/passport-openidconnect" "^0.3.0"
|
||||||
aws-sdk "^2.901.0"
|
aws-sdk "^2.901.0"
|
||||||
|
@ -1056,10 +1056,10 @@
|
||||||
svelte-flatpickr "^3.2.3"
|
svelte-flatpickr "^3.2.3"
|
||||||
svelte-portal "^1.0.0"
|
svelte-portal "^1.0.0"
|
||||||
|
|
||||||
"@budibase/bbui@^1.0.19":
|
"@budibase/bbui@^1.0.22":
|
||||||
version "1.0.19"
|
version "1.0.22"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.0.19.tgz#d79c99e8c0adcf24d9b83f00a15eb262ad73a7e2"
|
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.0.22.tgz#ac3bd3a8699bd0be84aac3c5dff9d093e5b08462"
|
||||||
integrity sha512-GhsyqkDjHMvU1MCr7oXKIZi6NOhmkunJ6eAoob8obCLDm+LXC/1Q8ymSuJicctQpDpraaFS7zqQ6vYY9v7kpiQ==
|
integrity sha512-8/5rXEOwkr0OcQD1fn5GpmI3d5dS1cIJBAODjTVtlZrTdacwlz5W2j3zIh+CBG0X7zhVxEze3zs2b1vDNTvK6A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
|
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
|
||||||
"@spectrum-css/actionbutton" "^1.0.1"
|
"@spectrum-css/actionbutton" "^1.0.1"
|
||||||
|
@ -1106,14 +1106,14 @@
|
||||||
svelte-flatpickr "^3.2.3"
|
svelte-flatpickr "^3.2.3"
|
||||||
svelte-portal "^1.0.0"
|
svelte-portal "^1.0.0"
|
||||||
|
|
||||||
"@budibase/client@^1.0.18":
|
"@budibase/client@^1.0.19-alpha.1":
|
||||||
version "1.0.19"
|
version "1.0.22"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-1.0.19.tgz#50ba2ad91ac2fd57c51306b80fbab24a26ba1403"
|
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-1.0.22.tgz#80d6c3fb2b57a050199dde4a4b3e82b221601c25"
|
||||||
integrity sha512-8vAsD7VkLfq9ZrD+QPXGUcj/2D3vGO++IPr0zIKGNVG5FlOLFceQ9b7itExSFWutyVAjK/e/yq56tugnf0S+Fg==
|
integrity sha512-Cpao7l2lIWyJZJs8+zq1wFnQGaWRTDiRG+HkkjvqQZDkZexlo89zWPkY56NBbMT1qAXd6K3zAdRNNKVCBCtOaA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/bbui" "^1.0.19"
|
"@budibase/bbui" "^1.0.22"
|
||||||
"@budibase/standard-components" "^0.9.139"
|
"@budibase/standard-components" "^0.9.139"
|
||||||
"@budibase/string-templates" "^1.0.19"
|
"@budibase/string-templates" "^1.0.22"
|
||||||
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"
|
||||||
|
@ -1163,10 +1163,10 @@
|
||||||
svelte-apexcharts "^1.0.2"
|
svelte-apexcharts "^1.0.2"
|
||||||
svelte-flatpickr "^3.1.0"
|
svelte-flatpickr "^3.1.0"
|
||||||
|
|
||||||
"@budibase/string-templates@^1.0.18", "@budibase/string-templates@^1.0.19":
|
"@budibase/string-templates@^1.0.19-alpha.1", "@budibase/string-templates@^1.0.22":
|
||||||
version "1.0.19"
|
version "1.0.22"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.19.tgz#4b476dfc5d317e56d84a24dffd34715cc74c7b37"
|
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.22.tgz#b795c61e53d541c0aa346a90d04b50dcca6ae117"
|
||||||
integrity sha512-MmSHF2HK3JS3goyNr3mUQi3azt5vSWlmSGlYFyw473jplRVYkmI8wXrP8gVy9mNJ4vksn3bkgFPI8Hi9RoNSbA==
|
integrity sha512-1ZhxzL75kVhP44fJlCWwqmGIPjZol1eB/xi3O11xJPYQ7lfzeJcGUpksvlgbLgBlw+MKkgppK7gEoMP247E0Qw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/handlebars-helpers" "^0.11.7"
|
"@budibase/handlebars-helpers" "^0.11.7"
|
||||||
dayjs "^1.10.4"
|
dayjs "^1.10.4"
|
||||||
|
@ -5829,6 +5829,15 @@ form-data@^3.0.0:
|
||||||
combined-stream "^1.0.8"
|
combined-stream "^1.0.8"
|
||||||
mime-types "^2.1.12"
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
|
form-data@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||||
|
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||||
|
dependencies:
|
||||||
|
asynckit "^0.4.0"
|
||||||
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
formidable@^1.1.1, formidable@^1.2.0:
|
formidable@^1.1.1, formidable@^1.2.0:
|
||||||
version "1.2.6"
|
version "1.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168"
|
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168"
|
||||||
|
@ -13081,7 +13090,7 @@ xml2js@0.4.19:
|
||||||
sax ">=0.6.0"
|
sax ">=0.6.0"
|
||||||
xmlbuilder "~9.0.1"
|
xmlbuilder "~9.0.1"
|
||||||
|
|
||||||
xml2js@^0.4.19, xml2js@^0.4.5:
|
xml2js@^0.4.19, xml2js@^0.4.23, xml2js@^0.4.5:
|
||||||
version "0.4.23"
|
version "0.4.23"
|
||||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
||||||
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/string-templates",
|
"name": "@budibase/string-templates",
|
||||||
"version": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"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": "1.0.19-alpha.2",
|
"version": "1.0.22",
|
||||||
"description": "Budibase background service",
|
"description": "Budibase background service",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -29,8 +29,8 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/auth": "^1.0.19-alpha.2",
|
"@budibase/auth": "^1.0.22",
|
||||||
"@budibase/string-templates": "^1.0.19-alpha.2",
|
"@budibase/string-templates": "^1.0.22",
|
||||||
"@koa/router": "^8.0.0",
|
"@koa/router": "^8.0.0",
|
||||||
"@sentry/node": "^6.0.0",
|
"@sentry/node": "^6.0.0",
|
||||||
"@techpass/passport-openidconnect": "^0.3.0",
|
"@techpass/passport-openidconnect": "^0.3.0",
|
||||||
|
|
Loading…
Reference in New Issue