Merge branch 'develop' of github.com:Budibase/budibase into group-fixes
This commit is contained in:
commit
9b29bd6709
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
name: Epic
|
||||||
|
about: Plan a new project
|
||||||
|
title: ''
|
||||||
|
labels: epic
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
Brief summary of what this Epic is, whether it's a larger project, goal, or user story. Describe the job to be done, which persona this Epic is mainly for, or if more multiple, break it down by user and job story.
|
||||||
|
|
||||||
|
## Spec
|
||||||
|
Link to confluence spec
|
||||||
|
|
||||||
|
## Teams and Stakeholders
|
||||||
|
Describe who needs to be kept up-to-date about this Epic, included in discussions, or updated along the way. Stakeholders can be both in Product/Engineering, as well as other teams like Customer Success who might want to keep customers updated on the Epic project.
|
||||||
|
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
- [ ] Spec Created and pasted above
|
||||||
|
- [ ] Product Review
|
||||||
|
- [ ] Designs created
|
||||||
|
- [ ] Individual Tasks created and assigned to Epic
|
|
@ -76,6 +76,7 @@ affinity: {}
|
||||||
globals:
|
globals:
|
||||||
appVersion: "latest"
|
appVersion: "latest"
|
||||||
budibaseEnv: PRODUCTION
|
budibaseEnv: PRODUCTION
|
||||||
|
tenantFeatureFlags: "*:LICENSING,*:USER_GROUPS"
|
||||||
enableAnalytics: "1"
|
enableAnalytics: "1"
|
||||||
sentryDSN: ""
|
sentryDSN: ""
|
||||||
posthogToken: "phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU"
|
posthogToken: "phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
declare -a ENV_VARS=("COUCHDB_USER" "COUCHDB_PASSWORD" "DATA_DIR" "MINIO_ACCESS_KEY" "MINIO_SECRET_KEY" "INTERNAL_API_KEY" "JWT_SECRET" "REDIS_PASSWORD")
|
declare -a ENV_VARS=("COUCHDB_USER" "COUCHDB_PASSWORD" "DATA_DIR" "MINIO_ACCESS_KEY" "MINIO_SECRET_KEY" "INTERNAL_API_KEY" "JWT_SECRET" "REDIS_PASSWORD")
|
||||||
declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONMENT" "CLUSTER_PORT" "DEPLOYMENT_ENVIRONMENT" "MINIO_URL" "NODE_ENV" "POSTHOG_TOKEN" "REDIS_URL" "SELF_HOSTED" "WORKER_PORT" "WORKER_URL")
|
declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONMENT" "CLUSTER_PORT" "DEPLOYMENT_ENVIRONMENT" "MINIO_URL" "NODE_ENV" "POSTHOG_TOKEN" "REDIS_URL" "SELF_HOSTED" "WORKER_PORT" "WORKER_URL" "TENANT_FEATURE_FLAGS")
|
||||||
# Check the env vars set in Dockerfile have come through, AAS seems to drop them
|
# Check the env vars set in Dockerfile have come through, AAS seems to drop them
|
||||||
[[ -z "${APP_PORT}" ]] && export APP_PORT=4001
|
[[ -z "${APP_PORT}" ]] && export APP_PORT=4001
|
||||||
[[ -z "${ARCHITECTURE}" ]] && export ARCHITECTURE=amd
|
[[ -z "${ARCHITECTURE}" ]] && export ARCHITECTURE=amd
|
||||||
|
@ -10,6 +10,7 @@ declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONME
|
||||||
[[ -z "${MINIO_URL}" ]] && export MINIO_URL=http://localhost:9000
|
[[ -z "${MINIO_URL}" ]] && export MINIO_URL=http://localhost:9000
|
||||||
[[ -z "${NODE_ENV}" ]] && export NODE_ENV=production
|
[[ -z "${NODE_ENV}" ]] && export NODE_ENV=production
|
||||||
[[ -z "${POSTHOG_TOKEN}" ]] && export POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
[[ -z "${POSTHOG_TOKEN}" ]] && export POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||||
|
[[ -z "${TENANT_FEATURE_FLAGS}" ]] && export TENANT_FEATURE_FLAGS="*:LICENSING,*:USER_GROUPS"
|
||||||
[[ -z "${REDIS_URL}" ]] && export REDIS_URL=localhost:6379
|
[[ -z "${REDIS_URL}" ]] && export REDIS_URL=localhost:6379
|
||||||
[[ -z "${SELF_HOSTED}" ]] && export SELF_HOSTED=1
|
[[ -z "${SELF_HOSTED}" ]] && export SELF_HOSTED=1
|
||||||
[[ -z "${WORKER_PORT}" ]] && export WORKER_PORT=4002
|
[[ -z "${WORKER_PORT}" ]] && export WORKER_PORT=4002
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"kill-port": "^1.6.1",
|
"kill-port": "^1.6.1",
|
||||||
"lerna": "3.14.1",
|
"lerna": "3.14.1",
|
||||||
|
"madge": "^5.0.1",
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
"prettier-plugin-svelte": "^2.3.0",
|
"prettier-plugin-svelte": "^2.3.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
"bootstrap": "lerna bootstrap && lerna link && ./scripts/link-dependencies.sh",
|
"bootstrap": "lerna bootstrap && lerna link && ./scripts/link-dependencies.sh",
|
||||||
"build": "lerna run build",
|
"build": "lerna run build",
|
||||||
"build:dev": "lerna run prebuild && tsc --build --watch --preserveWatchOutput",
|
"build:dev": "lerna run prebuild && tsc --build --watch --preserveWatchOutput",
|
||||||
|
"deps:circular": "madge packages/server/dist/index.js packages/worker/src/index.ts packages/backend-core/dist/src/index.js packages/cli/src/index.js --circular",
|
||||||
"release": "lerna publish ${RELEASE_VERSION_TYPE:-patch} --yes --force-publish && yarn release:pro",
|
"release": "lerna publish ${RELEASE_VERSION_TYPE:-patch} --yes --force-publish && yarn release:pro",
|
||||||
"release:develop": "lerna publish prerelease --yes --force-publish --dist-tag develop --exact && yarn release:pro:develop",
|
"release:develop": "lerna publish prerelease --yes --force-publish --dist-tag develop --exact && yarn release:pro:develop",
|
||||||
"release:pro": "bash scripts/pro/release.sh",
|
"release:pro": "bash scripts/pro/release.sh",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/backend-core",
|
"name": "@budibase/backend-core",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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": "1.3.21-alpha.0",
|
"@budibase/types": "1.4.8-alpha.3",
|
||||||
"@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",
|
||||||
|
|
|
@ -2,7 +2,7 @@ import env from "../environment"
|
||||||
import { SEPARATOR, DocumentType } from "../db/constants"
|
import { SEPARATOR, DocumentType } from "../db/constants"
|
||||||
import cls from "./FunctionContext"
|
import cls from "./FunctionContext"
|
||||||
import { dangerousGetDB, closeDB } from "../db"
|
import { dangerousGetDB, closeDB } from "../db"
|
||||||
import { baseGlobalDBName } from "../tenancy/utils"
|
import { baseGlobalDBName } from "../db/tenancy"
|
||||||
import { IdentityContext } from "@budibase/types"
|
import { IdentityContext } from "@budibase/types"
|
||||||
import { DEFAULT_TENANT_ID as _DEFAULT_TENANT_ID } from "../constants"
|
import { DEFAULT_TENANT_ID as _DEFAULT_TENANT_ID } from "../constants"
|
||||||
import { ContextKey } from "./constants"
|
import { ContextKey } from "./constants"
|
||||||
|
|
|
@ -45,6 +45,7 @@ export enum DocumentType {
|
||||||
DEV_INFO = "devinfo",
|
DEV_INFO = "devinfo",
|
||||||
AUTOMATION_LOG = "log_au",
|
AUTOMATION_LOG = "log_au",
|
||||||
ACCOUNT_METADATA = "acc_metadata",
|
ACCOUNT_METADATA = "acc_metadata",
|
||||||
|
PLUGIN = "plg",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StaticDatabases = {
|
export const StaticDatabases = {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { DEFAULT_TENANT_ID } from "../constants"
|
import { DEFAULT_TENANT_ID } from "../constants"
|
||||||
import { StaticDatabases, SEPARATOR } from "../db/constants"
|
import { StaticDatabases, SEPARATOR } from "./constants"
|
||||||
import { getTenantId } from "../context"
|
import { getTenantId } from "../context"
|
||||||
|
|
||||||
export const getGlobalDBName = (tenantId?: string) => {
|
export const getGlobalDBName = (tenantId?: string) => {
|
|
@ -3,7 +3,7 @@ import { DEFAULT_TENANT_ID, Configs } from "../constants"
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
import { SEPARATOR, DocumentType, UNICODE_MAX, ViewName } from "./constants"
|
import { SEPARATOR, DocumentType, UNICODE_MAX, ViewName } from "./constants"
|
||||||
import { getTenantId, getGlobalDB } from "../context"
|
import { getTenantId, getGlobalDB } from "../context"
|
||||||
import { getGlobalDBName } from "../tenancy"
|
import { getGlobalDBName } from "./tenancy"
|
||||||
import fetch from "node-fetch"
|
import fetch from "node-fetch"
|
||||||
import { doWithDB, allDbs } from "./index"
|
import { doWithDB, allDbs } from "./index"
|
||||||
import { getCouchInfo } from "./pouch"
|
import { getCouchInfo } from "./pouch"
|
||||||
|
@ -16,6 +16,7 @@ import * as events from "../events"
|
||||||
export * from "./constants"
|
export * from "./constants"
|
||||||
export * from "./conversions"
|
export * from "./conversions"
|
||||||
export { default as Replication } from "./Replication"
|
export { default as Replication } from "./Replication"
|
||||||
|
export * from "./tenancy"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new app ID.
|
* Generates a new app ID.
|
||||||
|
@ -367,6 +368,21 @@ export const generateDevInfoID = (userId: any) => {
|
||||||
return `${DocumentType.DEV_INFO}${SEPARATOR}${userId}`
|
return `${DocumentType.DEV_INFO}${SEPARATOR}${userId}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new plugin ID - to be used in the global DB.
|
||||||
|
* @returns {string} The new plugin ID which a plugin metadata document can be stored under.
|
||||||
|
*/
|
||||||
|
export const generatePluginID = (name: string) => {
|
||||||
|
return `${DocumentType.PLUGIN}${SEPARATOR}${name}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets parameters for retrieving automations, this is a utility function for the getDocParams function.
|
||||||
|
*/
|
||||||
|
export const getPluginParams = (pluginId?: string | null, otherProps = {}) => {
|
||||||
|
return getDocParams(DocumentType.PLUGIN, pluginId, otherProps)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the most granular configuration document from the DB based on the type, workspace and userID passed.
|
* Returns the most granular configuration document from the DB based on the type, workspace and userID passed.
|
||||||
* @param {Object} db - db instance to query
|
* @param {Object} db - db instance to query
|
||||||
|
|
|
@ -23,9 +23,11 @@ export default class LoggingProcessor implements EventProcessor {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let timestampString = getTimestampString(timestamp)
|
let timestampString = getTimestampString(timestamp)
|
||||||
console.log(
|
let message = `[audit] [tenant=${identity.tenantId}] [identityType=${identity.type}] [identity=${identity.id}] ${timestampString} ${event} `
|
||||||
`[audit] [tenant=${identity.tenantId}] [identityType=${identity.type}] [identity=${identity.id}] ${timestampString} ${event} `
|
if (env.isDev()) {
|
||||||
)
|
message = message + `[debug: [properties=${JSON.stringify(properties)}] ]`
|
||||||
|
}
|
||||||
|
console.log(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
async identify(identity: Identity, timestamp?: string | number) {
|
async identify(identity: Identity, timestamp?: string | number) {
|
||||||
|
|
|
@ -1,27 +1,78 @@
|
||||||
import { publishEvent } from "../events"
|
import { publishEvent } from "../events"
|
||||||
import {
|
import {
|
||||||
Event,
|
Event,
|
||||||
License,
|
|
||||||
LicenseActivatedEvent,
|
LicenseActivatedEvent,
|
||||||
LicenseDowngradedEvent,
|
LicensePlanChangedEvent,
|
||||||
LicenseUpdatedEvent,
|
LicenseTierChangedEvent,
|
||||||
LicenseUpgradedEvent,
|
PlanType,
|
||||||
|
Account,
|
||||||
|
LicensePortalOpenedEvent,
|
||||||
|
LicenseCheckoutSuccessEvent,
|
||||||
|
LicenseCheckoutOpenedEvent,
|
||||||
|
LicensePaymentFailedEvent,
|
||||||
|
LicensePaymentRecoveredEvent,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
|
||||||
// TODO
|
export async function tierChanged(account: Account, from: number, to: number) {
|
||||||
export async function updgraded(license: License) {
|
const properties: LicenseTierChangedEvent = {
|
||||||
const properties: LicenseUpgradedEvent = {}
|
accountId: account.accountId,
|
||||||
await publishEvent(Event.LICENSE_UPGRADED, properties)
|
to,
|
||||||
|
from,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.LICENSE_TIER_CHANGED, properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
export async function planChanged(
|
||||||
export async function downgraded(license: License) {
|
account: Account,
|
||||||
const properties: LicenseDowngradedEvent = {}
|
from: PlanType,
|
||||||
await publishEvent(Event.LICENSE_DOWNGRADED, properties)
|
to: PlanType
|
||||||
|
) {
|
||||||
|
const properties: LicensePlanChangedEvent = {
|
||||||
|
accountId: account.accountId,
|
||||||
|
to,
|
||||||
|
from,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.LICENSE_PLAN_CHANGED, properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
export async function activated(account: Account) {
|
||||||
export async function activated(license: License) {
|
const properties: LicenseActivatedEvent = {
|
||||||
const properties: LicenseActivatedEvent = {}
|
accountId: account.accountId,
|
||||||
|
}
|
||||||
await publishEvent(Event.LICENSE_ACTIVATED, properties)
|
await publishEvent(Event.LICENSE_ACTIVATED, properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function checkoutOpened(account: Account) {
|
||||||
|
const properties: LicenseCheckoutOpenedEvent = {
|
||||||
|
accountId: account.accountId,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.LICENSE_CHECKOUT_OPENED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function checkoutSuccess(account: Account) {
|
||||||
|
const properties: LicenseCheckoutSuccessEvent = {
|
||||||
|
accountId: account.accountId,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.LICENSE_CHECKOUT_SUCCESS, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function portalOpened(account: Account) {
|
||||||
|
const properties: LicensePortalOpenedEvent = {
|
||||||
|
accountId: account.accountId,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.LICENSE_PORTAL_OPENED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function paymentFailed(account: Account) {
|
||||||
|
const properties: LicensePaymentFailedEvent = {
|
||||||
|
accountId: account.accountId,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.LICENSE_PAYMENT_FAILED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function paymentRecovered(account: Account) {
|
||||||
|
const properties: LicensePaymentRecoveredEvent = {
|
||||||
|
accountId: account.accountId,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.LICENSE_PAYMENT_RECOVERED, properties)
|
||||||
|
}
|
||||||
|
|
|
@ -3,12 +3,8 @@ import { doWithDB } from "../db"
|
||||||
import { DocumentType, StaticDatabases } from "../db/constants"
|
import { DocumentType, StaticDatabases } from "../db/constants"
|
||||||
import { getAllApps } from "../db/utils"
|
import { getAllApps } from "../db/utils"
|
||||||
import environment from "../environment"
|
import environment from "../environment"
|
||||||
import {
|
import { doInTenant, getTenantIds, getTenantId } from "../tenancy"
|
||||||
doInTenant,
|
import { getGlobalDBName } from "../db/tenancy"
|
||||||
getTenantIds,
|
|
||||||
getGlobalDBName,
|
|
||||||
getTenantId,
|
|
||||||
} from "../tenancy"
|
|
||||||
import * as context from "../context"
|
import * as context from "../context"
|
||||||
import { DEFINITIONS } from "."
|
import { DEFINITIONS } from "."
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -75,6 +75,15 @@ function validateDatasource(schema) {
|
||||||
})
|
})
|
||||||
.unknown(true)
|
.unknown(true)
|
||||||
.required(),
|
.required(),
|
||||||
|
extra: joi.object().pattern(
|
||||||
|
joi.string(),
|
||||||
|
joi.object({
|
||||||
|
type: joi.string().required(),
|
||||||
|
displayName: joi.string().required(),
|
||||||
|
required: joi.boolean(),
|
||||||
|
data: joi.object(),
|
||||||
|
})
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
runJoi(validator, schema)
|
runJoi(validator, schema)
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import * as context from "../context"
|
import * as context from "../context"
|
||||||
import * as tenancy from "./tenancy"
|
import * as tenancy from "./tenancy"
|
||||||
import * as utils from "./utils"
|
|
||||||
|
|
||||||
const pkg = {
|
const pkg = {
|
||||||
...context,
|
...context,
|
||||||
...tenancy,
|
...tenancy,
|
||||||
...utils,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export = pkg
|
export = pkg
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { doWithDB } from "../db"
|
import { doWithDB } from "../db"
|
||||||
import { queryPlatformView } from "../db/views"
|
import { queryPlatformView } from "../db/views"
|
||||||
import { StaticDatabases, ViewName } from "../db/constants"
|
import { StaticDatabases, ViewName } from "../db/constants"
|
||||||
import { getGlobalDBName } from "./utils"
|
import { getGlobalDBName } from "../db/tenancy"
|
||||||
import {
|
import {
|
||||||
getTenantId,
|
getTenantId,
|
||||||
DEFAULT_TENANT_ID,
|
DEFAULT_TENANT_ID,
|
||||||
|
@ -9,7 +9,7 @@ import {
|
||||||
getTenantIDFromAppID,
|
getTenantIDFromAppID,
|
||||||
} from "../context"
|
} from "../context"
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
import { PlatformUser, PlatformUserByEmail } from "@budibase/types"
|
import { PlatformUser } from "@budibase/types"
|
||||||
|
|
||||||
const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants
|
const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants
|
||||||
const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name
|
const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name
|
||||||
|
|
|
@ -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": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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": "1.3.21-alpha.0",
|
"@budibase/string-templates": "1.4.8-alpha.3",
|
||||||
"@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",
|
||||||
|
|
|
@ -2,7 +2,7 @@ import filterTests from "../support/filterTests"
|
||||||
const interact = require("../support/interact")
|
const interact = require("../support/interact")
|
||||||
|
|
||||||
filterTests(["all"], () => {
|
filterTests(["all"], () => {
|
||||||
context("Create Components", () => {
|
xcontext("Create Components", () => {
|
||||||
let headlineId
|
let headlineId
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -71,10 +71,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "1.3.21-alpha.0",
|
"@budibase/bbui": "1.4.8-alpha.3",
|
||||||
"@budibase/client": "1.3.21-alpha.0",
|
"@budibase/client": "1.4.8-alpha.3",
|
||||||
"@budibase/frontend-core": "1.3.21-alpha.0",
|
"@budibase/frontend-core": "1.4.8-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.21-alpha.0",
|
"@budibase/string-templates": "1.4.8-alpha.3",
|
||||||
"@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",
|
||||||
|
|
|
@ -9,14 +9,14 @@ import {
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import {
|
import {
|
||||||
queries as queriesStores,
|
queries as queriesStores,
|
||||||
roles as rolesStore,
|
|
||||||
tables as tablesStore,
|
tables as tablesStore,
|
||||||
|
roles as rolesStore,
|
||||||
} from "stores/backend"
|
} from "stores/backend"
|
||||||
import {
|
import {
|
||||||
|
makePropSafe,
|
||||||
|
isJSBinding,
|
||||||
decodeJSBinding,
|
decodeJSBinding,
|
||||||
encodeJSBinding,
|
encodeJSBinding,
|
||||||
isJSBinding,
|
|
||||||
makePropSafe,
|
|
||||||
} from "@budibase/string-templates"
|
} from "@budibase/string-templates"
|
||||||
import { TableNames } from "../constants"
|
import { TableNames } from "../constants"
|
||||||
import { JSONUtils } from "@budibase/frontend-core"
|
import { JSONUtils } from "@budibase/frontend-core"
|
||||||
|
@ -71,17 +71,19 @@ export const getAuthBindings = () => {
|
||||||
runtime: `${safeUser}.${safeOAuth2}.${safeAccessToken}`,
|
runtime: `${safeUser}.${safeOAuth2}.${safeAccessToken}`,
|
||||||
readable: `Current User.OAuthToken`,
|
readable: `Current User.OAuthToken`,
|
||||||
key: "accessToken",
|
key: "accessToken",
|
||||||
|
display: { name: "OAuthToken" },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
bindings = Object.keys(authBindings).map(key => {
|
bindings = authBindings.map(fieldBinding => {
|
||||||
const fieldBinding = authBindings[key]
|
|
||||||
return {
|
return {
|
||||||
type: "context",
|
type: "context",
|
||||||
runtimeBinding: fieldBinding.runtime,
|
runtimeBinding: fieldBinding.runtime,
|
||||||
readableBinding: fieldBinding.readable,
|
readableBinding: fieldBinding.readable,
|
||||||
fieldSchema: { type: "string", name: fieldBinding.key },
|
fieldSchema: { type: "string", name: fieldBinding.key },
|
||||||
providerId: "user",
|
providerId: "user",
|
||||||
|
category: "Current User",
|
||||||
|
display: fieldBinding.display,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return bindings
|
return bindings
|
||||||
|
@ -93,7 +95,7 @@ export const getAuthBindings = () => {
|
||||||
* @param {string} prefix A contextual string prefix/path for a user readable binding
|
* @param {string} prefix A contextual string prefix/path for a user readable binding
|
||||||
* @return {object[]} An array containing readable/runtime binding objects
|
* @return {object[]} An array containing readable/runtime binding objects
|
||||||
*/
|
*/
|
||||||
export const toBindingsArray = (valueMap, prefix) => {
|
export const toBindingsArray = (valueMap, prefix, category) => {
|
||||||
if (!valueMap) {
|
if (!valueMap) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
@ -101,11 +103,20 @@ export const toBindingsArray = (valueMap, prefix) => {
|
||||||
if (!binding || !valueMap[binding]) {
|
if (!binding || !valueMap[binding]) {
|
||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
acc.push({
|
|
||||||
|
let config = {
|
||||||
type: "context",
|
type: "context",
|
||||||
runtimeBinding: binding,
|
runtimeBinding: binding,
|
||||||
readableBinding: `${prefix}.${binding}`,
|
readableBinding: `${prefix}.${binding}`,
|
||||||
})
|
icon: "Brackets",
|
||||||
|
}
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
config.category = category
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.push(config)
|
||||||
|
|
||||||
return acc
|
return acc
|
||||||
}, [])
|
}, [])
|
||||||
}
|
}
|
||||||
|
@ -382,21 +393,25 @@ export const getUserBindings = () => {
|
||||||
const { schema } = getSchemaForTable(TableNames.USERS)
|
const { schema } = getSchemaForTable(TableNames.USERS)
|
||||||
const keys = Object.keys(schema).sort()
|
const keys = Object.keys(schema).sort()
|
||||||
const safeUser = makePropSafe("user")
|
const safeUser = makePropSafe("user")
|
||||||
keys.forEach(key => {
|
|
||||||
|
bindings = keys.reduce((acc, key) => {
|
||||||
const fieldSchema = schema[key]
|
const fieldSchema = schema[key]
|
||||||
bindings.push({
|
if (fieldSchema.type !== "link") {
|
||||||
type: "context",
|
acc.push({
|
||||||
runtimeBinding: `${safeUser}.${makePropSafe(key)}`,
|
type: "context",
|
||||||
readableBinding: `Current User.${key}`,
|
runtimeBinding: `${safeUser}.${makePropSafe(key)}`,
|
||||||
// Field schema and provider are required to construct relationship
|
readableBinding: `Current User.${key}`,
|
||||||
// datasource options, based on bindable properties
|
// Field schema and provider are required to construct relationship
|
||||||
fieldSchema,
|
// datasource options, based on bindable properties
|
||||||
providerId: "user",
|
fieldSchema,
|
||||||
category: "Current User",
|
providerId: "user",
|
||||||
icon: "User",
|
category: "Current User",
|
||||||
display: fieldSchema,
|
icon: "User",
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
|
||||||
return bindings
|
return bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
backgroundColour={templateEntry.background}
|
backgroundColour={templateEntry.background}
|
||||||
icon={templateEntry.icon}
|
icon={templateEntry.icon}
|
||||||
>
|
>
|
||||||
{#if $licensing?.usageMetrics?.apps < 100}
|
{#if !($licensing?.usageMetrics?.apps >= 100)}
|
||||||
<Button
|
<Button
|
||||||
cta
|
cta
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
|
|
@ -1,20 +1,31 @@
|
||||||
<script>
|
<script>
|
||||||
import { Body, Button, Heading, Layout } from "@budibase/bbui"
|
import { Body, Button, Heading, Icon, Input, Layout } from "@budibase/bbui"
|
||||||
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
|
import {
|
||||||
import { getUserBindings } from "builderStore/dataBinding"
|
readableToRuntimeBinding,
|
||||||
|
runtimeToReadableBinding,
|
||||||
|
} from "builderStore/dataBinding"
|
||||||
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
|
|
||||||
export let bindable = true
|
export let bindable = true
|
||||||
export let queryBindings = []
|
export let queryBindings = []
|
||||||
|
export let bindings = []
|
||||||
const userBindings = getUserBindings()
|
export let customParams = {}
|
||||||
|
|
||||||
let internalBindings = queryBindings.reduce((acc, binding) => {
|
|
||||||
acc[binding.name] = binding.default
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
|
|
||||||
function newQueryBinding() {
|
function newQueryBinding() {
|
||||||
queryBindings = [...queryBindings, {}]
|
queryBindings = [...queryBindings, {}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteQueryBinding(idx) {
|
||||||
|
queryBindings.splice(idx, 1)
|
||||||
|
queryBindings = queryBindings
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is necessary due to the way readable and writable bindings are stored.
|
||||||
|
// The readable binding in the UI gets converted to a UUID value that the client understands
|
||||||
|
// for parsing, then converted back so we can display it the readable form in the UI
|
||||||
|
function onBindingChange(param, valueToParse) {
|
||||||
|
customParams[param] = readableToRuntimeBinding(bindings, valueToParse)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Layout noPadding={bindable} gap="S">
|
<Layout noPadding={bindable} gap="S">
|
||||||
|
@ -35,34 +46,57 @@
|
||||||
{/if}
|
{/if}
|
||||||
</Body>
|
</Body>
|
||||||
<div class="bindings" class:bindable>
|
<div class="bindings" class:bindable>
|
||||||
<KeyValueBuilder
|
{#each queryBindings as binding, idx}
|
||||||
bind:object={internalBindings}
|
<Input
|
||||||
tooltip="Set the name of the binding which can be used in Handlebars statements throughout your query"
|
placeholder="Binding Name"
|
||||||
name="binding"
|
thin
|
||||||
headings
|
disabled={bindable}
|
||||||
keyPlaceholder="Binding name"
|
bind:value={binding.name}
|
||||||
valuePlaceholder="Default"
|
/>
|
||||||
bindings={[...userBindings]}
|
<Input
|
||||||
bindingDrawerLeft="260px"
|
placeholder="Default"
|
||||||
on:change={e => {
|
thin
|
||||||
queryBindings = e.detail.map(binding => {
|
disabled={bindable}
|
||||||
return {
|
on:change={evt => onBindingChange(binding.name, evt.detail)}
|
||||||
name: binding.name,
|
bind:value={binding.default}
|
||||||
default: binding.value,
|
/>
|
||||||
}
|
{#if bindable}
|
||||||
})
|
<DrawerBindableInput
|
||||||
}}
|
title={`Query binding "${binding.name}"`}
|
||||||
/>
|
placeholder="Value"
|
||||||
|
thin
|
||||||
|
on:change={evt => onBindingChange(binding.name, evt.detail)}
|
||||||
|
value={runtimeToReadableBinding(
|
||||||
|
bindings,
|
||||||
|
customParams?.[binding.name]
|
||||||
|
)}
|
||||||
|
{bindings}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<Icon hoverable name="Close" on:click={() => deleteQueryBinding(idx)} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.bindings.bindable {
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bindings {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 5%;
|
||||||
|
grid-gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.height {
|
.height {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
import ExtraQueryConfig from "./ExtraQueryConfig.svelte"
|
import ExtraQueryConfig from "./ExtraQueryConfig.svelte"
|
||||||
import IntegrationQueryEditor from "components/integration/index.svelte"
|
import IntegrationQueryEditor from "components/integration/index.svelte"
|
||||||
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
|
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
|
||||||
import BindingBuilder from "components/integration/QueryBindingBuilder.svelte"
|
import BindingBuilder from "components/integration/QueryViewerBindingBuilder.svelte"
|
||||||
import { datasources, integrations, queries } from "stores/backend"
|
import { datasources, integrations, queries } from "stores/backend"
|
||||||
import { capitalise } from "../../helpers"
|
import { capitalise } from "../../helpers"
|
||||||
import CodeMirrorEditor from "components/common/CodeMirrorEditor.svelte"
|
import CodeMirrorEditor from "components/common/CodeMirrorEditor.svelte"
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<script>
|
||||||
|
import { Body, Button, Heading, Layout } from "@budibase/bbui"
|
||||||
|
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
|
||||||
|
import { getUserBindings } from "builderStore/dataBinding"
|
||||||
|
export let bindable = true
|
||||||
|
export let queryBindings = []
|
||||||
|
|
||||||
|
const userBindings = getUserBindings()
|
||||||
|
|
||||||
|
let internalBindings = queryBindings.reduce((acc, binding) => {
|
||||||
|
acc[binding.name] = binding.default
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
function newQueryBinding() {
|
||||||
|
queryBindings = [...queryBindings, {}]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Layout noPadding={bindable} gap="S">
|
||||||
|
<div class="controls" class:height={!bindable}>
|
||||||
|
<Heading size="XS">Bindings</Heading>
|
||||||
|
{#if !bindable}
|
||||||
|
<Button secondary on:click={newQueryBinding}>Add Binding</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<Body size="S">
|
||||||
|
{#if !bindable}
|
||||||
|
Bindings come in two parts: the binding name, and a default/fallback
|
||||||
|
value. These bindings can be used as Handlebars expressions throughout the
|
||||||
|
query.
|
||||||
|
{:else}
|
||||||
|
Enter a value for each binding. The default values will be used for any
|
||||||
|
values left blank.
|
||||||
|
{/if}
|
||||||
|
</Body>
|
||||||
|
<div class="bindings" class:bindable>
|
||||||
|
<KeyValueBuilder
|
||||||
|
bind:object={internalBindings}
|
||||||
|
tooltip="Set the name of the binding which can be used in Handlebars statements throughout your query"
|
||||||
|
name="binding"
|
||||||
|
headings
|
||||||
|
keyPlaceholder="Binding name"
|
||||||
|
valuePlaceholder="Default"
|
||||||
|
bindings={[...userBindings]}
|
||||||
|
bindingDrawerLeft="260px"
|
||||||
|
on:change={e => {
|
||||||
|
queryBindings = e.detail.map(binding => {
|
||||||
|
return {
|
||||||
|
name: binding.name,
|
||||||
|
default: binding.value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.height {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,6 +8,7 @@
|
||||||
import { ExpiringKeys } from "./constants"
|
import { ExpiringKeys } from "./constants"
|
||||||
import { getBanners } from "./licensingBanners"
|
import { getBanners } from "./licensingBanners"
|
||||||
import { banner } from "@budibase/bbui"
|
import { banner } from "@budibase/bbui"
|
||||||
|
import { FEATURE_FLAGS, isEnabled } from "../../../helpers/featureFlags"
|
||||||
|
|
||||||
const oneDayInSeconds = 86400
|
const oneDayInSeconds = 86400
|
||||||
|
|
||||||
|
@ -81,7 +82,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (userLoaded && licensingLoaded && loaded) {
|
$: if (
|
||||||
|
userLoaded &&
|
||||||
|
licensingLoaded &&
|
||||||
|
loaded &&
|
||||||
|
isEnabled(FEATURE_FLAGS.LICENSING)
|
||||||
|
) {
|
||||||
queuedModals = processModals()
|
queuedModals = processModals()
|
||||||
queuedBanners = getBanners()
|
queuedBanners = getBanners()
|
||||||
showNextModal()
|
showNextModal()
|
||||||
|
|
|
@ -60,14 +60,20 @@
|
||||||
|
|
||||||
$: staticVariables = datasource?.config?.staticVariables || {}
|
$: staticVariables = datasource?.config?.staticVariables || {}
|
||||||
|
|
||||||
$: customRequestBindings = toBindingsArray(requestBindings, "Binding")
|
$: customRequestBindings = toBindingsArray(
|
||||||
|
requestBindings,
|
||||||
|
"Binding",
|
||||||
|
"Bindings"
|
||||||
|
)
|
||||||
$: globalDynamicRequestBindings = toBindingsArray(
|
$: globalDynamicRequestBindings = toBindingsArray(
|
||||||
globalDynamicBindings,
|
globalDynamicBindings,
|
||||||
|
"Dynamic",
|
||||||
"Dynamic"
|
"Dynamic"
|
||||||
)
|
)
|
||||||
$: dataSourceStaticBindings = toBindingsArray(
|
$: dataSourceStaticBindings = toBindingsArray(
|
||||||
staticVariables,
|
staticVariables,
|
||||||
"Datasource.Static"
|
"Datasource.Static",
|
||||||
|
"Datasource Static"
|
||||||
)
|
)
|
||||||
|
|
||||||
$: mergedBindings = [
|
$: mergedBindings = [
|
||||||
|
|
|
@ -56,7 +56,11 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
let dragDisabled = true
|
let dragDisabled = true
|
||||||
$: settings = getComponentSettings($selectedComponent?._component)
|
$: settings = getComponentSettings($selectedComponent?._component)?.concat({
|
||||||
|
label: "Custom CSS",
|
||||||
|
key: "_css",
|
||||||
|
type: "text",
|
||||||
|
})
|
||||||
$: settingOptions = settings.map(setting => ({
|
$: settingOptions = settings.map(setting => ({
|
||||||
label: setting.label,
|
label: setting.label,
|
||||||
value: setting.key,
|
value: setting.key,
|
||||||
|
|
|
@ -1,30 +1,41 @@
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
TextArea,
|
|
||||||
DetailSummary,
|
DetailSummary,
|
||||||
ActionButton,
|
ActionButton,
|
||||||
Drawer,
|
Drawer,
|
||||||
DrawerContent,
|
|
||||||
Layout,
|
|
||||||
Body,
|
|
||||||
Button,
|
Button,
|
||||||
notifications,
|
notifications,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { store } from "builderStore"
|
import { selectedScreen, store } from "builderStore"
|
||||||
|
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
|
||||||
|
import {
|
||||||
|
getBindableProperties,
|
||||||
|
readableToRuntimeBinding,
|
||||||
|
runtimeToReadableBinding,
|
||||||
|
} from "builderStore/dataBinding"
|
||||||
|
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
|
||||||
let tempValue
|
let tempValue
|
||||||
let drawer
|
let drawer
|
||||||
|
|
||||||
|
$: bindings = getBindableProperties(
|
||||||
|
$selectedScreen,
|
||||||
|
$store.selectedComponentId
|
||||||
|
)
|
||||||
|
|
||||||
const openDrawer = () => {
|
const openDrawer = () => {
|
||||||
tempValue = componentInstance?._styles?.custom
|
tempValue = runtimeToReadableBinding(
|
||||||
|
bindings,
|
||||||
|
componentInstance?._styles?.custom
|
||||||
|
)
|
||||||
drawer.show()
|
drawer.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
try {
|
try {
|
||||||
await store.actions.components.updateCustomStyle(tempValue)
|
const value = readableToRuntimeBinding(bindings, tempValue)
|
||||||
|
await store.actions.components.updateCustomStyle(value)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error updating custom style")
|
notifications.error("Error updating custom style")
|
||||||
}
|
}
|
||||||
|
@ -42,26 +53,17 @@
|
||||||
</DetailSummary>
|
</DetailSummary>
|
||||||
{#key componentInstance?._id}
|
{#key componentInstance?._id}
|
||||||
<Drawer bind:this={drawer} title="Custom CSS">
|
<Drawer bind:this={drawer} title="Custom CSS">
|
||||||
|
<svelte:fragment slot="description">
|
||||||
|
Custom CSS overrides all other component styles.
|
||||||
|
</svelte:fragment>
|
||||||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||||
<DrawerContent slot="body">
|
<svelte:component
|
||||||
<div class="content">
|
this={ClientBindingPanel}
|
||||||
<Layout gap="S" noPadding>
|
slot="body"
|
||||||
<Body size="S">Custom CSS overrides all other component styles.</Body>
|
value={tempValue}
|
||||||
<TextArea bind:value={tempValue} placeholder="Enter some CSS..." />
|
on:change={event => (tempValue = event.detail)}
|
||||||
</Layout>
|
allowJS
|
||||||
</div>
|
{bindings}
|
||||||
</DrawerContent>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
{/key}
|
{/key}
|
||||||
|
|
||||||
<style>
|
|
||||||
.content {
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.content :global(textarea) {
|
|
||||||
font-family: monospace;
|
|
||||||
min-height: 240px !important;
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
{
|
{
|
||||||
title: "Plugins",
|
title: "Plugins",
|
||||||
href: "/builder/portal/manage/plugins",
|
href: "/builder/portal/manage/plugins",
|
||||||
badge: "New",
|
badge: "Beta",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
Search,
|
Search,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { plugins } from "stores/portal"
|
import { plugins, admin } from "stores/portal"
|
||||||
import PluginRow from "./_components/PluginRow.svelte"
|
import PluginRow from "./_components/PluginRow.svelte"
|
||||||
import AddPluginModal from "./_components/AddPluginModal.svelte"
|
import AddPluginModal from "./_components/AddPluginModal.svelte"
|
||||||
|
|
||||||
|
@ -20,9 +20,12 @@
|
||||||
let filterOptions = [
|
let filterOptions = [
|
||||||
{ label: "All plugins", value: "all" },
|
{ label: "All plugins", value: "all" },
|
||||||
{ label: "Components", value: "component" },
|
{ label: "Components", value: "component" },
|
||||||
{ label: "Datasources", value: "datasource" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (!$admin.cloud) {
|
||||||
|
filterOptions.push({ label: "Datasources", value: "datasource" })
|
||||||
|
}
|
||||||
|
|
||||||
$: filteredPlugins = $plugins
|
$: filteredPlugins = $plugins
|
||||||
.filter(plugin => {
|
.filter(plugin => {
|
||||||
return filter === "all" || plugin.schema.type === filter
|
return filter === "all" || plugin.schema.type === filter
|
||||||
|
|
|
@ -3,10 +3,12 @@ import { API } from "api"
|
||||||
import { auth } from "stores/portal"
|
import { auth } from "stores/portal"
|
||||||
import { Constants } from "@budibase/frontend-core"
|
import { Constants } from "@budibase/frontend-core"
|
||||||
import { StripeStatus } from "components/portal/licensing/constants"
|
import { StripeStatus } from "components/portal/licensing/constants"
|
||||||
|
import { FEATURE_FLAGS, isEnabled } from "../../helpers/featureFlags"
|
||||||
|
|
||||||
export const createLicensingStore = () => {
|
export const createLicensingStore = () => {
|
||||||
const DEFAULT = {
|
const DEFAULT = {
|
||||||
plans: {},
|
plans: {},
|
||||||
|
usageMetrics: {},
|
||||||
}
|
}
|
||||||
const oneDayInMilliseconds = 86400000
|
const oneDayInMilliseconds = 86400000
|
||||||
|
|
||||||
|
@ -27,78 +29,80 @@ export const createLicensingStore = () => {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getUsageMetrics: async () => {
|
getUsageMetrics: async () => {
|
||||||
const quota = get(store).quotaUsage
|
if (isEnabled(FEATURE_FLAGS.LICENSING)) {
|
||||||
const license = get(auth).user.license
|
const quota = get(store).quotaUsage
|
||||||
const now = new Date()
|
const license = get(auth).user.license
|
||||||
|
const now = new Date()
|
||||||
|
|
||||||
const getMetrics = (keys, license, quota) => {
|
const getMetrics = (keys, license, quota) => {
|
||||||
if (!license || !quota || !keys) {
|
if (!license || !quota || !keys) {
|
||||||
return {}
|
return {}
|
||||||
|
}
|
||||||
|
return keys.reduce((acc, key) => {
|
||||||
|
const quotaLimit = license[key].value
|
||||||
|
const quotaUsed = (quota[key] / quotaLimit) * 100
|
||||||
|
acc[key] = quotaLimit > -1 ? Math.round(quotaUsed) : -1
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
}
|
}
|
||||||
return keys.reduce((acc, key) => {
|
const monthlyMetrics = getMetrics(
|
||||||
const quotaLimit = license[key].value
|
["dayPasses", "queries", "automations"],
|
||||||
const quotaUsed = (quota[key] / quotaLimit) * 100
|
license.quotas.usage.monthly,
|
||||||
acc[key] = quotaLimit > -1 ? Math.round(quotaUsed) : -1
|
quota.monthly.current
|
||||||
return acc
|
)
|
||||||
}, {})
|
const staticMetrics = getMetrics(
|
||||||
}
|
["apps", "rows"],
|
||||||
const monthlyMetrics = getMetrics(
|
license.quotas.usage.static,
|
||||||
["dayPasses", "queries", "automations"],
|
quota.usageQuota
|
||||||
license.quotas.usage.monthly,
|
|
||||||
quota.monthly.current
|
|
||||||
)
|
|
||||||
const staticMetrics = getMetrics(
|
|
||||||
["apps", "rows"],
|
|
||||||
license.quotas.usage.static,
|
|
||||||
quota.usageQuota
|
|
||||||
)
|
|
||||||
|
|
||||||
const getDaysBetween = (dateStart, dateEnd) => {
|
|
||||||
return dateEnd > dateStart
|
|
||||||
? Math.round(
|
|
||||||
(dateEnd.getTime() - dateStart.getTime()) / oneDayInMilliseconds
|
|
||||||
)
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const quotaResetDate = new Date(quota.quotaReset)
|
|
||||||
const quotaResetDaysRemaining = getDaysBetween(now, quotaResetDate)
|
|
||||||
|
|
||||||
const accountDowngraded =
|
|
||||||
license?.billing?.subscription?.downgradeAt &&
|
|
||||||
license?.billing?.subscription?.downgradeAt <= now.getTime() &&
|
|
||||||
license?.billing?.subscription?.status === StripeStatus.PAST_DUE &&
|
|
||||||
license?.plan.type === Constants.PlanType.FREE
|
|
||||||
|
|
||||||
const pastDueAtMilliseconds = license?.billing?.subscription?.pastDueAt
|
|
||||||
const downgradeAtMilliseconds =
|
|
||||||
license?.billing?.subscription?.downgradeAt
|
|
||||||
let pastDueDaysRemaining
|
|
||||||
let pastDueEndDate
|
|
||||||
|
|
||||||
if (pastDueAtMilliseconds && downgradeAtMilliseconds) {
|
|
||||||
pastDueEndDate = new Date(downgradeAtMilliseconds)
|
|
||||||
pastDueDaysRemaining = getDaysBetween(
|
|
||||||
new Date(pastDueAtMilliseconds),
|
|
||||||
pastDueEndDate
|
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
store.update(state => {
|
const getDaysBetween = (dateStart, dateEnd) => {
|
||||||
return {
|
return dateEnd > dateStart
|
||||||
...state,
|
? Math.round(
|
||||||
usageMetrics: { ...monthlyMetrics, ...staticMetrics },
|
(dateEnd.getTime() - dateStart.getTime()) / oneDayInMilliseconds
|
||||||
quotaResetDaysRemaining,
|
)
|
||||||
quotaResetDate,
|
: 0
|
||||||
accountDowngraded,
|
|
||||||
accountPastDue: pastDueAtMilliseconds != null,
|
|
||||||
pastDueEndDate,
|
|
||||||
pastDueDaysRemaining,
|
|
||||||
isFreePlan: () => {
|
|
||||||
return license?.plan.type === Constants.PlanType.FREE
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
const quotaResetDate = new Date(quota.quotaReset)
|
||||||
|
const quotaResetDaysRemaining = getDaysBetween(now, quotaResetDate)
|
||||||
|
|
||||||
|
const accountDowngraded =
|
||||||
|
license?.billing?.subscription?.downgradeAt &&
|
||||||
|
license?.billing?.subscription?.downgradeAt <= now.getTime() &&
|
||||||
|
license?.billing?.subscription?.status === StripeStatus.PAST_DUE &&
|
||||||
|
license?.plan.type === Constants.PlanType.FREE
|
||||||
|
|
||||||
|
const pastDueAtMilliseconds = license?.billing?.subscription?.pastDueAt
|
||||||
|
const downgradeAtMilliseconds =
|
||||||
|
license?.billing?.subscription?.downgradeAt
|
||||||
|
let pastDueDaysRemaining
|
||||||
|
let pastDueEndDate
|
||||||
|
|
||||||
|
if (pastDueAtMilliseconds && downgradeAtMilliseconds) {
|
||||||
|
pastDueEndDate = new Date(downgradeAtMilliseconds)
|
||||||
|
pastDueDaysRemaining = getDaysBetween(
|
||||||
|
new Date(pastDueAtMilliseconds),
|
||||||
|
pastDueEndDate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
store.update(state => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
usageMetrics: { ...monthlyMetrics, ...staticMetrics },
|
||||||
|
quotaResetDaysRemaining,
|
||||||
|
quotaResetDate,
|
||||||
|
accountDowngraded,
|
||||||
|
accountPastDue: pastDueAtMilliseconds != null,
|
||||||
|
pastDueEndDate,
|
||||||
|
pastDueDaysRemaining,
|
||||||
|
isFreePlan: () => {
|
||||||
|
return license?.plan.type === Constants.PlanType.FREE
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,7 @@ export function createPluginsStore() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = await API.createPlugin(pluginData)
|
let res = await API.createPlugin(pluginData)
|
||||||
|
let newPlugin = res.plugin
|
||||||
let newPlugin = res.plugins[0]
|
|
||||||
update(state => {
|
update(state => {
|
||||||
const currentIdx = state.findIndex(plugin => plugin._id === newPlugin._id)
|
const currentIdx = state.findIndex(plugin => plugin._id === newPlugin._id)
|
||||||
if (currentIdx >= 0) {
|
if (currentIdx >= 0) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/cli",
|
"name": "@budibase/cli",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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": "1.3.21-alpha.0",
|
"@budibase/backend-core": "1.4.8-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.21-alpha.0",
|
"@budibase/string-templates": "1.4.8-alpha.3",
|
||||||
"@budibase/types": "1.3.21-alpha.0",
|
"@budibase/types": "1.4.8-alpha.3",
|
||||||
"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",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/client",
|
"name": "@budibase/client",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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": "1.3.21-alpha.0",
|
"@budibase/bbui": "1.4.8-alpha.3",
|
||||||
"@budibase/frontend-core": "1.3.21-alpha.0",
|
"@budibase/frontend-core": "1.4.8-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.21-alpha.0",
|
"@budibase/string-templates": "1.4.8-alpha.3",
|
||||||
"@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",
|
||||||
|
|
|
@ -142,6 +142,10 @@
|
||||||
// Determine and apply settings to the component
|
// Determine and apply settings to the component
|
||||||
$: applySettings(staticSettings, enrichedSettings, conditionalSettings)
|
$: applySettings(staticSettings, enrichedSettings, conditionalSettings)
|
||||||
|
|
||||||
|
// Determine custom css.
|
||||||
|
// Broken out as a separate variable to minimize reactivity updates.
|
||||||
|
$: customCSS = cachedSettings?._css
|
||||||
|
|
||||||
// Scroll the selected element into view
|
// Scroll the selected element into view
|
||||||
$: selected && scrollIntoView()
|
$: selected && scrollIntoView()
|
||||||
|
|
||||||
|
@ -151,6 +155,7 @@
|
||||||
children: children.length,
|
children: children.length,
|
||||||
styles: {
|
styles: {
|
||||||
...instance._styles,
|
...instance._styles,
|
||||||
|
custom: customCSS,
|
||||||
id,
|
id,
|
||||||
empty: emptyState,
|
empty: emptyState,
|
||||||
interactive,
|
interactive,
|
||||||
|
@ -249,14 +254,18 @@
|
||||||
// Get raw settings
|
// Get raw settings
|
||||||
let settings = {}
|
let settings = {}
|
||||||
Object.entries(instance)
|
Object.entries(instance)
|
||||||
.filter(([name]) => name === "_conditions" || !name.startsWith("_"))
|
.filter(([name]) => !name.startsWith("_"))
|
||||||
.forEach(([key, value]) => {
|
.forEach(([key, value]) => {
|
||||||
settings[key] = value
|
settings[key] = value
|
||||||
})
|
})
|
||||||
|
|
||||||
// Derive static, dynamic and nested settings if the instance changed
|
|
||||||
let newStaticSettings = { ...settings }
|
let newStaticSettings = { ...settings }
|
||||||
let newDynamicSettings = { ...settings }
|
let newDynamicSettings = { ...settings }
|
||||||
|
|
||||||
|
// Attach some internal properties
|
||||||
|
newDynamicSettings["_conditions"] = instance._conditions
|
||||||
|
newDynamicSettings["_css"] = instance._styles?.custom
|
||||||
|
|
||||||
|
// Derive static, dynamic and nested settings if the instance changed
|
||||||
settingsDefinition?.forEach(setting => {
|
settingsDefinition?.forEach(setting => {
|
||||||
if (setting.nested) {
|
if (setting.nested) {
|
||||||
delete newDynamicSettings[setting.key]
|
delete newDynamicSettings[setting.key]
|
||||||
|
@ -370,6 +379,11 @@
|
||||||
// setting it on initialSettings directly, we avoid a double render.
|
// setting it on initialSettings directly, we avoid a double render.
|
||||||
cachedSettings[key] = allSettings[key]
|
cachedSettings[key] = allSettings[key]
|
||||||
|
|
||||||
|
// Don't update components for internal properties
|
||||||
|
if (key.startsWith("_")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (ref?.$$set) {
|
if (ref?.$$set) {
|
||||||
// Programmatically set the prop to avoid svelte reactive statements
|
// Programmatically set the prop to avoid svelte reactive statements
|
||||||
// firing inside components. This circumvents the problems caused by
|
// firing inside components. This circumvents the problems caused by
|
||||||
|
|
|
@ -374,6 +374,11 @@
|
||||||
min-height: 180px;
|
min-height: 180px;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
.embedded-map :global(a.map-svg-button) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
.embedded-map :global(.leaflet-top),
|
.embedded-map :global(.leaflet-top),
|
||||||
.embedded-map :global(.leaflet-bottom) {
|
.embedded-map :global(.leaflet-bottom) {
|
||||||
z-index: 998;
|
z-index: 998;
|
||||||
|
|
|
@ -37,7 +37,7 @@ const FullScreenControl = L.Control.extend({
|
||||||
this._fullScreenButton = this._createButton(
|
this._fullScreenButton = this._createButton(
|
||||||
options.fullScreenContent,
|
options.fullScreenContent,
|
||||||
options.fullScreenTitle,
|
options.fullScreenTitle,
|
||||||
"map-fullscreen",
|
"map-fullscreen map-svg-button",
|
||||||
container,
|
container,
|
||||||
this._fullScreen
|
this._fullScreen
|
||||||
)
|
)
|
||||||
|
@ -87,7 +87,7 @@ const LocationControl = L.Control.extend({
|
||||||
this._locationButton = this._createButton(
|
this._locationButton = this._createButton(
|
||||||
options.locationContent,
|
options.locationContent,
|
||||||
options.locationTitle,
|
options.locationTitle,
|
||||||
"map-location",
|
"map-location map-svg-button",
|
||||||
container,
|
container,
|
||||||
this._location
|
this._location
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export const PlanType = {
|
export const PlanType = {
|
||||||
FREE: "free",
|
FREE: "free",
|
||||||
|
PRO: "pro",
|
||||||
TEAM: "team",
|
TEAM: "team",
|
||||||
BUSINESS: "business",
|
BUSINESS: "business",
|
||||||
ENTERPRISE: "enterprise",
|
ENTERPRISE: "enterprise",
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/frontend-core",
|
"name": "@budibase/frontend-core",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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": "1.3.21-alpha.0",
|
"@budibase/bbui": "1.4.8-alpha.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"svelte": "^3.46.2"
|
"svelte": "^3.46.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ ENV COUCH_DB_URL=https://couchdb.budi.live:5984
|
||||||
ENV BUDIBASE_ENVIRONMENT=PRODUCTION
|
ENV BUDIBASE_ENVIRONMENT=PRODUCTION
|
||||||
ENV SERVICE=app-service
|
ENV SERVICE=app-service
|
||||||
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||||
|
ENV TENANT_FEATURE_FLAGS=*:LICENSING,*:USER_GROUPS
|
||||||
|
|
||||||
# copy files and install dependencies
|
# copy files and install dependencies
|
||||||
COPY . ./
|
COPY . ./
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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": "1.3.21-alpha.0",
|
"@budibase/backend-core": "1.4.8-alpha.3",
|
||||||
"@budibase/client": "1.3.21-alpha.0",
|
"@budibase/client": "1.4.8-alpha.3",
|
||||||
"@budibase/pro": "1.3.21-alpha.0",
|
"@budibase/pro": "1.4.8-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.21-alpha.0",
|
"@budibase/string-templates": "1.4.8-alpha.3",
|
||||||
"@budibase/types": "1.3.21-alpha.0",
|
"@budibase/types": "1.4.8-alpha.3",
|
||||||
"@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",
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
const env = require("../../environment")
|
const env = require("../../environment")
|
||||||
const { getAllApps } = require("@budibase/backend-core/db")
|
const { getAllApps, getGlobalDBName } = require("@budibase/backend-core/db")
|
||||||
const {
|
const {
|
||||||
exportDB,
|
exportDB,
|
||||||
sendTempFile,
|
sendTempFile,
|
||||||
readFileSync,
|
readFileSync,
|
||||||
} = require("../../utilities/fileSystem")
|
} = require("../../utilities/fileSystem")
|
||||||
const { stringToReadStream } = require("../../utilities")
|
const { stringToReadStream } = require("../../utilities")
|
||||||
const {
|
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
||||||
getGlobalDBName,
|
|
||||||
getGlobalDB,
|
|
||||||
} = require("@budibase/backend-core/tenancy")
|
|
||||||
const { create } = require("./application")
|
const { create } = require("./application")
|
||||||
const { getDocParams, DocumentType, isDevAppID } = require("../../db/utils")
|
const { getDocParams, DocumentType, isDevAppID } = require("../../db/utils")
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
const { DocumentType, getPluginParams } = require("../../db/utils")
|
import { DocumentType } from "../../db/utils"
|
||||||
const { getComponentLibraryManifest } = require("../../utilities/fileSystem")
|
import { Plugin } from "@budibase/types"
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
import { db as dbCore, context, tenancy } from "@budibase/backend-core"
|
||||||
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
import { getComponentLibraryManifest } from "../../utilities/fileSystem"
|
||||||
|
|
||||||
exports.fetchAppComponentDefinitions = async function (ctx) {
|
exports.fetchAppComponentDefinitions = async function (ctx: any) {
|
||||||
try {
|
try {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const app = await db.get(DocumentType.APP_METADATA)
|
const app = await db.get(DocumentType.APP_METADATA)
|
||||||
|
|
||||||
let componentManifests = await Promise.all(
|
let componentManifests = await Promise.all(
|
||||||
app.componentLibraries.map(async library => {
|
app.componentLibraries.map(async (library: any) => {
|
||||||
let manifest = await getComponentLibraryManifest(library)
|
let manifest = await getComponentLibraryManifest(library)
|
||||||
return {
|
return {
|
||||||
manifest,
|
manifest,
|
||||||
|
@ -17,7 +17,7 @@ exports.fetchAppComponentDefinitions = async function (ctx) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const definitions = {}
|
const definitions: { [key: string]: any } = {}
|
||||||
for (let { manifest, library } of componentManifests) {
|
for (let { manifest, library } of componentManifests) {
|
||||||
for (let key of Object.keys(manifest)) {
|
for (let key of Object.keys(manifest)) {
|
||||||
if (key === "features") {
|
if (key === "features") {
|
||||||
|
@ -33,16 +33,16 @@ exports.fetchAppComponentDefinitions = async function (ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom components
|
// Add custom components
|
||||||
const globalDB = getGlobalDB()
|
const globalDB = tenancy.getGlobalDB()
|
||||||
const response = await globalDB.allDocs(
|
const response = await globalDB.allDocs(
|
||||||
getPluginParams(null, {
|
dbCore.getPluginParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
response.rows
|
response.rows
|
||||||
.map(row => row.doc)
|
.map((row: any) => row.doc)
|
||||||
.filter(plugin => plugin.schema.type === "component")
|
.filter((plugin: Plugin) => plugin.schema.type === "component")
|
||||||
.forEach(plugin => {
|
.forEach((plugin: Plugin) => {
|
||||||
const fullComponentName = `plugin/${plugin.name}`
|
const fullComponentName = `plugin/${plugin.name}`
|
||||||
definitions[fullComponentName] = {
|
definitions[fullComponentName] = {
|
||||||
component: fullComponentName,
|
component: fullComponentName,
|
|
@ -1,22 +1,16 @@
|
||||||
import { ObjectStoreBuckets } from "../../../constants"
|
|
||||||
import { loadJSFile } from "../../../utilities/fileSystem"
|
|
||||||
import { npmUpload, urlUpload, githubUpload, fileUpload } from "./uploaders"
|
import { npmUpload, urlUpload, githubUpload, fileUpload } from "./uploaders"
|
||||||
import { getGlobalDB } from "@budibase/backend-core/tenancy"
|
import { getGlobalDB } from "@budibase/backend-core/tenancy"
|
||||||
import { validate } from "@budibase/backend-core/plugins"
|
import { validate } from "@budibase/backend-core/plugins"
|
||||||
import { generatePluginID, getPluginParams } from "../../../db/utils"
|
import { PluginType, FileType, PluginSource } from "@budibase/types"
|
||||||
import {
|
|
||||||
uploadDirectory,
|
|
||||||
deleteFolder,
|
|
||||||
} from "@budibase/backend-core/objectStore"
|
|
||||||
import { PluginType, FileType, PluginSource, Plugin } from "@budibase/types"
|
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { ClientAppSocket } from "../../../websocket"
|
import { ClientAppSocket } from "../../../websocket"
|
||||||
import { events } from "@budibase/backend-core"
|
import { db as dbCore } from "@budibase/backend-core"
|
||||||
|
import { plugins } from "@budibase/pro"
|
||||||
|
|
||||||
export async function getPlugins(type?: PluginType) {
|
export async function getPlugins(type?: PluginType) {
|
||||||
const db = getGlobalDB()
|
const db = getGlobalDB()
|
||||||
const response = await db.allDocs(
|
const response = await db.allDocs(
|
||||||
getPluginParams(null, {
|
dbCore.getPluginParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -37,7 +31,7 @@ export async function upload(ctx: any) {
|
||||||
let docs = []
|
let docs = []
|
||||||
// can do single or multiple plugins
|
// can do single or multiple plugins
|
||||||
for (let plugin of plugins) {
|
for (let plugin of plugins) {
|
||||||
const doc = await processPlugin(plugin, PluginSource.FILE)
|
const doc = await processUploadedPlugin(plugin, PluginSource.FILE)
|
||||||
docs.push(doc)
|
docs.push(doc)
|
||||||
}
|
}
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
@ -91,18 +85,19 @@ export async function create(ctx: any) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const doc = await storePlugin(metadata, directory, source)
|
const doc = await plugins.storePlugin(metadata, directory, source)
|
||||||
|
|
||||||
|
ClientAppSocket.emit("plugins-update", { name, hash: doc.hash })
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
message: "Plugin uploaded successfully",
|
message: "Plugin uploaded successfully",
|
||||||
plugins: [doc],
|
plugins: [doc],
|
||||||
}
|
}
|
||||||
|
ctx.body = { plugin: doc }
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const errMsg = err?.message ? err?.message : err
|
const errMsg = err?.message ? err?.message : err
|
||||||
|
|
||||||
ctx.throw(400, `Failed to import plugin: ${errMsg}`)
|
ctx.throw(400, `Failed to import plugin: ${errMsg}`)
|
||||||
}
|
}
|
||||||
ctx.status = 200
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetch(ctx: any) {
|
export async function fetch(ctx: any) {
|
||||||
|
@ -110,99 +105,21 @@ export async function fetch(ctx: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(ctx: any) {
|
export async function destroy(ctx: any) {
|
||||||
const db = getGlobalDB()
|
|
||||||
const { pluginId } = ctx.params
|
const { pluginId } = ctx.params
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const plugin: Plugin = await db.get(pluginId)
|
await plugins.deletePlugin(pluginId)
|
||||||
const bucketPath = `${plugin.name}/`
|
|
||||||
await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath)
|
|
||||||
|
|
||||||
await db.remove(pluginId, plugin._rev)
|
ctx.body = { message: `Plugin ${ctx.params.pluginId} deleted.` }
|
||||||
await events.plugin.deleted(plugin)
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const errMsg = err?.message ? err?.message : err
|
ctx.throw(400, err.message)
|
||||||
|
|
||||||
ctx.throw(400, `Failed to delete plugin: ${errMsg}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.message = `Plugin ${ctx.params.pluginId} deleted.`
|
|
||||||
ctx.status = 200
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function storePlugin(
|
export async function processUploadedPlugin(
|
||||||
metadata: any,
|
plugin: FileType,
|
||||||
directory: any,
|
|
||||||
source?: PluginSource
|
source?: PluginSource
|
||||||
) {
|
) {
|
||||||
const db = getGlobalDB()
|
|
||||||
const version = metadata.package.version,
|
|
||||||
name = metadata.package.name,
|
|
||||||
description = metadata.package.description,
|
|
||||||
hash = metadata.schema.hash
|
|
||||||
|
|
||||||
// first open the tarball into tmp directory
|
|
||||||
const bucketPath = `${name}/`
|
|
||||||
const files = await uploadDirectory(
|
|
||||||
ObjectStoreBuckets.PLUGINS,
|
|
||||||
directory,
|
|
||||||
bucketPath
|
|
||||||
)
|
|
||||||
const jsFile = files.find((file: any) => file.name.endsWith(".js"))
|
|
||||||
if (!jsFile) {
|
|
||||||
throw new Error(`Plugin missing .js file.`)
|
|
||||||
}
|
|
||||||
// validate the JS for a datasource
|
|
||||||
if (metadata.schema.type === PluginType.DATASOURCE) {
|
|
||||||
const js = loadJSFile(directory, jsFile.name)
|
|
||||||
// TODO: this isn't safe - but we need full node environment
|
|
||||||
// in future we should do this in a thread for safety
|
|
||||||
try {
|
|
||||||
eval(js)
|
|
||||||
} catch (err: any) {
|
|
||||||
const message = err?.message ? err.message : JSON.stringify(err)
|
|
||||||
throw new Error(`JS invalid: ${message}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const jsFileName = jsFile.name
|
|
||||||
const pluginId = generatePluginID(name)
|
|
||||||
|
|
||||||
// overwrite existing docs entirely if they exist
|
|
||||||
let rev
|
|
||||||
try {
|
|
||||||
const existing = await db.get(pluginId)
|
|
||||||
rev = existing._rev
|
|
||||||
} catch (err) {
|
|
||||||
rev = undefined
|
|
||||||
}
|
|
||||||
let doc: Plugin = {
|
|
||||||
_id: pluginId,
|
|
||||||
_rev: rev,
|
|
||||||
...metadata,
|
|
||||||
name,
|
|
||||||
version,
|
|
||||||
hash,
|
|
||||||
description,
|
|
||||||
jsUrl: `${bucketPath}${jsFileName}`,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source) {
|
|
||||||
doc = {
|
|
||||||
...doc,
|
|
||||||
source,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await db.put(doc)
|
|
||||||
await events.plugin.imported(doc)
|
|
||||||
ClientAppSocket.emit("plugin-update", { name, hash })
|
|
||||||
return {
|
|
||||||
...doc,
|
|
||||||
_rev: response.rev,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function processPlugin(plugin: FileType, source?: PluginSource) {
|
|
||||||
const { metadata, directory } = await fileUpload(plugin)
|
const { metadata, directory } = await fileUpload(plugin)
|
||||||
validate(metadata?.schema)
|
validate(metadata?.schema)
|
||||||
|
|
||||||
|
@ -211,5 +128,7 @@ export async function processPlugin(plugin: FileType, source?: PluginSource) {
|
||||||
throw new Error("Only component plugins are supported outside of self-host")
|
throw new Error("Only component plugins are supported outside of self-host")
|
||||||
}
|
}
|
||||||
|
|
||||||
return await storePlugin(metadata, directory, source)
|
const doc = await plugins.storePlugin(metadata, directory, source)
|
||||||
|
ClientAppSocket.emit("plugin-update", { name: doc.name, hash: doc.hash })
|
||||||
|
return doc
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
const {
|
import { getScreenParams, generateScreenID, DocumentType } from "../../db/utils"
|
||||||
getScreenParams,
|
import {
|
||||||
generateScreenID,
|
events,
|
||||||
getPluginParams,
|
context,
|
||||||
DocumentType,
|
tenancy,
|
||||||
} = require("../../db/utils")
|
db as dbCore,
|
||||||
const { AccessController } = require("@budibase/backend-core/roles")
|
roles,
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
} from "@budibase/backend-core"
|
||||||
const { events } = require("@budibase/backend-core")
|
import { updateAppPackage } from "./application"
|
||||||
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
import { Plugin, ScreenProps } from "@budibase/types"
|
||||||
const { updateAppPackage } = require("./application")
|
|
||||||
|
|
||||||
exports.fetch = async ctx => {
|
exports.fetch = async (ctx: any) => {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
|
|
||||||
const screens = (
|
const screens = (
|
||||||
await db.allDocs(
|
await db.allDocs(
|
||||||
|
@ -19,16 +18,16 @@ exports.fetch = async ctx => {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
).rows.map(element => element.doc)
|
).rows.map((el: any) => el.doc)
|
||||||
|
|
||||||
ctx.body = await new AccessController().checkScreensAccess(
|
ctx.body = await new roles.AccessController().checkScreensAccess(
|
||||||
screens,
|
screens,
|
||||||
ctx.user.role._id
|
ctx.user.role._id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.save = async ctx => {
|
exports.save = async (ctx: any) => {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
let screen = ctx.request.body
|
let screen = ctx.request.body
|
||||||
|
|
||||||
let eventFn
|
let eventFn
|
||||||
|
@ -40,19 +39,19 @@ exports.save = async ctx => {
|
||||||
const response = await db.put(screen)
|
const response = await db.put(screen)
|
||||||
|
|
||||||
// Find any custom components being used
|
// Find any custom components being used
|
||||||
let pluginNames = []
|
let pluginNames: string[] = []
|
||||||
let pluginAdded = false
|
let pluginAdded = false
|
||||||
findPlugins(screen.props, pluginNames)
|
findPlugins(screen.props, pluginNames)
|
||||||
if (pluginNames.length) {
|
if (pluginNames.length) {
|
||||||
const globalDB = getGlobalDB()
|
const globalDB = tenancy.getGlobalDB()
|
||||||
const pluginsResponse = await globalDB.allDocs(
|
const pluginsResponse = await globalDB.allDocs(
|
||||||
getPluginParams(null, {
|
dbCore.getPluginParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const requiredPlugins = pluginsResponse.rows
|
const requiredPlugins = pluginsResponse.rows
|
||||||
.map(row => row.doc)
|
.map((row: any) => row.doc)
|
||||||
.filter(plugin => {
|
.filter((plugin: Plugin) => {
|
||||||
return (
|
return (
|
||||||
plugin.schema.type === "component" &&
|
plugin.schema.type === "component" &&
|
||||||
pluginNames.includes(`plugin/${plugin.name}`)
|
pluginNames.includes(`plugin/${plugin.name}`)
|
||||||
|
@ -63,8 +62,8 @@ exports.save = async ctx => {
|
||||||
const application = await db.get(DocumentType.APP_METADATA)
|
const application = await db.get(DocumentType.APP_METADATA)
|
||||||
let usedPlugins = application.usedPlugins || []
|
let usedPlugins = application.usedPlugins || []
|
||||||
|
|
||||||
requiredPlugins.forEach(plugin => {
|
requiredPlugins.forEach((plugin: Plugin) => {
|
||||||
if (!usedPlugins.find(x => x._id === plugin._id)) {
|
if (!usedPlugins.find((x: Plugin) => x._id === plugin._id)) {
|
||||||
pluginAdded = true
|
pluginAdded = true
|
||||||
usedPlugins.push({
|
usedPlugins.push({
|
||||||
_id: plugin._id,
|
_id: plugin._id,
|
||||||
|
@ -93,8 +92,8 @@ exports.save = async ctx => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.destroy = async ctx => {
|
exports.destroy = async (ctx: any) => {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const id = ctx.params.screenId
|
const id = ctx.params.screenId
|
||||||
const screen = await db.get(id)
|
const screen = await db.get(id)
|
||||||
|
|
||||||
|
@ -107,7 +106,7 @@ exports.destroy = async ctx => {
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
}
|
}
|
||||||
|
|
||||||
const findPlugins = (component, foundPlugins) => {
|
const findPlugins = (component: ScreenProps, foundPlugins: string[]) => {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return
|
return
|
||||||
}
|
}
|
|
@ -5,10 +5,12 @@ const { doInAppContext } = require("@budibase/backend-core/context")
|
||||||
const { doInTenant } = require("@budibase/backend-core/tenancy")
|
const { doInTenant } = require("@budibase/backend-core/tenancy")
|
||||||
const {
|
const {
|
||||||
quotas,
|
quotas,
|
||||||
|
} = require("@budibase/pro")
|
||||||
|
const {
|
||||||
QuotaUsageType,
|
QuotaUsageType,
|
||||||
StaticQuotaName,
|
StaticQuotaName,
|
||||||
MonthlyQuotaName,
|
MonthlyQuotaName,
|
||||||
} = require("@budibase/pro")
|
} = require("@budibase/types")
|
||||||
|
|
||||||
describe("/rows", () => {
|
describe("/rows", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
|
|
|
@ -42,7 +42,6 @@ const DocumentType = {
|
||||||
MEM_VIEW: "view",
|
MEM_VIEW: "view",
|
||||||
USER_FLAG: "flag",
|
USER_FLAG: "flag",
|
||||||
AUTOMATION_METADATA: "meta_au",
|
AUTOMATION_METADATA: "meta_au",
|
||||||
PLUGIN: "plg",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const InternalTables = {
|
const InternalTables = {
|
||||||
|
@ -384,10 +383,3 @@ exports.getMultiIDParams = ids => {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets parameters for retrieving automations, this is a utility function for the getDocParams function.
|
|
||||||
*/
|
|
||||||
exports.getPluginParams = (pluginId = null, otherProps = {}) => {
|
|
||||||
return getDocParams(DocumentType.PLUGIN, pluginId, otherProps)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { getTenantId } from "@budibase/backend-core/tenancy"
|
import { getTenantId } from "@budibase/backend-core/tenancy"
|
||||||
import { getAllApps } from "@budibase/backend-core/db"
|
import { getAllApps } from "@budibase/backend-core/db"
|
||||||
import { quotas, QuotaUsageType, StaticQuotaName } from "@budibase/pro"
|
import { quotas } from "@budibase/pro"
|
||||||
|
import { QuotaUsageType, StaticQuotaName } from "@budibase/types"
|
||||||
|
|
||||||
export const run = async () => {
|
export const run = async () => {
|
||||||
// get app count
|
// get app count
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { getTenantId } from "@budibase/backend-core/tenancy"
|
import { getTenantId } from "@budibase/backend-core/tenancy"
|
||||||
import { getAllApps } from "@budibase/backend-core/db"
|
import { getAllApps } from "@budibase/backend-core/db"
|
||||||
import { getUniqueRows } from "../../../utilities/usageQuota/rows"
|
import { getUniqueRows } from "../../../utilities/usageQuota/rows"
|
||||||
import { quotas, QuotaUsageType, StaticQuotaName } from "@budibase/pro"
|
import { quotas } from "@budibase/pro"
|
||||||
|
import { QuotaUsageType, StaticQuotaName } from "@budibase/types"
|
||||||
|
|
||||||
export const run = async () => {
|
export const run = async () => {
|
||||||
// get all rows in all apps
|
// get all rows in all apps
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import TestConfig from "../../../../tests/utilities/TestConfiguration"
|
import TestConfig from "../../../../tests/utilities/TestConfiguration"
|
||||||
import * as syncApps from "../syncApps"
|
import * as syncApps from "../syncApps"
|
||||||
import { quotas, QuotaUsageType, StaticQuotaName } from "@budibase/pro"
|
import { quotas } from "@budibase/pro"
|
||||||
|
import { QuotaUsageType, StaticQuotaName } from "@budibase/types"
|
||||||
|
|
||||||
describe("syncApps", () => {
|
describe("syncApps", () => {
|
||||||
let config = new TestConfig(false)
|
let config = new TestConfig(false)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import TestConfig from "../../../../tests/utilities/TestConfiguration"
|
import TestConfig from "../../../../tests/utilities/TestConfiguration"
|
||||||
import * as syncRows from "../syncRows"
|
import * as syncRows from "../syncRows"
|
||||||
import { quotas, QuotaUsageType, StaticQuotaName } from "@budibase/pro"
|
import { quotas } from "@budibase/pro"
|
||||||
|
import { QuotaUsageType, StaticQuotaName } from "@budibase/types"
|
||||||
|
|
||||||
describe("syncRows", () => {
|
describe("syncRows", () => {
|
||||||
let config = new TestConfig(false)
|
let config = new TestConfig(false)
|
||||||
|
|
|
@ -112,13 +112,6 @@ exports.loadHandlebarsFile = path => {
|
||||||
return fs.readFileSync(path, "utf8")
|
return fs.readFileSync(path, "utf8")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as above just with a different name.
|
|
||||||
*/
|
|
||||||
exports.loadJSFile = (directory, name) => {
|
|
||||||
return fs.readFileSync(join(directory, name), "utf8")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When return a file from the API need to write the file to the system temporarily so we
|
* When return a file from the API need to write the file to the system temporarily so we
|
||||||
* can create a read stream to send.
|
* can create a read stream to send.
|
||||||
|
|
|
@ -4,7 +4,7 @@ import chokidar from "chokidar"
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import { tenancy } from "@budibase/backend-core"
|
import { tenancy } from "@budibase/backend-core"
|
||||||
import { DEFAULT_TENANT_ID } from "@budibase/backend-core/constants"
|
import { DEFAULT_TENANT_ID } from "@budibase/backend-core/constants"
|
||||||
import { processPlugin } from "./api/controllers/plugin"
|
import { processUploadedPlugin } from "./api/controllers/plugin"
|
||||||
|
|
||||||
export function watch() {
|
export function watch() {
|
||||||
const watchPath = path.join(env.PLUGINS_DIR, "./**/*.tar.gz")
|
const watchPath = path.join(env.PLUGINS_DIR, "./**/*.tar.gz")
|
||||||
|
@ -28,7 +28,7 @@ export function watch() {
|
||||||
const split = path.split("/")
|
const split = path.split("/")
|
||||||
const name = split[split.length - 1]
|
const name = split[split.length - 1]
|
||||||
console.log("Importing plugin:", path)
|
console.log("Importing plugin:", path)
|
||||||
await processPlugin({ name, path })
|
await processUploadedPlugin({ name, path })
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const message = err?.message ? err?.message : err
|
const message = err?.message ? err?.message : err
|
||||||
console.error("Failed to import plugin:", message)
|
console.error("Failed to import plugin:", message)
|
||||||
|
|
|
@ -1094,12 +1094,12 @@
|
||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@budibase/backend-core@1.3.21-alpha.0":
|
"@budibase/backend-core@1.4.8-alpha.3":
|
||||||
version "1.3.21-alpha.0"
|
version "1.4.8-alpha.3"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.3.21-alpha.0.tgz#f64dc43f38e1ba8d43ae99fdb67f1f052a0af68e"
|
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.4.8-alpha.3.tgz#3a291fa610846cd2d15ec816974fe9b4ebc394b0"
|
||||||
integrity sha512-eVQXs9+ddfjtGYNanXkFCgYYxVwI90To4y1LY3CfUvegcDaJIt26XX9B7uKNwRdWl37XqptwbmaqDfsWlsxIew==
|
integrity sha512-MpZe5xe7mAuJ3sMh87E6go8XaUyCiAjyK+siubvYYP4zI3AVU60fF6rfHT7Q8Cl/taDVhrboDDbHTjk8jkwr5A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/types" "1.3.21-alpha.0"
|
"@budibase/types" "1.4.8-alpha.3"
|
||||||
"@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"
|
||||||
|
@ -1180,13 +1180,13 @@
|
||||||
svelte-flatpickr "^3.2.3"
|
svelte-flatpickr "^3.2.3"
|
||||||
svelte-portal "^1.0.0"
|
svelte-portal "^1.0.0"
|
||||||
|
|
||||||
"@budibase/pro@1.3.21-alpha.0":
|
"@budibase/pro@1.4.8-alpha.3":
|
||||||
version "1.3.21-alpha.0"
|
version "1.4.8-alpha.3"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.3.21-alpha.0.tgz#e6f3b1b044ff8da0d63fece6b86f10ed076dba6b"
|
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.4.8-alpha.3.tgz#20a6fe18b87ff73f699eda4b58741519f9aa6bb0"
|
||||||
integrity sha512-NPKZEo9Pz+XFA2/6KUFMhhPIpNzUBZ1AZzQeyeCyjZtXA88ipVA7xdhiJp0OJg1eXwo/QWB1KM/HY7q1kKDkWg==
|
integrity sha512-m+yvK0okqz0pE6ILAGESETHJHLOgUz8l9+mj/Bc4Wu0P6WyW4li81Wlz9WDcwUW2bSjpuf/MC1CjG05iS4opTQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/backend-core" "1.3.21-alpha.0"
|
"@budibase/backend-core" "1.4.8-alpha.3"
|
||||||
"@budibase/types" "1.3.21-alpha.0"
|
"@budibase/types" "1.4.8-alpha.3"
|
||||||
"@koa/router" "8.0.8"
|
"@koa/router" "8.0.8"
|
||||||
joi "17.6.0"
|
joi "17.6.0"
|
||||||
node-fetch "^2.6.1"
|
node-fetch "^2.6.1"
|
||||||
|
@ -1209,10 +1209,10 @@
|
||||||
svelte-apexcharts "^1.0.2"
|
svelte-apexcharts "^1.0.2"
|
||||||
svelte-flatpickr "^3.1.0"
|
svelte-flatpickr "^3.1.0"
|
||||||
|
|
||||||
"@budibase/types@1.3.21-alpha.0":
|
"@budibase/types@1.4.8-alpha.3":
|
||||||
version "1.3.21-alpha.0"
|
version "1.4.8-alpha.3"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.21-alpha.0.tgz#665d76bfce66f3bdef064ac9e3bef13e6567da6d"
|
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.4.8-alpha.3.tgz#85640009c992d37a56938fc601a786f5fd5e1739"
|
||||||
integrity sha512-IkNMFfARkRJRzTSeoRJhqI9hxdkwpq7Wodlj6Mk8++zcMm33RD2Yx4htTBAYEWeeTLYPu67hpvEjQ9OhAZUZNA==
|
integrity sha512-hqSGL0WXEtEuMsgAJ87jat/6MAUw7fFEuWRcUdnC9QtiF2yB4cjWStqVcfsBtiSt9VZ9xzNzcu1/++nPN/uF9w==
|
||||||
|
|
||||||
"@bull-board/api@3.7.0":
|
"@bull-board/api@3.7.0":
|
||||||
version "3.7.0"
|
version "3.7.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/string-templates",
|
"name": "@budibase/string-templates",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/types",
|
"name": "@budibase/types",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"description": "Budibase types",
|
"description": "Budibase types",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Hosting } from "../../sdk"
|
import { Feature, Hosting, PlanType, Quotas } from "../../sdk"
|
||||||
|
|
||||||
export interface CreateAccount {
|
export interface CreateAccount {
|
||||||
email: string
|
email: string
|
||||||
|
@ -22,6 +22,11 @@ export const isCreatePasswordAccount = (
|
||||||
account: CreateAccount
|
account: CreateAccount
|
||||||
): account is CreatePassswordAccount => account.authType === AuthType.PASSWORD
|
): account is CreatePassswordAccount => account.authType === AuthType.PASSWORD
|
||||||
|
|
||||||
|
export interface LicenseOverrides {
|
||||||
|
features?: Feature[]
|
||||||
|
quotas?: Quotas
|
||||||
|
}
|
||||||
|
|
||||||
export interface Account extends CreateAccount {
|
export interface Account extends CreateAccount {
|
||||||
// generated
|
// generated
|
||||||
accountId: string
|
accountId: string
|
||||||
|
@ -31,9 +36,12 @@ export interface Account extends CreateAccount {
|
||||||
verificationSent: boolean
|
verificationSent: boolean
|
||||||
// licensing
|
// licensing
|
||||||
tier: string // deprecated
|
tier: string // deprecated
|
||||||
|
planType?: PlanType
|
||||||
|
planTier?: number
|
||||||
stripeCustomerId?: string
|
stripeCustomerId?: string
|
||||||
licenseKey?: string
|
licenseKey?: string
|
||||||
licenseKeyActivatedAt?: number
|
licenseKeyActivatedAt?: number
|
||||||
|
licenseOverrides?: LicenseOverrides
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PasswordAccount extends Account {
|
export interface PasswordAccount extends Account {
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
import { Document } from "../document"
|
import { Document } from "../document"
|
||||||
|
|
||||||
|
export interface ScreenProps extends Document {
|
||||||
|
_instanceName: string
|
||||||
|
_styles: { [key: string]: any }
|
||||||
|
_component: string
|
||||||
|
_children: ScreenProps[]
|
||||||
|
size?: string
|
||||||
|
gap?: string
|
||||||
|
direction?: string
|
||||||
|
vAlign?: string
|
||||||
|
hAlign?: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface Screen extends Document {
|
export interface Screen extends Document {
|
||||||
layoutId?: string
|
layoutId?: string
|
||||||
showNavigation?: boolean
|
showNavigation?: boolean
|
||||||
|
@ -9,4 +21,5 @@ export interface Screen extends Document {
|
||||||
roleId: string
|
roleId: string
|
||||||
homeScreen?: boolean
|
homeScreen?: boolean
|
||||||
}
|
}
|
||||||
|
props: ScreenProps
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,4 @@ export * from "./config"
|
||||||
export * from "./user"
|
export * from "./user"
|
||||||
export * from "./userGroup"
|
export * from "./userGroup"
|
||||||
export * from "./plugin"
|
export * from "./plugin"
|
||||||
|
export * from "./quotas"
|
||||||
|
|
|
@ -23,6 +23,7 @@ export interface Plugin extends Document {
|
||||||
jsUrl?: string
|
jsUrl?: string
|
||||||
source: PluginSource
|
source: PluginSource
|
||||||
package: { [key: string]: any }
|
package: { [key: string]: any }
|
||||||
|
hash: string
|
||||||
schema: {
|
schema: {
|
||||||
type: PluginType
|
type: PluginType
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { MonthlyQuotaName, StaticQuotaName } from "../../sdk"
|
||||||
|
|
||||||
|
export interface QuotaUsage {
|
||||||
|
_id: string
|
||||||
|
_rev?: string
|
||||||
|
quotaReset: string
|
||||||
|
usageQuota: {
|
||||||
|
[key in StaticQuotaName]: number
|
||||||
|
}
|
||||||
|
monthly: {
|
||||||
|
[key: string]: {
|
||||||
|
[key in MonthlyQuotaName]: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -133,9 +133,14 @@ export enum Event {
|
||||||
AUTOMATION_TRIGGER_UPDATED = "automation:trigger:updated",
|
AUTOMATION_TRIGGER_UPDATED = "automation:trigger:updated",
|
||||||
|
|
||||||
// LICENSE
|
// LICENSE
|
||||||
LICENSE_UPGRADED = "license:upgraded",
|
LICENSE_PLAN_CHANGED = "license:plan:changed",
|
||||||
LICENSE_DOWNGRADED = "license:downgraded",
|
LICENSE_TIER_CHANGED = "license:tier:changed",
|
||||||
LICENSE_ACTIVATED = "license:activated",
|
LICENSE_ACTIVATED = "license:activated",
|
||||||
|
LICENSE_PAYMENT_FAILED = "license:payment:failed",
|
||||||
|
LICENSE_PAYMENT_RECOVERED = "license:payment:recovered",
|
||||||
|
LICENSE_CHECKOUT_OPENED = "license:checkout:opened",
|
||||||
|
LICENSE_CHECKOUT_SUCCESS = "license:checkout:success",
|
||||||
|
LICENSE_PORTAL_OPENED = "license:portal:opened",
|
||||||
|
|
||||||
// ACCOUNT
|
// ACCOUNT
|
||||||
ACCOUNT_CREATED = "account:created",
|
ACCOUNT_CREATED = "account:created",
|
||||||
|
|
|
@ -1,7 +1,37 @@
|
||||||
export interface LicenseUpgradedEvent {}
|
import { PlanType } from "../licensing"
|
||||||
|
|
||||||
export interface LicenseDowngradedEvent {}
|
export interface LicenseTierChangedEvent {
|
||||||
|
accountId: string
|
||||||
|
from: number
|
||||||
|
to: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface LicenseUpdatedEvent {}
|
export interface LicensePlanChangedEvent {
|
||||||
|
accountId: string
|
||||||
|
from: PlanType
|
||||||
|
to: PlanType
|
||||||
|
}
|
||||||
|
|
||||||
export interface LicenseActivatedEvent {}
|
export interface LicenseActivatedEvent {
|
||||||
|
accountId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LicenseCheckoutOpenedEvent {
|
||||||
|
accountId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LicenseCheckoutSuccessEvent {
|
||||||
|
accountId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LicensePortalOpenedEvent {
|
||||||
|
accountId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LicensePaymentFailedEvent {
|
||||||
|
accountId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LicensePaymentRecoveredEvent {
|
||||||
|
accountId: string
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ export interface Subscription {
|
||||||
cancelAt: number | null | undefined
|
cancelAt: number | null | undefined
|
||||||
currentPeriodStart: number
|
currentPeriodStart: number
|
||||||
currentPeriodEnd: number
|
currentPeriodEnd: number
|
||||||
|
status: string
|
||||||
|
pastDueAt?: number | null
|
||||||
|
downgradeAt?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Billing {
|
export interface Billing {
|
||||||
|
|
|
@ -6,6 +6,7 @@ export interface AccountPlan {
|
||||||
export enum PlanType {
|
export enum PlanType {
|
||||||
FREE = "free",
|
FREE = "free",
|
||||||
PRO = "pro",
|
PRO = "pro",
|
||||||
|
TEAM = "team",
|
||||||
BUSINESS = "business",
|
BUSINESS = "business",
|
||||||
ENTERPRISE = "enterprise",
|
ENTERPRISE = "enterprise",
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ export enum QuotaType {
|
||||||
export enum StaticQuotaName {
|
export enum StaticQuotaName {
|
||||||
ROWS = "rows",
|
ROWS = "rows",
|
||||||
APPS = "apps",
|
APPS = "apps",
|
||||||
|
USER_GROUPS = "userGroups",
|
||||||
|
PLUGINS = "plugins",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MonthlyQuotaName {
|
export enum MonthlyQuotaName {
|
||||||
|
@ -22,7 +24,6 @@ export enum MonthlyQuotaName {
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ConstantQuotaName {
|
export enum ConstantQuotaName {
|
||||||
QUERY_TIMEOUT_SECONDS = "queryTimeoutSeconds",
|
|
||||||
AUTOMATION_LOG_RETENTION_DAYS = "automationLogRetentionDays",
|
AUTOMATION_LOG_RETENTION_DAYS = "automationLogRetentionDays",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +55,7 @@ export const isConstantQuota = (
|
||||||
export type PlanQuotas = {
|
export type PlanQuotas = {
|
||||||
[PlanType.FREE]: Quotas
|
[PlanType.FREE]: Quotas
|
||||||
[PlanType.PRO]: Quotas
|
[PlanType.PRO]: Quotas
|
||||||
|
[PlanType.TEAM]: Quotas
|
||||||
[PlanType.BUSINESS]: Quotas
|
[PlanType.BUSINESS]: Quotas
|
||||||
[PlanType.ENTERPRISE]: Quotas
|
[PlanType.ENTERPRISE]: Quotas
|
||||||
}
|
}
|
||||||
|
@ -68,10 +70,11 @@ export type Quotas = {
|
||||||
[QuotaUsageType.STATIC]: {
|
[QuotaUsageType.STATIC]: {
|
||||||
[StaticQuotaName.ROWS]: Quota
|
[StaticQuotaName.ROWS]: Quota
|
||||||
[StaticQuotaName.APPS]: Quota
|
[StaticQuotaName.APPS]: Quota
|
||||||
|
[StaticQuotaName.USER_GROUPS]: Quota
|
||||||
|
[StaticQuotaName.PLUGINS]: Quota
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[QuotaType.CONSTANT]: {
|
[QuotaType.CONSTANT]: {
|
||||||
[ConstantQuotaName.QUERY_TIMEOUT_SECONDS]: Quota
|
|
||||||
[ConstantQuotaName.AUTOMATION_LOG_RETENTION_DAYS]: Quota
|
[ConstantQuotaName.AUTOMATION_LOG_RETENTION_DAYS]: Quota
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,5 +23,6 @@ ENV NODE_ENV=production
|
||||||
ENV CLUSTER_MODE=${CLUSTER_MODE}
|
ENV CLUSTER_MODE=${CLUSTER_MODE}
|
||||||
ENV SERVICE=worker-service
|
ENV SERVICE=worker-service
|
||||||
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||||
|
ENV TENANT_FEATURE_FLAGS=*:LICENSING,*:USER_GROUPS
|
||||||
|
|
||||||
CMD ["./docker_run.sh"]
|
CMD ["./docker_run.sh"]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/worker",
|
"name": "@budibase/worker",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "1.3.21-alpha.0",
|
"version": "1.4.8-alpha.3",
|
||||||
"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": "1.3.21-alpha.0",
|
"@budibase/backend-core": "1.4.8-alpha.3",
|
||||||
"@budibase/pro": "1.3.21-alpha.0",
|
"@budibase/pro": "1.4.8-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.21-alpha.0",
|
"@budibase/string-templates": "1.4.8-alpha.3",
|
||||||
"@budibase/types": "1.3.21-alpha.0",
|
"@budibase/types": "1.4.8-alpha.3",
|
||||||
"@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",
|
||||||
|
|
|
@ -10,7 +10,9 @@ const router = new Router()
|
||||||
function buildEmailSendValidation() {
|
function buildEmailSendValidation() {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return joiValidator.body(Joi.object({
|
return joiValidator.body(Joi.object({
|
||||||
email: Joi.string().email(),
|
email: Joi.string().email({
|
||||||
|
multiple: true,
|
||||||
|
}),
|
||||||
purpose: Joi.string().valid(...Object.values(EmailTemplatePurpose)),
|
purpose: Joi.string().valid(...Object.values(EmailTemplatePurpose)),
|
||||||
workspaceId: Joi.string().allow("", null),
|
workspaceId: Joi.string().allow("", null),
|
||||||
from: Joi.string().allow("", null),
|
from: Joi.string().allow("", null),
|
||||||
|
|
|
@ -291,12 +291,12 @@
|
||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@budibase/backend-core@1.3.21-alpha.0":
|
"@budibase/backend-core@1.4.8-alpha.3":
|
||||||
version "1.3.21-alpha.0"
|
version "1.4.8-alpha.3"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.3.21-alpha.0.tgz#f64dc43f38e1ba8d43ae99fdb67f1f052a0af68e"
|
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.4.8-alpha.3.tgz#3a291fa610846cd2d15ec816974fe9b4ebc394b0"
|
||||||
integrity sha512-eVQXs9+ddfjtGYNanXkFCgYYxVwI90To4y1LY3CfUvegcDaJIt26XX9B7uKNwRdWl37XqptwbmaqDfsWlsxIew==
|
integrity sha512-MpZe5xe7mAuJ3sMh87E6go8XaUyCiAjyK+siubvYYP4zI3AVU60fF6rfHT7Q8Cl/taDVhrboDDbHTjk8jkwr5A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/types" "1.3.21-alpha.0"
|
"@budibase/types" "1.4.8-alpha.3"
|
||||||
"@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"
|
||||||
|
@ -327,21 +327,21 @@
|
||||||
uuid "8.3.2"
|
uuid "8.3.2"
|
||||||
zlib "1.0.5"
|
zlib "1.0.5"
|
||||||
|
|
||||||
"@budibase/pro@1.3.21-alpha.0":
|
"@budibase/pro@1.4.8-alpha.3":
|
||||||
version "1.3.21-alpha.0"
|
version "1.4.8-alpha.3"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.3.21-alpha.0.tgz#e6f3b1b044ff8da0d63fece6b86f10ed076dba6b"
|
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.4.8-alpha.3.tgz#20a6fe18b87ff73f699eda4b58741519f9aa6bb0"
|
||||||
integrity sha512-NPKZEo9Pz+XFA2/6KUFMhhPIpNzUBZ1AZzQeyeCyjZtXA88ipVA7xdhiJp0OJg1eXwo/QWB1KM/HY7q1kKDkWg==
|
integrity sha512-m+yvK0okqz0pE6ILAGESETHJHLOgUz8l9+mj/Bc4Wu0P6WyW4li81Wlz9WDcwUW2bSjpuf/MC1CjG05iS4opTQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/backend-core" "1.3.21-alpha.0"
|
"@budibase/backend-core" "1.4.8-alpha.3"
|
||||||
"@budibase/types" "1.3.21-alpha.0"
|
"@budibase/types" "1.4.8-alpha.3"
|
||||||
"@koa/router" "8.0.8"
|
"@koa/router" "8.0.8"
|
||||||
joi "17.6.0"
|
joi "17.6.0"
|
||||||
node-fetch "^2.6.1"
|
node-fetch "^2.6.1"
|
||||||
|
|
||||||
"@budibase/types@1.3.21-alpha.0":
|
"@budibase/types@1.4.8-alpha.3":
|
||||||
version "1.3.21-alpha.0"
|
version "1.4.8-alpha.3"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.21-alpha.0.tgz#665d76bfce66f3bdef064ac9e3bef13e6567da6d"
|
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.4.8-alpha.3.tgz#85640009c992d37a56938fc601a786f5fd5e1739"
|
||||||
integrity sha512-IkNMFfARkRJRzTSeoRJhqI9hxdkwpq7Wodlj6Mk8++zcMm33RD2Yx4htTBAYEWeeTLYPu67hpvEjQ9OhAZUZNA==
|
integrity sha512-hqSGL0WXEtEuMsgAJ87jat/6MAUw7fFEuWRcUdnC9QtiF2yB4cjWStqVcfsBtiSt9VZ9xzNzcu1/++nPN/uF9w==
|
||||||
|
|
||||||
"@cspotcode/source-map-consumer@0.8.0":
|
"@cspotcode/source-map-consumer@0.8.0":
|
||||||
version "0.8.0"
|
version "0.8.0"
|
||||||
|
|
|
@ -32,7 +32,7 @@ describe("Public API - /rows endpoints", () => {
|
||||||
expect(row._id).toBeDefined()
|
expect(row._id).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("POST - Search rows", async () => {
|
/*it("POST - Search rows", async () => {
|
||||||
const [response, rows] = await config.rows.search({
|
const [response, rows] = await config.rows.search({
|
||||||
query: {
|
query: {
|
||||||
string: {
|
string: {
|
||||||
|
@ -44,7 +44,7 @@ describe("Public API - /rows endpoints", () => {
|
||||||
expect(rows[0]._id).toEqual(config.context._id)
|
expect(rows[0]._id).toEqual(config.context._id)
|
||||||
expect(rows[0].tableId).toEqual(config.context.tableId)
|
expect(rows[0].tableId).toEqual(config.context.tableId)
|
||||||
expect(rows[0].testColumn).toEqual(config.context.testColumn)
|
expect(rows[0].testColumn).toEqual(config.context.testColumn)
|
||||||
})
|
})*/
|
||||||
|
|
||||||
it("GET - Retrieve a row", async () => {
|
it("GET - Retrieve a row", async () => {
|
||||||
const [response, row] = await config.rows.read(config.context._id)
|
const [response, row] = await config.rows.read(config.context._id)
|
||||||
|
|
Loading…
Reference in New Issue