This commit is contained in:
Martin McKeaveney 2020-07-07 21:29:20 +01:00
parent be8311aba2
commit c953fa679a
21 changed files with 167 additions and 167 deletions

View File

@ -36,7 +36,7 @@
class={determineClassName(type)} class={determineClassName(type)}
bind:value bind:value
class:uk-form-danger={errors.length > 0}> class:uk-form-danger={errors.length > 0}>
<option></option> <option />
{#each options as opt} {#each options as opt}
<option value={opt}>{opt}</option> <option value={opt}>{opt}</option>
{/each} {/each}

View File

@ -59,7 +59,9 @@
if (field.name.startsWith("_")) { if (field.name.startsWith("_")) {
errors.push(`field '${field.name}' - name cannot begin with '_''`) errors.push(`field '${field.name}' - name cannot begin with '_''`)
} else if (restrictedFieldNames.includes(field.name)) { } else if (restrictedFieldNames.includes(field.name)) {
errors.push(`field '${field.name}' - is a restricted name, please rename`) errors.push(
`field '${field.name}' - is a restricted name, please rename`
)
} else if (!field.name || !field.name.trim()) { } else if (!field.name || !field.name.trim()) {
errors.push("field name cannot be blank") errors.push("field name cannot be blank")
} }
@ -75,9 +77,7 @@
async function saveModel() { async function saveModel() {
const errors = validate() const errors = validate()
if (errors.length > 0) { if (errors.length > 0) {
notifier.danger( notifier.danger(errors.join("/n"))
errors.join("/n")
)
return return
} }

View File

@ -25,69 +25,69 @@
name: "Screen Placeholder", name: "Screen Placeholder",
route: "*", route: "*",
props: { props: {
"_id": "49c3d0a2-7028-46f0-b004-7eddf62ad01c", _id: "49c3d0a2-7028-46f0-b004-7eddf62ad01c",
"_component": "@budibase/standard-components/container", _component: "@budibase/standard-components/container",
"_styles": { _styles: {
"normal": { normal: {
"padding": "0px", padding: "0px",
"font-family": "Roboto", "font-family": "Roboto",
"border-width": "0", "border-width": "0",
"border-style": "None", "border-style": "None",
"text-align": "center" "text-align": "center",
}, },
"hover": {}, hover: {},
"active": {}, active: {},
"selected": {} selected: {},
}, },
"_code": "", _code: "",
"className": "", className: "",
"onLoad": [], onLoad: [],
"type": "div", type: "div",
"_children": [ _children: [
{ {
"_id": "335428f7-f9ca-4acd-9e76-71bc8ad27324", _id: "335428f7-f9ca-4acd-9e76-71bc8ad27324",
"_component": "@budibase/standard-components/container", _component: "@budibase/standard-components/container",
"_styles": { _styles: {
"normal": { normal: {
"padding": "16px", padding: "16px",
"border-style": "Dashed", "border-style": "Dashed",
"border-width": "2px", "border-width": "2px",
"border-color": "#8a8989fa" "border-color": "#8a8989fa",
}, },
"hover": {}, hover: {},
"active": {}, active: {},
"selected": {} selected: {},
}, },
"_code": "", _code: "",
"className": "", className: "",
"onLoad": [], onLoad: [],
"type": "div", type: "div",
"_instanceId": "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3", _instanceId: "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3",
"_instanceName": "Container", _instanceName: "Container",
"_children": [ _children: [
{ {
"_id": "ddb6a225-33ba-4ba8-91da-bc6a2697ebf9", _id: "ddb6a225-33ba-4ba8-91da-bc6a2697ebf9",
"_component": "@budibase/standard-components/heading", _component: "@budibase/standard-components/heading",
"_styles": { _styles: {
"normal": { normal: {
"font-family": "Roboto" "font-family": "Roboto",
}, },
"hover": {}, hover: {},
"active": {}, active: {},
"selected": {} selected: {},
},
_code: "",
className: "",
text: "Your screens go here",
type: "h1",
_instanceId: "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3",
_instanceName: "Heading",
_children: [],
}, },
"_code": "",
"className": "",
"text": "Your screens go here",
"type": "h1",
"_instanceId": "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3",
"_instanceName": "Heading",
"_children": []
}
]
}
], ],
"_instanceName": "Content Placeholder" },
],
_instanceName: "Content Placeholder",
}, },
} }

View File

@ -1,5 +1,5 @@
<script> <script>
import {buildStyle} from "../helpers.js" import { buildStyle } from "../helpers.js"
import { fade } from "svelte/transition" import { fade } from "svelte/transition"
export let backgroundSize = "10px" export let backgroundSize = "10px"

View File

@ -177,7 +177,6 @@
$: border = v > 90 && s < 5 ? "1px dashed #dedada" : "" $: border = v > 90 && s < 5 ? "1px dashed #dedada" : ""
$: selectedColorStyle = buildStyle({ background: value, border }) $: selectedColorStyle = buildStyle({ background: value, border })
$: hasSwatches = swatches.length > 0 $: hasSwatches = swatches.length > 0
</script> </script>
<Portal> <Portal>

View File

@ -1,6 +1,6 @@
<script> <script>
import {createEventDispatcher} from "svelte" import { createEventDispatcher } from "svelte"
import {keyevents} from "../actions" import { keyevents } from "../actions"
export let text = "" export let text = ""
export let selected = false export let selected = false
@ -8,7 +8,14 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
</script> </script>
<div class="flatbutton" tabindex="0" use:keyevents={{"Enter": () => dispatch("click")}} class:selected on:click>{text}</div> <div
class="flatbutton"
tabindex="0"
use:keyevents={{ Enter: () => dispatch('click') }}
class:selected
on:click>
{text}
</div>
<style> <style>
.flatbutton { .flatbutton {

View File

@ -1,6 +1,6 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte" import { onMount, createEventDispatcher } from "svelte"
import {drag, keyevents} from "../actions" import { drag, keyevents } from "../actions"
export let value = 1 export let value = 1
export let type = "hue" export let type = "hue"
@ -21,7 +21,6 @@
let percentageClick = (clickPosition / sliderWidth).toFixed(2) let percentageClick = (clickPosition / sliderWidth).toFixed(2)
if (percentageClick >= 0 && percentageClick <= 1) { if (percentageClick >= 0 && percentageClick <= 1) {
let value = type === "hue" ? 360 * percentageClick : percentageClick let value = type === "hue" ? 360 * percentageClick : percentageClick
dispatch("change", { color: value, isDrag }) dispatch("change", { color: value, isDrag })
} }
@ -29,7 +28,7 @@
function handleLeftKey() { function handleLeftKey() {
let v = value - incrementFactor let v = value - incrementFactor
if(isWithinLimit(v)) { if (isWithinLimit(v)) {
value = v value = v
dispatch("change", { color: value }) dispatch("change", { color: value })
} }
@ -37,10 +36,9 @@
function handleRightKey() { function handleRightKey() {
let v = value + incrementFactor let v = value + incrementFactor
if(isWithinLimit(v)) { if (isWithinLimit(v)) {
value = v value = v
dispatch("change", { color: value }) dispatch("change", { color: value })
} }
} }
@ -53,7 +51,7 @@
<div <div
tabindex="0" tabindex="0"
bind:this={slider} bind:this={slider}
use:keyevents={{37: handleLeftKey, 39: handleRightKey}} use:keyevents={{ 37: handleLeftKey, 39: handleRightKey }}
bind:clientWidth={sliderWidth} bind:clientWidth={sliderWidth}
on:click={event => onSliderChange(event.clientX)} on:click={event => onSliderChange(event.clientX)}
class="color-format-slider" class="color-format-slider"

View File

@ -27,7 +27,8 @@
animation: false, animation: false,
}) })
$: dropdown && UIkit.util.on(dropdown, "shown", () => (hidden = false)) $: dropdown && UIkit.util.on(dropdown, "shown", () => (hidden = false))
$: noChildrenAllowed = !component || $: noChildrenAllowed =
!component ||
getComponentDefinition($store, component._component).children === false getComponentDefinition($store, component._component).children === false
$: noPaste = !$store.componentToPaste $: noPaste = !$store.componentToPaste

View File

@ -1 +1 @@
<slot/> <slot />

View File

@ -43,7 +43,7 @@
<Button secondary medium on:click={deployApp}> <Button secondary medium on:click={deployApp}>
Deploy App Deploy App
{#if loading} {#if loading}
<Spinner ratio={"0.5"} /> <Spinner ratio={'0.5'} />
{/if} {/if}
</Button> </Button>
{/if} {/if}

View File

@ -15,8 +15,8 @@
// Get the correct screen children. // Get the correct screen children.
const screenChildren = $store.pages[$params.page]._screens.find( const screenChildren = $store.pages[$params.page]._screens.find(
screen => screen =>
(screen.props._instanceName === $params.screen screen.props._instanceName === $params.screen ||
|| screen.props._instanceName === decodeURIComponent($params.screen)) screen.props._instanceName === decodeURIComponent($params.screen)
).props._children ).props._children
findComponent(componentIds, screenChildren) findComponent(componentIds, screenChildren)
} }

View File

@ -1,37 +1,37 @@
const fs = require("fs") const fs = require("fs")
const AWS = require("aws-sdk") const AWS = require("aws-sdk")
const fetch = require("node-fetch") const fetch = require("node-fetch")
const { const { budibaseAppsDir } = require("../../../utilities/budibaseDir")
budibaseAppsDir,
} = require("../../../utilities/budibaseDir")
async function invalidateCDN(cfDistribution, appId) { async function invalidateCDN(cfDistribution, appId) {
const cf = new AWS.CloudFront({}) const cf = new AWS.CloudFront({})
return cf.createInvalidation({ return cf
.createInvalidation({
DistributionId: cfDistribution, DistributionId: cfDistribution,
InvalidationBatch: { InvalidationBatch: {
CallerReference: appId, CallerReference: appId,
Paths: { Paths: {
Quantity: 1, Quantity: 1,
Items: [ Items: [`/assets/${appId}/*`],
`/assets/${appId}/*` },
] },
} })
} .promise()
}).promise()
} }
async function fetchTemporaryCredentials() { async function fetchTemporaryCredentials() {
const response = await fetch(process.env.DEPLOYMENT_CREDENTIALS_URL, { const response = await fetch(process.env.DEPLOYMENT_CREDENTIALS_URL, {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
apiKey: process.env.BUDIBASE_API_KEY apiKey: process.env.BUDIBASE_API_KEY,
}) }),
}) })
if (response.status !== 200) { if (response.status !== 200) {
throw new Error(`Error fetching temporary credentials for api key: ${BUDIBASE_API_KEY}`) throw new Error(
`Error fetching temporary credentials for api key: ${process.env.BUDIBASE_API_KEY}`
)
} }
const json = await response.json() const json = await response.json()
@ -42,8 +42,8 @@ async function fetchTemporaryCredentials() {
const CONTENT_TYPE_MAP = { const CONTENT_TYPE_MAP = {
html: "text/html", html: "text/html",
css: "text/css", css: "text/css",
js: "application/javascript" js: "application/javascript",
}; }
/** /**
* Recursively walk a directory tree and execute a callback on all files. * Recursively walk a directory tree and execute a callback on all files.
@ -63,7 +63,7 @@ function walkDir(dirPath, callback) {
} }
} }
exports.uploadAppAssets = async function ({ appId }) { exports.uploadAppAssets = async function({ appId }) {
const { const {
credentials, credentials,
accountId, accountId,
@ -74,13 +74,13 @@ exports.uploadAppAssets = async function ({ appId }) {
AWS.config.update({ AWS.config.update({
accessKeyId: credentials.AccessKeyId, accessKeyId: credentials.AccessKeyId,
secretAccessKey: credentials.SecretAccessKey, secretAccessKey: credentials.SecretAccessKey,
sessionToken: credentials.SessionToken sessionToken: credentials.SessionToken,
}); })
const s3 = new AWS.S3({ const s3 = new AWS.S3({
params: { params: {
Bucket: bucket Bucket: bucket,
} },
}) })
const appAssetsPath = `${budibaseAppsDir()}/${appId}/public` const appAssetsPath = `${budibaseAppsDir()}/${appId}/public`
@ -94,14 +94,16 @@ exports.uploadAppAssets = async function ({ appId }) {
const fileExtension = [...filePath.split(".")].pop() const fileExtension = [...filePath.split(".")].pop()
const fileBytes = fs.readFileSync(filePath) const fileBytes = fs.readFileSync(filePath)
const upload = s3.upload({ const upload = s3
.upload({
Key: filePath.replace(appAssetsPath, `assets/${appId}`), Key: filePath.replace(appAssetsPath, `assets/${appId}`),
Body: fileBytes, Body: fileBytes,
ContentType: CONTENT_TYPE_MAP[fileExtension], ContentType: CONTENT_TYPE_MAP[fileExtension],
Metadata: { Metadata: {
accountId accountId,
} },
}).promise() })
.promise()
uploads.push(upload) uploads.push(upload)
}) })

View File

@ -1,33 +1,27 @@
const CouchDB = require("pouchdb") const CouchDB = require("pouchdb")
const PouchDB = require("../../../db") const PouchDB = require("../../../db")
const { const { uploadAppAssets } = require("./aws")
uploadAppAssets,
} = require("./aws")
function replicate(local, remote) { function replicate(local, remote) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const replication = local.sync(remote)
const replication = local.sync(remote);
replication.on("complete", () => resolve()) replication.on("complete", () => resolve())
replication.on("error", err => reject(err)) replication.on("error", err => reject(err))
}); })
} }
async function replicateCouch(instanceId, clientId) { async function replicateCouch(instanceId, clientId) {
const databases = [`client_${clientId}`, "client_app_lookup", instanceId]
const databases = [
`client_${clientId}`,
"client_app_lookup",
instanceId
];
const replications = databases.map(local => { const replications = databases.map(local => {
const localDb = new PouchDB(local); const localDb = new PouchDB(local)
const remoteDb = new CouchDB(`${process.env.DEPLOYMENT_COUCH_DB_URL}/${local}`) const remoteDb = new CouchDB(
`${process.env.DEPLOYMENT_COUCH_DB_URL}/${local}`
)
return replicate(localDb, remoteDb); return replicate(localDb, remoteDb)
}); })
await Promise.all(replications) await Promise.all(replications)
} }
@ -37,21 +31,21 @@ exports.deployApp = async function(ctx) {
const clientAppLookupDB = new PouchDB("client_app_lookup") const clientAppLookupDB = new PouchDB("client_app_lookup")
const { clientId } = await clientAppLookupDB.get(ctx.user.appId) const { clientId } = await clientAppLookupDB.get(ctx.user.appId)
ctx.log.info(`Uploading assets for appID ${ctx.user.appId} assets to s3..`); ctx.log.info(`Uploading assets for appID ${ctx.user.appId} assets to s3..`)
await uploadAppAssets({ await uploadAppAssets({
clientId, clientId,
appId: ctx.user.appId appId: ctx.user.appId,
}) })
// replicate the DB to the couchDB cluster in prod // replicate the DB to the couchDB cluster in prod
ctx.log.info("Replicating local PouchDB to remote.."); ctx.log.info("Replicating local PouchDB to remote..")
await replicateCouch(ctx.user.instanceId, clientId); await replicateCouch(ctx.user.instanceId, clientId)
ctx.body = { ctx.body = {
status: "SUCCESS", status: "SUCCESS",
completed: Date.now() completed: Date.now(),
} }
} catch (err) { } catch (err) {
ctx.throw(err.status || 500, `Deployment Failed: ${err.message}`); ctx.throw(err.status || 500, `Deployment Failed: ${err.message}`)
} }
} }

View File

@ -18,7 +18,7 @@ exports.serveBuilder = async function(ctx) {
} }
exports.serveApp = async function(ctx) { exports.serveApp = async function(ctx) {
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"; const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"
// default to homedir // default to homedir
const appPath = resolve( const appPath = resolve(
@ -50,7 +50,8 @@ exports.serveApp = async function(ctx) {
} }
if (process.env.CLOUD) { if (process.env.CLOUD) {
const S3_URL = `https://${appId}.app.budi.live/assets/${appId}/${mainOrAuth}/${ctx.file || "index.production.html"}` const S3_URL = `https://${appId}.app.budi.live/assets/${appId}/${mainOrAuth}/${ctx.file ||
"index.production.html"}`
const response = await fetch(S3_URL) const response = await fetch(S3_URL)
const body = await response.text() const body = await response.text()
ctx.body = body ctx.body = body
@ -62,7 +63,7 @@ exports.serveApp = async function(ctx) {
exports.serveAppAsset = async function(ctx) { exports.serveAppAsset = async function(ctx) {
// default to homedir // default to homedir
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"; const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"
const appPath = resolve( const appPath = resolve(
budibaseAppsDir(), budibaseAppsDir(),
@ -94,11 +95,13 @@ exports.serveComponentLibrary = async function(ctx) {
if (process.env.CLOUD) { if (process.env.CLOUD) {
const appId = ctx.user.appId const appId = ctx.user.appId
const S3_URL = encodeURI(`https://${appId}.app.budi.live/assets/componentlibrary/${ctx.query.library}/dist/index.js`) const S3_URL = encodeURI(
`https://${appId}.app.budi.live/assets/componentlibrary/${ctx.query.library}/dist/index.js`
)
const response = await fetch(S3_URL) const response = await fetch(S3_URL)
const body = await response.text() const body = await response.text()
ctx.type = 'application/javascript' ctx.type = "application/javascript"
ctx.body = body; ctx.body = body
return return
} }

View File

@ -11,7 +11,7 @@ const staticRoutes = require("./static")
const componentRoutes = require("./component") const componentRoutes = require("./component")
const workflowRoutes = require("./workflow") const workflowRoutes = require("./workflow")
const accesslevelRoutes = require("./accesslevel") const accesslevelRoutes = require("./accesslevel")
const deployRoutes = require("./deploy"); const deployRoutes = require("./deploy")
module.exports = { module.exports = {
deployRoutes, deployRoutes,

View File

@ -1,6 +1,4 @@
const { resolve, join } = require("path") const { resolve } = require("path")
const { homedir } = require("os")
async function runServer() { async function runServer() {
const budibaseDir = "~/.budibase" const budibaseDir = "~/.budibase"

View File

@ -70,7 +70,7 @@ const buildIndexHtml = async (config, appId, pageName, appPath, pkg) => {
const indexHtml = sqrl.Render(indexHtmlTemplate, templateObj) const indexHtml = sqrl.Render(indexHtmlTemplate, templateObj)
const deployableHtml = sqrl.Render(indexHtmlTemplate, { const deployableHtml = sqrl.Render(indexHtmlTemplate, {
...templateObj, ...templateObj,
production: true production: true,
}) })
await writeFile(indexHtmlPath, indexHtml, { flag: "w+" }) await writeFile(indexHtmlPath, indexHtml, { flag: "w+" })

View File

@ -32,5 +32,4 @@
}) })
</script> </script>
<section bind:this={target}> <section bind:this={target} />
</section>

View File

@ -22,7 +22,7 @@
let record let record
// if srcdoc, then we assume this is the builder preview // if srcdoc, then we assume this is the builder preview
if(pathParts.length === 0 || pathParts[0] === "srcdoc") { if (pathParts.length === 0 || pathParts[0] === "srcdoc") {
record = await fetchFirstRecord() record = await fetchFirstRecord()
} else { } else {
const id = pathParts[pathParts.length - 1] const id = pathParts[pathParts.length - 1]
@ -48,5 +48,4 @@
}) })
</script> </script>
<section bind:this={target}> <section bind:this={target} />
</section>