Merge branch 'master' of github.com:Budibase/budibase into component-sdk

This commit is contained in:
Andrew Kingston 2020-11-18 11:23:06 +00:00
commit aef49616a7
39 changed files with 2420 additions and 1452 deletions

View File

@ -52,6 +52,8 @@ jobs:
mac_certs: ${{ secrets.mac_certs }}
mac_certs_password: ${{ secrets.mac_certs_password }}
windows_certs: ${{ secrets.windows_certs }}
windows_certs_password: ${{ secrets.windows_certs_password }}
# release the app after building
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

View File

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

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
"version": "0.3.6",
"version": "0.3.8",
"license": "AGPL-3.0",
"private": true,
"scripts": {
@ -63,8 +63,8 @@
}
},
"dependencies": {
"@budibase/bbui": "^1.50.1",
"@budibase/client": "^0.3.6",
"@budibase/bbui": "^1.50.2",
"@budibase/client": "^0.3.8",
"@budibase/colorpicker": "^1.0.1",
"@budibase/svelte-ag-grid": "^0.0.16",
"@fortawesome/fontawesome-free": "^5.14.0",

View File

@ -193,8 +193,8 @@ export const getFrontendStore = () => {
)
state.currentComponentInfo = safeProps
screen.props = safeProps
savePromise = store.actions.pages.save()
}
savePromise = store.actions.pages.save()
return state
})
@ -216,14 +216,14 @@ export const getFrontendStore = () => {
if (pageName == null) {
pageName = state.pages.main.name
}
for (let screenToDelete of Array.isArray(screenToDelete)
? screenToDelete
: [screenToDelete]) {
for (let screenToDelete of Array.isArray(screensToDelete)
? screensToDelete
: [screensToDelete]) {
// Remove screen from current page as well
// TODO: Should be done server side
state.pages[pageName]._screens = state.pages[
pageName
]._screens.filter(scr => scr.name !== screenToDelete.name)
]._screens.filter(scr => scr._id !== screenToDelete._id)
deletePromise = api.delete(
`/api/screens/${screenToDelete._id}/${screenToDelete._rev}`
)
@ -277,18 +277,20 @@ export const getFrontendStore = () => {
const pageToSave = page || storeContents.pages[pageName]
// TODO: revisit. This sends down a very weird payload
const response = await api
.post(`/api/pages/${pageToSave._id}`, {
page: {
componentLibraries: storeContents.pages.componentLibraries,
...pageToSave,
},
screens: pageToSave._screens,
})
.then(response => response.json())
const response = await api.post(`/api/pages/${pageToSave._id}`, {
page: {
componentLibraries: storeContents.pages.componentLibraries,
...pageToSave,
},
screens: pageToSave._screens,
})
const json = await response.json()
if (!json.ok) throw new Error("Error updating page")
store.update(state => {
state.pages[pageName]._rev = response.rev
state.pages[pageName]._rev = json.rev
return state
})
},
@ -304,7 +306,6 @@ export const getFrontendStore = () => {
return state
})
},
// addChildComponent
create: (componentToAdd, presetProps) => {
store.update(state => {
function findSlot(component_array) {

View File

@ -2,11 +2,17 @@
import { onMount, onDestroy } from "svelte"
import Spinner from "components/common/Spinner.svelte"
import { slide } from "svelte/transition"
import { Heading, Body, Button, Modal } from "@budibase/bbui"
import { Heading, Body, Button, Modal, ModalContent } from "@budibase/bbui"
import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications"
import CreateWebhookDeploymentModal from "./CreateWebhookDeploymentModal.svelte"
const DeploymentStatus = {
SUCCESS: "SUCCESS",
PENDING: "PENDING",
FAILURE: "FAILURE",
}
const DATE_OPTIONS = {
fullDate: {
weekday: "long",
@ -25,6 +31,8 @@
export let appId
let modal
let errorReasonModal
let errorReason
let poll
let deployments = []
let deploymentUrl = `https://${appId}.app.budi.live/${appId}`
@ -32,10 +40,35 @@
const formatDate = (date, format) =>
Intl.DateTimeFormat("en-GB", DATE_OPTIONS[format]).format(date)
// Required to check any updated deployment statuses between polls
function checkIncomingDeploymentStatus(current, incoming) {
for (let incomingDeployment of incoming) {
if (incomingDeployment.status === DeploymentStatus.FAILURE) {
const currentDeployment = current.find(
deployment => deployment._id === incomingDeployment._id
)
// We have just been notified of an ongoing deployments failure
if (
!currentDeployment ||
currentDeployment.status === DeploymentStatus.PENDING
) {
showErrorReasonModal(incomingDeployment.err)
}
}
}
}
async function fetchDeployments() {
try {
const response = await api.get(`/api/deployments`)
deployments = await response.json()
const json = await response.json()
if (deployments.length > 0) {
checkIncomingDeploymentStatus(deployments, json)
}
deployments = json
} catch (err) {
console.error(err)
clearInterval(poll)
@ -43,7 +76,13 @@
}
}
function showErrorReasonModal(err) {
errorReason = err
errorReasonModal.show()
}
onMount(() => {
fetchDeployments()
poll = setInterval(fetchDeployments, POLL_INTERVAL)
})
@ -55,10 +94,12 @@
<header>
<h4>Deployment History</h4>
<div class="deploy-div">
<a target="_blank" href={`https://${appId}.app.budi.live/${appId}`}>
View Your Deployed App →
</a>
<Button primary on:click={() => modal.show()}>View webhooks</Button>
{#if deployments.some(deployment => deployment.status === DeploymentStatus.SUCCESS)}
<a target="_blank" href={`https://${appId}.app.budi.live/${appId}`}>
View Your Deployed App →
</a>
<Button primary on:click={() => modal.show()}>View webhooks</Button>
{/if}
</div>
</header>
<div class="deployment-list">
@ -77,7 +118,14 @@
<Spinner size="10" />
{/if}
<div class={`deployment-status ${deployment.status}`}>
{deployment.status}
<span>
{deployment.status}
{#if deployment.status === DeploymentStatus.FAILURE}
<i
class="ri-information-line"
on:click={() => showErrorReasonModal(deployment.err)} />
{/if}
</span>
</div>
</div>
</article>
@ -88,6 +136,14 @@
<Modal bind:this={modal} width="30%">
<CreateWebhookDeploymentModal />
</Modal>
<Modal bind:this={errorReasonModal} width="30%">
<ModalContent
title="Deployment Error"
confirmText="OK"
showCancelButton={false}>
{errorReason}
</ModalContent>
</Modal>
<style>
.deployment:nth-child(odd) {
@ -186,5 +242,11 @@
.FAILURE {
color: var(--red);
background: var(--red-light);
cursor: pointer;
}
i {
position: relative;
top: 2px;
}
</style>

View File

@ -68,7 +68,6 @@
flex-direction: row;
justify-content: flex-start;
align-items: center;
z-index: 1;
min-height: 24px;
flex-wrap: wrap;
gap: var(--spacing-l);

View File

@ -7,8 +7,6 @@
export let onChange = () => {}
let boundValue = getValidOptions(value, options)
$: setValue(boundValue)
$: sanitiseOptions(options)
function getValidOptions(selectedOptions, allOptions) {
// Fix the hardcoded default string value
@ -18,17 +16,14 @@
return selectedOptions.filter(val => allOptions.indexOf(val) !== -1)
}
function setValue(val) {
onChange(val)
}
function sanitiseOptions(options) {
boundValue = getValidOptions(value, options)
function setValue(value) {
boundValue = getValidOptions(value.detail, options)
onChange(boundValue)
}
</script>
<div>
<Multiselect extraThin secondary bind:value={boundValue}>
<Multiselect extraThin secondary value={boundValue} on:change={setValue}>
{#each options as option}
<option value={option}>{option}</option>
{/each}

View File

@ -32,11 +32,11 @@
icon="ri-layout-3-line"
text="Master Screen"
withArrow
selected={$store.currentComponentInfo._id === _layout.component.props._id}
opened={$store.currentPreviewItem.name === _layout.title}
selected={$store.currentComponentInfo?._id === _layout.component.props._id}
opened={$store.currentPreviewItem?.name === _layout.title}
on:click={setCurrentScreenToLayout} />
{#if $store.currentPreviewItem.name === _layout.title && _layout.component.props._children}
{#if $store.currentPreviewItem?.name === _layout.title && _layout.component.props._children}
<ComponentsHierarchyChildren
thisComponent={_layout.component.props}
components={_layout.component.props._children}

View File

@ -50,8 +50,8 @@
const isDuplicateName = name => {
let duplicate = false
const lookForDuplicate = rootPops => {
walkProps(rootPops, (inst, cancel) => {
const lookForDuplicate = rootProps => {
walkProps(rootProps, (inst, cancel) => {
if (inst._instanceName === name && inst._id !== componentInstance._id) {
duplicate = true
cancel()
@ -62,7 +62,7 @@
lookForDuplicate($store.pages[$store.currentPageName].props)
if (duplicate) return true
// if viwing screen, check current screen for duplicate
// if viewing screen, check current screen for duplicate
if ($store.currentFrontEndType === "screen") {
lookForDuplicate($store.currentPreviewItem.props)
} else {

View File

@ -188,6 +188,17 @@ export default {
],
},
},
// {
// _component: "@budibase/standard-components/richtext",
// name: "Rich Text",
// description:
// "A component that allows the user to enter long form text.",
// icon: "ri-edit-box-line",
// properties: {
// design: { ...all },
// settings: [],
// },
// },
{
_component: "@budibase/standard-components/datepicker",
name: "Date Picker",

View File

@ -17,19 +17,16 @@
$: appId = $store.appId
async function deployApp() {
loading = true
const DEPLOY_URL = `/api/deploy`
try {
notifier.info("Starting Deployment..")
notifier.info(`Deployment started. Please wait.`)
const response = await api.post(DEPLOY_URL)
const json = await response.json()
if (response.status !== 200) {
throw new Error()
}
notifier.info(`Deployment started. Please wait.`)
loading = false
analytics.captureEvent("Deployed App", {
appId,
})
@ -43,7 +40,6 @@
})
analytics.captureException(err)
notifier.danger("Deployment unsuccessful. Please try again later.")
loading = false
}
}
</script>
@ -51,13 +47,7 @@
<section>
<div>
<h4>It's time to shine!</h4>
<Button secondary medium on:click={deployApp}>
Deploy App
{#if loading}
<Spacer extraSmall />
<Spinner size="10" />
{/if}
</Button>
<Button secondary medium on:click={deployApp}>Deploy App</Button>
</div>
<img
src="/_builder/assets/deploy-rocket.jpg"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/client",
"version": "0.3.6",
"version": "0.3.8",
"license": "MPL-2.0",
"main": "dist/budibase-client.js",
"module": "dist/budibase-client.esm.mjs",

View File

@ -12,7 +12,7 @@ JWT_SECRET={{cookieKey1}}
PORT=4001
# error level for koa-pino
LOG_LEVEL=error
LOG_LEVEL=info
DEPLOYMENT_CREDENTIALS_URL="https://dt4mpwwap8.execute-api.eu-west-1.amazonaws.com/prod/"
DEPLOYMENT_DB_URL="https://couchdb.budi.live:5984"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

0
packages/server/build/entitlements.mac.plist Normal file → Executable file
View File

0
packages/server/build/icon.icns Normal file → Executable file
View File

0
packages/server/build/icon.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,6 +1,7 @@
{
"name": "@budibase/server",
"version": "0.3.6",
"email": "hi@budibase.com",
"version": "0.3.8",
"description": "Budibase Web Server",
"main": "src/electron.js",
"repository": {
@ -8,18 +9,26 @@
"url": "https://github.com/Budibase/budibase.git"
},
"build": {
"icon": "./build/icons/512x512.png",
"appId": "com.budibase.builder",
"productName": "Budibase Builder",
"afterSign": "electron-builder-notarize",
"mac": {
"icon": "./assets/icons/icon.icns",
"category": "public.app-category.developer-tools",
"hardenedRuntime": true
},
"linux": {
"maintainer": "Budibase",
"icon": "./build/icons/",
"target": [
"AppImage"
"AppImage",
"deb"
],
"category": "Development"
},
"extraMetadata": {
"name": "Budibase Builder"
}
},
"scripts": {
@ -38,10 +47,10 @@
"keywords": [
"budibase"
],
"author": "Michael Shanks",
"author": "Budibase",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@budibase/client": "^0.3.6",
"@budibase/client": "^0.3.8",
"@koa/router": "^8.0.0",
"@sendgrid/mail": "^7.1.1",
"@sentry/node": "^5.19.2",
@ -77,7 +86,7 @@
"pouchdb-all-dbs": "^1.0.2",
"pouchdb-replication-stream": "^1.2.9",
"sanitize-s3-objectkey": "^0.0.1",
"squirrelly": "^7.5.0",
"svelte": "^3.29.4",
"tar-fs": "^2.1.0",
"to-json-schema": "^0.2.5",
"uuid": "^3.3.2",
@ -89,7 +98,7 @@
"devDependencies": {
"@jest/test-sequencer": "^24.8.0",
"electron": "10.1.3",
"electron-builder": "^22.7.0",
"electron-builder": "^22.9.1",
"electron-builder-notarize": "^1.1.2",
"eslint": "^6.8.0",
"jest": "^24.8.0",

View File

@ -2,46 +2,11 @@ const fs = require("fs")
const { join } = require("../../../utilities/centralPath")
const AWS = require("aws-sdk")
const fetch = require("node-fetch")
const uuid = require("uuid")
const sanitize = require("sanitize-s3-objectkey")
const { budibaseAppsDir } = require("../../../utilities/budibaseDir")
const PouchDB = require("../../../db")
const env = require("../../../environment")
async function invalidateCDN(cfDistribution, appId) {
const cf = new AWS.CloudFront({})
const resp = await cf
.createInvalidation({
DistributionId: cfDistribution,
InvalidationBatch: {
CallerReference: `${appId}-${uuid.v4()}`,
Paths: {
Quantity: 1,
Items: [`/assets/${appId}/*`],
},
},
})
.promise()
return resp.Invalidation.Id
}
exports.isInvalidationComplete = async function(
distributionId,
invalidationId
) {
if (distributionId == null || invalidationId == null) {
return false
}
const cf = new AWS.CloudFront({})
const resp = await cf
.getInvalidation({
DistributionId: distributionId,
Id: invalidationId,
})
.promise()
return resp.Invalidation.Status === "Completed"
}
/**
* Finalises the deployment, updating the quota for the user API key
* The verification process returns the levels to update to.
@ -90,17 +55,17 @@ exports.verifyDeployment = async function({ appId, quota }) {
}),
})
const json = await response.json()
if (json.errors) {
throw new Error(json.errors)
}
if (response.status !== 200) {
throw new Error(
`Error fetching temporary credentials for api key: ${env.BUDIBASE_API_KEY}`
)
}
const json = await response.json()
if (json.errors) {
throw new Error(json.errors)
}
// set credentials here, means any time we're verified we're ready to go
if (json.credentials) {
AWS.config.update({
@ -162,12 +127,7 @@ async function prepareUploadForS3({ s3Key, metadata, s3, file }) {
exports.prepareUploadForS3 = prepareUploadForS3
exports.uploadAppAssets = async function({
appId,
bucket,
cfDistribution,
accountId,
}) {
exports.uploadAppAssets = async function({ appId, bucket, accountId }) {
const s3 = new AWS.S3({
params: {
Bucket: bucket,
@ -224,8 +184,7 @@ exports.uploadAppAssets = async function({
db.put(fileUploads)
try {
await Promise.all(uploads)
return await invalidateCDN(cfDistribution, appId)
return await Promise.all(uploads)
} catch (err) {
console.error("Error uploading budibase app assets to s3", err)
throw err

View File

@ -4,7 +4,6 @@ const {
uploadAppAssets,
verifyDeployment,
updateDeploymentQuota,
isInvalidationComplete,
} = require("./aws")
const { DocumentTypes, SEPARATOR, UNICODE_MAX } = require("../../../db/utils")
const newid = require("../../../db/newid")
@ -20,53 +19,17 @@ const DeploymentStatus = {
}
// checks that deployments are in a good state, any pending will be updated
async function checkAllDeployments(deployments, user) {
async function checkAllDeployments(deployments) {
let updated = false
function update(deployment, status) {
deployment.status = status
delete deployment.invalidationId
delete deployment.cfDistribution
updated = true
}
for (let deployment of Object.values(deployments.history)) {
// check that no deployments have crashed etc and are now stuck
if (
deployment.status === DeploymentStatus.PENDING &&
Date.now() - deployment.updatedAt > MAX_PENDING_TIME_MS
) {
update(deployment, DeploymentStatus.FAILURE)
}
// if pending but not past failure point need to update them
else if (deployment.status === DeploymentStatus.PENDING) {
let complete = false
try {
complete = await isInvalidationComplete(
deployment.cfDistribution,
deployment.invalidationId
)
} catch (err) {
// system may have restarted, need to re-verify
if (
err !== undefined &&
err.code === "InvalidClientTokenId" &&
deployment.quota
) {
await verifyDeployment({
...user,
quota: deployment.quota,
})
complete = await isInvalidationComplete(
deployment.cfDistribution,
deployment.invalidationId
)
} else {
throw err
}
}
if (complete) {
update(deployment, DeploymentStatus.SUCCESS)
}
deployment.status = status
deployment.err = "Timed out"
updated = true
}
}
return { updated, deployments }
@ -157,7 +120,7 @@ async function deployApp({ appId, deploymentId }) {
console.log(`Uploading assets for appID ${appId} assets to s3..`)
const invalidationId = await uploadAppAssets({
await uploadAppAssets({
appId,
...verification,
})
@ -174,10 +137,9 @@ async function deployApp({ appId, deploymentId }) {
await storeLocalDeploymentHistory({
_id: deploymentId,
appId,
invalidationId,
cfDistribution: verification.cfDistribution,
quota: verification.quota,
status: DeploymentStatus.PENDING,
status: DeploymentStatus.SUCCESS,
})
} catch (err) {
await storeLocalDeploymentHistory({
@ -226,7 +188,7 @@ exports.deployApp = async function(ctx) {
status: DeploymentStatus.PENDING,
})
await deployApp({
deployApp({
...ctx.user,
deploymentId: deployment._id,
})

View File

@ -1,25 +1,28 @@
require("svelte/register")
const send = require("koa-send")
const { resolve, join } = require("../../utilities/centralPath")
const { resolve, join } = require("../../../utilities/centralPath")
const fetch = require("node-fetch")
const fs = require("fs-extra")
const uuid = require("uuid")
const AWS = require("aws-sdk")
const { prepareUploadForS3 } = require("./deploy/aws")
const { prepareUploadForS3 } = require("../deploy/aws")
const handlebars = require("handlebars")
const {
budibaseAppsDir,
budibaseTempDir,
} = require("../../utilities/budibaseDir")
const CouchDB = require("../../db")
const setBuilderToken = require("../../utilities/builder/setBuilderToken")
const fileProcessor = require("../../utilities/fileProcessor")
const { AuthTypes } = require("../../constants")
const env = require("../../environment")
} = require("../../../utilities/budibaseDir")
const CouchDB = require("../../../db")
const setBuilderToken = require("../../../utilities/builder/setBuilderToken")
const fileProcessor = require("../../../utilities/fileProcessor")
const { AuthTypes } = require("../../../constants")
const env = require("../../../environment")
// this was the version before we started versioning the component library
const COMP_LIB_BASE_APP_VERSION = "0.2.5"
exports.serveBuilder = async function(ctx) {
let builderPath = resolve(__dirname, "../../../builder")
let builderPath = resolve(__dirname, "../../../../builder")
if (ctx.file === "index.html") {
await setBuilderToken(ctx)
}
@ -138,30 +141,29 @@ exports.performLocalFileProcessing = async function(ctx) {
}
exports.serveApp = async function(ctx) {
const mainOrAuth =
ctx.auth.authenticated === AuthTypes.APP ? "main" : "unauthenticated"
const App = require("./templates/BudibaseApp.svelte").default
// default to homedir
const appPath = resolve(
budibaseAppsDir(),
ctx.params.appId,
"public",
mainOrAuth
const db = new CouchDB(ctx.params.appId)
const appInfo = await db.get(ctx.params.appId)
const { head, html, css } = App.render({
title: appInfo.name,
pageName:
ctx.auth.authenticated === AuthTypes.APP ? "main" : "unauthenticated",
production: env.CLOUD,
appId: ctx.params.appId,
})
const template = handlebars.compile(
fs.readFileSync(`${__dirname}/templates/app.hbs`, "utf8")
)
const appId = ctx.user.appId
if (env.CLOUD) {
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
return
}
await send(ctx, ctx.file || "index.html", { root: ctx.devPath || appPath })
ctx.body = template({
head,
body: html,
style: css.code,
})
}
exports.serveAttachment = async function(ctx) {

View File

@ -0,0 +1,59 @@
<script>
export let title = ""
export let favicon = ""
export let appId
export let pageName = ""
export let production
export const PRODUCTION_ASSETS_URL = `https://${appId}.app.budi.live`
function publicPath(path) {
if (production) {
return `${PRODUCTION_ASSETS_URL}/assets/${appId}/${pageName}/${path}`
}
return `/assets/${path}`
}
</script>
<svelte:head>
<meta charset="utf8" />
<meta name="viewport" content="width=device-width" />
<title>{title}</title>
<link rel="icon" type="image/png" href={favicon} />
<link rel="stylesheet" href={publicPath('bundle.css')} />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Roboto+Mono" />
<style>
html,
body {
font-family: Inter;
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
*,
*:before,
*:after {
box-sizing: border-box;
}
</style>
</svelte:head>
<body id="app">
<script src={publicPath('clientFrontendDefinition.js')}>
</script>
<script src={publicPath('budibase-client.js')}>
</script>
<script>
loadBudibase()
</script>
</body>

View File

@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
{{{head}}}
</head>
{{{body}}}
</html>

View File

@ -8,6 +8,36 @@ const {
generateRowID,
} = require("../../db/utils")
async function checkForColumnUpdates(db, oldTable, updatedTable) {
let updatedRows
const rename = updatedTable._rename
let deletedColumns = []
if (oldTable && oldTable.schema && updatedTable.schema) {
deletedColumns = Object.keys(oldTable.schema).filter(
colName => updatedTable.schema[colName] == null
)
}
// check for renaming of columns or deleted columns
if (rename || deletedColumns.length !== 0) {
const rows = await db.allDocs(
getRowParams(updatedTable._id, null, {
include_docs: true,
})
)
updatedRows = rows.rows.map(({ doc }) => {
if (rename) {
doc[rename.updated] = doc[rename.old]
delete doc[rename.old]
} else if (deletedColumns.length !== 0) {
deletedColumns.forEach(colName => delete doc[colName])
}
return doc
})
delete updatedTable._rename
}
return updatedRows
}
exports.fetch = async function(ctx) {
const db = new CouchDB(ctx.user.appId)
const body = await db.allDocs(
@ -33,7 +63,6 @@ exports.save = async function(ctx) {
views: {},
...rest,
}
let renameDocs = []
// if the table obj had an _id then it will have been retrieved
let oldTable
@ -65,20 +94,10 @@ exports.save = async function(ctx) {
ctx.throw(400, "Cannot rename a linked column.")
} else if (_rename && tableToSave.primaryDisplay === _rename.old) {
ctx.throw(400, "Cannot rename the display column.")
} else if (_rename) {
const rows = await db.allDocs(
getRowParams(tableToSave._id, null, {
include_docs: true,
})
)
renameDocs = rows.rows.map(({ doc }) => {
doc[_rename.updated] = doc[_rename.old]
delete doc[_rename.old]
return doc
})
delete tableToSave._rename
}
let updatedRows = await checkForColumnUpdates(db, oldTable, tableToSave)
// update schema of non-statistics views when new columns are added
for (let view in tableToSave.views) {
const tableView = tableToSave.views[view]
@ -100,8 +119,8 @@ exports.save = async function(ctx) {
// don't perform any updates until relationships have been
// checked by the updateLinks function
if (renameDocs.length !== 0) {
await db.bulkDocs(renameDocs)
if (updatedRows && updatedRows.length !== 0) {
await db.bulkDocs(updatedRows)
}
const result = await db.post(tableToSave)
tableToSave._rev = result.rev

View File

@ -66,6 +66,8 @@ router.use(async (ctx, next) => {
}
})
router.get("/health", ctx => (ctx.status = 200))
router.use(authRoutes.routes())
router.use(authRoutes.allowedMethods())

View File

@ -38,6 +38,6 @@ function replicateLocal() {
})
}
//replicateLocal()
// replicateLocal()
module.exports = Pouch

View File

@ -49,6 +49,7 @@ async function startApp() {
win = new BrowserWindow({
width: 1920,
height: 1080,
icon: join(__dirname, "..", "build", "icons", "512x512.png"),
})
win.setTitle(APP_TITLE)
win.loadURL(APP_URL)

View File

@ -1,27 +1,63 @@
const { constants, copyFile, writeFile, readFile } = require("fs-extra")
const { join, resolve } = require("../centralPath")
const sqrl = require("squirrelly")
const { convertCssToFiles } = require("./convertCssToFiles")
const publicPath = require("./publicPath")
const { ensureDir, constants, copyFile, writeFile } = require("fs-extra")
const { join } = require("../centralPath")
const { budibaseAppsDir } = require("../budibaseDir")
/**
* Compile all the non-db static web assets that are required for the running of
* a budibase application. This includes CSS, the JSON structure of the DOM and
* the client library, a script responsible for reading the JSON structure
* and rendering the application.
* @param {} appId - id of the application we want to compile static assets for
* @param {*} pageName - name of the page that the assets will be served for
* @param {*} pkg - app package information/metadata
*/
module.exports = async (appId, pageName, pkg) => {
const appPath = join(budibaseAppsDir(), appId)
const pagePath = join(budibaseAppsDir(), appId, "public", pageName)
pkg.screens = pkg.screens || []
await convertCssToFiles(publicPath(appPath, pageName), pkg)
await ensureDir(pagePath)
await buildIndexHtml(appId, pageName, appPath, pkg)
await buildPageCssBundle(pagePath, pkg)
await buildFrontendAppDefinition(appId, pageName, pkg, appPath)
await buildFrontendAppDefinition(pagePath, pkg)
await copyClientLib(appPath, pageName)
await copyClientLib(pagePath)
}
const copyClientLib = async (appPath, pageName) => {
/**
* Reads the _css property of a page and its screens, and creates a singular CSS
* bundle for the page at <appId>/public/<pageName>/bundle.css
* @param {String} publicPagePath - path to the public assets directory of the budibase application
* @param {Object} pkg - app package information
* @param {"main" | "unauthenticated"} pageName - the pagename of the page we are compiling CSS for.
*/
const buildPageCssBundle = async (publicPagePath, pkg) => {
let cssString = ""
for (let screen of pkg.screens || []) {
if (!screen._css) continue
if (screen._css.trim().length === 0) {
delete screen._css
continue
}
cssString += screen._css
}
if (pkg.page._css) cssString += pkg.page._css
writeFile(join(publicPagePath, "bundle.css"), cssString)
}
/**
* Copy the budibase client library and sourcemap from NPM to <appId>/public/<pageName>.
* The client library is then served as a static asset when the budibase application
* is running in preview or prod
* @param {String} pagePath - path to write the client library to
*/
const copyClientLib = async pagePath => {
const sourcepath = require.resolve("@budibase/client")
const destPath = join(publicPath(appPath, pageName), "budibase-client.js")
const destPath = join(pagePath, "budibase-client.js")
await copyFile(sourcepath, destPath, constants.COPYFILE_FICLONE)
@ -32,45 +68,17 @@ const copyClientLib = async (appPath, pageName) => {
)
}
const buildIndexHtml = async (appId, pageName, appPath, pkg) => {
const appPublicPath = publicPath(appPath, pageName)
const stylesheetUrl = s => (s.startsWith("http") ? s : `/${appId}/${s}`)
const templateObj = {
title: pkg.page.title || "Budibase App",
favicon: `${pkg.page.favicon || "/_shared/favicon.png"}`,
stylesheets: (pkg.page.stylesheets || []).map(stylesheetUrl),
screenStyles: pkg.screens.filter(s => s._css).map(s => s._css),
pageStyle: pkg.page._css,
appId,
pageName,
}
const indexHtmlTemplate = await readFile(
resolve(__dirname, "index.template.html"),
"utf8"
)
const indexHtmlPath = join(appPublicPath, "index.html")
const deployableHtmlPath = join(appPublicPath, "index.production.html")
const indexHtml = sqrl.Render(indexHtmlTemplate, templateObj)
const deployableHtml = sqrl.Render(indexHtmlTemplate, {
...templateObj,
production: true,
})
await writeFile(indexHtmlPath, indexHtml, { flag: "w+" })
await writeFile(deployableHtmlPath, deployableHtml, { flag: "w+" })
}
const buildFrontendAppDefinition = async (appId, pageName, pkg) => {
const appPath = join(budibaseAppsDir(), appId)
const appPublicPath = publicPath(appPath, pageName)
const filename = join(appPublicPath, "clientFrontendDefinition.js")
/**
* Build the frontend definition for a budibase application. This includes all page and screen information,
* and is injected into the budibase client library to tell it how to start constructing
* the DOM from components defined in the frontendDefinition.
* @param {String} pagePath - path to the public folder of the page where the definition will be written
* @param {Object} pkg - app package information from which the frontendDefinition will be built.
*/
const buildFrontendAppDefinition = async (pagePath, pkg) => {
const filename = join(pagePath, "clientFrontendDefinition.js")
// Delete CSS code from the page and screens so it's not injected
delete pkg.page._css
for (let screen of pkg.screens) {

View File

@ -1,43 +0,0 @@
const crypto = require("crypto")
const { ensureDir, emptyDir, writeFile } = require("fs-extra")
const { join } = require("../centralPath")
module.exports.convertCssToFiles = async (publicPagePath, pkg) => {
const cssDir = join(publicPagePath, "css")
await ensureDir(cssDir)
await emptyDir(cssDir)
for (let screen of pkg.screens || []) {
if (!screen._css) continue
if (screen._css.trim().length === 0) {
delete screen._css
continue
}
screen._css = await createCssFile(cssDir, screen._css)
}
if (pkg.page._css) {
pkg.page._css = await createCssFile(cssDir, pkg.page._css)
}
}
module.exports.getHashedCssPaths = (cssDir, _css) => {
const fileName =
crypto
.createHash("md5")
.update(_css)
.digest("hex") + ".css"
const filePath = join(cssDir, fileName)
const url = `/css/${fileName}`
return { filePath, url }
}
const createCssFile = async (cssDir, _css) => {
const { filePath, url } = module.exports.getHashedCssPaths(cssDir, _css)
await writeFile(filePath, _css)
return url
}

View File

@ -1,63 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>{{ title }}</title>
<link rel='icon' type='image/png' href='{{ favicon }}'>
<style>
html,
body {
font-family: Inter;
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
*, *:before, *:after {
box-sizing: border-box;
}
</style>
{{ each(options.stylesheets) }}
<link rel='stylesheet' href='{{ @this }}'>
{{ /each }}
{{ each(options.screenStyles) }}
{{ if(options.production) }}
<link rel='stylesheet' href='/assets/{{ appId }}/{{ pageName }}{{ @this }}'>
{{#else}}
<link rel='stylesheet' href='/assets{{ @this }}'>
{{ /if }}
{{ /each }}
{{ if(options.pageStyle) }}
{{ if(options.production) }}
<link rel='stylesheet' href='/assets/{{ appId }}/{{ pageName }}{{ pageStyle }}'>
{{#else}}
<link rel='stylesheet' href='/assets{{ pageStyle }}'>
{{ /if }}
{{ /if }}
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono">
{{ if(options.production) }}
<script src='/assets/{{ appId }}/{{ pageName }}/clientFrontendDefinition.js'></script>
<script src='/assets/{{ appId }}/{{ pageName }}/budibase-client.js'></script>
{{#else}}
<script src='/assets/clientFrontendDefinition.js'></script>
<script src='/assets/budibase-client.js'></script>
{{ /if }}
</head>
<body id="app">
<script>
loadBudibase();
</script>
</body>
</html>

View File

@ -1,3 +0,0 @@
const { join } = require("../centralPath")
module.exports = (appPath, pageName) => join(appPath, "public", pageName)

View File

@ -1,6 +1,6 @@
const { existsSync, readFile, writeFile, ensureDir } = require("fs-extra")
const { join, resolve } = require("./centralPath")
const Sqrl = require("squirrelly")
const handlebars = require("handlebars")
const uuid = require("uuid")
module.exports = async opts => {
@ -31,7 +31,8 @@ const createDevEnvFile = async opts => {
}
)
opts.cookieKey1 = opts.cookieKey1 || uuid.v4()
const config = Sqrl.Render(template, opts)
const envTemplate = handlebars.compile(template)
const config = envTemplate(opts)
await writeFile(destConfigFile, config, { flag: "w+" })
}
}

View File

@ -877,9 +877,9 @@
"@types/node" "*"
"@types/fs-extra@^9.0.1":
version "9.0.2"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.2.tgz#e1e1b578c48e8d08ae7fc36e552b94c6f4621609"
integrity sha512-jp0RI6xfZpi5JL8v7WQwpBEQTq63RqW2kxwTZt+m27LcJqQdPVU1yGnT1ZI4EtCDynQQJtIGyQahkiCGCS7e+A==
version "9.0.4"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.4.tgz#12553138cf0438db9a31cdc8b0a3aa9332eb67aa"
integrity sha512-50GO5ez44lxK5MDH90DYHFFfqxH7+fTqEEnvguQRzJ/tY9qFrMSHLiYHite+F3SNmf7+LHC1eMXojuD+E3Qcyg==
dependencies:
"@types/node" "*"
@ -941,9 +941,9 @@
"@types/yargs-parser" "*"
"@types/yargs@^15.0.5":
version "15.0.8"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.8.tgz#7644904cad7427eb704331ea9bf1ee5499b82e23"
integrity sha512-b0BYzFUzBpOhPjpl1wtAHU994jBeKF4TKVlT7ssFv44T617XNcPdRoG4AzHLVshLzlrF7i3lTelH7UbuNYV58Q==
version "15.0.9"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.9.tgz#524cd7998fe810cdb02f26101b699cccd156ff19"
integrity sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g==
dependencies:
"@types/yargs-parser" "*"
@ -1150,21 +1150,21 @@ app-builder-bin@3.5.10:
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-3.5.10.tgz#4a7f9999fccc0c435b6284ae1366bc76a17c4a7d"
integrity sha512-Jd+GW68lR0NeetgZDo47PdWBEPdnD+p0jEa7XaxjRC8u6Oo/wgJsfKUkORRgr2NpkD19IFKN50P6JYy04XHFLQ==
app-builder-lib@22.8.1:
version "22.8.1"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-22.8.1.tgz#02cd14c0a83d3a758675d28c327731832b2c0bc1"
integrity sha512-D/ac1+vuGIAAwEeTtXl8b+qWl7Gz/IQatFyzYl2ocag/7N8LqUjKzZFJJISQPWt6PFDPDH0oCj8/GMh63aV0yw==
app-builder-lib@22.9.1:
version "22.9.1"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-22.9.1.tgz#ccb8f1a02b628514a5dfab9401fa2a976689415c"
integrity sha512-KfXim/fiNwFW2SKffsjEMdAU7RbbEXn62x5YyXle1b4j9X/wEHW9iwox8De6y0hJdR+/kCC/49lI+VgNwLhV7A==
dependencies:
"7zip-bin" "~5.0.3"
"@develar/schema-utils" "~2.6.5"
async-exit-hook "^2.0.1"
bluebird-lst "^1.0.9"
builder-util "22.8.1"
builder-util "22.9.1"
builder-util-runtime "8.7.2"
chromium-pickle-js "^0.2.0"
debug "^4.2.0"
ejs "^3.1.3"
electron-publish "22.8.1"
debug "^4.3.0"
ejs "^3.1.5"
electron-publish "22.9.1"
fs-extra "^9.0.1"
hosted-git-info "^3.0.5"
is-ci "^2.0.0"
@ -1592,10 +1592,10 @@ builder-util-runtime@8.7.2:
debug "^4.1.1"
sax "^1.2.4"
builder-util@22.8.1:
version "22.8.1"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-22.8.1.tgz#efdfb327dbc22c59aa1e2f55adbe0e771086e839"
integrity sha512-LZG+E1xszMdut5hL5h7RkJQ7yOsQqdhJYgn1wvOP7MmF3MoUPRNDiRodLpYiWlaqZmgYhcfaipR/Mb8F/RqK8w==
builder-util@22.9.1:
version "22.9.1"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-22.9.1.tgz#b7087a5cde477f90d718ca5d7fafb6ae261b16af"
integrity sha512-5hN/XOaYu4ZQUS6F+5CXE6jTo+NAnVqAxDuKGSaHWb9bejfv/rluChTLoY3/nJh7RFjkoyVjvFJv7zQDB1QmHw==
dependencies:
"7zip-bin" "~5.0.3"
"@types/debug" "^4.1.5"
@ -1604,7 +1604,7 @@ builder-util@22.8.1:
bluebird-lst "^1.0.9"
builder-util-runtime "8.7.2"
chalk "^4.1.0"
debug "^4.2.0"
debug "^4.3.0"
fs-extra "^9.0.1"
is-ci "^2.0.0"
js-yaml "^3.14.0"
@ -1799,14 +1799,14 @@ cliui@^5.0.0:
strip-ansi "^5.2.0"
wrap-ansi "^5.1.0"
cliui@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"
wrap-ansi "^7.0.0"
clone-buffer@1.0.0:
version "1.0.0"
@ -2066,7 +2066,7 @@ dateformat@^3.0.3:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0:
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==
@ -2094,6 +2094,13 @@ debug@^3.1.0, debug@^3.2.6:
dependencies:
ms "^2.1.1"
debug@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.0.tgz#efa41cbf14fc9448075367fdaaddf82376da211e"
integrity sha512-jjO6JD2rKfiZQnBoRzhRTbXjHLGLfH+UtGkWLc/UXAh/rzZMyjbgn0NcfFpqT8nd1kTtFnDiJcrIFkq4UKeJVg==
dependencies:
ms "2.1.2"
decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@ -2284,13 +2291,13 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
dmg-builder@22.8.1:
version "22.8.1"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-22.8.1.tgz#9b3bcbbc43e5fed232525d61a5567ea4b66085c3"
integrity sha512-WeGom1moM00gBII6swljl4DQGrlJuEivoUhOmh8U9p1ALgeJL+EiTHbZFERlj8Ejy62xUUjURV+liOxUKmJFWg==
dmg-builder@22.9.1:
version "22.9.1"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-22.9.1.tgz#64647224f37ee47fc9bd01947c21cc010a30511f"
integrity sha512-jc+DAirqmQrNT6KbDHdfEp8D1kD0DBTnsLhwUR3MX+hMBun5bT134LQzpdK0GKvd22GqF8L1Cz/NOgaVjscAXQ==
dependencies:
app-builder-lib "22.8.1"
builder-util "22.8.1"
app-builder-lib "22.9.1"
builder-util "22.9.1"
fs-extra "^9.0.1"
iconv-lite "^0.6.2"
js-yaml "^3.14.0"
@ -2379,7 +2386,7 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
ejs@^3.1.3:
ejs@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b"
integrity sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w==
@ -2395,25 +2402,25 @@ electron-builder-notarize@^1.1.2:
js-yaml "^3.14.0"
read-pkg-up "^7.0.0"
electron-builder@^22.7.0:
version "22.8.1"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.8.1.tgz#84295190dae17b3892df7aa39ac334983aeaea06"
integrity sha512-Hs7KTMq1rGSvT0fwGKXrjbLiJkK6sAKDQooUSwklOkktUgWi4ATjlP0fVE3l8SmS7zcLoww2yDZonSDqxEFhaQ==
electron-builder@^22.9.1:
version "22.9.1"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.9.1.tgz#a2962db6f2757bc01d02489f38fafe0809f68f60"
integrity sha512-GXPt8l5Mxwm1QKYopUM6/Tdh9W3695G6Ax+IFyj5pQ51G4SD5L1uq4/RkPSsOgs3rP7jNSV6g6OfDzdtVufPdA==
dependencies:
"@types/yargs" "^15.0.5"
app-builder-lib "22.8.1"
app-builder-lib "22.9.1"
bluebird-lst "^1.0.9"
builder-util "22.8.1"
builder-util "22.9.1"
builder-util-runtime "8.7.2"
chalk "^4.1.0"
dmg-builder "22.8.1"
dmg-builder "22.9.1"
fs-extra "^9.0.1"
is-ci "^2.0.0"
lazy-val "^1.0.4"
read-config-file "6.0.0"
sanitize-filename "^1.6.3"
update-notifier "^4.1.0"
yargs "^15.4.1"
update-notifier "^4.1.1"
yargs "^16.0.3"
electron-is-dev@^1.0.1, electron-is-dev@^1.1.0, electron-is-dev@^1.2.0:
version "1.2.0"
@ -2428,14 +2435,14 @@ electron-notarize@^0.2.0:
debug "^4.1.1"
fs-extra "^8.1.0"
electron-publish@22.8.1:
version "22.8.1"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-22.8.1.tgz#747e0d7f921cd1808f999713d29f599dbb390c4f"
integrity sha512-zqI66vl7j1CJZJ60J+1ez1tQNQeuqVspW44JvYDa5kZbM5wSFDAJFMK9RWHOqRF1Ezd4LDeiBa4aeTOwOt9syA==
electron-publish@22.9.1:
version "22.9.1"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-22.9.1.tgz#7cc76ac4cc53efd29ee31c1e5facb9724329068e"
integrity sha512-ducLjRJLEeU87FaTCWaUyDjCoLXHkawkltP2zqS/n2PyGke54ZIql0tBuUheht4EpR8AhFbVJ11spSn1gy8r6w==
dependencies:
"@types/fs-extra" "^9.0.1"
bluebird-lst "^1.0.9"
builder-util "22.8.1"
builder-util "22.9.1"
builder-util-runtime "8.7.2"
chalk "^4.1.0"
fs-extra "^9.0.1"
@ -2612,6 +2619,11 @@ es6-error@^4.1.1:
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-goat@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
@ -3247,7 +3259,7 @@ gensync@^1.0.0-beta.1:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
get-caller-file@^2.0.1:
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@ -3537,9 +3549,9 @@ hosted-git-info@^2.1.4:
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
hosted-git-info@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.5.tgz#bea87905ef7317442e8df3087faa3c842397df03"
integrity sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ==
version "3.0.7"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.7.tgz#a30727385ea85acfcee94e0aad9e368c792e036c"
integrity sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==
dependencies:
lru-cache "^6.0.0"
@ -6985,11 +6997,6 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
squirrelly@^7.5.0:
version "7.9.2"
resolved "https://registry.yarnpkg.com/squirrelly/-/squirrelly-7.9.2.tgz#f8b0a08201b73653351afe9f7f24878237d2751a"
integrity sha512-QsLQ43p7/p5LfhqMsUM1PP0DU/YuirA/pZ1RQKU8/qZjWHD8uTblpfPoCVkD9VLrS1jCJ+2gqECv3amlPgrLCA==
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
@ -7235,6 +7242,11 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
svelte@^3.29.4:
version "3.29.4"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.29.4.tgz#d0f80cb58109ef52963855c23496f7153bb2eb7e"
integrity sha512-oW0fGHlyFFMvzRtIvOs84b0fOc0gmZNQcL5Is3hxuTpvaYX3pfd8oHy4KnOvbq4Ca6SG6AHdRMk7OhApTo0NqA==
symbol-tree@^3.2.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
@ -7630,7 +7642,7 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
update-notifier@^4.0.0, update-notifier@^4.1.0:
update-notifier@^4.0.0, update-notifier@^4.1.1:
version "4.1.3"
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3"
integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==
@ -7864,10 +7876,10 @@ wrap-ansi@^5.1.0:
string-width "^3.0.0"
strip-ansi "^5.0.0"
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
@ -7979,6 +7991,11 @@ y18n@^4.0.0:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
y18n@^5.0.2:
version "5.0.5"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18"
integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==
yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
@ -7997,13 +8014,10 @@ yargs-parser@^13.1.2:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^18.1.2:
version "18.1.3"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^20.2.2:
version "20.2.4"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
yargs@^13.2.4, yargs@^13.3.0:
version "13.3.2"
@ -8021,22 +8035,18 @@ yargs@^13.2.4, yargs@^13.3.0:
y18n "^4.0.0"
yargs-parser "^13.1.2"
yargs@^15.4.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
yargs@^16.0.3:
version "16.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.1.0.tgz#fc333fe4791660eace5a894b39d42f851cd48f2a"
integrity sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==
dependencies:
cliui "^6.0.0"
decamelize "^1.2.0"
find-up "^4.1.0"
get-caller-file "^2.0.1"
cliui "^7.0.2"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
require-main-filename "^2.0.0"
set-blocking "^2.0.0"
string-width "^4.2.0"
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^18.1.2"
y18n "^5.0.2"
yargs-parser "^20.2.2"
yauzl@^2.10.0, yauzl@^2.4.2:
version "2.10.0"

View File

@ -174,6 +174,13 @@
"onchange": "event"
}
},
"richtext": {
"name": "Rich Text",
"description": "A component that allows the user to enter long form text.",
"props": {
"value": "string"
}
},
"checkbox": {
"name": "Checkbox",
"bindable": "value",

View File

@ -13,7 +13,7 @@
"dev:builder": "rollup -cw"
},
"devDependencies": {
"@budibase/client": "^0.3.6",
"@budibase/client": "^0.3.8",
"@rollup/plugin-alias": "^3.1.1",
"@rollup/plugin-commonjs": "^16.0.0",
"@rollup/plugin-json": "^4.1.0",
@ -32,7 +32,7 @@
"keywords": [
"svelte"
],
"version": "0.3.6",
"version": "0.3.8",
"license": "MIT",
"gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
"dependencies": {
@ -44,6 +44,7 @@
"fast-sort": "^2.2.0",
"flatpickr": "^4.6.6",
"lodash.debounce": "^4.0.8",
"quill": "^1.3.7",
"svelte-apexcharts": "^1.0.2",
"svelte-flatpickr": "^3.1.0"
}

View File

@ -0,0 +1,34 @@
<script>
import { RichText } from "@budibase/bbui"
export let _bb
export let content = ""
const updateValue = content => {
if (_bb) {
_bb.setBinding("value", content)
}
}
$: updateValue(content)
// Need to determine what options we want to expose.
let options = {
modules: {
toolbar: [
[
{
header: [1, 2, 3, false],
},
],
["bold", "italic", "underline", "strike"],
],
},
placeholder: "Type something...",
theme: "snow",
}
</script>
<RichText bind:content {options} />

View File

@ -5,6 +5,7 @@ export { default as text } from "./Text.svelte"
export { default as heading } from "./Heading.svelte"
export { default as input } from "./Input.svelte"
export { default as textfield } from "./Textfield.svelte"
export { default as richtext } from "./RichText.svelte"
export { default as button } from "./Button.svelte"
export { default as login } from "./Login.svelte"
export { default as link } from "./Link.svelte"