Merge branch 'master' of github.com:Budibase/budibase into develop

This commit is contained in:
mike12345567 2022-10-06 16:54:25 +01:00
commit ea2fb6de1b
33 changed files with 257 additions and 155 deletions

View File

@ -19,8 +19,8 @@ ADD packages/worker .
RUN node /pinVersions.js && yarn && yarn build && /cleanup.sh RUN node /pinVersions.js && yarn && yarn build && /cleanup.sh
FROM couchdb:3.2.1 FROM couchdb:3.2.1
# TARGETARCH can be amd64 or arm e.g. docker build --build-arg TARGETARCH=amd64 ARG TARGETARCH
ARG TARGETARCH=amd64 ENV TARGETARCH $TARGETARCH
#TARGETBUILD can be set to single (for single docker image) or aas (for azure app service) #TARGETBUILD can be set to single (for single docker image) or aas (for azure app service)
# e.g. docker build --build-arg TARGETBUILD=aas .... # e.g. docker build --build-arg TARGETBUILD=aas ....
ARG TARGETBUILD=single ARG TARGETBUILD=single

View File

@ -1,5 +1,5 @@
{ {
"version": "2.0.14-alpha.1", "version": "2.0.23",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

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

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/bbui", "name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.", "description": "A UI solution used in the different Budibase projects.",
"version": "2.0.14-alpha.1", "version": "2.0.23",
"license": "MPL-2.0", "license": "MPL-2.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"module": "dist/bbui.es.js", "module": "dist/bbui.es.js",
@ -38,7 +38,7 @@
], ],
"dependencies": { "dependencies": {
"@adobe/spectrum-css-workflow-icons": "^1.2.1", "@adobe/spectrum-css-workflow-icons": "^1.2.1",
"@budibase/string-templates": "2.0.14-alpha.1", "@budibase/string-templates": "^2.0.23",
"@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actionbutton": "^1.0.1",
"@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1",
"@spectrum-css/avatar": "^3.0.2", "@spectrum-css/avatar": "^3.0.2",

View File

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

View File

@ -396,19 +396,17 @@ export const getUserBindings = () => {
bindings = keys.reduce((acc, key) => { bindings = keys.reduce((acc, key) => {
const fieldSchema = schema[key] const fieldSchema = schema[key]
if (fieldSchema.type !== "link") { acc.push({
acc.push({ type: "context",
type: "context", runtimeBinding: `${safeUser}.${makePropSafe(key)}`,
runtimeBinding: `${safeUser}.${makePropSafe(key)}`, readableBinding: `Current User.${key}`,
readableBinding: `Current User.${key}`, // Field schema and provider are required to construct relationship
// Field schema and provider are required to construct relationship // datasource options, based on bindable properties
// datasource options, based on bindable properties fieldSchema,
fieldSchema, providerId: "user",
providerId: "user", category: "Current User",
category: "Current User", icon: "User",
icon: "User", })
})
}
return acc return acc
}, []) }, [])

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/cli", "name": "@budibase/cli",
"version": "2.0.14-alpha.1", "version": "2.0.23",
"description": "Budibase CLI, for developers, self hosting and migrations.", "description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js", "main": "src/index.js",
"bin": { "bin": {
@ -26,9 +26,9 @@
"outputPath": "build" "outputPath": "build"
}, },
"dependencies": { "dependencies": {
"@budibase/backend-core": "2.0.14-alpha.1", "@budibase/backend-core": "^2.0.23",
"@budibase/string-templates": "2.0.14-alpha.1", "@budibase/string-templates": "^2.0.23",
"@budibase/types": "2.0.14-alpha.1", "@budibase/types": "^2.0.23",
"axios": "0.21.2", "axios": "0.21.2",
"chalk": "4.1.0", "chalk": "4.1.0",
"cli-progress": "3.11.2", "cli-progress": "3.11.2",

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/client", "name": "@budibase/client",
"version": "2.0.14-alpha.1", "version": "2.0.23",
"license": "MPL-2.0", "license": "MPL-2.0",
"module": "dist/budibase-client.js", "module": "dist/budibase-client.js",
"main": "dist/budibase-client.js", "main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "2.0.14-alpha.1", "@budibase/bbui": "^2.0.23",
"@budibase/frontend-core": "2.0.14-alpha.1", "@budibase/frontend-core": "^2.0.23",
"@budibase/string-templates": "2.0.14-alpha.1", "@budibase/string-templates": "^2.0.23",
"@spectrum-css/button": "^3.0.3", "@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3", "@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3", "@spectrum-css/divider": "^1.0.3",

View File

@ -16,7 +16,6 @@
themeStore, themeStore,
appStore, appStore,
devToolsStore, devToolsStore,
environmentStore,
} from "stores" } from "stores"
import NotificationDisplay from "components/overlay/NotificationDisplay.svelte" import NotificationDisplay from "components/overlay/NotificationDisplay.svelte"
import ConfirmationDisplay from "components/overlay/ConfirmationDisplay.svelte" import ConfirmationDisplay from "components/overlay/ConfirmationDisplay.svelte"
@ -48,8 +47,6 @@
!$builderStore.inBuilder && !$builderStore.inBuilder &&
$devToolsStore.enabled && $devToolsStore.enabled &&
!$routeStore.queryParams?.peek !$routeStore.queryParams?.peek
$: objectStoreUrl = $environmentStore.cloud ? "https://cdn.budi.live" : ""
$: pluginsUrl = `${objectStoreUrl}/plugins`
// Handle no matching route // Handle no matching route
$: { $: {
@ -95,8 +92,7 @@
<svelte:head> <svelte:head>
{#if $builderStore.usedPlugins?.length} {#if $builderStore.usedPlugins?.length}
{#each $builderStore.usedPlugins as plugin (plugin.hash)} {#each $builderStore.usedPlugins as plugin (plugin.hash)}
<script <script src={`${plugin.jsUrl}?r=${plugin.hash || ""}`}></script>
src={`${pluginsUrl}/${plugin.jsUrl}?r=${plugin.hash || ""}`}></script>
{/each} {/each}
{/if} {/if}
</svelte:head> </svelte:head>

View File

@ -1,37 +1,39 @@
export class ApexOptionsBuilder { export class ApexOptionsBuilder {
formatters = { constructor() {
["Default"]: val => (isNaN(val) ? val : Math.round(val * 100) / 100), this.formatters = {
["Thousands"]: val => `${Math.round(val / 1000)}K`, ["Default"]: val => (isNaN(val) ? val : Math.round(val * 100) / 100),
["Millions"]: val => `${Math.round(val / 1000000)}M`, ["Thousands"]: val => `${Math.round(val / 1000)}K`,
} ["Millions"]: val => `${Math.round(val / 1000000)}M`,
options = { }
series: [], this.options = {
legend: { series: [],
show: false, legend: {
position: "top",
horizontalAlign: "right",
showForSingleSeries: true,
showForNullSeries: true,
showForZeroSeries: true,
},
chart: {
toolbar: {
show: false, show: false,
position: "top",
horizontalAlign: "right",
showForSingleSeries: true,
showForNullSeries: true,
showForZeroSeries: true,
}, },
zoom: { chart: {
enabled: false, toolbar: {
show: false,
},
zoom: {
enabled: false,
},
}, },
}, xaxis: {
xaxis: { labels: {
labels: { formatter: this.formatters.Default,
formatter: this.formatters.Default, },
}, },
}, yaxis: {
yaxis: { labels: {
labels: { formatter: this.formatters.Default,
formatter: this.formatters.Default, },
}, },
}, }
} }
setOption(path, value) { setOption(path, value) {

View File

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

View File

@ -14,52 +14,52 @@ import { convertJSONSchemaToTableSchema } from "../utils/json"
* For other types of datasource, this class is overridden and extended. * For other types of datasource, this class is overridden and extended.
*/ */
export default class DataFetch { export default class DataFetch {
// API client
API = null
// Feature flags
featureStore = writable({
supportsSearch: false,
supportsSort: false,
supportsPagination: false,
})
// Config
options = {
datasource: null,
limit: 10,
// Search config
filter: null,
query: null,
// Sorting config
sortColumn: null,
sortOrder: "ascending",
sortType: null,
// Pagination config
paginate: true,
}
// State of the fetch
store = writable({
rows: [],
info: null,
schema: null,
loading: false,
loaded: false,
query: null,
pageNumber: 0,
cursor: null,
cursors: [],
})
/** /**
* Constructs a new DataFetch instance. * Constructs a new DataFetch instance.
* @param opts the fetch options * @param opts the fetch options
*/ */
constructor(opts) { constructor(opts) {
// API client
this.API = null
// Feature flags
this.featureStore = writable({
supportsSearch: false,
supportsSort: false,
supportsPagination: false,
})
// Config
this.options = {
datasource: null,
limit: 10,
// Search config
filter: null,
query: null,
// Sorting config
sortColumn: null,
sortOrder: "ascending",
sortType: null,
// Pagination config
paginate: true,
}
// State of the fetch
this.store = writable({
rows: [],
info: null,
schema: null,
loading: false,
loaded: false,
query: null,
pageNumber: 0,
cursor: null,
cursors: [],
})
// Merge options with their default values // Merge options with their default values
this.API = opts?.API this.API = opts?.API
this.options = { this.options = {

View File

@ -121,7 +121,12 @@ export const buildLuceneQuery = filter => {
query.allOr = true query.allOr = true
return return
} }
if (type === "datetime" && !isHbs) { if (
type === "datetime" &&
!isHbs &&
operator !== "empty" &&
operator !== "notEmpty"
) {
// Ensure date value is a valid date and parse into correct format // Ensure date value is a valid date and parse into correct format
if (!value) { if (!value) {
return return

View File

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

View File

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

View File

@ -50,6 +50,7 @@ import { errors, events, migrations } from "@budibase/backend-core"
import { App, Layout, Screen, MigrationType } from "@budibase/types" import { App, Layout, Screen, MigrationType } from "@budibase/types"
import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts" import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts"
import { groups } from "@budibase/pro" import { groups } from "@budibase/pro"
import { enrichPluginURLs } from "../../utilities/plugins"
const URL_REGEX_SLASH = /\/|\\/g const URL_REGEX_SLASH = /\/|\\/g
@ -208,10 +209,13 @@ export const fetchAppDefinition = async (ctx: any) => {
export const fetchAppPackage = async (ctx: any) => { export const fetchAppPackage = async (ctx: any) => {
const db = context.getAppDB() const db = context.getAppDB()
const application = await db.get(DocumentType.APP_METADATA) let application = await db.get(DocumentType.APP_METADATA)
const layouts = await getLayouts() const layouts = await getLayouts()
let screens = await getScreens() let screens = await getScreens()
// Enrich plugin URLs
application.usedPlugins = enrichPluginURLs(application.usedPlugins)
// Only filter screens if the user is not a builder // Only filter screens if the user is not a builder
if (!(ctx.user.builder && ctx.user.builder.global)) { if (!(ctx.user.builder && ctx.user.builder.global)) {
const userRoleId = getUserRoleId(ctx) const userRoleId = getUserRoleId(ctx)

View File

@ -68,6 +68,7 @@ exports.buildSchemaFromDb = async function (ctx) {
datasource.entities = tables datasource.entities = tables
} }
setDefaultDisplayColumns(datasource)
const dbResp = await db.put(datasource) const dbResp = await db.put(datasource)
datasource._rev = dbResp.rev datasource._rev = dbResp.rev
@ -78,6 +79,24 @@ exports.buildSchemaFromDb = async function (ctx) {
ctx.body = response ctx.body = response
} }
/**
* Make sure all datasource entities have a display name selected
*/
const setDefaultDisplayColumns = datasource => {
//
for (let entity of Object.values(datasource.entities)) {
if (entity.primaryDisplay) {
continue
}
const notAutoColumn = Object.values(entity.schema).find(
schema => !schema.autocolumn
)
if (notAutoColumn) {
entity.primaryDisplay = notAutoColumn.name
}
}
}
/** /**
* Check for variables that have been updated or removed and invalidate them. * Check for variables that have been updated or removed and invalidate them.
*/ */
@ -155,6 +174,7 @@ exports.save = async function (ctx) {
const { tables, error } = await buildSchemaHelper(datasource) const { tables, error } = await buildSchemaHelper(datasource)
schemaError = error schemaError = error
datasource.entities = tables datasource.entities = tables
setDefaultDisplayColumns(datasource)
} }
const dbResp = await db.put(datasource) const dbResp = await db.put(datasource)
@ -238,19 +258,6 @@ const buildSchemaHelper = async datasource => {
const connector = new Connector(datasource.config) const connector = new Connector(datasource.config)
await connector.buildSchema(datasource._id, datasource.entities) await connector.buildSchema(datasource._id, datasource.entities)
// make sure they all have a display name selected
for (let entity of Object.values(datasource.entities ?? {})) {
if (entity.primaryDisplay) {
continue
}
const notAutoColumn = Object.values(entity.schema).find(
schema => !schema.autocolumn
)
if (notAutoColumn) {
entity.primaryDisplay = notAutoColumn.name
}
}
const errors = connector.schemaErrors const errors = connector.schemaErrors
let error = null let error = null
if (errors && Object.keys(errors).length > 0) { if (errors && Object.keys(errors).length > 0) {

View File

@ -52,14 +52,19 @@ export async function read(ctx: any, next: any) {
} }
export async function update(ctx: any, next: any) { export async function update(ctx: any, next: any) {
ctx.request.body = await addRev(fixRow(ctx.request.body, ctx.params)) const { tableId } = ctx.params
ctx.request.body = await addRev(fixRow(ctx.request.body, ctx.params), tableId)
await rowController.save(ctx) await rowController.save(ctx)
await next() await next()
} }
export async function destroy(ctx: any, next: any) { export async function destroy(ctx: any, next: any) {
const { tableId } = ctx.params
// set the body as expected, with the _id and _rev fields // set the body as expected, with the _id and _rev fields
ctx.request.body = await addRev(fixRow({ _id: ctx.params.rowId }, ctx.params)) ctx.request.body = await addRev(
fixRow({ _id: ctx.params.rowId }, ctx.params),
tableId
)
await rowController.destroy(ctx) await rowController.destroy(ctx)
// destroy controller doesn't currently return the row as the body, need to adjust this // destroy controller doesn't currently return the row as the body, need to adjust this
// in the public API to be correct // in the public API to be correct

View File

@ -22,7 +22,7 @@ export async function addRev(
} }
/** /**
* Performs a case insensitive search on the provided documents, using the * Performs a case in-sensitive search on the provided documents, using the
* provided key and value. This will be a string based search, using the * provided key and value. This will be a string based search, using the
* startsWith function. * startsWith function.
*/ */

View File

@ -240,6 +240,10 @@ async function execute(
const { rows, pagination, extra } = await quotas.addQuery(runFn, { const { rows, pagination, extra } = await quotas.addQuery(runFn, {
datasourceId: datasource._id, datasourceId: datasource._id,
}) })
// remove the raw from execution incase transformer being used to hide data
if (extra?.raw) {
delete extra.raw
}
if (opts && opts.rowsOnly) { if (opts && opts.rowsOnly) {
ctx.body = rows ctx.body = rows
} else { } else {

View File

@ -145,7 +145,7 @@ class QueryBuilder {
* @param options The preprocess options * @param options The preprocess options
* @returns {string|*} * @returns {string|*}
*/ */
preprocess(value, { escape, lowercase, wrap } = {}) { preprocess(value, { escape, lowercase, wrap, type } = {}) {
const hasVersion = !!this.version const hasVersion = !!this.version
// Determine if type needs wrapped // Determine if type needs wrapped
const originalType = typeof value const originalType = typeof value
@ -157,8 +157,11 @@ class QueryBuilder {
if (escape && originalType === "string") { if (escape && originalType === "string") {
value = `${value}`.replace(/[ #+\-&|!(){}\]^"~*?:\\]/g, "\\$&") value = `${value}`.replace(/[ #+\-&|!(){}\]^"~*?:\\]/g, "\\$&")
} }
// Wrap in quotes // Wrap in quotes
if (hasVersion && wrap) { if (originalType === "string" && !isNaN(value) && !type) {
value = `"${value}"`
} else if (hasVersion && wrap) {
value = originalType === "number" ? value : `"${value}"` value = originalType === "number" ? value : `"${value}"`
} }
return value return value
@ -253,6 +256,7 @@ class QueryBuilder {
value = builder.preprocess(value, { value = builder.preprocess(value, {
escape: true, escape: true,
lowercase: true, lowercase: true,
type: "string",
}) })
return `${key}:${value}*` return `${key}:${value}*`
}) })
@ -281,6 +285,7 @@ class QueryBuilder {
value = builder.preprocess(value, { value = builder.preprocess(value, {
escape: true, escape: true,
lowercase: true, lowercase: true,
type: "fuzzy",
}) })
return `${key}:${value}~` return `${key}:${value}~`
}) })

View File

@ -1,3 +1,5 @@
import { enrichPluginURLs } from "../../../utilities/plugins"
require("svelte/register") require("svelte/register")
const send = require("koa-send") const send = require("koa-send")
@ -107,12 +109,13 @@ export const serveApp = async function (ctx: any) {
if (!env.isJest()) { if (!env.isJest()) {
const App = require("./templates/BudibaseApp.svelte").default const App = require("./templates/BudibaseApp.svelte").default
const plugins = enrichPluginURLs(appInfo.usedPlugins)
const { head, html, css } = App.render({ const { head, html, css } = App.render({
title: appInfo.name, title: appInfo.name,
production: env.isProd(), production: env.isProd(),
appId, appId,
clientLibPath: clientLibraryPath(appId, appInfo.version, ctx), clientLibPath: clientLibraryPath(appId, appInfo.version, ctx),
usedPlugins: appInfo.usedPlugins, usedPlugins: plugins,
}) })
const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`) const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`)

View File

@ -88,9 +88,7 @@
<!-- But before loadBudibase is called --> <!-- But before loadBudibase is called -->
{#if usedPlugins?.length} {#if usedPlugins?.length}
{#each usedPlugins as plugin} {#each usedPlugins as plugin}
<script <script type="application/javascript" src={plugin.jsUrl}></script>
type="application/javascript"
src={`/plugins/${plugin.jsUrl}`}></script>
{/each} {/each}
{/if} {/if}
<script type="application/javascript"> <script type="application/javascript">

View File

@ -14,8 +14,10 @@ import {
fixAutoColumnSubType, fixAutoColumnSubType,
} from "../../../utilities/rowProcessor" } from "../../../utilities/rowProcessor"
import { runStaticFormulaChecks } from "./bulkFormula" import { runStaticFormulaChecks } from "./bulkFormula"
import { Table } from "../../../definitions/common" import { Table } from "@budibase/types"
import { quotas } from "@budibase/pro" import { quotas } from "@budibase/pro"
import { isEqual } from "lodash"
import { cloneDeep } from "lodash/fp"
function checkAutoColumns(table: Table, oldTable: Table) { function checkAutoColumns(table: Table, oldTable: Table) {
if (!table.schema) { if (!table.schema) {
@ -123,10 +125,16 @@ export async function save(ctx: any) {
if (updatedRows && updatedRows.length !== 0) { if (updatedRows && updatedRows.length !== 0) {
await db.bulkDocs(updatedRows) await db.bulkDocs(updatedRows)
} }
const result = await db.put(tableToSave) let result = await db.put(tableToSave)
tableToSave._rev = result.rev tableToSave._rev = result.rev
const savedTable = cloneDeep(tableToSave)
tableToSave = await tableSaveFunctions.after(tableToSave) tableToSave = await tableSaveFunctions.after(tableToSave)
// the table may be updated as part of the table save after functionality - need to write it
if (!isEqual(savedTable, tableToSave)) {
result = await db.put(tableToSave)
tableToSave._rev = result.rev
}
// has to run after, make sure it has _id // has to run after, make sure it has _id
await runStaticFormulaChecks(tableToSave, { oldTable, deletion: null }) await runStaticFormulaChecks(tableToSave, { oldTable, deletion: null })
return tableToSave return tableToSave

View File

@ -247,7 +247,7 @@ class TableSaveFunctions {
// after saving // after saving
async after(table: any) { async after(table: any) {
table = await handleSearchIndexes(table) table = await handleSearchIndexes(table)
await handleDataImport(this.user, table, this.dataImport) table = await handleDataImport(this.user, table, this.dataImport)
return table return table
} }

View File

@ -173,4 +173,24 @@ describe("internal search", () => {
}, PARAMS) }, PARAMS)
checkLucene(response, `*:* AND NOT column:(a AND b AND c)`, PARAMS) checkLucene(response, `*:* AND NOT column:(a AND b AND c)`, PARAMS)
}) })
it("test equal without version query", async () => {
PARAMS.version = null
const response = await search.paginatedSearch({
equal: {
"column": "1",
}
}, PARAMS)
const query = response.rows[0].query
const json = JSON.parse(query)
if (PARAMS.sort) {
expect(json.sort).toBe(`${PARAMS.sort}<${PARAMS.sortType}>`)
}
if (PARAMS.bookmark) {
expect(json.bookmark).toBe(PARAMS.bookmark)
}
expect(json.include_docs).toBe(true)
expect(json.q).toBe(`(*:* AND column:"1") AND tableId:${PARAMS.tableId}`)
})
}) })

View File

@ -252,7 +252,7 @@ class Orchestrator {
let loopStepNumber: any = undefined let loopStepNumber: any = undefined
let loopSteps: LoopStep[] | undefined = [] let loopSteps: LoopStep[] | undefined = []
let metadata let metadata
let wasLoopStep = false
// check if this is a recurring automation, // check if this is a recurring automation,
if (isProdAppID(this._appId) && isRecurring(automation)) { if (isProdAppID(this._appId) && isRecurring(automation)) {
metadata = await this.getMetadata() metadata = await this.getMetadata()
@ -267,6 +267,7 @@ class Orchestrator {
let input, let input,
iterations = 1, iterations = 1,
iterationCount = 0 iterationCount = 0
if (step.stepId === LOOP_STEP_ID) { if (step.stepId === LOOP_STEP_ID) {
loopStep = step loopStep = step
loopStepNumber = stepCount loopStepNumber = stepCount
@ -277,10 +278,8 @@ class Orchestrator {
input = await processObject(loopStep.inputs, this._context) input = await processObject(loopStep.inputs, this._context)
iterations = getLoopIterations(loopStep as LoopStep, input) iterations = getLoopIterations(loopStep as LoopStep, input)
} }
for (let index = 0; index < iterations; index++) { for (let index = 0; index < iterations; index++) {
let originalStepInput = cloneDeep(step.inputs) let originalStepInput = cloneDeep(step.inputs)
// Handle if the user has set a max iteration count or if it reaches the max limit set by us // Handle if the user has set a max iteration count or if it reaches the max limit set by us
if (loopStep && input.binding) { if (loopStep && input.binding) {
let newInput = await processObject( let newInput = await processObject(
@ -313,7 +312,6 @@ class Orchestrator {
} else { } else {
item = loopStep.inputs.binding item = loopStep.inputs.binding
} }
this._context.steps[loopStepNumber] = { this._context.steps[loopStepNumber] = {
currentItem: item[index], currentItem: item[index],
} }
@ -331,6 +329,16 @@ class Orchestrator {
innerValue, innerValue,
`steps.${loopStepNumber}` `steps.${loopStepNumber}`
) )
} else if (typeof value === "object") {
for (let [innerObject, innerValue] of Object.entries(
originalStepInput[key][innerKey]
)) {
originalStepInput[key][innerKey][innerObject] =
automationUtils.substituteLoopStep(
innerValue,
`steps.${loopStepNumber}`
)
}
} }
} }
} else { } else {
@ -386,6 +394,7 @@ class Orchestrator {
let stepFn = await this.getStepFunctionality(step.stepId) let stepFn = await this.getStepFunctionality(step.stepId)
let inputs = await processObject(originalStepInput, this._context) let inputs = await processObject(originalStepInput, this._context)
inputs = automationUtils.cleanInputValues(inputs, step.schema.inputs) inputs = automationUtils.cleanInputValues(inputs, step.schema.inputs)
try { try {
// appId is always passed // appId is always passed
const outputs = await stepFn({ const outputs = await stepFn({
@ -394,6 +403,7 @@ class Orchestrator {
emitter: this._emitter, emitter: this._emitter,
context: this._context, context: this._context,
}) })
this._context.steps[stepCount] = outputs this._context.steps[stepCount] = outputs
// if filter causes us to stop execution don't break the loop, set a var // if filter causes us to stop execution don't break the loop, set a var
// so that we can finish iterating through the steps and record that it stopped // so that we can finish iterating through the steps and record that it stopped
@ -419,6 +429,7 @@ class Orchestrator {
console.error(`Automation error - ${step.stepId} - ${err}`) console.error(`Automation error - ${step.stepId} - ${err}`)
return err return err
} }
if (loopStep) { if (loopStep) {
iterationCount++ iterationCount++
if (index === iterations - 1) { if (index === iterations - 1) {
@ -429,6 +440,13 @@ class Orchestrator {
} }
} }
// Delete the step after the loop step as it's irrelevant, since information is included
// in the loop step
if (wasLoopStep) {
this._context.steps.splice(loopStepNumber + 1, 1)
wasLoopStep = false
}
if (loopSteps && loopSteps.length) { if (loopSteps && loopSteps.length) {
let tempOutput = { let tempOutput = {
success: true, success: true,
@ -441,9 +459,10 @@ class Orchestrator {
outputs: tempOutput, outputs: tempOutput,
inputs: step.inputs, inputs: step.inputs,
}) })
this._context.steps[loopStepNumber] = tempOutput
this._context.steps.splice(loopStepNumber, 0, tempOutput)
loopSteps = undefined loopSteps = undefined
wasLoopStep = true
} }
} }

View File

@ -0,0 +1,21 @@
const env = require("../environment")
const { plugins: ProPlugins } = require("@budibase/pro")
const { objectStore } = require("@budibase/backend-core")
exports.enrichPluginURLs = plugins => {
if (!plugins || !plugins.length) {
return []
}
return plugins.map(plugin => {
const cloud = !env.SELF_HOSTED
const bucket = objectStore.ObjectStoreBuckets.PLUGINS
const jsFileName = "plugin.min.js"
// In self host we need to prefix the path, as the bucket name is not part
// of the bucket path. In cloud, it's already part of the bucket path.
let jsUrl = cloud ? "https://cdn.budi.live/" : `/${bucket}/`
jsUrl += ProPlugins.getBucketPath(plugin.name)
jsUrl += jsFileName
return { ...plugin, jsUrl }
})
}

View File

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

View File

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

View File

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

View File

@ -1,8 +1,10 @@
#!/bin/bash #!/bin/bash
if [[ $TARGETARCH == arm* ]] ; if [[ $TARGETARCH == arm* ]] ;
then then
echo "INSTALLING ARM64 MINIO"
wget https://dl.min.io/server/minio/release/linux-arm64/minio wget https://dl.min.io/server/minio/release/linux-arm64/minio
else else
echo "INSTALLING AMD64 MINIO"
wget https://dl.min.io/server/minio/release/linux-amd64/minio wget https://dl.min.io/server/minio/release/linux-amd64/minio
fi fi
chmod +x minio chmod +x minio

View File

@ -18,6 +18,11 @@ git clone https://$PERSONAL_ACCESS_TOKEN@github.com/Budibase/budibase-pro.git
if [[ -d "budibase-pro" ]]; then if [[ -d "budibase-pro" ]]; then
cd budibase-pro cd budibase-pro
if [[ -z "${BRANCH}" ]]; then
echo Using GITHUB_REF_NAME: $GITHUB_REF_NAME
export BRANCH=$GITHUB_REF_NAME
fi
# Try to checkout the matching pro branch # Try to checkout the matching pro branch
git checkout $BRANCH git checkout $BRANCH