Merge branch 'master' of github.com:Budibase/budibase into qol-updates

This commit is contained in:
Martin McKeaveney 2021-01-29 15:46:50 +00:00
commit ff490ef843
34 changed files with 430 additions and 169 deletions

View File

@ -34,3 +34,14 @@ jobs:
CI: true CI: true
name: Budibase CI name: Budibase CI
- run: yarn test:e2e:ci - run: yarn test:e2e:ci
- name: Build and Push Staging Docker Image
# Only run on push
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
yarn build:docker:staging
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }}

View File

@ -1,9 +1,15 @@
#!/bin/bash #!/bin/bash
tag=$1
tag=${tag:-latest}
pushd ../../build pushd ../../build
docker-compose build --force app-service docker-compose build --force app-service
docker-compose build --force worker-service docker-compose build --force worker-service
docker tag build_app-service budibase/budibase-apps:latest
docker tag build_app-service budibase/budibase-apps:$tag
docker tag build_worker-service budibase/budibase-worker:$tag
docker push budibase/budibase-apps docker push budibase/budibase-apps
docker tag build_worker-service budibase/budibase-worker:latest
docker push budibase/budibase-worker docker push budibase/budibase-worker
popd popd

View File

@ -1,5 +1,5 @@
{ {
"version": "0.5.3", "version": "0.6.2",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

@ -33,6 +33,7 @@
"format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\"", "format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\"",
"test:e2e": "lerna run cy:test", "test:e2e": "lerna run cy:test",
"test:e2e:ci": "lerna run cy:ci", "test:e2e:ci": "lerna run cy:ci",
"build:docker": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -" "build:docker": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -",
"build:docker:staging": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh staging && cd -"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/builder", "name": "@budibase/builder",
"version": "0.5.3", "version": "0.6.2",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"private": true, "private": true,
"scripts": { "scripts": {
@ -64,9 +64,9 @@
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "^1.55.2", "@budibase/bbui": "^1.55.2",
"@budibase/client": "^0.5.3", "@budibase/client": "^0.6.2",
"@budibase/colorpicker": "^1.0.1", "@budibase/colorpicker": "^1.0.1",
"@budibase/string-templates": "^0.5.3", "@budibase/string-templates": "^0.6.2",
"@budibase/svelte-ag-grid": "^0.0.16", "@budibase/svelte-ag-grid": "^0.0.16",
"@sentry/browser": "5.19.1", "@sentry/browser": "5.19.1",
"@svelteschool/svelte-forms": "^0.7.0", "@svelteschool/svelte-forms": "^0.7.0",

View File

@ -106,6 +106,16 @@ function highlightFeedbackIcon() {
return isFeedbackTimeElapsed(firstRunStr) return isFeedbackTimeElapsed(firstRunStr)
} }
// Opt In/Out
const ifAnalyticsEnabled = func => () => {
if (analyticsEnabled && process.env.POSTHOG_TOKEN) {
return func()
}
}
const disabled = () => posthog.has_opted_out_capturing()
const optIn = () => posthog.opt_in_capturing()
const optOut = () => posthog.opt_out_capturing()
export default { export default {
activate, activate,
identify, identify,
@ -115,4 +125,7 @@ export default {
requestFeedbackOnDeploy, requestFeedbackOnDeploy,
submitFeedback, submitFeedback,
highlightFeedbackIcon, highlightFeedbackIcon,
disabled: ifAnalyticsEnabled(disabled),
optIn: ifAnalyticsEnabled(optIn),
optOut: ifAnalyticsEnabled(optOut),
} }

View File

@ -43,6 +43,7 @@
<Input <Input
value={field.name} value={field.name}
secondary secondary
placeholder="Enter field name"
on:change={fieldNameChanged(field.name)} /> on:change={fieldNameChanged(field.name)} />
<Select <Select
secondary secondary

View File

@ -0,0 +1,41 @@
<script>
export let width = "100"
export let height = "100"
</script>
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
{width}
{height}
viewBox="0 0 2900 2000">
<g id="layer101">
<path
fill="#5b350f"
d="M735 1983 c-137 -19 -322 -95 -431 -175 -138 -103 -250 -315 -284 -542 -24 -161 22 -298 129 -382 123 -97 318 -180 577 -243 l130 -32 29 -67 c41 -94 135 -231 199 -289 292 -267 732 -319 1094 -128 148 79 224 151 418 400 137 176 173 242 228 414 41 130 70 301 70 416 0 236 -146 421 -382 484 -206 56 -392 19 -733 -144 -96 -47 -181 -85 -189 -85 -7 0 -61 46 -119 103 -163 159 -283 231 -433 261 -71 15 -229 19 -303 9z" />
</g>
<g id="layer102">
<path
fill="#406f23"
d="M735 1983 c-137 -19 -322 -95 -431 -175 -138 -103 -250 -315 -284 -542 -24 -161 22 -298 129 -382 123 -97 318 -180 577 -243 l130 -32 29 -67 c41 -94 135 -231 199 -289 292 -267 732 -319 1094 -128 148 79 224 151 418 400 137 176 173 242 228 414 41 130 70 301 70 416 0 236 -146 421 -382 484 -206 56 -392 19 -733 -144 -96 -47 -181 -85 -189 -85 -7 0 -61 46 -119 103 -163 159 -283 231 -433 261 -71 15 -229 19 -303 9z m460 -643 c163 -51 296 -150 329 -246 23 -69 20 -93 -20 -174 -51 -100 -126 -173 -238 -230 l-89 -45 -131 0 c-151 0 -222 18 -323 84 -138 89 -243 264 -243 406 0 62 12 76 120 134 160 85 229 102 405 96 87 -2 139 -9 190 -25z" />
</g>
<g id="layer103">
<path
fill="#c6d821"
d="M2215 1789 c-27 -4 -68 -15 -90 -23 -42 -15 -264 -116 -397 -180 l-77 -38 78 -102 c102 -134 144 -208 175 -305 37 -116 49 -200 44 -309 -7 -157 -46 -218 -175 -278 -94 -44 -178 -56 -313 -43 -108 10 -401 53 -479 70 -24 5 -45 8 -47 6 -2 -2 20 -44 49 -92 67 -115 176 -225 281 -284 87 -49 235 -103 335 -121 91 -16 253 -14 346 5 175 37 269 95 419 264 307 347 422 563 457 859 18 148 9 247 -29 325 -88 179 -340 286 -577 246z" />
<path
fill="#c6d821"
d="M549 1680 c-272 -34 -426 -142 -495 -346 -22 -68 -26 -91 -22 -164 6 -115 32 -173 112 -248 70 -65 236 -153 370 -196 241 -79 722 -172 985 -192 180 -14 343 55 404 170 34 64 30 168 -11 271 -88 223 -245 373 -568 542 -222 116 -379 161 -584 168 -69 2 -155 0 -191 -5z m646 -340 c163 -51 296 -150 329 -246 23 -69 20 -93 -20 -174 -50 -100 -126 -173 -235 -229 -84 -42 -90 -44 -200 -48 -190 -8 -312 37 -434 161 -98 99 -155 221 -155 331 0 62 12 76 120 134 160 85 229 102 405 96 87 -2 139 -9 190 -25z" />
</g>
<g id="layer104">
<path
fill="#f6f654"
d="M2190 1721 c-57 -19 -469 -184 -494 -198 -12 -7 -5 -21 34 -72 28 -35 71 -96 97 -137 l46 -74 69 0 c38 0 83 -6 102 -14 52 -22 105 -75 139 -140 28 -55 32 -70 32 -147 0 -84 -2 -90 -48 -183 -96 -187 -234 -296 -376 -296 -44 0 -80 7 -110 20 -28 13 -65 20 -105 20 -72 0 -264 22 -426 49 -63 10 -117 17 -118 15 -10 -8 59 -113 110 -169 106 -115 238 -183 448 -231 155 -35 313 -29 447 17 78 27 210 117 279 191 82 89 277 353 336 456 92 159 137 344 125 513 -9 117 -37 189 -101 258 -109 116 -332 172 -486 122z" />
<path
fill="#f6f654"
d="M490 1624 c-153 -33 -275 -125 -339 -257 -54 -109 -59 -201 -17 -301 32 -76 164 -189 288 -245 51 -23 260 -91 281 -91 3 0 -21 25 -54 56 -94 91 -150 193 -170 313 -14 90 1 111 123 172 161 81 195 91 343 96 111 5 143 2 215 -16 221 -55 380 -192 380 -327 0 -52 -46 -143 -106 -212 -75 -85 -233 -170 -323 -173 -25 -1 -25 -1 4 -10 140 -43 411 -62 527 -38 142 30 238 125 238 234 0 88 -58 230 -139 337 -105 139 -431 343 -676 423 -161 52 -429 71 -575 39z" />
</g>
</svg>

View File

@ -7,6 +7,7 @@ import S3 from "./S3.svelte"
import Airtable from "./Airtable.svelte" import Airtable from "./Airtable.svelte"
import SqlServer from "./SQLServer.svelte" import SqlServer from "./SQLServer.svelte"
import MySQL from "./MySQL.svelte" import MySQL from "./MySQL.svelte"
import ArangoDB from "./ArangoDB.svelte"
export default { export default {
POSTGRES: Postgres, POSTGRES: Postgres,
@ -18,4 +19,5 @@ export default {
S3: S3, S3: S3,
AIRTABLE: Airtable, AIRTABLE: Airtable,
MYSQL: MySQL, MYSQL: MySQL,
ARANGODB: ArangoDB,
} }

View File

@ -20,10 +20,7 @@
</script> </script>
<div on:click|stopPropagation bind:this={anchor}> <div on:click|stopPropagation bind:this={anchor}>
<TextButton <TextButton text on:click={dropdown.show} active={false}>
text
on:click={dropdown.show}
active={false}>
<Icon name="add" /> <Icon name="add" />
Add Parameters Add Parameters
</TextButton> </TextButton>

View File

@ -1,6 +1,6 @@
<script> <script>
import { notificationStore } from "builderStore/store/notifications" import { notificationStore } from "builderStore/store/notifications"
import { flip } from 'svelte/animate'; import { flip } from "svelte/animate"
import { fly } from "svelte/transition" import { fly } from "svelte/transition"
export let themes = { export let themes = {

View File

@ -33,6 +33,9 @@
parameters: {}, parameters: {},
[EVENT_TYPE_KEY]: actionType.name, [EVENT_TYPE_KEY]: actionType.name,
} }
if (!actions) {
actions = []
}
actions.push(newAction) actions.push(newAction)
selectedAction = newAction selectedAction = newAction
actions = actions actions = actions
@ -73,7 +76,8 @@
<div class="action-container"> <div class="action-container">
<div class="action-header" on:click={selectAction(action)}> <div class="action-header" on:click={selectAction(action)}>
<span class:selected={action === selectedAction}> <span class:selected={action === selectedAction}>
{index + 1}. {action[EVENT_TYPE_KEY]} {index + 1}.
{action[EVENT_TYPE_KEY]}
</span> </span>
</div> </div>
<i <i

View File

@ -34,7 +34,9 @@
})) }))
return [...acc, ...viewsArr] return [...acc, ...viewsArr]
}, []) }, [])
$: queries = $backendUiStore.queries.filter(query => query.queryVerb === "read").map(query => ({ $: queries = $backendUiStore.queries
.filter(query => query.queryVerb === "read")
.map(query => ({
label: query.name, label: query.name,
name: query.name, name: query.name,
tableId: query._id, tableId: query._id,

View File

@ -24,7 +24,7 @@
</script> </script>
<form on:submit|preventDefault> <form on:submit|preventDefault>
<div class="field"> <div class="field">
{#each schemaKeys as field} {#each schemaKeys as field}
<Input <Input
placeholder="Enter {field} name" placeholder="Enter {field} name"
@ -34,7 +34,7 @@
required={schema.fields[field]?.required} required={schema.fields[field]?.required}
bind:value={fields[field]} /> bind:value={fields[field]} />
{/each} {/each}
</div> </div>
</form> </form>
{#if schema.customisable} {#if schema.customisable}
<Editor <Editor

View File

@ -136,7 +136,10 @@
</div> </div>
{#if config} {#if config}
<div class="props"> <div class="props">
<div class="query-type">Query type: <span class="query-type-span">{config[query.queryVerb].type}</span></div> <div class="query-type">
Query type:
<span class="query-type-span">{config[query.queryVerb].type}</span>
</div>
<div class="select"> <div class="select">
<Select primary thin bind:value={query.queryVerb}> <Select primary thin bind:value={query.queryVerb}>
{#each Object.keys(config) as queryVerb} {#each Object.keys(config) as queryVerb}
@ -145,7 +148,9 @@
</Select> </Select>
</div> </div>
</div> </div>
<EditQueryParamsPopover bind:parameters={query.parameters} bindable={false} /> <EditQueryParamsPopover
bind:parameters={query.parameters}
bindable={false} />
{/if} {/if}
</header> </header>
<Spacer extraLarge /> <Spacer extraLarge />
@ -182,7 +187,11 @@
{#each fields as field, idx} {#each fields as field, idx}
<Spacer small /> <Spacer small />
<div class="field"> <div class="field">
<Input outline placeholder="Field Name" type={'text'} bind:value={field.name} /> <Input
outline
placeholder="Field Name"
type={'text'}
bind:value={field.name} />
<Select thin border bind:value={field.type}> <Select thin border bind:value={field.type}>
<option value={''}>Select a field type</option> <option value={''}>Select a field type</option>
<option value={'STRING'}>Text</option> <option value={'STRING'}>Text</option>
@ -206,7 +215,6 @@
{/if} {/if}
<style> <style>
.input { .input {
width: 300px; width: 300px;
} }

View File

@ -20,7 +20,6 @@
} }
</script> </script>
{#if schema} {#if schema}
{#key query._id} {#key query._id}
{#if schema.type === QueryTypes.SQL} {#if schema.type === QueryTypes.SQL}

View File

@ -1,6 +1,7 @@
<script> <script>
import { Input, Label } from "@budibase/bbui" import { Input, Label, TextButton } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import analytics from "analytics" import analytics from "analytics"
@ -10,7 +11,7 @@
if (key === "budibase") { if (key === "budibase") {
const isValid = await analytics.identifyByApiKey(value) const isValid = await analytics.identifyByApiKey(value)
if (!isValid) { if (!isValid) {
// TODO: add validation message notifier.danger("Your API Key is invalid.")
keys = { ...keys } keys = { ...keys }
return return
} }
@ -38,7 +39,10 @@
thin thin
edit edit
value={keys.budibase} value={keys.budibase}
label="Budibase API Key" /> label="Budibase Cloud API Key" />
<TextButton text medium blue href="https://portal.budi.live">
Log in to the Budibase Hosting Portal to get your API Key. →
</TextButton>
<div> <div>
<Label extraSmall grey>Instance ID (Webhooks)</Label> <Label extraSmall grey>Instance ID (Webhooks)</Label>
<span>{$backendUiStore.selectedDatabase._id}</span> <span>{$backendUiStore.selectedDatabase._id}</span>

View File

@ -10,6 +10,8 @@
let hostingInfo let hostingInfo
let selfhosted = false let selfhosted = false
$: analyticsDisabled = analytics.disabled()
async function save() { async function save() {
hostingInfo.type = selfhosted ? HostingTypes.SELF : HostingTypes.CLOUD hostingInfo.type = selfhosted ? HostingTypes.SELF : HostingTypes.CLOUD
if (!selfhosted && hostingInfo._rev) { if (!selfhosted && hostingInfo._rev) {
@ -35,6 +37,14 @@
} }
} }
function toggleAnalytics() {
if (analyticsDisabled) {
analytics.optIn()
} else {
analytics.optOut()
}
}
onMount(async () => { onMount(async () => {
hostingInfo = await hostingStore.actions.fetch() hostingInfo = await hostingStore.actions.fetch()
selfhosted = hostingInfo.type === "self" selfhosted = hostingInfo.type === "self"
@ -59,6 +69,16 @@
<Input bind:value={hostingInfo.selfHostKey} label="Hosting Key" /> <Input bind:value={hostingInfo.selfHostKey} label="Hosting Key" />
<Toggle thin text="HTTPS" bind:checked={hostingInfo.useHttps} /> <Toggle thin text="HTTPS" bind:checked={hostingInfo.useHttps} />
{/if} {/if}
<h5>Analytics</h5>
<p>
If you would like to send analytics that help us make budibase better,
please let us know below.
</p>
<Toggle
thin
text="Send Analytics To Budibase"
checked={!analyticsDisabled}
on:change={toggleAnalytics} />
</ModalContent> </ModalContent>
<style> <style>

View File

@ -22,36 +22,11 @@
//Move this to context="module" once svelte-forms is updated so that it can bind to stores correctly //Move this to context="module" once svelte-forms is updated so that it can bind to stores correctly
const createAppStore = writable({ currentStep: 0, values: {} }) const createAppStore = writable({ currentStep: 0, values: {} })
export let hasKey
export let template export let template
let isApiKeyValid
let lastApiKey let lastApiKey
let fetchApiKeyPromise let fetchApiKeyPromise
const validateApiKey = async apiKey => {
if (isApiKeyValid) return true
if (!apiKey) return false
// make sure we only fetch once, unless API Key is changed
if (isApiKeyValid === undefined || apiKey !== lastApiKey) {
lastApiKey = apiKey
// svelte reactivity was causing a requst to get fired mutiple times
// so, we make everything await the same promise, if one exists
if (!fetchApiKeyPromise) {
fetchApiKeyPromise = analytics.identifyByApiKey(apiKey)
}
isApiKeyValid = await fetchApiKeyPromise
fetchApiKeyPromise = undefined
}
return isApiKeyValid
}
const apiValidation = {
apiKey: string()
.required("Please enter your API key.")
.test("valid-apikey", "This API key is invalid", validateApiKey),
}
const infoValidation = { const infoValidation = {
applicationName: string().required("Your application must have a name."), applicationName: string().required("Your application must have a name."),
} }
@ -66,7 +41,7 @@
let submitting = false let submitting = false
let errors = {} let errors = {}
let validationErrors = {} let validationErrors = {}
let validationSchemas = [apiValidation, infoValidation, userValidation] let validationSchemas = [infoValidation, userValidation]
function buildStep(component) { function buildStep(component) {
return { return {
@ -76,7 +51,7 @@
} }
// steps need to be initialized for cypress from the get go // steps need to be initialized for cypress from the get go
let steps = [buildStep(API), buildStep(Info), buildStep(User)] let steps = [buildStep(Info), buildStep(User)]
onMount(async () => { onMount(async () => {
let hostingInfo = await hostingStore.actions.fetch() let hostingInfo = await hostingStore.actions.fetch()
@ -87,17 +62,11 @@
infoValidation.applicationName = string() infoValidation.applicationName = string()
.required("Your application must have a name.") .required("Your application must have a name.")
.notOneOf(existingAppNames) .notOneOf(existingAppNames)
isApiKeyValid = true
steps = [buildStep(Info), buildStep(User)] steps = [buildStep(Info), buildStep(User)]
validationSchemas = [infoValidation, userValidation] validationSchemas = [infoValidation, userValidation]
} }
}) })
if (hasKey) {
validationSchemas.shift()
steps.shift()
}
// Handles form navigation // Handles form navigation
const back = () => { const back = () => {
if ($createAppStore.currentStep > 0) { if ($createAppStore.currentStep > 0) {
@ -145,11 +114,6 @@
async function createNewApp() { async function createNewApp() {
submitting = true submitting = true
try { try {
// Add API key if there is none.
if (!hasKey) {
await updateKey(["budibase", $createAppStore.values.apiKey])
}
// Create App // Create App
const appResp = await post("/api/applications", { const appResp = await post("/api/applications", {
name: $createAppStore.values.applicationName, name: $createAppStore.values.applicationName,

View File

@ -58,7 +58,6 @@
</div> </div>
</div> </div>
</section> </section>
{/if} {/if}
<style> <style>

View File

@ -17,6 +17,18 @@
$: appId = $store.appId $: appId = $store.appId
async function deployApp() { async function deployApp() {
// Must have cloud or self host API key to deploy
if (!$hostingStore.hostingInfo?.selfHostKey) {
const response = await api.get(`/api/keys/`)
const userKeys = await response.json()
if (!userKeys.budibase) {
notifier.danger(
"No budibase API Keys configured. You must set either a self hosted or cloud API key to deploy your budibase app."
)
}
return
}
const DEPLOY_URL = `/api/deploy` const DEPLOY_URL = `/api/deploy`
try { try {

View File

@ -1,4 +1,5 @@
<script> <script>
import { store } from "builderStore"
import api from "builderStore/api" import api from "builderStore/api"
import AppList from "components/start/AppList.svelte" import AppList from "components/start/AppList.svelte"
import { get } from "builderStore/api" import { get } from "builderStore/api"
@ -35,10 +36,6 @@
hasKey = true hasKey = true
analytics.identify(keys.userId) analytics.identify(keys.userId)
} }
if (!keys.budibase) {
modal.show()
}
} }
function selectTemplate(newTemplate) { function selectTemplate(newTemplate) {

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/client", "name": "@budibase/client",
"version": "0.5.3", "version": "0.6.2",
"license": "MPL-2.0", "license": "MPL-2.0",
"main": "dist/budibase-client.js", "main": "dist/budibase-client.js",
"module": "dist/budibase-client.js", "module": "dist/budibase-client.js",
@ -9,14 +9,14 @@
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"dependencies": { "dependencies": {
"@budibase/string-templates": "^0.5.3", "@budibase/string-templates": "^0.6.2",
"deep-equal": "^2.0.1", "deep-equal": "^2.0.1",
"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"
}, },
"devDependencies": { "devDependencies": {
"@budibase/standard-components": "^0.5.3", "@budibase/standard-components": "^0.6.2",
"@rollup/plugin-commonjs": "^16.0.0", "@rollup/plugin-commonjs": "^16.0.0",
"@rollup/plugin-node-resolve": "^10.0.0", "@rollup/plugin-node-resolve": "^10.0.0",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",

View File

@ -2,9 +2,14 @@
import { writable } from "svelte/store" import { writable } from "svelte/store"
import { setContext, onMount } from "svelte" import { setContext, onMount } from "svelte"
import Component from "./Component.svelte" import Component from "./Component.svelte"
import NotificationDisplay from './NotificationDisplay.svelte' import NotificationDisplay from "./NotificationDisplay.svelte"
import SDK from "../sdk" import SDK from "../sdk"
import { createDataStore, initialise, screenStore, notificationStore } from "../store" import {
createDataStore,
initialise,
screenStore,
notificationStore,
} from "../store"
// Provide contexts // Provide contexts
setContext("sdk", SDK) setContext("sdk", SDK)

View File

@ -1,5 +1,5 @@
<script> <script>
import { flip } from 'svelte/animate'; import { flip } from "svelte/animate"
import { fly } from "svelte/transition" import { fly } from "svelte/transition"
import { getContext } from "svelte" import { getContext } from "svelte"
const { notifications } = getContext("sdk") const { notifications } = getContext("sdk")
@ -11,9 +11,9 @@
info: "#5bc0de", info: "#5bc0de",
default: "#aaaaaa", default: "#aaaaaa",
} }
</script> </script>
<div class="notifications"> <div class="notifications">
{#each $notifications as notification (notification.id)} {#each $notifications as notification (notification.id)}
<div <div
animate:flip animate:flip
@ -24,9 +24,9 @@
{#if notification.icon}<i class={notification.icon} />{/if} {#if notification.icon}<i class={notification.icon} />{/if}
</div> </div>
{/each} {/each}
</div> </div>
<style> <style>
.notifications { .notifications {
position: fixed; position: fixed;
top: 10px; top: 10px;
@ -56,5 +56,4 @@
color: white; color: white;
font-weight: 500; font-weight: 500;
} }
</style> </style>

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/server", "name": "@budibase/server",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "0.5.3", "version": "0.6.2",
"description": "Budibase Web Server", "description": "Budibase Web Server",
"main": "src/electron.js", "main": "src/electron.js",
"repository": { "repository": {
@ -49,13 +49,14 @@
"author": "Budibase", "author": "Budibase",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@budibase/client": "^0.5.3", "@budibase/client": "^0.6.2",
"@budibase/string-templates": "^0.5.3", "@budibase/string-templates": "^0.6.2",
"@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",
"@sentry/node": "^5.19.2", "@sentry/node": "^5.19.2",
"airtable": "^0.10.1", "airtable": "^0.10.1",
"arangojs": "^7.2.0",
"aws-sdk": "^2.767.0", "aws-sdk": "^2.767.0",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"chmodr": "^1.2.0", "chmodr": "^1.2.0",

View File

@ -77,11 +77,21 @@ exports.getLinkDocuments = async function({
} }
params.include_docs = !!includeDocs params.include_docs = !!includeDocs
try { try {
const response = await db.query(getQueryIndex(ViewNames.LINK), params) let linkRows = (await db.query(getQueryIndex(ViewNames.LINK), params)).rows
// filter to get unique entries
const foundIds = []
linkRows = linkRows.filter(link => {
const unique = foundIds.indexOf(link.id) === -1
if (unique) {
foundIds.push(link.id)
}
return unique
})
if (includeDocs) { if (includeDocs) {
return response.rows.map(row => row.doc) return linkRows.map(row => row.doc)
} else { } else {
return response.rows.map(row => row.value) return linkRows.map(row => row.value)
} }
} catch (err) { } catch (err) {
// check if the view doesn't exist, it should for all new instances // check if the view doesn't exist, it should for all new instances

View File

@ -0,0 +1,83 @@
const { Database, aql } = require("arangojs")
const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
const SCHEMA = {
docs: "https://github.com/arangodb/arangojs",
datasource: {
url: {
type: FIELD_TYPES.STRING,
default: "http://localhost:8529",
required: true,
},
username: {
type: FIELD_TYPES.STRING,
default: "root",
required: true,
},
password: {
type: FIELD_TYPES.PASSWORD,
required: true,
},
databaseName: {
type: FIELD_TYPES.STRING,
default: "_system",
required: true,
},
collection: {
type: FIELD_TYPES.STRING,
required: true,
},
},
query: {
read: {
type: QUERY_TYPES.SQL,
},
create: {
type: QUERY_TYPES.JSON,
},
},
}
class ArangoDBIntegration {
constructor(config) {
config.auth = {
username: config.username,
password: config.password,
}
this.config = config
this.client = new Database(config)
}
async read(query) {
try {
const result = await this.client.query(query.sql)
return result.all()
} catch (err) {
console.error("Error querying arangodb", err.message)
throw err
} finally {
this.client.close()
}
}
async create(query) {
const clc = this.client.collection(this.config.collection)
try {
const result = await this.client.query(
aql`INSERT ${query.json} INTO ${clc} RETURN NEW`
)
return result.all()
} catch (err) {
console.error("Error querying arangodb", err.message)
throw err
} finally {
this.client.close()
}
}
}
module.exports = {
schema: SCHEMA,
integration: ArangoDBIntegration,
}

View File

@ -7,6 +7,7 @@ const sqlServer = require("./microsoftSqlServer")
const s3 = require("./s3") const s3 = require("./s3")
const airtable = require("./airtable") const airtable = require("./airtable")
const mysql = require("./mysql") const mysql = require("./mysql")
const arangodb = require("./arangodb")
const DEFINITIONS = { const DEFINITIONS = {
POSTGRES: postgres.schema, POSTGRES: postgres.schema,
@ -18,6 +19,7 @@ const DEFINITIONS = {
S3: s3.schema, S3: s3.schema,
AIRTABLE: airtable.schema, AIRTABLE: airtable.schema,
MYSQL: mysql.schema, MYSQL: mysql.schema,
ARANGODB: arangodb.schema,
} }
const INTEGRATIONS = { const INTEGRATIONS = {
@ -30,6 +32,7 @@ const INTEGRATIONS = {
SQL_SERVER: sqlServer.integration, SQL_SERVER: sqlServer.integration,
AIRTABLE: airtable.integration, AIRTABLE: airtable.integration,
MYSQL: mysql.integration, MYSQL: mysql.integration,
ARANGODB: arangodb.integration,
} }
module.exports = { module.exports = {

View File

@ -947,6 +947,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.8.tgz#fe2012f2355e4ce08bca44aeb3abbb21cf88d33f" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.8.tgz#fe2012f2355e4ce08bca44aeb3abbb21cf88d33f"
integrity sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw== integrity sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==
"@types/node@>=13.13.4":
version "14.14.22"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18"
integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==
"@types/node@>=8.0.0 <15": "@types/node@>=8.0.0 <15":
version "14.14.20" version "14.14.20"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.20.tgz#f7974863edd21d1f8a494a73e8e2b3658615c340" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.20.tgz#f7974863edd21d1f8a494a73e8e2b3658615c340"
@ -1278,6 +1283,17 @@ app-builder-lib@22.9.1:
semver "^7.3.2" semver "^7.3.2"
temp-file "^3.3.7" temp-file "^3.3.7"
arangojs@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/arangojs/-/arangojs-7.2.0.tgz#e576926b4b3469c5a130cceba45fada8b5f015d1"
integrity sha512-9mQRCcttaG0lckapNF9TA71ZU7H2ATXK2a1w+0fj+Y4TlTP1bNDMIz3ZN+EnaSgEtwVu0rb6N6Ac97Yd56GmkQ==
dependencies:
"@types/node" ">=13.13.4"
es6-error "^4.0.1"
multi-part "^3.0.0"
x3-linkedlist "1.2.0"
xhr "^2.4.1"
archive-type@^4.0.0: archive-type@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70"
@ -2759,7 +2775,7 @@ es3ify@^0.2.2:
jstransform "~11.0.0" jstransform "~11.0.0"
through "~2.3.4" through "~2.3.4"
es6-error@^4.1.1: es6-error@^4.0.1, es6-error@^4.1.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
@ -3173,6 +3189,11 @@ file-type@^11.1.0:
resolved "https://registry.yarnpkg.com/file-type/-/file-type-11.1.0.tgz#93780f3fed98b599755d846b99a1617a2ad063b8" resolved "https://registry.yarnpkg.com/file-type/-/file-type-11.1.0.tgz#93780f3fed98b599755d846b99a1617a2ad063b8"
integrity sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g== integrity sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==
file-type@^12.1.0:
version "12.4.2"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-12.4.2.tgz#a344ea5664a1d01447ee7fb1b635f72feb6169d9"
integrity sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==
file-type@^3.8.0: file-type@^3.8.0:
version "3.9.0" version "3.9.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
@ -3524,6 +3545,14 @@ global@~4.3.0:
min-document "^2.19.0" min-document "^2.19.0"
process "~0.5.1" process "~0.5.1"
global@~4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
dependencies:
min-document "^2.19.0"
process "^0.11.10"
globals@^11.1.0: globals@^11.1.0:
version "11.12.0" version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@ -5441,11 +5470,19 @@ mime-db@1.44.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
"mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: mime-db@1.45.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
version "1.45.0" version "1.45.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea"
integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==
mime-kind@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/mime-kind/-/mime-kind-3.0.0.tgz#23bb3aba03ed6a1ea8c4f6093a9c7ab7121a9cb2"
integrity sha512-sx9lClVP7GXY2mO3aVDWTQLhfvAdDvNhGi3o3g7+ae3aKaoybeGbEIlnreoRKjrbDpvlPltlkIryxOtatojeXQ==
dependencies:
file-type "^12.1.0"
mime-types "^2.1.24"
mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24: mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24:
version "2.1.27" version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
@ -5453,6 +5490,13 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24:
dependencies: dependencies:
mime-db "1.44.0" mime-db "1.44.0"
mime-types@^2.1.24:
version "2.1.28"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd"
integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==
dependencies:
mime-db "1.45.0"
mime@^1.3.4, mime@^1.4.1: mime@^1.3.4, mime@^1.4.1:
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@ -5549,6 +5593,19 @@ mssql@^6.2.3:
tarn "^1.1.5" tarn "^1.1.5"
tedious "^6.6.2" tedious "^6.6.2"
multi-part-lite@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/multi-part-lite/-/multi-part-lite-1.0.0.tgz#7b86baf8ff83ef20ca13f1269a0f35aec42b9000"
integrity sha512-KxIRbBZZ45hoKX1ROD/19wJr0ql1bef1rE8Y1PCwD3PuNXV42pp7Wo8lEHYuAajoT4vfAFcd3rPjlkyEEyt1nw==
multi-part@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/multi-part/-/multi-part-3.0.0.tgz#2bde386e8c1dcc9f15a2277267a7f5ed13aa0cc0"
integrity sha512-pDbdYQ6DLDxAsD83w9R7r7rlW56cETL7hIB5bCWX7FJYw0K+kL5JwHr0I8tRk9lGeFcAzf+2OEzXWlG/4wCnFw==
dependencies:
mime-kind "^3.0.0"
multi-part-lite "^1.0.0"
mute-stream@0.0.8: mute-stream@0.0.8:
version "0.0.8" version "0.0.8"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
@ -6452,6 +6509,11 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
process@~0.5.1: process@~0.5.1:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
@ -8264,6 +8326,11 @@ ws@^5.2.0:
dependencies: dependencies:
async-limiter "~1.0.0" async-limiter "~1.0.0"
x3-linkedlist@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/x3-linkedlist/-/x3-linkedlist-1.2.0.tgz#c70467559b7c748595f0f79222af1d709402699e"
integrity sha512-mH/YwxpYSKNa8bDNF1yOuZCMuV+K80LtDN8vcLDUAwNazCxptDNsYt+zA/EJeYiGbdtKposhKLZjErGVOR8mag==
xdg-basedir@^4.0.0: xdg-basedir@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
@ -8279,6 +8346,16 @@ xhr@^2.0.1:
parse-headers "^2.0.0" parse-headers "^2.0.0"
xtend "^4.0.0" xtend "^4.0.0"
xhr@^2.4.1:
version "2.6.0"
resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d"
integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==
dependencies:
global "~4.4.0"
is-function "^1.0.1"
parse-headers "^2.0.0"
xtend "^4.0.0"
xml-name-validator@^3.0.0: xml-name-validator@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"

View File

@ -1,3 +0,0 @@
*
!dist/*
!components.json

View File

@ -10,6 +10,11 @@
"start:dev": "sirv public --single --dev", "start:dev": "sirv public --single --dev",
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"files": [
"manifest.json",
"package.json",
"dist"
],
"devDependencies": { "devDependencies": {
"@rollup/plugin-alias": "^3.1.1", "@rollup/plugin-alias": "^3.1.1",
"@rollup/plugin-commonjs": "^16.0.0", "@rollup/plugin-commonjs": "^16.0.0",
@ -29,7 +34,7 @@
"keywords": [ "keywords": [
"svelte" "svelte"
], ],
"version": "0.5.3", "version": "0.6.2",
"license": "MIT", "license": "MIT",
"gitHead": "62ebf3cedcd7e9b2494b4f8cbcfb90927609b491", "gitHead": "62ebf3cedcd7e9b2494b4f8cbcfb90927609b491",
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/string-templates", "name": "@budibase/string-templates",
"version": "0.5.3", "version": "0.6.2",
"description": "Handlebars wrapper for Budibase templating.", "description": "Handlebars wrapper for Budibase templating.",
"main": "dist/bundle.js", "main": "dist/bundle.js",
"module": "dist/bundle.js", "module": "dist/bundle.js",

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/deployment", "name": "@budibase/deployment",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "0.5.3", "version": "0.6.2",
"description": "Budibase Deployment Server", "description": "Budibase Deployment Server",
"main": "src/index.js", "main": "src/index.js",
"repository": { "repository": {