1
0
Fork 0
mirror of synced 2024-07-11 01:06:04 +12:00

Merge branch 'develop' of github.com:Budibase/budibase into side-panel

This commit is contained in:
Andrew Kingston 2022-11-22 16:52:09 +00:00
commit c01b9af1f0
81 changed files with 5454 additions and 639 deletions

View file

@ -60,8 +60,6 @@ spec:
secretKeyRef:
name: {{ template "budibase.fullname" . }}
key: jwtSecret
- name: LOG_LEVEL
value: {{ .Values.services.apps.logLevel | default "info" | quote }}
{{ if .Values.services.objectStore.region }}
- name: AWS_REGION
value: {{ .Values.services.objectStore.region }}

View file

@ -124,12 +124,21 @@ http {
}
location /api/backups/ {
# calls to export apps are limited
limit_req zone=ratelimit burst=20 nodelay;
# 1800s timeout for app export requests
proxy_read_timeout 1800s;
proxy_connect_timeout 1800s;
proxy_send_timeout 1800s;
proxy_pass http://app-service;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://$apps:4002;
}
location /api/ {

View file

@ -43,6 +43,24 @@ server {
rewrite ^/worker/(.*)$ /$1 break;
}
location /api/backups/ {
# calls to export apps are limited
limit_req zone=ratelimit burst=20 nodelay;
# 1800s timeout for app export requests
proxy_read_timeout 1800s;
proxy_connect_timeout 1800s;
proxy_send_timeout 1800s;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:4001;
}
location /api/ {
# calls to the API are rate limited with bursting
limit_req zone=ratelimit burst=20 nodelay;

View file

@ -27,12 +27,14 @@ if [[ "${TARGETBUILD}" = "aas" ]]; then
else
DATA_DIR=${DATA_DIR:-/data}
fi
mkdir -p ${DATA_DIR}
# Mount NFS or GCP Filestore if env vars exist for it
if [[ -z ${FILESHARE_IP} && -z ${FILESHARE_NAME} ]]; then
if [[ ! -z ${FILESHARE_IP} && ! -z ${FILESHARE_NAME} ]]; then
echo "Mounting NFS share"
apt update && apt install -y nfs-common nfs-kernel-server
echo "Mount file share ${FILESHARE_IP}:/${FILESHARE_NAME} to ${DATA_DIR}"
mount -o nolock ${FILESHARE_IP}:/${FILESHARE_NAME} ${DATA_DIR}
echo "Mounting completed."
echo "Mounting result: $?"
fi
if [ -f "${DATA_DIR}/.env" ]; then
@ -74,9 +76,9 @@ mkdir -p ${DATA_DIR}/couch/{dbs,views}
mkdir -p ${DATA_DIR}/minio
mkdir -p ${DATA_DIR}/search
chown -R couchdb:couchdb ${DATA_DIR}/couch
redis-server --requirepass $REDIS_PASSWORD &
/opt/clouseau/bin/clouseau &
/minio/minio server ${DATA_DIR}/minio &
redis-server --requirepass $REDIS_PASSWORD > /dev/stdout 2>&1 &
/opt/clouseau/bin/clouseau > /dev/stdout 2>&1 &
/minio/minio server ${DATA_DIR}/minio > /dev/stdout 2>&1 &
/docker-entrypoint.sh /opt/couchdb/bin/couchdb &
/etc/init.d/nginx restart
if [[ ! -z "${CUSTOM_DOMAIN}" ]]; then
@ -85,16 +87,18 @@ if [[ ! -z "${CUSTOM_DOMAIN}" ]]; then
chmod +x /etc/cron.d/certificate-renew
# Request the certbot certificate
/app/letsencrypt/certificate-request.sh ${CUSTOM_DOMAIN}
/etc/init.d/nginx restart
fi
/etc/init.d/nginx restart
pushd app
pm2 start --name app "yarn run:docker"
pm2 start -l /dev/stdout --name app "yarn run:docker"
popd
pushd worker
pm2 start --name worker "yarn run:docker"
pm2 start -l /dev/stdout --name worker "yarn run:docker"
popd
sleep 10
echo "curl to couchdb endpoints"
curl -X PUT ${COUCH_DB_URL}/_users
curl -X PUT ${COUCH_DB_URL}/_replicator
echo "end of runner.sh, sleeping ..."
sleep infinity

View file

@ -1,5 +1,5 @@
{
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"npmClient": "yarn",
"packages": [
"packages/*"

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/backend-core",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Budibase backend core libraries used in server and worker",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
@ -20,7 +20,7 @@
"test:watch": "jest --watchAll"
},
"dependencies": {
"@budibase/types": "2.1.22-alpha.8",
"@budibase/types": "2.1.32-alpha.3",
"@shopify/jest-koa-mocks": "5.0.1",
"@techpass/passport-openidconnect": "0.3.2",
"aws-sdk": "2.1030.0",

View file

@ -0,0 +1,44 @@
exports.UserStatus = {
ACTIVE: "active",
INACTIVE: "inactive",
}
exports.Cookie = {
CurrentApp: "budibase:currentapp",
Auth: "budibase:auth",
Init: "budibase:init",
ACCOUNT_RETURN_URL: "budibase:account:returnurl",
DatasourceAuth: "budibase:datasourceauth",
OIDC_CONFIG: "budibase:oidc:config",
}
exports.Header = {
API_KEY: "x-budibase-api-key",
LICENSE_KEY: "x-budibase-license-key",
API_VER: "x-budibase-api-version",
APP_ID: "x-budibase-app-id",
TYPE: "x-budibase-type",
PREVIEW_ROLE: "x-budibase-role",
TENANT_ID: "x-budibase-tenant-id",
TOKEN: "x-budibase-token",
CSRF_TOKEN: "x-csrf-token",
}
exports.GlobalRoles = {
OWNER: "owner",
ADMIN: "admin",
BUILDER: "builder",
WORKSPACE_MANAGER: "workspace_manager",
}
exports.Config = {
SETTINGS: "settings",
ACCOUNT: "account",
SMTP: "smtp",
GOOGLE: "google",
OIDC: "oidc",
OIDC_LOGOS: "logos_oidc",
}
exports.MAX_VALID_DATE = new Date(2147483647000)
exports.DEFAULT_TENANT_ID = "default"

View file

@ -92,3 +92,4 @@ export const StaticDatabases = {
export const APP_PREFIX = DocumentType.APP + SEPARATOR
export const APP_DEV = DocumentType.APP_DEV + SEPARATOR
export const APP_DEV_PREFIX = APP_DEV
export const BUDIBASE_DATASOURCE_TYPE = "budibase"

View file

@ -6,10 +6,15 @@ import {
DatabaseOpts,
DatabaseQueryOpts,
DatabasePutOpts,
DatabaseCreateIndexOpts,
DatabaseDeleteIndexOpts,
Document,
isDocument,
} from "@budibase/types"
import { getCouchInfo } from "./connections"
import { directCouchCall } from "./utils"
import { getPouchDB } from "./pouchDB"
import { WriteStream, ReadStream } from "fs"
export class DatabaseImpl implements Database {
public readonly name: string
@ -77,12 +82,23 @@ export class DatabaseImpl implements Database {
return this.updateOutput(() => db.get(id))
}
async remove(id?: string, rev?: string) {
async remove(idOrDoc: string | Document, rev?: string) {
const db = await this.checkSetup()
if (!id || !rev) {
let _id: string
let _rev: string
if (isDocument(idOrDoc)) {
_id = idOrDoc._id!
_rev = idOrDoc._rev!
} else {
_id = idOrDoc
_rev = rev!
}
if (!_id || !_rev) {
throw new Error("Unable to remove doc without a valid _id and _rev.")
}
return this.updateOutput(() => db.destroy(id, rev))
return this.updateOutput(() => db.destroy(_id, _rev))
}
async put(document: AnyDocument, opts?: DatabasePutOpts) {
@ -146,34 +162,32 @@ export class DatabaseImpl implements Database {
return this.updateOutput(() => db.compact())
}
private doWithPouchDB(func: string) {
const dbName = this.name
return async (args: any[]) => {
const pouch = getPouchDB(dbName)
// @ts-ignore
return pouch[func](...args)
}
}
// All below functions are in-frequently called, just utilise PouchDB
// for them as it implements them better than we can
async dump(...args: any[]) {
return this.doWithPouchDB("dump")(args)
async dump(stream: WriteStream, opts?: { filter?: any }) {
const pouch = getPouchDB(this.name)
// @ts-ignore
return pouch.dump(stream, opts)
}
async load(...args: any[]) {
return this.doWithPouchDB("load")(args)
async load(stream: ReadStream) {
const pouch = getPouchDB(this.name)
// @ts-ignore
return pouch.load(stream)
}
async createIndex(...args: any[]) {
return this.doWithPouchDB("createIndex")(args)
async createIndex(opts: DatabaseCreateIndexOpts) {
const pouch = getPouchDB(this.name)
return pouch.createIndex(opts)
}
async deleteIndex(...args: any[]) {
return this.doWithPouchDB("createIndex")(args)
async deleteIndex(opts: DatabaseDeleteIndexOpts) {
const pouch = getPouchDB(this.name)
return pouch.deleteIndex(opts)
}
async getIndexes(...args: any[]) {
return this.doWithPouchDB("createIndex")(args)
async getIndexes() {
const pouch = getPouchDB(this.name)
return pouch.getIndexes()
}
}

View file

@ -145,7 +145,9 @@ export const queryView = async <T>(
return docs.length <= 1 ? (docs[0] as T) : (docs as T[])
}
} catch (err: any) {
if (err != null && err.name === "not_found") {
const pouchNotFound = err && err.name === "not_found"
const couchNotFound = err && err.status === 404
if (pouchNotFound || couchNotFound) {
await removeDeprecated(db, viewName)
await createFunc()
return queryView(viewName, params, db, createFunc, opts)

View file

@ -1,12 +1,34 @@
import { AppBackup, AppBackupRestoreEvent, Event } from "@budibase/types"
import {
AppBackup,
AppBackupRestoreEvent,
AppBackupTriggeredEvent,
AppBackupTrigger,
AppBackupType,
Event,
} from "@budibase/types"
import { publishEvent } from "../events"
export async function appBackupRestored(backup: AppBackup) {
const properties: AppBackupRestoreEvent = {
appId: backup.appId,
backupName: backup.name!,
restoreId: backup._id!,
backupCreatedAt: backup.timestamp,
}
await publishEvent(Event.APP_BACKUP_RESTORED, properties)
}
export async function appBackupTriggered(
appId: string,
backupId: string,
type: AppBackupType,
trigger: AppBackupTrigger
) {
const properties: AppBackupTriggeredEvent = {
appId: appId,
backupId,
type,
trigger,
}
await publishEvent(Event.APP_BACKUP_TRIGGERED, properties)
}

View file

@ -51,6 +51,7 @@ function validateDatasource(schema) {
const queryValidator = joi
.object({
type: joi.string().allow(...Object.values(QueryType)),
readable: joi.boolean(),
fields: joi.object().pattern(joi.string(), fieldValidator),
})
.required()

View file

@ -1,7 +1,7 @@
{
"name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"license": "MPL-2.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",
@ -38,7 +38,7 @@
],
"dependencies": {
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
"@budibase/string-templates": "2.1.22-alpha.8",
"@budibase/string-templates": "2.1.32-alpha.3",
"@spectrum-css/actionbutton": "^1.0.1",
"@spectrum-css/actiongroup": "^1.0.1",
"@spectrum-css/avatar": "^3.0.2",
@ -85,5 +85,8 @@
"svelte-flatpickr": "^3.2.3",
"svelte-portal": "^1.0.0"
},
"resolutions": {
"loader-utils": "1.4.1"
},
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc"
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"license": "GPL-3.0",
"private": true,
"scripts": {
@ -71,10 +71,10 @@
}
},
"dependencies": {
"@budibase/bbui": "2.1.22-alpha.8",
"@budibase/client": "2.1.22-alpha.8",
"@budibase/frontend-core": "2.1.22-alpha.8",
"@budibase/string-templates": "2.1.22-alpha.8",
"@budibase/bbui": "2.1.32-alpha.3",
"@budibase/client": "2.1.32-alpha.3",
"@budibase/frontend-core": "2.1.32-alpha.3",
"@budibase/string-templates": "2.1.32-alpha.3",
"@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1",

View file

@ -304,6 +304,8 @@
const newError = {}
if (!external && fieldInfo.name?.startsWith("_")) {
newError.name = `Column name cannot start with an underscore.`
} else if (fieldInfo.name && !fieldInfo.name.match(/^[_a-zA-Z0-9\s]*$/g)) {
newError.name = `Illegal character; must be alpha-numeric.`
} else if (PROHIBITED_COLUMN_NAMES.some(name => fieldInfo.name === name)) {
newError.name = `${PROHIBITED_COLUMN_NAMES.join(
", "

View file

@ -97,7 +97,7 @@
}
function fieldOptions(field) {
return schema[field]?.type === "options"
return schema[field]?.type === "options" || schema[field]?.type === "array"
? schema[field]?.constraints.inclusion
: [true, false]
}

View file

@ -2,7 +2,7 @@
import { onMount } from "svelte"
import { get } from "svelte/store"
import { goto, params } from "@roxi/routify"
import { BUDIBASE_INTERNAL_DB } from "constants"
import { BUDIBASE_INTERNAL_DB_ID } from "constants/backend"
import { database, datasources, queries, tables, views } from "stores/backend"
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
@ -129,7 +129,7 @@
size="18"
/>
</div>
{#if datasource._id !== BUDIBASE_INTERNAL_DB}
{#if datasource._id !== BUDIBASE_INTERNAL_DB_ID}
<EditDatasourcePopover {datasource} />
{/if}
</NavItem>

View file

@ -10,10 +10,23 @@
Divider,
Layout,
} from "@budibase/bbui"
import { datasources } from "stores/backend"
import TableDataImport from "../TableDataImport.svelte"
import {
BUDIBASE_INTERNAL_DB_ID,
BUDIBASE_DATASOURCE_TYPE,
} from "constants/backend"
import { buildAutoColumn, getAutoColumnInformation } from "builderStore/utils"
$: tableNames = $tables.list.map(table => table.name)
$: selectedSource = $datasources.list.find(
source => source._id === $datasources.selected
)
$: isSelectedInternal = selectedSource?.type === BUDIBASE_DATASOURCE_TYPE
$: targetDatasourceId = isSelectedInternal
? selectedSource._id
: BUDIBASE_INTERNAL_DB_ID
export let name
let dataImport
@ -45,7 +58,7 @@
schema: addAutoColumns(name, dataImport.schema || {}),
dataImport,
type: "internal",
sourceId: "bb_internal",
sourceId: targetDatasourceId,
}
// Only set primary display if defined

View file

@ -19,6 +19,7 @@ import FormFieldSelect from "./controls/FormFieldSelect.svelte"
import ValidationEditor from "./controls/ValidationEditor/ValidationEditor.svelte"
import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte"
import ColumnEditor from "./controls/ColumnEditor/ColumnEditor.svelte"
import BasicColumnEditor from "./controls/ColumnEditor/BasicColumnEditor.svelte"
import BarButtonList from "./controls/BarButtonList.svelte"
const componentMap = {
@ -43,6 +44,7 @@ const componentMap = {
filter: FilterEditor,
url: URLSelect,
columns: ColumnEditor,
"columns/basic": BasicColumnEditor,
"field/sortable": SortableFieldSelect,
"field/string": FormFieldSelect,
"field/number": FormFieldSelect,

View file

@ -23,14 +23,18 @@
export let bindings = []
export let nested
$: showAvailableActions = !actions?.length
let actionQuery
$: parsedQuery =
typeof actionQuery === "string" ? actionQuery.toLowerCase().trim() : ""
let selectedAction = actions?.length ? actions[0] : null
$: {
// Ensure parameters object is never null
if (selectedAction && !selectedAction.parameters) {
selectedAction.parameters = {}
}
}
$: parsedQuery =
typeof actionQuery === "string" ? actionQuery.toLowerCase().trim() : ""
$: showAvailableActions = !actions?.length
$: mappedActionTypes = actionTypes.reduce((acc, action) => {
let parsedName = action.name.toLowerCase().trim()
if (parsedQuery.length && parsedName.indexOf(parsedQuery) < 0) {
@ -40,7 +44,6 @@
acc[action.type].push(action)
return acc
}, {})
// These are ephemeral bindings which only exist while executing actions
$: eventContexBindings = getEventContextBindings(
$currentAsset,
@ -50,9 +53,8 @@
selectedAction?.id
)
$: allBindings = eventContexBindings.concat(bindings)
// Assign a unique ID to each action
$: {
// Ensure each action has a unique ID
if (actions) {
actions.forEach(action => {
if (!action.id) {
@ -61,13 +63,11 @@
})
}
}
$: selectedActionComponent =
selectedAction &&
actionTypes.find(t => t.name === selectedAction[EVENT_TYPE_KEY])?.component
// Select the first action if we delete an action
$: {
// Select the first action if we delete an action
if (selectedAction && !actions?.includes(selectedAction)) {
selectedAction = actions?.[0]
}

View file

@ -1,14 +1,16 @@
<script>
import { Label, Body } from "@budibase/bbui"
import { Label } from "@budibase/bbui"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
export let parameters
export let bindings = []
</script>
<Body size="S">Navigate To screen, or leave blank.</Body>
<br />
<div class="root">
<span>
You can optionally navigate to another screen after closing the screen
modal.
</span>
<Label small>Screen</Label>
<DrawerBindableInput
title="Destination URL"
@ -20,6 +22,9 @@
</div>
<style>
span {
grid-column: 1 / 3;
}
.root {
display: grid;
align-items: center;

View file

@ -3,7 +3,10 @@
import { datasources, integrations, queries } from "stores/backend"
import BindingBuilder from "components/integration/QueryBindingBuilder.svelte"
import IntegrationQueryEditor from "components/integration/index.svelte"
import { BUDIBASE_DATASOURCE_ID } from "constants/backend"
import {
BUDIBASE_INTERNAL_DB_ID,
BUDIBASE_DATASOURCE_TYPE,
} from "constants/backend"
export let parameters
export let bindings = []
@ -14,7 +17,8 @@
)
// Executequery must exclude budibase datasource
$: executeQueryDatasources = $datasources.list.filter(
x => x._id !== BUDIBASE_DATASOURCE_ID
x =>
x._id !== BUDIBASE_INTERNAL_DB_ID && x.type !== BUDIBASE_DATASOURCE_TYPE
)
function fetchQueryDefinition(query) {

View file

@ -0,0 +1,10 @@
<script>
import ColumnEditor from "./ColumnEditor.svelte"
</script>
<ColumnEditor
{...$$props}
on:change
allowCellEditing={false}
subject="Dynamic Filter"
/>

View file

@ -17,6 +17,7 @@
export let columns = []
export let options = []
export let schema = {}
export let allowCellEditing = true
const flipDurationMs = 150
let dragDisabled = true
@ -123,7 +124,9 @@
on:change={e => (column.displayName = e.detail)}
/>
<Input bind:value={column.displayName} placeholder="Label" />
<CellEditor bind:column />
{#if allowCellEditing}
<CellEditor bind:column />
{/if}
<Icon
name="Close"
hoverable

View file

@ -11,6 +11,8 @@
export let componentInstance
export let value = []
export let allowCellEditing = true
export let subject = "Table"
const dispatch = createEventDispatcher()
@ -68,10 +70,16 @@
</script>
<ActionButton on:click={open}>Configure columns</ActionButton>
<Drawer bind:this={drawer} title="Table Columns">
<Drawer bind:this={drawer} title="{subject} Columns">
<svelte:fragment slot="description">
Configure the columns in your table.
Configure the columns in your {subject.toLowerCase()}.
</svelte:fragment>
<Button cta slot="buttons" on:click={save}>Save</Button>
<ColumnDrawer slot="body" bind:columns={boundValue} {options} {schema} />
<ColumnDrawer
slot="body"
bind:columns={boundValue}
{options}
{schema}
{allowCellEditing}
/>
</Drawer>

View file

@ -1,6 +1,12 @@
<script>
import { writable, get as svelteGet } from "svelte/store"
import { notifications, Input, ModalContent, Dropzone } from "@budibase/bbui"
import {
notifications,
Input,
ModalContent,
Dropzone,
Toggle,
} from "@budibase/bbui"
import { store, automationStore } from "builderStore"
import { API } from "api"
import { apps, admin, auth } from "stores/portal"
@ -16,6 +22,7 @@
let creating = false
let defaultAppName
let includeSampleDB = true
const values = writable({ name: "", url: null })
const validation = createValidationStore()
@ -98,6 +105,8 @@
data.append("templateName", template.name)
data.append("templateKey", template.key)
data.append("templateFile", $values.file)
} else {
data.append("sampleData", includeSampleDB)
}
// Create App
@ -192,6 +201,15 @@
</div>
{/if}
</span>
{#if !template && !template?.fromFile}
<span>
<Toggle
text="Include sample data"
bind:value={includeSampleDB}
disabled={creating}
/>
</span>
{/if}
</ModalContent>
<style>

View file

@ -173,7 +173,8 @@ export const SWITCHABLE_TYPES = [
...ALLOWABLE_NUMBER_TYPES,
]
export const BUDIBASE_DATASOURCE_ID = "bb_internal"
export const BUDIBASE_INTERNAL_DB_ID = "bb_internal"
export const BUDIBASE_DATASOURCE_TYPE = "budibase"
export const IntegrationTypes = {
POSTGRES: "POSTGRES",

View file

@ -43,8 +43,6 @@ export const LAYOUT_NAMES = {
},
}
export const BUDIBASE_INTERNAL_DB = "bb_internal"
// one or more word characters and whitespace
export const APP_NAME_REGEX = /^[\w\s]+$/
// zero or more non-whitespace characters

View file

@ -1,7 +1,6 @@
<script>
import { redirect, params } from "@roxi/routify"
import { redirect } from "@roxi/routify"
import { Button, Tabs, Tab, Layout } from "@budibase/bbui"
import { BUDIBASE_INTERNAL_DB } from "constants"
import DatasourceNavigator from "components/backend/DatasourceNavigator/DatasourceNavigator.svelte"
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte"
@ -9,10 +8,6 @@
let modal
$: isExternal =
$params.selectedDatasource &&
$params.selectedDatasource !== BUDIBASE_INTERNAL_DB
function selectFirstDatasource() {
$redirect("./table")
}

View file

@ -2,10 +2,15 @@
import { Button, Heading, Body, Layout, Modal, Divider } from "@budibase/bbui"
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
import ICONS from "components/backend/DatasourceNavigator/icons"
import { tables } from "stores/backend"
import { tables, datasources } from "stores/backend"
import { goto } from "@roxi/routify"
let modal
$: internalTablesBySourceId = $tables.list.filter(
table =>
table.type !== "external" && $datasources.selected === table.sourceId
)
</script>
<Modal bind:this={modal}>
@ -27,7 +32,7 @@
<Divider />
<Heading size="S">Tables</Heading>
<div class="table-list">
{#each $tables.list.filter(table => table.type !== "external") as table}
{#each internalTablesBySourceId as table}
<div
class="table-list-item"
on:click={$goto(`../../table/${table._id}`)}

View file

@ -0,0 +1,7 @@
<script>
import { datasources } from "stores/backend"
datasources.select("datasource_internal_bb_default")
</script>
<slot />

View file

@ -0,0 +1,87 @@
<script>
import { Button, Heading, Body, Layout, Modal, Divider } from "@budibase/bbui"
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
import ICONS from "components/backend/DatasourceNavigator/icons"
import { tables, datasources } from "stores/backend"
import { goto } from "@roxi/routify"
let modal
$: internalTablesBySourceId = $tables.list.filter(
table =>
table.type !== "external" && $datasources.selected === table.sourceId
)
</script>
<Modal bind:this={modal}>
<CreateTableModal />
</Modal>
<section>
<Layout>
<Layout gap="XS" noPadding>
<header>
<svelte:component this={ICONS.BUDIBASE} height="26" width="26" />
<Heading size="M">Sample Data</Heading>
</header>
<Body size="M">A little something to get you up and running!</Body>
<Body size="M"
>If you have no need for this datasource, feel free to delete it.</Body
>
</Layout>
<Divider />
<Heading size="S">Tables</Heading>
<div class="table-list">
<!-- {JSON.stringify($tables.list.map(source => source.sourceId))} -->
{#each internalTablesBySourceId as table}
<div
class="table-list-item"
on:click={$goto(`../../table/${table._id}`)}
>
<Body size="S">{table.name}</Body>
{#if table.primaryDisplay}
<Body size="S">Display column: {table.primaryDisplay}</Body>
{/if}
</div>
{/each}
</div>
<div>
<Button cta on:click={modal.show}>Create new table</Button>
</div>
</Layout>
</section>
<style>
section {
margin: 0 auto;
width: 640px;
}
header {
display: flex;
gap: var(--spacing-l);
align-items: center;
}
.table-list {
display: flex;
flex-direction: column;
gap: var(--spacing-m);
}
.table-list-item {
border-radius: var(--border-radius-m);
background: var(--background);
border: var(--border-dark);
display: grid;
grid-template-columns: 2fr 0.75fr 20px;
align-items: center;
padding: var(--spacing-m);
gap: var(--layout-xs);
transition: 200ms background ease;
}
.table-list-item:hover {
background: var(--grey-1);
cursor: pointer;
}
</style>

View file

@ -7,8 +7,8 @@
let modal
$: setupComplete =
$datasources.list.find(x => (x._id = "bb_internal"))?.entities.length > 1 ||
$datasources.list.length > 1
$datasources.list.find(x => (x._id = "bb_internal"))?.entities?.length >
1 || $datasources.list.length > 1
onMount(() => {
if (!setupComplete && !$admin.isDev) {

View file

@ -155,9 +155,9 @@ export function createAuthStore() {
await actions.getSelf()
},
logout: async () => {
setUser(null)
setPostLogout()
await API.logOut()
setPostLogout()
setUser(null)
await setInitInfo({})
},
updateSelf: async fields => {

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {
@ -26,9 +26,9 @@
"outputPath": "build"
},
"dependencies": {
"@budibase/backend-core": "2.1.22-alpha.8",
"@budibase/string-templates": "2.1.22-alpha.8",
"@budibase/types": "2.1.22-alpha.8",
"@budibase/backend-core": "2.1.32-alpha.3",
"@budibase/string-templates": "2.1.32-alpha.3",
"@budibase/types": "2.1.32-alpha.3",
"axios": "0.21.2",
"chalk": "4.1.0",
"cli-progress": "3.11.2",
@ -41,7 +41,7 @@
"joi": "17.6.0",
"lookpath": "1.1.0",
"node-fetch": "2",
"pkg": "5.7.0",
"pkg": "5.8.0",
"posthog-node": "1.0.7",
"pouchdb": "7.3.0",
"pouchdb-replication-stream": "1.2.9",

View file

@ -9,11 +9,30 @@
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/generator@7.18.2":
version "7.18.2"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d"
integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==
dependencies:
"@babel/types" "^7.18.2"
"@jridgewell/gen-mapping" "^0.3.0"
jsesc "^2.5.1"
"@babel/helper-string-parser@^7.19.4":
version "7.19.4"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
"@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
"@babel/highlight@^7.10.4":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
@ -23,10 +42,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@7.17.10":
version "7.17.10"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.10.tgz#873b16db82a8909e0fbd7f115772f4b739f6ce78"
integrity sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==
"@babel/parser@7.18.4":
version "7.18.4"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef"
integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==
"@babel/runtime@^7.15.4":
version "7.18.9"
@ -35,14 +54,23 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/types@7.17.10":
version "7.17.10"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.10.tgz#d35d7b4467e439fcf06d195f8100e0fea7fc82c4"
integrity sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==
"@babel/types@7.18.4":
version "7.18.4"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354"
integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@babel/types@^7.18.2":
version "7.20.2"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842"
integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==
dependencies:
"@babel/helper-string-parser" "^7.19.4"
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@ -84,6 +112,38 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@jridgewell/gen-mapping@^0.3.0":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.17"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==
dependencies:
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -701,7 +761,7 @@ deep-extend@^0.6.0, deep-extend@~0.6.0:
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
deep-is@^0.1.3, deep-is@~0.1.3:
deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
@ -833,18 +893,6 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
escodegen@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==
dependencies:
esprima "^4.0.1"
estraverse "^5.2.0"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
source-map "~0.6.1"
eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
@ -925,7 +973,7 @@ espree@^7.3.0, espree@^7.3.1:
acorn-jsx "^5.3.1"
eslint-visitor-keys "^1.3.0"
esprima@^4.0.0, esprima@^4.0.1:
esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
@ -1019,7 +1067,7 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
fast-levenshtein@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
@ -1585,6 +1633,11 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
@ -1723,14 +1776,6 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
dependencies:
prelude-ls "~1.1.2"
type-check "~0.3.2"
lie@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
@ -2009,18 +2054,6 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
dependencies:
deep-is "~0.1.3"
fast-levenshtein "~2.0.6"
levn "~0.3.0"
prelude-ls "~1.1.2"
type-check "~0.3.2"
word-wrap "~1.2.3"
optionator@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
@ -2136,10 +2169,10 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==
pkg-fetch@3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/pkg-fetch/-/pkg-fetch-3.4.1.tgz#be68bb9f7fdb0f6ed995abc518ab2e35aa64d2fd"
integrity sha512-fS4cdayCa1r4jHkOKGPJKnS9PEs6OWZst+s+m0+CmhmPZObMnxoRnf9T9yUWl+lzM2b5aJF7cnQIySCT7Hq8Dg==
pkg-fetch@3.4.2:
version "3.4.2"
resolved "https://registry.yarnpkg.com/pkg-fetch/-/pkg-fetch-3.4.2.tgz#6f68ebc54842b73f8c0808959a9df3739dcb28b7"
integrity sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==
dependencies:
chalk "^4.1.2"
fs-extra "^9.1.0"
@ -2150,22 +2183,22 @@ pkg-fetch@3.4.1:
tar-fs "^2.1.1"
yargs "^16.2.0"
pkg@5.7.0:
version "5.7.0"
resolved "https://registry.yarnpkg.com/pkg/-/pkg-5.7.0.tgz#6422df05e8aa147764be6ef912921d0fa719ea95"
integrity sha512-PTiAjNq/CGAtK5qUBR6pjheqnipTFjeecgSgIKEcAOJA4GpmZeOZC8pMOoT0rfes5vHsmcFo7wbSRTAmXQurrg==
pkg@5.8.0:
version "5.8.0"
resolved "https://registry.yarnpkg.com/pkg/-/pkg-5.8.0.tgz#a77644aeff0b94a1656d7f76558837f7c754a4c0"
integrity sha512-8h9PUDYFi+LOMLbIyGRdP21g08mAtHidSpofSrf8LWhxUWGHymaRzcopEGiynB5EhQmZUKM6PQ9kCImV2TpdjQ==
dependencies:
"@babel/parser" "7.17.10"
"@babel/types" "7.17.10"
"@babel/generator" "7.18.2"
"@babel/parser" "7.18.4"
"@babel/types" "7.18.4"
chalk "^4.1.2"
escodegen "^2.0.0"
fs-extra "^9.1.0"
globby "^11.1.0"
into-stream "^6.0.0"
is-core-module "2.9.0"
minimist "^1.2.6"
multistream "^4.1.0"
pkg-fetch "3.4.1"
pkg-fetch "3.4.2"
prebuild-install "6.1.4"
resolve "^1.22.0"
stream-meter "^1.0.4"
@ -2262,11 +2295,6 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
@ -2611,11 +2639,6 @@ sort-keys@^2.0.0:
dependencies:
is-plain-obj "^1.0.0"
source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
spark-md5@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc"
@ -2907,13 +2930,6 @@ type-check@^0.4.0, type-check@~0.4.0:
dependencies:
prelude-ls "^1.2.1"
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
dependencies:
prelude-ls "~1.1.2"
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
@ -3036,7 +3052,7 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.2 || 2 || 3 || 4"
word-wrap@^1.2.3, word-wrap@~1.2.3:
word-wrap@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==

View file

@ -85,7 +85,6 @@
"description": "This component contains things within itself",
"icon": "Selection",
"hasChildren": true,
"showSettingsBar": true,
"size": {
"width": 400,
"height": 200
@ -284,7 +283,6 @@
"description": "A basic html button that is ready for styling",
"icon": "Button",
"editable": true,
"showSettingsBar": true,
"size": {
"width": 105,
"height": 35
@ -421,7 +419,6 @@
"section"
],
"hasChildren": true,
"showSettingsBar": true,
"size": {
"width": 400,
"height": 100
@ -684,7 +681,6 @@
"illegalChildren": [
"section"
],
"showSettingsBar": true,
"editable": true,
"size": {
"width": 400,
@ -810,7 +806,6 @@
"illegalChildren": [
"section"
],
"showSettingsBar": true,
"editable": true,
"size": {
"width": 400,
@ -932,7 +927,6 @@
"tag": {
"name": "Tag",
"icon": "Label",
"showSettingsBar": true,
"size": {
"width": 100,
"height": 25
@ -1190,7 +1184,6 @@
"name": "Link",
"description": "A basic link component for internal and external links",
"icon": "Link",
"showSettingsBar": true,
"editable": true,
"size": {
"width": 200,
@ -3912,7 +3905,6 @@
"dynamicfilter": {
"name": "Dynamic Filter",
"icon": "Filter",
"showSettingsBar": true,
"size": {
"width": 100,
"height": 35
@ -3925,10 +3917,10 @@
"required": true
},
{
"type": "multifield",
"label": "Allowed filter fields",
"type": "columns/basic",
"label": "Allowed filter columns",
"key": "allowedFields",
"placeholder": "All fields"
"dependsOn": "dataProvider"
},
{
"type": "select",
@ -4802,7 +4794,6 @@
"section"
],
"hasChildren": true,
"showSettingsBar": true,
"size": {
"width": 400,
"height": 100
@ -5285,4 +5276,4 @@
"suffix": "repeater"
}
}
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/client",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
"@budibase/bbui": "2.1.22-alpha.8",
"@budibase/frontend-core": "2.1.22-alpha.8",
"@budibase/string-templates": "2.1.22-alpha.8",
"@budibase/bbui": "2.1.32-alpha.3",
"@budibase/frontend-core": "2.1.32-alpha.3",
"@budibase/string-templates": "2.1.32-alpha.3",
"@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3",
@ -59,5 +59,8 @@
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-visualizer": "^5.5.4"
},
"resolutions": {
"loader-utils": "1.4.1"
},
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc"
}

View file

@ -9,7 +9,7 @@
let structureLookupMap = {}
const registerBlockComponent = (id, order, parentId, instance) => {
// Ensure child array exists
// Ensure child map exists
if (!structureLookupMap[parentId]) {
structureLookupMap[parentId] = {}
}
@ -18,6 +18,14 @@
structureLookupMap[parentId][order] = instance
}
const unregisterBlockComponent = (order, parentId) => {
// Ensure child map exists
if (!structureLookupMap[parentId]) {
return
}
delete structureLookupMap[parentId][order]
}
const eject = () => {
// Start the new structure with the root component
let definition = structureLookupMap[$component.id][0]
@ -73,6 +81,7 @@
// We register block components with their raw props so that we can eject
// blocks later on
registerComponent: registerBlockComponent,
unregisterComponent: unregisterBlockComponent,
})
onMount(() => {

View file

@ -1,5 +1,5 @@
<script>
import { getContext } from "svelte"
import { getContext, onDestroy } from "svelte"
import { generate } from "shortid"
import { builderStore } from "../stores/builder.js"
import Component from "components/Component.svelte"
@ -42,6 +42,12 @@
block.registerComponent(id, order ?? 0, $component?.id, instance)
}
}
onDestroy(() => {
if ($builderStore.inBuilder) {
block.unregisterComponent(order ?? 0, $component?.id)
}
})
</script>
<Component {instance} isBlock>

View file

@ -1,248 +0,0 @@
<script>
import { getContext } from "svelte"
import BlockComponent from "../../BlockComponent.svelte"
import Block from "../../Block.svelte"
import Placeholder from "../Placeholder.svelte"
import { makePropSafe as safe } from "@budibase/string-templates"
export let actionType
export let dataSource
export let size
export let disabled
export let fields
export let labelPosition
export let title
export let showSaveButton
export let showDeleteButton
export let rowId
export let actionUrl
const { fetchDatasourceSchema } = getContext("sdk")
const FieldTypeToComponentMap = {
string: "stringfield",
number: "numberfield",
options: "optionsfield",
array: "multifieldselect",
boolean: "booleanfield",
longform: "longformfield",
datetime: "datetimefield",
attachment: "attachmentfield",
link: "relationshipfield",
json: "jsonfield",
barcodeqr: "codescanner",
}
let schema
let formId
let providerId
let repeaterId
$: fetchSchema(dataSource)
$: onSave = [
{
"##eventHandlerType": "Save Row",
parameters: {
providerId: formId,
tableId: dataSource?.tableId,
},
},
{
"##eventHandlerType": "Close Screen Modal",
},
{
"##eventHandlerType": "Close Side Panel",
},
{
"##eventHandlerType": "Navigate To",
parameters: {
url: actionUrl,
},
},
]
$: onDelete = [
{
"##eventHandlerType": "Delete Row",
parameters: {
confirm: true,
tableId: dataSource?.tableId,
rowId: `{{ ${safe(repeaterId)}.${safe("_id")} }}`,
revId: `{{ ${safe(repeaterId)}.${safe("_rev")} }}`,
},
},
{
"##eventHandlerType": "Close Screen Modal",
},
{
"##eventHandlerType": "Close Side Panel",
},
{
"##eventHandlerType": "Navigate To",
parameters: {
url: actionUrl,
},
},
]
$: filter = [
{
field: "_id",
operator: "equal",
type: "string",
value: !rowId ? `{{ ${safe("url")}.${safe("id")} }}` : rowId,
valueType: "Binding",
},
]
$: dataProvider = `{{ literal ${safe(providerId)} }}`
$: renderDeleteButton = showDeleteButton && actionType === "Update"
$: renderSaveButton = showSaveButton && actionType !== "View"
$: renderButtons = renderDeleteButton || renderSaveButton
$: renderHeader = renderButtons || title
const fetchSchema = async () => {
schema = (await fetchDatasourceSchema(dataSource)) || {}
}
const getComponentForField = field => {
if (!field || !schema?.[field]) {
return null
}
const type = schema[field].type
return FieldTypeToComponentMap[type]
}
</script>
<Block>
{#if fields?.length}
<BlockComponent
type="dataprovider"
context="provider"
bind:id={providerId}
props={{
dataSource,
filter,
limit: 1,
paginate: false,
}}
>
<BlockComponent
type="repeater"
context="repeater"
bind:id={repeaterId}
props={{
dataProvider,
noRowsMessage: "We couldn't find a row to display",
direction: "column",
hAlign: "center",
}}
>
<BlockComponent
type="form"
props={{
actionType: actionType === "Create" ? "Create" : "Update",
dataSource,
size,
disabled: disabled || actionType === "View",
}}
styles={{
normal: {
width: "600px",
},
}}
context="form"
bind:id={formId}
>
<BlockComponent
type="container"
props={{
direction: "column",
hAlign: "stretch",
vAlign: "top",
gap: "M",
}}
>
{#if renderHeader}
<BlockComponent
type="container"
props={{
direction: "row",
hAlign: "stretch",
vAlign: "center",
gap: "M",
wrap: true,
}}
order={0}
>
<BlockComponent
type="heading"
props={{ text: title || "" }}
order={0}
/>
{#if renderButtons}
<BlockComponent
type="container"
props={{
direction: "row",
hAlign: "stretch",
vAlign: "center",
gap: "M",
wrap: true,
}}
order={1}
>
{#if renderDeleteButton}
<BlockComponent
type="button"
props={{
text: "Delete",
onClick: onDelete,
quiet: true,
type: "secondary",
}}
order={0}
/>
{/if}
{#if renderSaveButton}
<BlockComponent
type="button"
props={{
text: "Save",
onClick: onSave,
type: "cta",
}}
order={1}
/>
{/if}
</BlockComponent>
{/if}
</BlockComponent>
{/if}
<BlockComponent
type="fieldgroup"
props={{ labelPosition }}
order={1}
>
{#each fields as field, idx}
{#if getComponentForField(field)}
<BlockComponent
type={getComponentForField(field)}
props={{
field,
label: field,
placeholder: field,
disabled,
}}
order={idx}
/>
{/if}
{/each}
</BlockComponent>
</BlockComponent>
</BlockComponent>
</BlockComponent>
</BlockComponent>
{:else}
<Placeholder
text="Choose your table and add some fields to your form to get started"
/>
{/if}
</Block>

View file

@ -0,0 +1,101 @@
<script>
import { getContext } from "svelte"
import BlockComponent from "components/BlockComponent.svelte"
import Block from "components/Block.svelte"
import { makePropSafe as safe } from "@budibase/string-templates"
import InnerFormBlock from "./InnerFormBlock.svelte"
export let actionType
export let dataSource
export let size
export let disabled
export let fields
export let labelPosition
export let title
export let showSaveButton
export let showDeleteButton
export let rowId
export let actionUrl
const { fetchDatasourceSchema } = getContext("sdk")
let schema
let providerId
let repeaterId
$: fetchSchema(dataSource)
$: dataProvider = `{{ literal ${safe(providerId)} }}`
$: filter = [
{
field: "_id",
operator: "equal",
type: "string",
value: !rowId ? `{{ ${safe("url")}.${safe("id")} }}` : rowId,
valueType: "Binding",
},
]
// We could simply spread $$props into the inner form and append our
// additions, but that would create svelte warnings about unused props and
// make maintenance in future more confusing as we typically always have a
// proper mapping of schema settings to component exports, without having to
// search multiple files
$: innerProps = {
dataSource,
actionUrl,
actionType,
size,
disabled,
fields,
labelPosition,
title,
showSaveButton,
showDeleteButton,
schema,
repeaterId,
}
const fetchSchema = async () => {
schema = (await fetchDatasourceSchema(dataSource)) || {}
}
</script>
<Block>
{#if actionType === "Create"}
<BlockComponent
type="container"
props={{
direction: "column",
hAlign: "left",
vAlign: "stretch",
}}
>
<InnerFormBlock {...innerProps} />
</BlockComponent>
{:else}
<BlockComponent
type="dataprovider"
context="provider"
bind:id={providerId}
props={{
dataSource,
filter,
limit: 1,
paginate: false,
}}
>
<BlockComponent
type="repeater"
context="repeater"
bind:id={repeaterId}
props={{
dataProvider,
noRowsMessage: "We couldn't find a row to display",
direction: "column",
hAlign: "center",
}}
>
<InnerFormBlock {...innerProps} />
</BlockComponent>
</BlockComponent>
{/if}
</Block>

View file

@ -0,0 +1,200 @@
<script>
import BlockComponent from "components/BlockComponent.svelte"
import Placeholder from "components/app/Placeholder.svelte"
import { makePropSafe as safe } from "@budibase/string-templates"
export let dataSource
export let actionUrl
export let actionType
export let size
export let disabled
export let fields
export let labelPosition
export let title
export let showSaveButton
export let showDeleteButton
export let schema
export let repeaterId
const FieldTypeToComponentMap = {
string: "stringfield",
number: "numberfield",
options: "optionsfield",
array: "multifieldselect",
boolean: "booleanfield",
longform: "longformfield",
datetime: "datetimefield",
attachment: "attachmentfield",
link: "relationshipfield",
json: "jsonfield",
barcodeqr: "codescanner",
}
let formId
$: onSave = [
{
"##eventHandlerType": "Save Row",
parameters: {
providerId: formId,
tableId: dataSource?.tableId,
},
},
{
"##eventHandlerType": "Close Screen Modal",
},
{
"##eventHandlerType": "Close Side Panel",
},
{
"##eventHandlerType": "Navigate To",
parameters: {
url: actionUrl,
},
},
]
$: onDelete = [
{
"##eventHandlerType": "Delete Row",
parameters: {
confirm: true,
tableId: dataSource?.tableId,
rowId: `{{ ${safe(repeaterId)}.${safe("_id")} }}`,
revId: `{{ ${safe(repeaterId)}.${safe("_rev")} }}`,
},
},
{
"##eventHandlerType": "Close Screen Modal",
},
{
"##eventHandlerType": "Close Side Panel",
},
{
"##eventHandlerType": "Navigate To",
parameters: {
url: actionUrl,
},
},
]
$: renderDeleteButton = showDeleteButton && actionType === "Update"
$: renderSaveButton = showSaveButton && actionType !== "View"
$: renderButtons = renderDeleteButton || renderSaveButton
$: renderHeader = renderButtons || title
const getComponentForField = field => {
if (!field || !schema?.[field]) {
return null
}
const type = schema[field].type
return FieldTypeToComponentMap[type]
}
</script>
{#if fields?.length}
<BlockComponent
type="form"
props={{
actionType: actionType === "Create" ? "Create" : "Update",
dataSource,
size,
disabled: disabled || actionType === "View",
}}
styles={{
normal: {
width: "600px",
"margin-left": "auto",
"margin-right": "auto",
},
}}
context="form"
bind:id={formId}
>
<BlockComponent
type="container"
props={{
direction: "column",
hAlign: "stretch",
vAlign: "top",
gap: "M",
}}
>
{#if renderHeader}
<BlockComponent
type="container"
props={{
direction: "row",
hAlign: "stretch",
vAlign: "center",
gap: "M",
wrap: true,
}}
order={0}
>
<BlockComponent
type="heading"
props={{ text: title || "" }}
order={0}
/>
{#if renderButtons}
<BlockComponent
type="container"
props={{
direction: "row",
hAlign: "stretch",
vAlign: "center",
gap: "M",
wrap: true,
}}
order={1}
>
{#if renderDeleteButton}
<BlockComponent
type="button"
props={{
text: "Delete",
onClick: onDelete,
quiet: true,
type: "secondary",
}}
order={0}
/>
{/if}
{#if renderSaveButton}
<BlockComponent
type="button"
props={{
text: "Save",
onClick: onSave,
type: "cta",
}}
order={1}
/>
{/if}
</BlockComponent>
{/if}
</BlockComponent>
{/if}
<BlockComponent type="fieldgroup" props={{ labelPosition }} order={1}>
{#each fields as field, idx}
{#if getComponentForField(field)}
<BlockComponent
type={getComponentForField(field)}
props={{
field,
label: field,
placeholder: field,
disabled,
}}
order={idx}
/>
{/if}
{/each}
</BlockComponent>
</BlockComponent>
</BlockComponent>
{:else}
<Placeholder
text="Choose your table and add some fields to your form to get started"
/>
{/if}

View file

@ -1,6 +1,6 @@
export { default as tableblock } from "./TableBlock.svelte"
export { default as cardsblock } from "./CardsBlock.svelte"
export { default as repeaterblock } from "./RepeaterBlock.svelte"
export { default as formblock } from "./FormBlock.svelte"
export { default as formblock } from "./form/FormBlock.svelte"
export { default as chartblock } from "./ChartBlock.svelte"
export { default as rowexplorer } from "./RowExplorer.svelte"

View file

@ -61,7 +61,10 @@
clonedSchema = schema
} else {
allowedFields?.forEach(field => {
if (schema[field]) {
if (schema[field.name]) {
clonedSchema[field.name] = schema[field.name]
clonedSchema[field.name].displayName = field.displayName
} else if (schema[field]) {
clonedSchema[field] = schema[field]
}
})

View file

@ -25,7 +25,10 @@
!BannedTypes.includes(field.type) ||
(field.type === "formula" && field.formulaType === "static")
)
.map(field => field.name)
.map(field => ({
label: field.displayName || field.name,
value: field.name,
}))
const addFilter = () => {
filters = [

View file

@ -6,7 +6,7 @@
export let label
export let placeholder
export let disabled = false
export let enableTime = false
export let enableTime = true
export let timeOnly = false
export let time24hr = false
export let ignoreTimezones = false

View file

@ -16,13 +16,16 @@
let measured = false
$: definition = $componentStore.selectedComponentDefinition
$: showBar = definition?.showSettingsBar && !$dndIsDragging
$: showBar =
definition?.showSettingsBar !== false && !$dndIsDragging && definition
$: {
if (!showBar) {
measured = false
}
}
$: settings = getBarSettings(definition)
$: isScreen =
$builderStore.selectedComponentId === $builderStore.screen?.props?._id
const getBarSettings = definition => {
let allSettings = []
@ -152,26 +155,30 @@
{:else if setting.type === "color"}
<SettingsColorPicker prop={setting.key} />
{/if}
{#if setting.barSeparator !== false}
{#if setting.barSeparator !== false && (settings.length != idx + 1 || !isScreen)}
<div class="divider" />
{/if}
{/each}
<SettingsButton
icon="Duplicate"
on:click={() => {
builderStore.actions.duplicateComponent(
$builderStore.selectedComponentId
)
}}
title="Duplicate component"
/>
<SettingsButton
icon="Delete"
on:click={() => {
builderStore.actions.deleteComponent($builderStore.selectedComponentId)
}}
title="Delete component"
/>
{#if !isScreen}
<SettingsButton
icon="Duplicate"
on:click={() => {
builderStore.actions.duplicateComponent(
$builderStore.selectedComponentId
)
}}
title="Duplicate component"
/>
<SettingsButton
icon="Delete"
on:click={() => {
builderStore.actions.deleteComponent(
$builderStore.selectedComponentId
)
}}
title="Delete component"
/>
{/if}
</div>
{/if}

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
{
"name": "@budibase/frontend-core",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase",
"license": "MPL-2.0",
"svelte": "src/index.js",
"dependencies": {
"@budibase/bbui": "2.1.22-alpha.8",
"@budibase/bbui": "2.1.32-alpha.3",
"lodash": "^4.17.21",
"svelte": "^3.46.2"
}

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/sdk",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Budibase Public API SDK",
"author": "Budibase",
"license": "MPL-2.0",

View file

@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Budibase Web Server",
"main": "src/index.ts",
"repository": {
@ -43,11 +43,11 @@
"license": "GPL-3.0",
"dependencies": {
"@apidevtools/swagger-parser": "10.0.3",
"@budibase/backend-core": "2.1.22-alpha.8",
"@budibase/client": "2.1.22-alpha.8",
"@budibase/pro": "2.1.22-alpha.8",
"@budibase/string-templates": "2.1.22-alpha.8",
"@budibase/types": "2.1.22-alpha.8",
"@budibase/backend-core": "2.1.32-alpha.3",
"@budibase/client": "2.1.32-alpha.3",
"@budibase/pro": "2.1.32-alpha.3",
"@budibase/string-templates": "2.1.32-alpha.3",
"@budibase/types": "2.1.32-alpha.3",
"@bull-board/api": "3.7.0",
"@bull-board/koa": "3.9.4",
"@elastic/elasticsearch": "7.10.0",

View file

@ -25,8 +25,14 @@ import {
migrations,
} from "@budibase/backend-core"
import { USERS_TABLE_SCHEMA } from "../../constants"
import { buildDefaultDocs } from "../../db/defaultData/datasource_bb_default"
import { removeAppFromUserRoles } from "../../utilities/workerRequests"
import { clientLibraryPath, stringToReadStream } from "../../utilities"
import {
clientLibraryPath,
stringToReadStream,
isQsTrue,
} from "../../utilities"
import { getLocksById } from "../../utilities/redis"
import {
updateClientLibrary,
@ -117,7 +123,7 @@ const checkAppName = (
}
}
async function createInstance(template: any) {
async function createInstance(template: any, includeSampleData: boolean) {
const tenantId = tenancy.isMultiTenant() ? tenancy.getTenantId() : null
const baseAppId = generateAppID(tenantId)
const appId = generateDevAppID(baseAppId)
@ -149,11 +155,23 @@ async function createInstance(template: any) {
} else {
// create the users table
await db.put(USERS_TABLE_SCHEMA)
if (includeSampleData) {
// create ootb stock db
await addDefaultTables(db)
}
}
return { _id: appId }
}
const addDefaultTables = async (db: any) => {
const defaultDbDocs = buildDefaultDocs()
// add in the default db data docs - tables, datasource, rows and links
await db.bulkDocs([...defaultDbDocs])
}
export const fetch = async (ctx: any) => {
const dev = ctx.query && ctx.query.status === AppStatus.DEV
const all = ctx.query && ctx.query.status === AppStatus.ALL
@ -234,7 +252,8 @@ const performAppCreate = async (ctx: any) => {
if (ctx.request.files && ctx.request.files.templateFile) {
instanceConfig.file = ctx.request.files.templateFile
}
const instance = await createInstance(instanceConfig)
const includeSampleData = isQsTrue(ctx.request.body.sampleData)
const instance = await createInstance(instanceConfig, includeSampleData)
const appId = instance._id
const db = context.getAppDB()

View file

@ -6,12 +6,14 @@ const {
BudibaseInternalDB,
getTableParams,
} = require("../../db/utils")
const { destroy: tableDestroy } = require("./table/internal")
const { BuildSchemaErrors, InvalidColumns } = require("../../constants")
const { getIntegration } = require("../../integrations")
const { getDatasourceAndQuery } = require("./row/utils")
const { invalidateDynamicVariables } = require("../../threads/utils")
const { getAppDB } = require("@budibase/backend-core/context")
const { events } = require("@budibase/backend-core")
const { db: dbCore } = require("@budibase/backend-core")
exports.fetch = async function (ctx) {
// Get internal tables
@ -21,11 +23,16 @@ exports.fetch = async function (ctx) {
include_docs: true,
})
)
const internal = internalTables.rows.map(row => row.doc)
const internal = internalTables.rows.reduce((acc, row) => {
const sourceId = row.doc.sourceId || "bb_internal"
acc[sourceId] = acc[sourceId] || []
acc[sourceId].push(row.doc)
return acc
}, {})
const bbInternalDb = {
...BudibaseInternalDB,
entities: internal,
}
// Get external datasources
@ -37,11 +44,17 @@ exports.fetch = async function (ctx) {
)
).rows.map(row => row.doc)
for (let datasource of datasources) {
const allDatasources = [bbInternalDb, ...datasources]
for (let datasource of allDatasources) {
if (datasource.config && datasource.config.auth) {
// strip secrets from response so they don't show in the network request
delete datasource.config.auth
}
if (datasource.type === dbCore.BUDIBASE_DATASOURCE_TYPE) {
datasource.entities = internal[datasource._id]
}
}
ctx.body = [bbInternalDb, ...datasources]
@ -196,20 +209,53 @@ exports.save = async function (ctx) {
ctx.body = response
}
const destroyInternalTablesBySourceId = async datasourceId => {
const db = getAppDB()
// Get all internal tables
const internalTables = await db.allDocs(
getTableParams(null, {
include_docs: true,
})
)
// Filter by datasource and return the docs.
const datasourceTableDocs = internalTables.rows.reduce((acc, table) => {
if (table.doc.sourceId == datasourceId) {
acc.push(table.doc)
}
return acc
}, [])
// Destroy the tables.
for (const table of datasourceTableDocs) {
await tableDestroy({
params: {
tableId: table._id,
},
})
}
}
exports.destroy = async function (ctx) {
const db = getAppDB()
const datasourceId = ctx.params.datasourceId
const datasource = await db.get(datasourceId)
// Delete all queries for the datasource
const queries = await db.allDocs(getQueryParams(datasourceId, null))
await db.bulkDocs(
queries.rows.map(row => ({
_id: row.id,
_rev: row.value.rev,
_deleted: true,
}))
)
if (datasource.type === dbCore.BUDIBASE_DATASOURCE_TYPE) {
await destroyInternalTablesBySourceId(datasourceId)
} else {
const queries = await db.allDocs(getQueryParams(datasourceId, null))
await db.bulkDocs(
queries.rows.map(row => ({
_id: row.id,
_rev: row.value.rev,
_deleted: true,
}))
)
}
// delete the datasource
await db.remove(datasourceId, ctx.params.revId)

View file

@ -62,6 +62,7 @@ exports.updateRelatedFormula = async (table, enrichedRows) => {
})
)
)
break
}
}
}
@ -124,7 +125,6 @@ exports.finaliseRow = async (
dynamic: false,
contextRows: enrichedRow,
})
// don't worry about rev, tables handle rev/lastID updates
// if another row has been written since processing this will
// handle the auto ID clash

View file

@ -2,7 +2,7 @@ import { updateLinks, EventType } from "../../../db/linkedRows"
import { getRowParams, generateTableID } from "../../../db/utils"
import { FieldTypes } from "../../../constants"
import { TableSaveFunctions, hasTypeChanged, handleDataImport } from "./utils"
const { getAppDB } = require("@budibase/backend-core/context")
import { context } from "@budibase/backend-core"
import { isTest } from "../../../environment"
import {
cleanupAttachments,
@ -35,7 +35,7 @@ function checkAutoColumns(table: Table, oldTable: Table) {
}
export async function save(ctx: any) {
const db = getAppDB()
const db = context.getAppDB()
const { dataImport, ...rest } = ctx.request.body
let tableToSave = {
type: "table",
@ -138,19 +138,19 @@ export async function save(ctx: any) {
}
export async function destroy(ctx: any) {
const db = getAppDB()
const db = context.getAppDB()
const tableToDelete = await db.get(ctx.params.tableId)
// Delete all rows for that table
const rows = await db.allDocs(
const rowsData = await db.allDocs(
getRowParams(ctx.params.tableId, null, {
include_docs: true,
})
)
await db.bulkDocs(
rows.rows.map((row: any) => ({ ...row.doc, _deleted: true }))
rowsData.rows.map((row: any) => ({ ...row.doc, _deleted: true }))
)
await quotas.removeRows(rows.rows.length, {
await quotas.removeRows(rowsData.rows.length, {
tableId: ctx.params.tableId,
})
@ -161,7 +161,7 @@ export async function destroy(ctx: any) {
})
// don't remove the table itself until very end
await db.remove(tableToDelete)
await db.remove(tableToDelete._id, tableToDelete._rev)
// remove table search index
if (!isTest() || env.COUCH_DB_URL) {
@ -179,7 +179,9 @@ export async function destroy(ctx: any) {
oldTable: null,
deletion: true,
})
await cleanupAttachments(tableToDelete, { rows })
await cleanupAttachments(tableToDelete, {
rows: rowsData.rows.map((row: any) => row.doc),
})
return tableToDelete
}

View file

@ -95,18 +95,7 @@ export function makeSureTableUpToDate(table: any, tableToSave: any) {
return tableToSave
}
export async function handleDataImport(user: any, table: any, dataImport: any) {
if (!dataImport || !dataImport.csvString) {
return table
}
const db = getAppDB()
// Populate the table with rows imported from CSV in a bulk update
const data = await transform({
...dataImport,
existingTable: table,
})
export function importToRows(data: any, table: any, user: any = {}) {
let finalData: any = []
for (let i = 0; i < data.length; i++) {
let row = data[i]
@ -136,6 +125,22 @@ export async function handleDataImport(user: any, table: any, dataImport: any) {
finalData.push(row)
}
return finalData
}
export async function handleDataImport(user: any, table: any, dataImport: any) {
if (!dataImport || !dataImport.csvString) {
return table
}
const db = getAppDB()
// Populate the table with rows imported from CSV in a bulk update
const data = await transform({
...dataImport,
existingTable: table,
})
let finalData: any = importToRows(data, table, user)
await quotas.addRows(finalData.length, () => db.bulkDocs(finalData), {
tableId: table._id,

View file

@ -0,0 +1,646 @@
const {
FieldTypes,
AutoFieldSubTypes,
RelationshipTypes,
} = require("../../constants/index")
const { importToRows } = require("../../api/controllers/table/utils")
const { cloneDeep } = require("lodash/fp")
const LinkDocument = require("../linkedRows/LinkDocument")
const { inventoryImport } = require("./inventoryImport")
const { employeeImport } = require("./employeeImport")
const { jobsImport } = require("./jobsImport")
const { expensesImport } = require("./expensesImport")
const { db: dbCore } = require("@budibase/backend-core")
exports.DEFAULT_JOBS_TABLE_ID = "ta_bb_jobs"
exports.DEFAULT_INVENTORY_TABLE_ID = "ta_bb_inventory"
exports.DEFAULT_EXPENSES_TABLE_ID = "ta_bb_expenses"
exports.DEFAULT_EMPLOYEE_TABLE_ID = "ta_bb_employee"
exports.DEFAULT_BB_DATASOURCE_ID = "datasource_internal_bb_default"
exports.DEFAULT_BB_DATASOURCE = {
_id: this.DEFAULT_BB_DATASOURCE_ID,
type: dbCore.BUDIBASE_DATASOURCE_TYPE,
name: "Sample Data",
source: "BUDIBASE",
config: {},
}
const syncLastIds = (table, rowCount) => {
Object.keys(table.schema).forEach(key => {
const entry = table.schema[key]
if (entry.autocolumn && entry.subtype == "autoID") {
entry.lastID = rowCount
}
})
}
const tableImport = (table, data) => {
const cloneTable = cloneDeep(table)
const rowDocs = importToRows(data, cloneTable)
syncLastIds(cloneTable, rowDocs.length)
return { rows: rowDocs, table: cloneTable }
}
// AUTO COLUMNS
const AUTO_COLUMNS = {
"Created At": {
name: "Created At",
type: FieldTypes.DATETIME,
subtype: AutoFieldSubTypes.CREATED_AT,
icon: "ri-magic-line",
autocolumn: true,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
},
"Updated At": {
name: "Updated At",
type: FieldTypes.DATETIME,
subtype: AutoFieldSubTypes.UPDATED_AT,
icon: "ri-magic-line",
autocolumn: true,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
},
}
exports.DEFAULT_INVENTORY_TABLE_SCHEMA = {
_id: this.DEFAULT_INVENTORY_TABLE_ID,
type: "internal",
views: {},
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
primaryDisplay: "Item Name",
name: "Inventory",
schema: {
"Item ID": {
name: "Item ID",
type: FieldTypes.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID,
icon: "ri-magic-line",
autocolumn: true,
constraints: {
type: FieldTypes.NUMBER,
presence: false,
numericality: {
greaterThanOrEqualTo: "",
lessThanOrEqualTo: "",
},
},
},
"Item Name": {
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {
maximum: null,
},
presence: {
allowEmpty: false,
},
},
name: "Item Name",
},
"Item Tags": {
type: FieldTypes.ARRAY,
constraints: {
type: FieldTypes.ARRAY,
presence: {
allowEmpty: false,
},
inclusion: ["Electrical", "Material", "Vehicle", "Office", "Tools"],
},
name: "Item Tags",
sortable: false,
},
Notes: {
type: FieldTypes.LONGFORM,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
name: "Notes",
useRichText: null,
},
Status: {
type: FieldTypes.ARRAY,
constraints: {
type: FieldTypes.ARRAY,
presence: {
allowEmpty: false,
},
inclusion: ["Available", "Repair", "Broken"],
},
name: "Status",
sortable: false,
},
SKU: {
type: FieldTypes.BARCODEQR,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
name: "SKU",
},
"Purchase Date": {
type: FieldTypes.DATETIME,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
name: "Purchase Date",
ignoreTimezones: true,
},
"Purchase Price": {
type: FieldTypes.NUMBER,
constraints: {
type: FieldTypes.NUMBER,
presence: false,
numericality: {
greaterThanOrEqualTo: null,
lessThanOrEqualTo: "",
},
},
name: "Purchase Price",
},
...AUTO_COLUMNS,
},
}
exports.DEFAULT_EMPLOYEE_TABLE_SCHEMA = {
_id: this.DEFAULT_EMPLOYEE_TABLE_ID,
type: "internal",
views: {},
name: "Employees",
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
primaryDisplay: "First Name",
schema: {
"First Name": {
name: "First Name",
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
},
"Last Name": {
name: "Last Name",
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
},
Email: {
name: "Email",
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
},
Address: {
name: "Address",
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
},
City: {
name: "City",
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
},
Postcode: {
name: "Postcode",
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
},
Phone: {
name: "Phone",
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
},
"EMPLOYEE ID": {
name: "EMPLOYEE ID",
type: FieldTypes.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID,
icon: "ri-magic-line",
autocolumn: true,
constraints: {
type: FieldTypes.NUMBER,
presence: false,
numericality: {
greaterThanOrEqualTo: "",
lessThanOrEqualTo: "",
},
},
},
"Employee Level": {
type: FieldTypes.ARRAY,
constraints: {
type: FieldTypes.ARRAY,
presence: false,
inclusion: ["Manager", "Junior", "Senior", "Apprentice", "Contractor"],
},
name: "Employee Level",
sortable: false,
},
"Badge Photo": {
type: "attachment",
constraints: {
type: FieldTypes.ARRAY,
presence: false,
},
name: "Badge Photo",
sortable: false,
},
Jobs: {
type: FieldTypes.LINK,
constraints: {
type: FieldTypes.ARRAY,
presence: false,
},
fieldName: "Assigned",
name: "Jobs",
relationshipType: RelationshipTypes.MANY_TO_MANY,
tableId: this.DEFAULT_JOBS_TABLE_ID,
},
"Start Date": {
type: FieldTypes.DATETIME,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
name: "Start Date",
ignoreTimezones: true,
},
"End Date": {
type: FieldTypes.DATETIME,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
name: "End Date",
ignoreTimezones: true,
},
...AUTO_COLUMNS,
},
}
exports.DEFAULT_JOBS_TABLE_SCHEMA = {
_id: this.DEFAULT_JOBS_TABLE_ID,
type: "internal",
name: "Jobs",
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
primaryDisplay: "Job ID",
schema: {
"Job ID": {
name: "Job ID",
type: FieldTypes.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID,
icon: "ri-magic-line",
autocolumn: true,
constraints: {
type: FieldTypes.NUMBER,
presence: false,
numericality: {
greaterThanOrEqualTo: "",
lessThanOrEqualTo: "",
},
},
},
"Quote Date": {
type: FieldTypes.DATETIME,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: {
allowEmpty: false,
},
datetime: {
latest: "",
earliest: "",
},
},
name: "Quote Date",
ignoreTimezones: true,
},
"Quote Price": {
type: FieldTypes.NUMBER,
constraints: {
type: FieldTypes.NUMBER,
presence: {
allowEmpty: false,
},
numericality: {
greaterThanOrEqualTo: "",
lessThanOrEqualTo: "",
},
},
name: "Quote Price",
},
"Works Start": {
type: FieldTypes.DATETIME,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
name: "Works Start",
ignoreTimezones: true,
},
Address: {
type: FieldTypes.LONGFORM,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
name: "Address",
useRichText: null,
},
"Customer Name": {
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {
maximum: null,
},
presence: false,
},
name: "Customer Name",
},
Notes: {
type: FieldTypes.LONGFORM,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
name: "Notes",
useRichText: null,
},
"Customer Phone": {
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {
maximum: null,
},
presence: false,
},
name: "Customer Phone",
},
"Customer Email": {
type: FieldTypes.STRING,
constraints: {
type: FieldTypes.STRING,
length: {
maximum: null,
},
presence: false,
},
name: "Customer Email",
},
Assigned: {
name: "Assigned",
type: FieldTypes.LINK,
tableId: this.DEFAULT_EMPLOYEE_TABLE_ID,
fieldName: "Jobs",
relationshipType: RelationshipTypes.MANY_TO_MANY,
// sortable: true,
},
"Works End": {
type: "datetime",
constraints: {
type: "string",
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
name: "Works End",
ignoreTimezones: true,
},
"Updated Price": {
type: "number",
constraints: {
type: "number",
presence: false,
numericality: {
greaterThanOrEqualTo: "",
lessThanOrEqualTo: "",
},
},
name: "Updated Price",
},
...AUTO_COLUMNS,
},
}
exports.DEFAULT_EXPENSES_TABLE_SCHEMA = {
_id: this.DEFAULT_EXPENSES_TABLE_ID,
type: "internal",
views: {},
name: "Expenses",
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
primaryDisplay: "Expense ID",
schema: {
"Expense ID": {
name: "Expense ID",
type: FieldTypes.NUMBER,
subtype: AutoFieldSubTypes.AUTO_ID,
icon: "ri-magic-line",
autocolumn: true,
constraints: {
type: FieldTypes.NUMBER,
presence: false,
numericality: {
greaterThanOrEqualTo: "",
lessThanOrEqualTo: "",
},
},
},
"Expense Tags": {
type: FieldTypes.ARRAY,
constraints: {
type: FieldTypes.ARRAY,
presence: {
allowEmpty: false,
},
inclusion: [
"Fuel",
"Food",
"Materials",
"Repair",
"Equipment",
"Fees",
"Service",
"Office",
"Other",
],
},
name: "Expense Tags",
sortable: false,
},
Cost: {
type: FieldTypes.NUMBER,
constraints: {
type: FieldTypes.NUMBER,
presence: {
allowEmpty: false,
},
numericality: {
greaterThanOrEqualTo: "",
lessThanOrEqualTo: "",
},
},
name: "Cost",
},
Notes: {
type: FieldTypes.LONGFORM,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
},
name: "Notes",
useRichText: null,
},
"Payment Due": {
type: FieldTypes.DATETIME,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
name: "Payment Due",
ignoreTimezones: true,
},
"Date Paid": {
type: FieldTypes.DATETIME,
constraints: {
type: FieldTypes.STRING,
length: {},
presence: false,
datetime: {
latest: "",
earliest: "",
},
},
name: "Date Paid",
ignoreTimezones: true,
},
Attachment: {
type: FieldTypes.ATTACHMENT,
constraints: {
type: FieldTypes.ARRAY,
presence: false,
},
name: "Attachment",
sortable: false,
},
...AUTO_COLUMNS,
},
}
exports.buildDefaultDocs = () => {
const inventoryData = tableImport(
this.DEFAULT_INVENTORY_TABLE_SCHEMA,
inventoryImport
)
const employeeData = tableImport(
this.DEFAULT_EMPLOYEE_TABLE_SCHEMA,
employeeImport
)
const jobData = tableImport(this.DEFAULT_JOBS_TABLE_SCHEMA, jobsImport)
const expensesData = tableImport(
this.DEFAULT_EXPENSES_TABLE_SCHEMA,
expensesImport
)
// Build one link doc for each employee/job
const jobEmployeeLinks = employeeData.rows.map((employee, index) => {
return new LinkDocument(
employeeData.table._id,
"Jobs",
employeeData.rows[index]._id,
jobData.table._id,
"Assigned",
jobData.rows[index]._id
)
})
return [
this.DEFAULT_BB_DATASOURCE,
inventoryData.table,
employeeData.table,
jobData.table,
expensesData.table,
...inventoryData.rows,
...employeeData.rows,
...jobData.rows,
...expensesData.rows,
...jobEmployeeLinks,
]
}

View file

@ -0,0 +1,152 @@
exports.employeeImport = [
{
"First Name": "Julie",
"Last Name": "Jimenez",
Email: "julie.jimenez@example.com",
Address: "4250 New Street",
City: "Stevenage",
Postcode: "EE32 3SE",
Phone: "01754 13523",
"Created At": "2022-11-10T17:56:18.353Z",
"Updated At": "2022-11-10T18:32:15.298Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Senior"],
"Start Date": "2015-02-12T12:00:00.000",
},
{
"First Name": "Mandy",
"Last Name": "Clark",
Email: "mandy.clark@example.com",
Address: "8632 North Street",
City: "Hereford",
Postcode: "GT81 7DG",
Phone: "016973 32814",
"Created At": "2022-11-10T17:56:18.353Z",
"Updated At": "2022-11-10T18:31:44.928Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Senior"],
"Start Date": "2017-09-10T12:00:00.000",
},
{
"First Name": "Holly",
"Last Name": "Carroll",
Email: "holly.carroll@example.com",
Address: "5976 Springfield Road",
City: "Edinburgh",
Postcode: "Y4 2LH",
Phone: "016977 73053",
"Created At": "2022-11-10T17:56:18.356Z",
"Updated At": "2022-11-10T18:31:32.086Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Senior"],
"Start Date": "2022-02-12T12:00:00.000",
},
{
"First Name": "Francis",
"Last Name": "Castro",
Email: "francis.castro@example.com",
Address: "3970 High Street",
City: "Wells",
Postcode: "X12 6QA",
Phone: "017684 23551",
"Created At": "2022-11-10T17:56:18.357Z",
"Updated At": "2022-11-10T18:31:16.976Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Apprentice"],
"Start Date": "2021-03-10T12:00:00.000",
},
{
"First Name": "Richard",
"Last Name": "Kelley",
Email: "richard.kelley@example.com",
Address: "2346 York Road",
City: "Leicester",
Postcode: "H7S 1AH",
Phone: "013873 65167",
"Created At": "2022-11-10T17:56:18.353Z",
"Updated At": "2022-11-10T18:32:23.314Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Apprentice"],
"Start Date": "2020-07-09T12:00:00.000",
},
{
"First Name": "Donald",
"Last Name": "Lynch",
Email: "donald.lynch@example.com",
Address: "9642 New Road",
City: "St Albans",
Postcode: "V9A 1NP",
Phone: "015242 46760",
"Created At": "2022-11-10T17:56:18.352Z",
"Updated At": "2022-11-10T18:30:38.439Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Junior"],
"Start Date": "2018-04-13T12:00:00.000",
},
{
"First Name": "Maria",
"Last Name": "Torres",
Email: "maria.torres@example.com",
Address: "9998 New Road",
City: "Aberdeen",
Postcode: "LP7 8JQ",
Phone: "0101 472 3365",
"Created At": "2022-11-10T17:56:18.353Z",
"Updated At": "2022-11-10T18:31:37.748Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Manager"],
"Start Date": "2016-05-22T12:00:00.000",
},
{
"First Name": "Suzy",
"Last Name": "Ruiz",
Email: "suzy.ruiz@example.com",
Address: "4641 Victoria Street",
City: "Armagh",
Postcode: "MO4X 8BP",
Phone: "015242 79977",
"Created At": "2022-11-10T17:56:18.354Z",
"Updated At": "2022-11-10T18:58:54.632Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Senior", "Manager"],
"Start Date": "2019-05-01T12:00:00.000",
},
{
"First Name": "Patrick",
"Last Name": "Garcia",
Email: "patrick.garcia@example.com",
Address: "7818 The Crescent",
City: "Bath",
Postcode: "OH5 3HE",
Phone: "017683 02608",
"Created At": "2022-11-10T17:56:18.353Z",
"Updated At": "2022-11-10T18:31:06.820Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Apprentice"],
"Start Date": "2014-08-30T12:00:00.000",
},
{
"First Name": "Brayden",
"Last Name": "Carpenter",
Email: "brayden.carpenter@example.com",
Address: "8755 The Drive",
City: "Bradford",
Postcode: "YH5 8RY",
Phone: "015395 12426",
"Created At": "2022-11-10T17:56:18.354Z",
"Updated At": "2022-11-10T20:41:26.977Z",
tableId: "ta_bb_employees",
type: "row",
"Employee Level": ["Contractor"],
"Start Date": "2022-11-09T12:00:00.000",
},
]

View file

@ -0,0 +1,114 @@
exports.expensesImport = [
{
"Date Paid": "2022-11-12T12:00:00.000",
"Payment Due": "2022-11-01T12:00:00.000",
Cost: 117.4,
Notes: "Two vans needed a top up",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T19:07:14.714Z",
"Updated At": "2022-11-10T20:02:14.440Z",
type: "row",
"Expense Tags": ["Fuel", "Equipment"],
},
{
"Date Paid": "2022-11-11T12:00:00.000",
Cost: 217,
Notes: "3 branded work bags and safety equipment for the new hires",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T19:10:35.459Z",
"Updated At": "2022-11-10T19:10:35.459Z",
type: "row",
"Expense Tags": ["Materials"],
},
{
"Date Paid": "2022-11-25T12:00:00.000",
Cost: 420.68,
Notes: "Monthly games night",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T19:20:08.264Z",
"Updated At": "2022-11-10T19:27:14.141Z",
type: "row",
"Expense Tags": ["Food"],
},
{
"Date Paid": "2022-11-24T12:00:00.000",
"Payment Due": "2022-11-24T12:00:00.000",
Cost: 45,
Notes: "Work van",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T18:20:16.709Z",
"Updated At": "2022-11-10T20:02:05.293Z",
type: "row",
"Expense Tags": ["Fuel", "Equipment"],
},
{
"Payment Due": "2022-11-25T12:00:00.000",
Cost: 200,
Notes: "Accountant payroll management",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T19:06:16.014Z",
"Updated At": "2022-11-10T19:06:16.014Z",
type: "row",
"Expense Tags": ["Fees", "Service"],
},
{
"Payment Due": "2022-11-26T12:00:00.000",
Cost: 28,
Notes: "Circular saw needed a new plug",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T20:03:18.051Z",
"Updated At": "2022-11-10T20:03:18.051Z",
type: "row",
"Expense Tags": ["Equipment", "Repair"],
},
{
"Payment Due": "2022-11-11T12:00:00.000",
Cost: 131.75,
Notes: "Solicitor contract reviews for employees",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T18:56:16.111Z",
"Updated At": "2022-11-10T19:20:58.681Z",
type: "row",
"Expense Tags": ["Fees", "Service"],
},
{
Cost: 2500,
Notes: "New Laptop for the office. ",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T18:04:11.401Z",
"Updated At": "2022-11-10T20:08:16.459Z",
type: "row",
"Date Paid": "2022-11-09T12:00:00.000",
"Expense Tags": ["Equipment"],
},
{
"Date Paid": "2022-10-25T12:00:00.000",
Cost: 275,
Notes: "Accountant payroll. Added new hire",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T20:01:31.783Z",
"Updated At": "2022-11-10T20:01:31.783Z",
type: "row",
"Expense Tags": ["Fees", "Service"],
},
{
"Payment Due": "2022-11-19T12:00:00.000",
Cost: 250,
Notes: "200 new branded pens and 40 beanie hats. ",
Attachment: [],
tableId: "ta_bb_expenses",
"Created At": "2022-11-10T19:09:08.074Z",
"Updated At": "2022-11-10T19:09:08.074Z",
type: "row",
"Expense Tags": ["Service"],
},
]

View file

@ -0,0 +1,106 @@
exports.inventoryImport = [
{
Status: ["Available"],
"Item Name": "Little Blue Van",
SKU: "",
Notes: "MAX PAYLOAD 595 kg \nMAX LOAD LENGTH 1620 mm",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T19:11:40.141Z",
"Updated At": "2022-11-10T20:05:04.608Z",
type: "row",
"Purchase Date": "2022-10-10T12:00:00.000",
"Purchase Price": 39995,
"Item Tags": ["Vehicle"],
},
{
Status: ["Available"],
"Item Name": "Masonry Drill",
SKU: "ABC-123",
Notes: "Making a burning smell",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T18:46:10.820Z",
"Updated At": "2022-11-10T20:11:23.766Z",
type: "row",
"Purchase Date": "1992-11-19T12:00:00.000",
"Item Tags": ["Electrical", "Tools"],
"Purchase Price": 250,
},
{
Status: ["Repair"],
"Item Name": "Circular saw",
SKU: "AB2-100",
Notes: "",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T19:04:38.805Z",
"Updated At": "2022-11-10T20:20:24.000Z",
type: "row",
"Purchase Date": "2012-11-15T12:00:00.000",
"Item Tags": ["Electrical"],
"Purchase Price": 300,
},
{
"Item Tags": ["Electrical"],
"Purchase Price": 210,
"Purchase Date": "2022-10-17T12:00:00.000",
Status: ["Available"],
"Item Name": "Tablet Device (5g)",
SKU: "PH-001",
Notes: "Android tablet for use on site",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T20:21:56.332Z",
"Updated At": "2022-11-10T20:21:56.332Z",
type: "row",
},
{
"Item Tags": ["Tools", "Electrical"],
"Purchase Price": 200,
"Purchase Date": "2022-10-12T12:00:00.000",
Status: ["Available"],
"Item Name": "Power Screwdriver",
SKU: "TKIT-002-A",
Notes: "",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T20:10:51.129Z",
"Updated At": "2022-11-10T20:13:37.821Z",
type: "row",
},
{
Status: ["Available"],
"Item Name": "Large Blue Van",
SKU: "",
Notes: "MAX LOAD LENGTH 4256 mm",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T19:03:41.698Z",
"Updated At": "2022-11-10T20:04:57.932Z",
type: "row",
"Purchase Date": "2022-10-10T12:00:00.000",
"Purchase Price": 65995,
"Item Tags": ["Vehicle"],
},
{
"Purchase Price": 2500,
"Purchase Date": "2022-11-09T12:00:00.000",
Status: ["Available"],
"Item Name": "Office Laptop",
SKU: "PC-123-ABC",
Notes: "Office Laptop \n",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T20:06:14.463Z",
"Updated At": "2022-11-10T20:07:02.532Z",
type: "row",
"Item Tags": ["Electrical", "Office"],
},
{
Status: ["Available"],
"Item Name": "Little Red Van",
SKU: "",
Notes: "MAX PAYLOAD 595 kg \nMAX LOAD LENGTH 1620 mm",
tableId: "ta_bb_inventory",
"Created At": "2022-11-10T19:55:02.367Z",
"Updated At": "2022-11-10T20:05:13.504Z",
type: "row",
"Purchase Date": "2022-07-17T12:00:00.000",
"Purchase Price": 39995,
"Item Tags": ["Vehicle"],
},
]

View file

@ -0,0 +1,158 @@
exports.jobsImport = [
{
"Works End": "2023-01-28T12:00:00.000",
"Customer Email": "susie.peterson@example.com",
"Customer Phone": "016973 88386",
Notes:
"Bring the large van as recycling has been requested. \nAlso, they have a large dog.",
"Customer Name": "Susie Peterson",
Address: "5452 The Crescent\nBrighton and Hove\nAI7G 7BN",
"Works Start": "2023-01-26T12:00:00.000",
"Quote Price": 4200,
"Quote Date": "2022-11-11T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T18:00:29.510Z",
"Updated At": "2022-11-10T20:37:45.120Z",
type: "row",
},
{
"Updated Price": 307,
"Works End": "2022-11-19T12:00:00.000",
"Customer Email": "micheal.murphy@example.co",
"Customer Phone": "07344 867816",
Notes:
"Adding new utils and tearing down the dividing walls. Bring large blue van.\n\nThe customer can be difficult. Avoid",
"Customer Name": "Micheal Murphy",
Address: "5266 York Road\nOxford\nG2 8EP",
"Works Start": "2022-11-10T12:00:00.000",
"Quote Price": 1231,
"Quote Date": "2022-10-04T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T20:53:39.882Z",
"Updated At": "2022-11-10T20:59:49.435Z",
type: "row",
},
{
"Customer Email": "",
"Customer Phone": "07374 594595",
Notes:
"Removal and recycle requested of all units.\n\nStill awaiting feedback. If this is still around after next wednesday, just delete it.",
"Customer Name": "Charlotte Carpenter",
Address: "7780 Mill Lane\nGreater Manchester\nDU57 3GA",
"Quote Price": 500,
"Quote Date": "2022-11-08T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T21:03:11.782Z",
"Updated At": "2022-11-10T21:03:11.782Z",
type: "row",
},
{
"Updated Price": 2001,
"Works End": "2022-11-16T12:00:00.000",
"Customer Email": "leah.freeman@example.com",
"Customer Phone": "07844 42134",
Notes:
"Original quote too high. Material costs dropped.\nFull system installation.",
"Customer Name": "Leah Freeman",
Address: "4252 Fairview Road\nChester\nW62 7JH",
"Works Start": "2022-11-09T12:00:00.000",
"Quote Price": 3000,
"Quote Date": "2022-10-04T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T20:25:44.284Z",
"Updated At": "2022-11-10T20:54:21.655Z",
type: "row",
},
{
"Works End": "2022-11-13T12:00:00.000",
"Customer Email": "scarlett.gibson@example.co",
"Customer Phone": "07572 745859",
Notes:
"This address has a service dog.\n\nQuote didn't account for a sinkhole at the property. Amended",
"Customer Name": "Scarlett Gibson",
Address: "5624 The Drive\nArmagh\nNU0 5DW",
"Works Start": "2022-11-12T12:00:00.000",
"Quote Price": 120,
"Quote Date": "2022-11-11T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T19:50:55.215Z",
"Updated At": "2022-11-10T20:44:12.004Z",
type: "row",
"Updated Price": 175,
},
{
"Customer Email": "lester.rose@example.com",
"Customer Phone": "07103 009138",
Notes: "4 Radiators Removed\nMany cats in the house",
"Customer Name": "Lester Rose",
Address: "8543 Albert Road\nNewport\nLancashire\nUnited Kingdom\nS58 5YW",
"Quote Price": 3543,
"Quote Date": "2022-11-10T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T18:43:21.110Z",
"Updated At": "2022-11-10T20:40:48.241Z",
type: "row",
},
{
"Works End": "2022-11-24T12:00:00.000",
"Customer Email": "joel.owens@example.com",
"Customer Phone": "07216 548317",
Notes:
"Full retrofit of current installation. Will need big blue van. \n\nThere's a decent coffee place nearby. Ensure you buy enough for everyone.",
"Customer Name": "Joel Owens",
Address: "5516 Oaks Cross\nNewry\nT6V 9SL",
"Works Start": "2022-11-24T12:00:00.000",
"Quote Price": 789,
"Quote Date": "2022-11-10T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T21:07:28.365Z",
"Updated At": "2022-11-10T21:08:18.661Z",
type: "row",
},
{
"Customer Email": "freddie.franklin@example.com",
"Customer Phone": "016977 48298",
Notes:
"Equipment updates and some general maintenance.\n\nHouse has 3 walls.",
"Customer Name": "Freddie Franklin",
Address: "2035 Brick Kiln Road\nCoventry\nTS81 7AW",
"Quote Price": 302,
"Quote Date": "2022-11-10T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T18:33:57.850Z",
"Updated At": "2022-11-10T20:57:54.015Z",
type: "row",
},
{
"Works End": "2022-11-12T12:00:00.000",
"Customer Email": "diane.henry@example.com",
"Customer Phone": "07635 514491",
Notes: "Large van required, recycling requested. \nNew customer",
"Customer Name": "Diane Henry",
Address:
"3518 Station Road\nSunderland\nCounty Down\nUnited Kingdom\nXC67 8ES",
"Works Start": "2022-11-11T12:00:00.000",
"Quote Price": 2039,
"Quote Date": "2022-11-10T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T19:23:08.036Z",
"Updated At": "2022-11-10T20:45:40.523Z",
type: "row",
},
{
"Works End": "2022-09-23T12:00:00.000",
"Customer Email": "warren.alvarez@example.com",
"Customer Phone": "07768 90794",
Notes:
"System restoration and upgrades. \nCustomer is a smoker, bring cleaning equipment",
"Customer Name": "Warren Alvarez",
Address: "867 High Street\nBath\nKF8 6ZS",
"Works Start": "2022-09-23T12:00:00.000",
"Quote Price": 1412,
"Quote Date": "2022-09-20T12:00:00.000",
tableId: "ta_bb_jobs",
"Created At": "2022-11-10T20:57:00.124Z",
"Updated At": "2022-11-10T21:08:00.446Z",
type: "row",
},
]

View file

@ -1,55 +1,9 @@
const { IncludeDocs, getLinkDocuments } = require("./linkUtils")
const {
generateLinkID,
InternalTables,
getUserMetadataParams,
} = require("../utils")
const { InternalTables, getUserMetadataParams } = require("../utils")
const Sentry = require("@sentry/node")
const { FieldTypes, RelationshipTypes } = require("../../constants")
const { getAppDB } = require("@budibase/backend-core/context")
/**
* Creates a new link document structure which can be put to the database. It is important to
* note that while this talks about linker/linked the link is bi-directional and for all intent
* and purposes it does not matter from which direction the link was initiated.
* @param {string} tableId1 The ID of the first table (the linker).
* @param {string} tableId2 The ID of the second table (the linked).
* @param {string} fieldName1 The name of the field in the linker table.
* @param {string} fieldName2 The name of the field in the linked table.
* @param {string} rowId1 The ID of the row which is acting as the linker.
* @param {string} rowId2 The ID of the row which is acting as the linked.
* @constructor
*/
function LinkDocument(
tableId1,
fieldName1,
rowId1,
tableId2,
fieldName2,
rowId2
) {
// build the ID out of unique references to this link document
this._id = generateLinkID(
tableId1,
tableId2,
rowId1,
rowId2,
fieldName1,
fieldName2
)
// required for referencing in view
this.type = FieldTypes.LINK
this.doc1 = {
tableId: tableId1,
fieldName: fieldName1,
rowId: rowId1,
}
this.doc2 = {
tableId: tableId2,
fieldName: fieldName2,
rowId: rowId2,
}
}
const LinkDocument = require("./LinkDocument")
class LinkController {
constructor({ tableId, row, table, oldTable }) {

View file

@ -0,0 +1,47 @@
const { generateLinkID } = require("../utils")
const { FieldTypes } = require("../../constants")
/**
* Creates a new link document structure which can be put to the database. It is important to
* note that while this talks about linker/linked the link is bi-directional and for all intent
* and purposes it does not matter from which direction the link was initiated.
* @param {string} tableId1 The ID of the first table (the linker).
* @param {string} tableId2 The ID of the second table (the linked).
* @param {string} fieldName1 The name of the field in the linker table.
* @param {string} fieldName2 The name of the field in the linked table.
* @param {string} rowId1 The ID of the row which is acting as the linker.
* @param {string} rowId2 The ID of the row which is acting as the linked.
* @constructor
*/
function LinkDocument(
tableId1,
fieldName1,
rowId1,
tableId2,
fieldName2,
rowId2
) {
// build the ID out of unique references to this link document
this._id = generateLinkID(
tableId1,
tableId2,
rowId1,
rowId2,
fieldName1,
fieldName2
)
// required for referencing in view
this.type = FieldTypes.LINK
this.doc1 = {
tableId: tableId1,
fieldName: fieldName1,
rowId: rowId1,
}
this.doc2 = {
tableId: tableId2,
fieldName: fieldName2,
rowId: rowId2,
}
}
module.exports = LinkDocument

View file

@ -15,7 +15,7 @@ export const SearchIndexes = {
export const BudibaseInternalDB = {
_id: "bb_internal",
type: "budibase",
type: dbCore.BUDIBASE_DATASOURCE_TYPE,
name: "Budibase DB",
source: "BUDIBASE",
config: {},

View file

@ -58,6 +58,7 @@ const SCHEMA: Integration = {
},
aggregate: {
type: QueryType.JSON,
readable: true,
steps: [
{
key: "$addFields",

View file

@ -97,7 +97,7 @@ async function updateAutomations(prodAppId: string, db: Database) {
const oldDevAppId = automation.appId,
oldProdAppId = dbCore.getProdAppID(automation.appId)
if (
automation.definition.trigger.stepId === AutomationTriggerStepId.WEBHOOK
automation.definition.trigger?.stepId === AutomationTriggerStepId.WEBHOOK
) {
const old = automation.definition.trigger.inputs
automation.definition.trigger.inputs = {

View file

@ -19,7 +19,7 @@ async function getAllInternalTables(db?: Database): Promise<Table[]> {
return internalTables.rows.map((tableDoc: any) => ({
...tableDoc.doc,
type: "internal",
sourceId: BudibaseInternalDB._id,
sourceId: tableDoc.doc.sourceId || BudibaseInternalDB._id,
}))
}

View file

@ -1273,12 +1273,12 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@budibase/backend-core@2.1.22-alpha.8":
version "2.1.22-alpha.8"
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.22-alpha.8.tgz#c68dcd104023b1b0c4b981471fb30387dfce01f7"
integrity sha512-ZQugFvr7j3wxXxOr7P33IrBKORNurwNO/JW5gtQLTStUKxp2ip7TQ1VyXiwBRDurzPuypEMk01L9gHNeWVEA7Q==
"@budibase/backend-core@2.1.32-alpha.3":
version "2.1.32-alpha.3"
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.32-alpha.3.tgz#d65f97f6c147e75aa83cfb4c22a5b3bd568bf62d"
integrity sha512-CSRn29z64bLEW3GLo6cTwpGjvTgIsfDOBwAiStEOlezzMNlDslvcOBCW0pQUo/0rf5C4zsTy4U1oHDElz7JJ2w==
dependencies:
"@budibase/types" "2.1.22-alpha.8"
"@budibase/types" "2.1.32-alpha.3"
"@shopify/jest-koa-mocks" "5.0.1"
"@techpass/passport-openidconnect" "0.3.2"
aws-sdk "2.1030.0"
@ -1361,13 +1361,13 @@
svelte-flatpickr "^3.2.3"
svelte-portal "^1.0.0"
"@budibase/pro@2.1.22-alpha.8":
version "2.1.22-alpha.8"
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.22-alpha.8.tgz#28d2d7133ce102950ad2e6f0328d12dd8f7091f8"
integrity sha512-qNNfLzNTv4ndZPEUEK4FgwLl+n6KqAisY18hVPj1pURV6zbZXg8vQwQlUNMrzUnvrJsuHAragVjXogmcNyvtVQ==
"@budibase/pro@2.1.32-alpha.3":
version "2.1.32-alpha.3"
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.32-alpha.3.tgz#32d67f5fe3aa6a993022e685f55a298b4fc364b5"
integrity sha512-FwaWZLI8NVSH3Y4RcSvD1ySJXa5yWFgfGha5Zz5rvy3Tw3oSr/AfH91VW4ZLyzpuBQrMJHxLtDmaz3Ywd/jSkQ==
dependencies:
"@budibase/backend-core" "2.1.22-alpha.8"
"@budibase/types" "2.1.22-alpha.8"
"@budibase/backend-core" "2.1.32-alpha.3"
"@budibase/types" "2.1.32-alpha.3"
"@koa/router" "8.0.8"
bull "4.10.1"
joi "17.6.0"
@ -1391,10 +1391,10 @@
svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0"
"@budibase/types@2.1.22-alpha.8":
version "2.1.22-alpha.8"
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.22-alpha.8.tgz#81806dc2e217f0e3b215f967b2e13dbe31144c3a"
integrity sha512-B/ejxypUMbyHThkFKaqNgZgHL4vIrvOeZiDq5NI0xbfzO3616hFcVKWhoHbehYfMMuSzYOgXwegkC4J7CTlE+Q==
"@budibase/types@2.1.32-alpha.3":
version "2.1.32-alpha.3"
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.32-alpha.3.tgz#87d53d7b5730f0067c1526a62f85afb13db82a51"
integrity sha512-4MGPfe63IKJMSS+4HdznyjEnExKGk1rMa2sfVOvRAZWzdVhgo5m0UarwoKf49lDF3NPiqTLdXQnB4p7AmwQbbg==
"@bull-board/api@3.7.0":
version "3.7.0"
@ -10098,9 +10098,9 @@ loader-runner@^4.2.0:
integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
loader-utils@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.3.tgz#d4b15b8504c63d1fc3f2ade52d41bc8459d6ede1"
integrity sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==
version "2.0.4"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/string-templates",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs",
"module": "dist/bundle.mjs",

View file

@ -1,6 +1,9 @@
const dayjs = require("dayjs")
dayjs.extend(require("dayjs/plugin/duration"))
dayjs.extend(require("dayjs/plugin/advancedFormat"))
dayjs.extend(require("dayjs/plugin/isoWeek"))
dayjs.extend(require("dayjs/plugin/weekYear"))
dayjs.extend(require("dayjs/plugin/weekOfYear"))
dayjs.extend(require("dayjs/plugin/relativeTime"))
dayjs.extend(require("dayjs/plugin/utc"))
dayjs.extend(require("dayjs/plugin/timezone"))

View file

@ -1284,7 +1284,7 @@ component-emitter@^1.2.1:
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
concat-stream@^1.4.4:
version "1.6.2"
@ -3178,9 +3178,9 @@ minimalistic-crypto-utils@^1.0.1:
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/types",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Budibase types",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View file

@ -1,6 +1,6 @@
import PouchDB from "pouchdb"
import Nano from "nano"
import { AllDocsResponse, AnyDocument } from "../"
import { AllDocsResponse, AnyDocument, Document } from "../"
export type PouchOptions = {
inMemory?: boolean
@ -33,6 +33,21 @@ export type DatabasePutOpts = {
force?: boolean
}
export type DatabaseCreateIndexOpts = {
index: {
fields: string[]
name?: string | undefined
ddoc?: string | undefined
type?: string | undefined
}
}
export type DatabaseDeleteIndexOpts = {
name: string
ddoc: string
type?: string | undefined
}
export type DatabaseQueryOpts = {
include_docs?: boolean
startkey?: string
@ -44,13 +59,20 @@ export type DatabaseQueryOpts = {
keys?: string[]
}
export const isDocument = (doc: any): doc is Document => {
return typeof doc === "object" && doc._id && doc._rev
}
export interface Database {
name: string
exists(): Promise<boolean>
checkSetup(): Promise<Nano.DocumentScope<any>>
get<T>(id?: string): Promise<T | any>
remove(id?: string, rev?: string): Promise<Nano.DocumentDestroyResponse>
remove(
id: string | Document,
rev?: string
): Promise<Nano.DocumentDestroyResponse>
put(
document: AnyDocument,
opts?: DatabasePutOpts

View file

@ -1,7 +1,15 @@
import { BaseEvent } from "./event"
import { AppBackupTrigger, AppBackupType } from "../../documents"
export interface AppBackupRestoreEvent extends BaseEvent {
appId: string
backupName: string
restoreId: string
backupCreatedAt: string
}
export interface AppBackupTriggeredEvent extends BaseEvent {
backupId: string
appId: string
trigger: AppBackupTrigger
type: AppBackupType
}

View file

@ -171,6 +171,7 @@ export enum Event {
// BACKUP
APP_BACKUP_RESTORED = "app:backup:restored",
APP_BACKUP_TRIGGERED = "app:backup:triggered",
}
// properties added at the final stage of the event pipeline

View file

@ -1,7 +1,7 @@
{
"name": "@budibase/worker",
"email": "hi@budibase.com",
"version": "2.1.22-alpha.8",
"version": "2.1.32-alpha.3",
"description": "Budibase background service",
"main": "src/index.ts",
"repository": {
@ -36,10 +36,10 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
"@budibase/backend-core": "2.1.22-alpha.8",
"@budibase/pro": "2.1.22-alpha.8",
"@budibase/string-templates": "2.1.22-alpha.8",
"@budibase/types": "2.1.22-alpha.8",
"@budibase/backend-core": "2.1.32-alpha.3",
"@budibase/pro": "2.1.32-alpha.3",
"@budibase/string-templates": "2.1.32-alpha.3",
"@budibase/types": "2.1.32-alpha.3",
"@koa/router": "8.0.8",
"@sentry/node": "6.17.7",
"@techpass/passport-openidconnect": "0.3.2",

View file

@ -3,7 +3,7 @@ const controller = require("../../controllers/global/configs")
const { joiValidator } = require("@budibase/backend-core/auth")
const { adminOnly } = require("@budibase/backend-core/auth")
const Joi = require("joi")
const { Config } = require("../../../constants")
const { Config } = require("@budibase/backend-core/constants")
const router = new Router()

View file

@ -470,12 +470,12 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@budibase/backend-core@2.1.22-alpha.8":
version "2.1.22-alpha.8"
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.22-alpha.8.tgz#c68dcd104023b1b0c4b981471fb30387dfce01f7"
integrity sha512-ZQugFvr7j3wxXxOr7P33IrBKORNurwNO/JW5gtQLTStUKxp2ip7TQ1VyXiwBRDurzPuypEMk01L9gHNeWVEA7Q==
"@budibase/backend-core@2.1.32-alpha.3":
version "2.1.32-alpha.3"
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.32-alpha.3.tgz#d65f97f6c147e75aa83cfb4c22a5b3bd568bf62d"
integrity sha512-CSRn29z64bLEW3GLo6cTwpGjvTgIsfDOBwAiStEOlezzMNlDslvcOBCW0pQUo/0rf5C4zsTy4U1oHDElz7JJ2w==
dependencies:
"@budibase/types" "2.1.22-alpha.8"
"@budibase/types" "2.1.32-alpha.3"
"@shopify/jest-koa-mocks" "5.0.1"
"@techpass/passport-openidconnect" "0.3.2"
aws-sdk "2.1030.0"
@ -508,22 +508,22 @@
uuid "8.3.2"
zlib "1.0.5"
"@budibase/pro@2.1.22-alpha.8":
version "2.1.22-alpha.8"
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.22-alpha.8.tgz#28d2d7133ce102950ad2e6f0328d12dd8f7091f8"
integrity sha512-qNNfLzNTv4ndZPEUEK4FgwLl+n6KqAisY18hVPj1pURV6zbZXg8vQwQlUNMrzUnvrJsuHAragVjXogmcNyvtVQ==
"@budibase/pro@2.1.32-alpha.3":
version "2.1.32-alpha.3"
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.32-alpha.3.tgz#32d67f5fe3aa6a993022e685f55a298b4fc364b5"
integrity sha512-FwaWZLI8NVSH3Y4RcSvD1ySJXa5yWFgfGha5Zz5rvy3Tw3oSr/AfH91VW4ZLyzpuBQrMJHxLtDmaz3Ywd/jSkQ==
dependencies:
"@budibase/backend-core" "2.1.22-alpha.8"
"@budibase/types" "2.1.22-alpha.8"
"@budibase/backend-core" "2.1.32-alpha.3"
"@budibase/types" "2.1.32-alpha.3"
"@koa/router" "8.0.8"
bull "4.10.1"
joi "17.6.0"
node-fetch "^2.6.1"
"@budibase/types@2.1.22-alpha.8":
version "2.1.22-alpha.8"
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.22-alpha.8.tgz#81806dc2e217f0e3b215f967b2e13dbe31144c3a"
integrity sha512-B/ejxypUMbyHThkFKaqNgZgHL4vIrvOeZiDq5NI0xbfzO3616hFcVKWhoHbehYfMMuSzYOgXwegkC4J7CTlE+Q==
"@budibase/types@2.1.32-alpha.3":
version "2.1.32-alpha.3"
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.32-alpha.3.tgz#87d53d7b5730f0067c1526a62f85afb13db82a51"
integrity sha512-4MGPfe63IKJMSS+4HdznyjEnExKGk1rMa2sfVOvRAZWzdVhgo5m0UarwoKf49lDF3NPiqTLdXQnB4p7AmwQbbg==
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"