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

View File

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

View File

@ -59,7 +59,9 @@
if (field.name.startsWith("_")) {
errors.push(`field '${field.name}' - name cannot begin with '_''`)
} 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()) {
errors.push("field name cannot be blank")
}
@ -75,9 +77,7 @@
async function saveModel() {
const errors = validate()
if (errors.length > 0) {
notifier.danger(
errors.join("/n")
)
notifier.danger(errors.join("/n"))
return
}

View File

@ -25,69 +25,69 @@
name: "Screen Placeholder",
route: "*",
props: {
"_id": "49c3d0a2-7028-46f0-b004-7eddf62ad01c",
"_component": "@budibase/standard-components/container",
"_styles": {
"normal": {
"padding": "0px",
_id: "49c3d0a2-7028-46f0-b004-7eddf62ad01c",
_component: "@budibase/standard-components/container",
_styles: {
normal: {
padding: "0px",
"font-family": "Roboto",
"border-width": "0",
"border-style": "None",
"text-align": "center"
"text-align": "center",
},
"hover": {},
"active": {},
"selected": {}
hover: {},
active: {},
selected: {},
},
"_code": "",
"className": "",
"onLoad": [],
"type": "div",
"_children": [
_code: "",
className: "",
onLoad: [],
type: "div",
_children: [
{
"_id": "335428f7-f9ca-4acd-9e76-71bc8ad27324",
"_component": "@budibase/standard-components/container",
"_styles": {
"normal": {
"padding": "16px",
_id: "335428f7-f9ca-4acd-9e76-71bc8ad27324",
_component: "@budibase/standard-components/container",
_styles: {
normal: {
padding: "16px",
"border-style": "Dashed",
"border-width": "2px",
"border-color": "#8a8989fa"
"border-color": "#8a8989fa",
},
"hover": {},
"active": {},
"selected": {}
hover: {},
active: {},
selected: {},
},
"_code": "",
"className": "",
"onLoad": [],
"type": "div",
"_instanceId": "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3",
"_instanceName": "Container",
"_children": [
_code: "",
className: "",
onLoad: [],
type: "div",
_instanceId: "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3",
_instanceName: "Container",
_children: [
{
"_id": "ddb6a225-33ba-4ba8-91da-bc6a2697ebf9",
"_component": "@budibase/standard-components/heading",
"_styles": {
"normal": {
"font-family": "Roboto"
_id: "ddb6a225-33ba-4ba8-91da-bc6a2697ebf9",
_component: "@budibase/standard-components/heading",
_styles: {
normal: {
"font-family": "Roboto",
},
"hover": {},
"active": {},
"selected": {}
hover: {},
active: {},
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>
import {buildStyle} from "../helpers.js"
import { buildStyle } from "../helpers.js"
import { fade } from "svelte/transition"
export let backgroundSize = "10px"

View File

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

View File

@ -1,6 +1,6 @@
<script>
import {createEventDispatcher} from "svelte"
import {keyevents} from "../actions"
import { createEventDispatcher } from "svelte"
import { keyevents } from "../actions"
export let text = ""
export let selected = false
@ -8,7 +8,14 @@
const dispatch = createEventDispatcher()
</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>
.flatbutton {
@ -24,7 +31,7 @@
justify-content: center;
align-items: center;
background: #f1f3f4;
outline-color: #003cb0;
outline-color: #003cb0;
outline-width: thin;
}

View File

@ -1,6 +1,6 @@
<script>
import { onMount, createEventDispatcher } from "svelte"
import {drag, keyevents} from "../actions"
import { drag, keyevents } from "../actions"
export let value = 1
export let type = "hue"
@ -21,15 +21,14 @@
let percentageClick = (clickPosition / sliderWidth).toFixed(2)
if (percentageClick >= 0 && percentageClick <= 1) {
let value = type === "hue" ? 360 * percentageClick : percentageClick
dispatch("change", { color: value, isDrag })
}
}
function handleLeftKey() {
let v = value - incrementFactor
if(isWithinLimit(v)) {
if (isWithinLimit(v)) {
value = v
dispatch("change", { color: value })
}
@ -37,13 +36,12 @@
function handleRightKey() {
let v = value + incrementFactor
if(isWithinLimit(v)) {
if (isWithinLimit(v)) {
value = v
dispatch("change", { color: value })
}
}
$: thumbPosition =
type === "hue" ? sliderWidth * (value / 360) : sliderWidth * value
@ -53,7 +51,7 @@
<div
tabindex="0"
bind:this={slider}
use:keyevents={{37: handleLeftKey, 39: handleRightKey}}
use:keyevents={{ 37: handleLeftKey, 39: handleRightKey }}
bind:clientWidth={sliderWidth}
on:click={event => onSliderChange(event.clientX)}
class="color-format-slider"
@ -77,7 +75,7 @@
margin: 10px 0px;
border: 1px solid #e8e8ef;
cursor: pointer;
outline-color: #003cb0;
outline-color: #003cb0;
outline-width: thin;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,49 +1,49 @@
const fs = require("fs")
const AWS = require("aws-sdk")
const fetch = require("node-fetch")
const {
budibaseAppsDir,
} = require("../../../utilities/budibaseDir")
const { budibaseAppsDir } = require("../../../utilities/budibaseDir")
async function invalidateCDN(cfDistribution, appId) {
const cf = new AWS.CloudFront({})
return cf.createInvalidation({
DistributionId: cfDistribution,
InvalidationBatch: {
CallerReference: appId,
Paths: {
Quantity: 1,
Items: [
`/assets/${appId}/*`
]
}
}
}).promise()
return cf
.createInvalidation({
DistributionId: cfDistribution,
InvalidationBatch: {
CallerReference: appId,
Paths: {
Quantity: 1,
Items: [`/assets/${appId}/*`],
},
},
})
.promise()
}
async function fetchTemporaryCredentials() {
const response = await fetch(process.env.DEPLOYMENT_CREDENTIALS_URL, {
method: "POST",
body: JSON.stringify({
apiKey: process.env.BUDIBASE_API_KEY
})
apiKey: process.env.BUDIBASE_API_KEY,
}),
})
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()
return json
}
}
const CONTENT_TYPE_MAP = {
html: "text/html",
css: "text/css",
js: "application/javascript"
};
js: "application/javascript",
}
/**
* Recursively walk a directory tree and execute a callback on all files.
@ -52,9 +52,9 @@ const CONTENT_TYPE_MAP = {
*/
function walkDir(dirPath, callback) {
for (let filename of fs.readdirSync(dirPath)) {
const filePath = `${dirPath}/${filename}`
const filePath = `${dirPath}/${filename}`
const stat = fs.lstatSync(filePath)
if (stat.isFile()) {
callback(filePath)
} else {
@ -63,24 +63,24 @@ function walkDir(dirPath, callback) {
}
}
exports.uploadAppAssets = async function ({ appId }) {
const {
credentials,
accountId,
exports.uploadAppAssets = async function({ appId }) {
const {
credentials,
accountId,
bucket,
cfDistribution,
} = await fetchTemporaryCredentials()
AWS.config.update({
accessKeyId: credentials.AccessKeyId,
accessKeyId: credentials.AccessKeyId,
secretAccessKey: credentials.SecretAccessKey,
sessionToken: credentials.SessionToken
});
sessionToken: credentials.SessionToken,
})
const s3 = new AWS.S3({
params: {
Bucket: bucket
}
Bucket: bucket,
},
})
const appAssetsPath = `${budibaseAppsDir()}/${appId}/public`
@ -94,14 +94,16 @@ exports.uploadAppAssets = async function ({ appId }) {
const fileExtension = [...filePath.split(".")].pop()
const fileBytes = fs.readFileSync(filePath)
const upload = s3.upload({
Key: filePath.replace(appAssetsPath, `assets/${appId}`),
Body: fileBytes,
ContentType: CONTENT_TYPE_MAP[fileExtension],
Metadata: {
accountId
}
}).promise()
const upload = s3
.upload({
Key: filePath.replace(appAssetsPath, `assets/${appId}`),
Body: fileBytes,
ContentType: CONTENT_TYPE_MAP[fileExtension],
Metadata: {
accountId,
},
})
.promise()
uploads.push(upload)
})
@ -109,9 +111,9 @@ exports.uploadAppAssets = async function ({ appId }) {
try {
await Promise.all(uploads)
await invalidateCDN(cfDistribution, appId)
await invalidateCDN(cfDistribution, appId)
} catch (err) {
console.error("Error uploading budibase app assets to s3", err)
throw err
}
}
}

View File

@ -1,35 +1,29 @@
const CouchDB = require("pouchdb")
const PouchDB = require("../../../db")
const {
uploadAppAssets,
} = require("./aws")
const { uploadAppAssets } = require("./aws")
function replicate(local, remote) {
return new Promise((resolve, reject) => {
const replication = local.sync(remote);
const replication = local.sync(remote)
replication.on("complete", () => resolve())
replication.on("error", err => reject(err))
});
})
}
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 localDb = new PouchDB(local)
const remoteDb = new CouchDB(
`${process.env.DEPLOYMENT_COUCH_DB_URL}/${local}`
)
const replications = databases.map(local => {
const localDb = new PouchDB(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)
}
exports.deployApp = async function(ctx) {
@ -37,21 +31,21 @@ exports.deployApp = async function(ctx) {
const clientAppLookupDB = new PouchDB("client_app_lookup")
const { clientId } = await clientAppLookupDB.get(ctx.user.appId)
ctx.log.info(`Uploading assets for appID ${ctx.user.appId} assets to s3..`);
await uploadAppAssets({
ctx.log.info(`Uploading assets for appID ${ctx.user.appId} assets to s3..`)
await uploadAppAssets({
clientId,
appId: ctx.user.appId
appId: ctx.user.appId,
})
// replicate the DB to the couchDB cluster in prod
ctx.log.info("Replicating local PouchDB to remote..");
await replicateCouch(ctx.user.instanceId, clientId);
ctx.log.info("Replicating local PouchDB to remote..")
await replicateCouch(ctx.user.instanceId, clientId)
ctx.body = {
status: "SUCCESS",
completed: Date.now()
ctx.body = {
status: "SUCCESS",
completed: Date.now(),
}
} 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) {
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated";
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"
// default to homedir
const appPath = resolve(
@ -32,7 +32,7 @@ exports.serveApp = async function(ctx) {
if (process.env.CLOUD) {
appId = ctx.subdomains[1]
}
// only set the appId cookie for /appId .. we COULD check for valid appIds
// but would like to avoid that DB hit
const looksLikeAppId = /^[0-9a-f]{32}$/.test(appId)
@ -50,10 +50,11 @@ exports.serveApp = async function(ctx) {
}
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 body = await response.text()
ctx.body = body
ctx.body = body
return
}
@ -62,7 +63,7 @@ exports.serveApp = async function(ctx) {
exports.serveAppAsset = async function(ctx) {
// default to homedir
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated";
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"
const appPath = resolve(
budibaseAppsDir(),
@ -94,11 +95,13 @@ exports.serveComponentLibrary = async function(ctx) {
if (process.env.CLOUD) {
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 body = await response.text()
ctx.type = 'application/javascript'
ctx.body = body;
ctx.type = "application/javascript"
ctx.body = body
return
}

View File

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

View File

@ -29,4 +29,4 @@ module.exports = async port => {
const serverPort = port || env.PORT
const server = http.createServer(app.callback())
return server.listen(serverPort || 4001)
}
}

View File

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

View File

@ -61,11 +61,11 @@ module.exports = async (ctx, next) => {
}
/**
* Return the full access level object either from constants
* Return the full access level object either from constants
* or the database based on the access level ID passed.
*
*
* @param {*} instanceId - instanceId of the user
* @param {*} accessLevelId - the id of the users access level
* @param {*} accessLevelId - the id of the users access level
*/
const getAccessLevel = async (instanceId, accessLevelId) => {
if (

View File

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

View File

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

View File

@ -22,7 +22,7 @@
let record
// 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()
} else {
const id = pathParts[pathParts.length - 1]
@ -48,5 +48,4 @@
})
</script>
<section bind:this={target}>
</section>
<section bind:this={target} />