Merge branch 'develop' of github.com:Budibase/budibase into cheeks-lab-day-eject-blocks
This commit is contained in:
commit
3283a0ab5a
|
@ -102,4 +102,6 @@ packages/builder/cypress/reports
|
||||||
stats.html
|
stats.html
|
||||||
|
|
||||||
# TypeScript cache
|
# TypeScript cache
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
|
budibase-component
|
||||||
|
budibase-datasource
|
||||||
|
|
|
@ -124,11 +124,15 @@ spec:
|
||||||
value: {{ .Values.globals.tenantFeatureFlags | quote }}
|
value: {{ .Values.globals.tenantFeatureFlags | quote }}
|
||||||
{{ if .Values.globals.bbAdminUserEmail }}
|
{{ if .Values.globals.bbAdminUserEmail }}
|
||||||
- name: BB_ADMIN_USER_EMAIL
|
- name: BB_ADMIN_USER_EMAIL
|
||||||
value: { { .Values.globals.bbAdminUserEmail | quote } }
|
value: {{ .Values.globals.bbAdminUserEmail | quote }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if .Values.globals.bbAdminUserPassword }}
|
{{ if .Values.globals.bbAdminUserPassword }}
|
||||||
- name: BB_ADMIN_USER_PASSWORD
|
- name: BB_ADMIN_USER_PASSWORD
|
||||||
value: { { .Values.globals.bbAdminUserPassword | quote } }
|
value: {{ .Values.globals.bbAdminUserPassword | quote }}
|
||||||
|
{{ end }}
|
||||||
|
{{ if .Values.globals.pluginsDir }}
|
||||||
|
- name: PLUGINS_DIR
|
||||||
|
value: {{ .Values.globals.pluginsDir | quote }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if .Values.services.apps.nodeDebug }}
|
{{ if .Values.services.apps.nodeDebug }}
|
||||||
- name: NODE_DEBUG
|
- name: NODE_DEBUG
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bulma": "^0.9.3",
|
"bulma": "^0.9.3",
|
||||||
"next": "12.1.0",
|
"next": "12.1.0",
|
||||||
"node-fetch": "^3.2.2",
|
"node-fetch": "^3.2.10",
|
||||||
"node-sass": "^7.0.1",
|
"sass": "^1.52.3",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-notifications-component": "^3.4.1"
|
"react-notifications-component": "^3.4.1"
|
||||||
|
@ -24,4 +24,4 @@
|
||||||
"eslint-config-next": "12.1.0",
|
"eslint-config-next": "12.1.0",
|
||||||
"typescript": "4.6.2"
|
"typescript": "4.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2020,10 +2020,10 @@ node-domexception@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||||
|
|
||||||
node-fetch@^3.2.2:
|
node-fetch@^3.2.10:
|
||||||
version "3.2.2"
|
version "3.2.10"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.2.tgz#16d33fbe32ca7c6ca1ca8ba5dfea1dd885c59f04"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8"
|
||||||
integrity sha512-Cwhq1JFIoon15wcIkFzubVNFE5GvXGV82pKf4knXXjvGmn7RJKcypeuqcVNZMGDZsAFWyIRya/anwAJr7TWJ7w==
|
integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==
|
||||||
dependencies:
|
dependencies:
|
||||||
data-uri-to-buffer "^4.0.0"
|
data-uri-to-buffer "^4.0.0"
|
||||||
fetch-blob "^3.1.4"
|
fetch-blob "^3.1.4"
|
||||||
|
|
|
@ -22,4 +22,7 @@ BUDIBASE_ENVIRONMENT=PRODUCTION
|
||||||
|
|
||||||
# An admin user can be automatically created initially if these are set
|
# An admin user can be automatically created initially if these are set
|
||||||
BB_ADMIN_USER_EMAIL=
|
BB_ADMIN_USER_EMAIL=
|
||||||
BB_ADMIN_USER_PASSWORD=
|
BB_ADMIN_USER_PASSWORD=
|
||||||
|
|
||||||
|
# A path that is watched for plugin bundles. Any bundles found are imported automatically/
|
||||||
|
PLUGINS_DIR=
|
|
@ -25,9 +25,12 @@ services:
|
||||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||||
BB_ADMIN_USER_EMAIL: ${BB_ADMIN_USER_EMAIL}
|
BB_ADMIN_USER_EMAIL: ${BB_ADMIN_USER_EMAIL}
|
||||||
BB_ADMIN_USER_PASSWORD: ${BB_ADMIN_USER_PASSWORD}
|
BB_ADMIN_USER_PASSWORD: ${BB_ADMIN_USER_PASSWORD}
|
||||||
|
PLUGINS_DIR: ${PLUGINS_DIR}
|
||||||
depends_on:
|
depends_on:
|
||||||
- worker-service
|
- worker-service
|
||||||
- redis-service
|
- redis-service
|
||||||
|
# volumes:
|
||||||
|
# - /some/path/to/plugins:/plugins
|
||||||
|
|
||||||
worker-service:
|
worker-service:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
|
@ -22,4 +22,7 @@ BUDIBASE_ENVIRONMENT=PRODUCTION
|
||||||
|
|
||||||
# An admin user can be automatically created initially if these are set
|
# An admin user can be automatically created initially if these are set
|
||||||
BB_ADMIN_USER_EMAIL=
|
BB_ADMIN_USER_EMAIL=
|
||||||
BB_ADMIN_USER_PASSWORD=
|
BB_ADMIN_USER_PASSWORD=
|
||||||
|
|
||||||
|
# A path that is watched for plugin bundles. Any bundles found are imported automatically/
|
||||||
|
PLUGINS_DIR=
|
|
@ -65,10 +65,6 @@ http {
|
||||||
proxy_pass http://{{ address }}:4001;
|
proxy_pass http://{{ address }}:4001;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /preview {
|
|
||||||
proxy_pass http://{{ address }}:4001;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /builder {
|
location /builder {
|
||||||
proxy_pass http://{{ address }}:3000;
|
proxy_pass http://{{ address }}:3000;
|
||||||
rewrite ^/builder(.*)$ /builder/$1 break;
|
rewrite ^/builder(.*)$ /builder/$1 break;
|
||||||
|
@ -84,6 +80,20 @@ http {
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /vite/ {
|
||||||
|
proxy_pass http://{{ address }}:3000;
|
||||||
|
rewrite ^/vite(.*)$ /$1 break;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /socket/ {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_pass http://{{ address }}:4001;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
|
@ -88,10 +88,6 @@ http {
|
||||||
proxy_pass http://$apps:4002;
|
proxy_pass http://$apps:4002;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /preview {
|
|
||||||
proxy_pass http://$apps:4002;
|
|
||||||
}
|
|
||||||
|
|
||||||
location = / {
|
location = / {
|
||||||
proxy_pass http://$apps:4002;
|
proxy_pass http://$apps:4002;
|
||||||
}
|
}
|
||||||
|
@ -162,6 +158,15 @@ http {
|
||||||
rewrite ^/db/(.*)$ /$1 break;
|
rewrite ^/db/(.*)$ /$1 break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /socket/ {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_pass http://$apps:4002;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
|
@ -4,9 +4,9 @@ echo ${TARGETBUILD} > /buildtarget.txt
|
||||||
if [[ "${TARGETBUILD}" = "aas" ]]; then
|
if [[ "${TARGETBUILD}" = "aas" ]]; then
|
||||||
# Azure AppService uses /home for persisent data & SSH on port 2222
|
# Azure AppService uses /home for persisent data & SSH on port 2222
|
||||||
DATA_DIR=/home
|
DATA_DIR=/home
|
||||||
mkdir -p $DATA_DIR/{search,minio,couchdb}
|
mkdir -p $DATA_DIR/{search,minio,couch}
|
||||||
mkdir -p $DATA_DIR/couchdb/{dbs,views}
|
mkdir -p $DATA_DIR/couch/{dbs,views}
|
||||||
chown -R couchdb:couchdb $DATA_DIR/couchdb/
|
chown -R couchdb:couchdb $DATA_DIR/couch/
|
||||||
apt update
|
apt update
|
||||||
apt-get install -y openssh-server
|
apt-get install -y openssh-server
|
||||||
sed -i "s/#Port 22/Port 2222/" /etc/ssh/sshd_config
|
sed -i "s/#Port 22/Port 2222/" /etc/ssh/sshd_config
|
||||||
|
@ -16,5 +16,4 @@ if [[ "${TARGETBUILD}" = "aas" ]]; then
|
||||||
else
|
else
|
||||||
sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini
|
sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini
|
||||||
sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini
|
sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini
|
||||||
|
|
||||||
fi
|
fi
|
|
@ -1,5 +1,5 @@
|
||||||
; CouchDB Configuration Settings
|
; CouchDB Configuration Settings
|
||||||
|
|
||||||
[couchdb]
|
[couchdb]
|
||||||
database_dir = DATA_DIR/couchdb/dbs
|
database_dir = DATA_DIR/couch/dbs
|
||||||
view_index_dir = DATA_DIR/couchdb/views
|
view_index_dir = DATA_DIR/couch/views
|
||||||
|
|
|
@ -66,6 +66,15 @@ server {
|
||||||
rewrite ^/db/(.*)$ /$1 break;
|
rewrite ^/db/(.*)$ /$1 break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /socket/ {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_pass http://127.0.0.1:4001;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
|
@ -36,10 +36,10 @@ fi
|
||||||
export COUCH_DB_URL=http://$COUCHDB_USER:$COUCHDB_PASSWORD@localhost:5984
|
export COUCH_DB_URL=http://$COUCHDB_USER:$COUCHDB_PASSWORD@localhost:5984
|
||||||
|
|
||||||
# make these directories in runner, incase of mount
|
# make these directories in runner, incase of mount
|
||||||
mkdir -p ${DATA_DIR}/couchdb/{dbs,views}
|
mkdir -p ${DATA_DIR}/couch/{dbs,views}
|
||||||
mkdir -p ${DATA_DIR}/minio
|
mkdir -p ${DATA_DIR}/minio
|
||||||
mkdir -p ${DATA_DIR}/search
|
mkdir -p ${DATA_DIR}/search
|
||||||
chown -R couchdb:couchdb ${DATA_DIR}/couchdb
|
chown -R couchdb:couchdb ${DATA_DIR}/couch
|
||||||
redis-server --requirepass $REDIS_PASSWORD &
|
redis-server --requirepass $REDIS_PASSWORD &
|
||||||
/opt/clouseau/bin/clouseau &
|
/opt/clouseau/bin/clouseau &
|
||||||
/minio/minio server ${DATA_DIR}/minio &
|
/minio/minio server ${DATA_DIR}/minio &
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "1.3.4-alpha.2",
|
"version": "1.3.15-alpha.3",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/backend-core",
|
"name": "@budibase/backend-core",
|
||||||
"version": "1.3.4-alpha.2",
|
"version": "1.3.15-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,8 @@
|
||||||
"test:watch": "jest --watchAll"
|
"test:watch": "jest --watchAll"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/types": "1.3.4-alpha.2",
|
"@budibase/types": "1.3.15-alpha.3",
|
||||||
|
"@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",
|
||||||
"bcrypt": "5.0.1",
|
"bcrypt": "5.0.1",
|
||||||
|
@ -60,7 +61,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@shopify/jest-koa-mocks": "3.1.5",
|
|
||||||
"@types/jest": "27.5.1",
|
"@types/jest": "27.5.1",
|
||||||
"@types/koa": "2.0.52",
|
"@types/koa": "2.0.52",
|
||||||
"@types/lodash": "4.14.180",
|
"@types/lodash": "4.14.180",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
...require("./src/plugin"),
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import { dangerousGetDB, closeDB } from "."
|
import { dangerousGetDB, closeDB } from "."
|
||||||
|
import { DocumentType } from "./constants"
|
||||||
|
|
||||||
class Replication {
|
class Replication {
|
||||||
source: any
|
source: any
|
||||||
|
@ -53,6 +54,14 @@ class Replication {
|
||||||
return this.replication
|
return this.replication
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appReplicateOpts() {
|
||||||
|
return {
|
||||||
|
filter: (doc: any) => {
|
||||||
|
return doc._id !== DocumentType.APP_METADATA
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rollback the target DB back to the state of the source DB
|
* Rollback the target DB back to the state of the source DB
|
||||||
*/
|
*/
|
||||||
|
@ -60,6 +69,7 @@ class Replication {
|
||||||
await this.target.destroy()
|
await this.target.destroy()
|
||||||
// Recreate the DB again
|
// Recreate the DB again
|
||||||
this.target = dangerousGetDB(this.target.name)
|
this.target = dangerousGetDB(this.target.name)
|
||||||
|
// take the opportunity to remove deleted tombstones
|
||||||
await this.replicate()
|
await this.replicate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,7 +254,16 @@ export async function getAllApps({ dev, all, idsOnly, efficient }: any = {}) {
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
if (idsOnly) {
|
if (idsOnly) {
|
||||||
return appDbNames
|
const devAppIds = appDbNames.filter(appId => isDevAppID(appId))
|
||||||
|
const prodAppIds = appDbNames.filter(appId => !isDevAppID(appId))
|
||||||
|
switch (dev) {
|
||||||
|
case true:
|
||||||
|
return devAppIds
|
||||||
|
case false:
|
||||||
|
return prodAppIds
|
||||||
|
default:
|
||||||
|
return appDbNames
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const appPromises = appDbNames.map((app: any) =>
|
const appPromises = appDbNames.map((app: any) =>
|
||||||
// skip setup otherwise databases could be re-created
|
// skip setup otherwise databases could be re-created
|
||||||
|
|
|
@ -50,6 +50,7 @@ const env = {
|
||||||
GLOBAL_BUCKET_NAME: process.env.GLOBAL_BUCKET_NAME || "global",
|
GLOBAL_BUCKET_NAME: process.env.GLOBAL_BUCKET_NAME || "global",
|
||||||
GLOBAL_CLOUD_BUCKET_NAME:
|
GLOBAL_CLOUD_BUCKET_NAME:
|
||||||
process.env.GLOBAL_CLOUD_BUCKET_NAME || "prod-budi-tenant-uploads",
|
process.env.GLOBAL_CLOUD_BUCKET_NAME || "prod-budi-tenant-uploads",
|
||||||
|
PLUGIN_BUCKET_NAME: process.env.PLUGIN_BUCKET_NAME || "plugins",
|
||||||
USE_COUCH: process.env.USE_COUCH || true,
|
USE_COUCH: process.env.USE_COUCH || true,
|
||||||
DISABLE_DEVELOPER_LICENSE: process.env.DISABLE_DEVELOPER_LICENSE,
|
DISABLE_DEVELOPER_LICENSE: process.env.DISABLE_DEVELOPER_LICENSE,
|
||||||
DEFAULT_LICENSE: process.env.DEFAULT_LICENSE,
|
DEFAULT_LICENSE: process.env.DEFAULT_LICENSE,
|
||||||
|
|
|
@ -18,6 +18,7 @@ import * as dbConstants from "./db/constants"
|
||||||
import logging from "./logging"
|
import logging from "./logging"
|
||||||
import pino from "./pino"
|
import pino from "./pino"
|
||||||
import * as middleware from "./middleware"
|
import * as middleware from "./middleware"
|
||||||
|
import plugins from "./plugin"
|
||||||
|
|
||||||
// mimic the outer package exports
|
// mimic the outer package exports
|
||||||
import * as db from "./pkg/db"
|
import * as db from "./pkg/db"
|
||||||
|
@ -56,6 +57,7 @@ const core = {
|
||||||
errors,
|
errors,
|
||||||
logging,
|
logging,
|
||||||
roles,
|
roles,
|
||||||
|
plugins,
|
||||||
...pino,
|
...pino,
|
||||||
...errorClasses,
|
...errorClasses,
|
||||||
middleware,
|
middleware,
|
||||||
|
|
|
@ -57,7 +57,11 @@ function publicPolicy(bucketName: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PUBLIC_BUCKETS = [ObjectStoreBuckets.APPS, ObjectStoreBuckets.GLOBAL]
|
const PUBLIC_BUCKETS = [
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
ObjectStoreBuckets.GLOBAL,
|
||||||
|
ObjectStoreBuckets.PLUGINS,
|
||||||
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a connection to the object store using the S3 SDK.
|
* Gets a connection to the object store using the S3 SDK.
|
||||||
|
@ -172,6 +176,14 @@ export const streamUpload = async (
|
||||||
const objectStore = ObjectStore(bucketName)
|
const objectStore = ObjectStore(bucketName)
|
||||||
await makeSureBucketExists(objectStore, bucketName)
|
await makeSureBucketExists(objectStore, bucketName)
|
||||||
|
|
||||||
|
// Set content type for certain known extensions
|
||||||
|
if (filename?.endsWith(".js")) {
|
||||||
|
extra = {
|
||||||
|
...extra,
|
||||||
|
ContentType: "application/javascript",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
Bucket: sanitizeBucket(bucketName),
|
Bucket: sanitizeBucket(bucketName),
|
||||||
Key: sanitizeKey(filename),
|
Key: sanitizeKey(filename),
|
||||||
|
@ -295,9 +307,13 @@ export const uploadDirectory = async (
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.downloadTarballDirect = async (url: string, path: string) => {
|
exports.downloadTarballDirect = async (
|
||||||
|
url: string,
|
||||||
|
path: string,
|
||||||
|
headers = {}
|
||||||
|
) => {
|
||||||
path = sanitizeKey(path)
|
path = sanitizeKey(path)
|
||||||
const response = await fetch(url)
|
const response = await fetch(url, { headers })
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`unexpected response ${response.statusText}`)
|
throw new Error(`unexpected response ${response.statusText}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ exports.ObjectStoreBuckets = {
|
||||||
TEMPLATES: env.TEMPLATES_BUCKET_NAME,
|
TEMPLATES: env.TEMPLATES_BUCKET_NAME,
|
||||||
GLOBAL: env.GLOBAL_BUCKET_NAME,
|
GLOBAL: env.GLOBAL_BUCKET_NAME,
|
||||||
GLOBAL_CLOUD: env.GLOBAL_CLOUD_BUCKET_NAME,
|
GLOBAL_CLOUD: env.GLOBAL_CLOUD_BUCKET_NAME,
|
||||||
|
PLUGINS: env.PLUGIN_BUCKET_NAME,
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.budibaseTempDir = function () {
|
exports.budibaseTempDir = function () {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import * as utils from "./utils"
|
||||||
|
|
||||||
|
const pkg = {
|
||||||
|
...utils,
|
||||||
|
}
|
||||||
|
|
||||||
|
export = pkg
|
|
@ -0,0 +1,94 @@
|
||||||
|
const {
|
||||||
|
DatasourceFieldType,
|
||||||
|
QueryType,
|
||||||
|
PluginType,
|
||||||
|
} = require("@budibase/types")
|
||||||
|
const joi = require("joi")
|
||||||
|
|
||||||
|
const DATASOURCE_TYPES = [
|
||||||
|
"Relational",
|
||||||
|
"Non-relational",
|
||||||
|
"Spreadsheet",
|
||||||
|
"Object store",
|
||||||
|
"Graph",
|
||||||
|
"API",
|
||||||
|
]
|
||||||
|
|
||||||
|
function runJoi(validator, schema) {
|
||||||
|
const { error } = validator.validate(schema)
|
||||||
|
if (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateComponent(schema) {
|
||||||
|
const validator = joi.object({
|
||||||
|
type: joi.string().allow("component").required(),
|
||||||
|
metadata: joi.object().unknown(true).required(),
|
||||||
|
hash: joi.string().optional(),
|
||||||
|
version: joi.string().optional(),
|
||||||
|
schema: joi
|
||||||
|
.object({
|
||||||
|
name: joi.string().required(),
|
||||||
|
settings: joi.array().items(joi.object().unknown(true)).required(),
|
||||||
|
})
|
||||||
|
.unknown(true),
|
||||||
|
})
|
||||||
|
runJoi(validator, schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateDatasource(schema) {
|
||||||
|
const fieldValidator = joi.object({
|
||||||
|
type: joi
|
||||||
|
.string()
|
||||||
|
.allow(...Object.values(DatasourceFieldType))
|
||||||
|
.required(),
|
||||||
|
required: joi.boolean().required(),
|
||||||
|
default: joi.any(),
|
||||||
|
display: joi.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const queryValidator = joi
|
||||||
|
.object({
|
||||||
|
type: joi.string().allow(...Object.values(QueryType)),
|
||||||
|
fields: joi.object().pattern(joi.string(), fieldValidator),
|
||||||
|
})
|
||||||
|
.required()
|
||||||
|
|
||||||
|
const validator = joi.object({
|
||||||
|
type: joi.string().allow("datasource").required(),
|
||||||
|
metadata: joi.object().unknown(true).required(),
|
||||||
|
hash: joi.string().optional(),
|
||||||
|
version: joi.string().optional(),
|
||||||
|
schema: joi.object({
|
||||||
|
docs: joi.string(),
|
||||||
|
friendlyName: joi.string().required(),
|
||||||
|
type: joi.string().allow(...DATASOURCE_TYPES),
|
||||||
|
description: joi.string().required(),
|
||||||
|
datasource: joi.object().pattern(joi.string(), fieldValidator).required(),
|
||||||
|
query: joi
|
||||||
|
.object({
|
||||||
|
create: queryValidator,
|
||||||
|
read: queryValidator,
|
||||||
|
update: queryValidator,
|
||||||
|
delete: queryValidator,
|
||||||
|
})
|
||||||
|
.unknown(true)
|
||||||
|
.required(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
runJoi(validator, schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.validate = schema => {
|
||||||
|
switch (schema?.type) {
|
||||||
|
case PluginType.COMPONENT:
|
||||||
|
validateComponent(schema)
|
||||||
|
break
|
||||||
|
case PluginType.DATASOURCE:
|
||||||
|
validateDatasource(schema)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown plugin type - check schema.json: ${schema.type}`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -543,13 +543,13 @@
|
||||||
semver "^7.3.5"
|
semver "^7.3.5"
|
||||||
tar "^6.1.11"
|
tar "^6.1.11"
|
||||||
|
|
||||||
"@shopify/jest-koa-mocks@3.1.5":
|
"@shopify/jest-koa-mocks@5.0.1":
|
||||||
version "3.1.5"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@shopify/jest-koa-mocks/-/jest-koa-mocks-3.1.5.tgz#11f77ccfbcaf35cf5ee2c6108a286e61e6bea084"
|
resolved "https://registry.yarnpkg.com/@shopify/jest-koa-mocks/-/jest-koa-mocks-5.0.1.tgz#fba490b6b7985fbb571eb9974897d396a3642e94"
|
||||||
integrity sha512-gQ3/7ELerv00TWO37AGFX5mT9CsFCS+3/UbKMuoIlKEU0QH2OX8BV9WBf/EKw7adCDNlxss0lqV6J8kf5pgr4A==
|
integrity sha512-4YskS9q8+TEHNoyopmuoy2XyhInyqeOl7CF5ShJs19sm6m0EA/jGGvgf/osv2PeTfuf42/L2G9CzWUSg49yTSg==
|
||||||
dependencies:
|
dependencies:
|
||||||
koa "^2.13.4"
|
koa "^2.13.4"
|
||||||
node-mocks-http "^1.5.8"
|
node-mocks-http "^1.11.0"
|
||||||
|
|
||||||
"@sideway/address@^4.1.3":
|
"@sideway/address@^4.1.3":
|
||||||
version "4.1.4"
|
version "4.1.4"
|
||||||
|
@ -3914,7 +3914,7 @@ node-int64@^0.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||||
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
|
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
|
||||||
|
|
||||||
node-mocks-http@^1.5.8:
|
node-mocks-http@^1.11.0:
|
||||||
version "1.11.0"
|
version "1.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.11.0.tgz#defc0febf6b935f08245397d47534a8de592996e"
|
resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.11.0.tgz#defc0febf6b935f08245397d47534a8de592996e"
|
||||||
integrity sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw==
|
integrity sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw==
|
||||||
|
|
|
@ -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.4-alpha.2",
|
"version": "1.3.15-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.4-alpha.2",
|
"@budibase/string-templates": "1.3.15-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",
|
||||||
|
|
|
@ -4,10 +4,15 @@
|
||||||
|
|
||||||
export let size = "M"
|
export let size = "M"
|
||||||
export let tooltip = ""
|
export let tooltip = ""
|
||||||
|
export let muted
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<TooltipWrapper {tooltip} {size}>
|
<TooltipWrapper {tooltip} {size}>
|
||||||
<label for="" class={`spectrum-FieldLabel spectrum-FieldLabel--size${size}`}>
|
<label
|
||||||
|
class:muted
|
||||||
|
for=""
|
||||||
|
class={`spectrum-FieldLabel spectrum-FieldLabel--size${size}`}
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</label>
|
</label>
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
|
@ -17,4 +22,8 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.muted {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
export let secondaryAction = undefined
|
export let secondaryAction = undefined
|
||||||
export let secondaryButtonWarning = false
|
export let secondaryButtonWarning = false
|
||||||
export let dataCy = null
|
export let dataCy = null
|
||||||
|
|
||||||
const { hide, cancel } = getContext(Context.Modal)
|
const { hide, cancel } = getContext(Context.Modal)
|
||||||
let loading = false
|
let loading = false
|
||||||
$: confirmDisabled = disabled || loading
|
$: confirmDisabled = disabled || loading
|
||||||
|
@ -88,12 +87,11 @@
|
||||||
<section class="spectrum-Dialog-content content-grid">
|
<section class="spectrum-Dialog-content content-grid">
|
||||||
<slot />
|
<slot />
|
||||||
</section>
|
</section>
|
||||||
{#if showCancelButton || showConfirmButton}
|
{#if showCancelButton || showConfirmButton || $$slots.footer}
|
||||||
<div
|
<div
|
||||||
class="spectrum-ButtonGroup spectrum-Dialog-buttonGroup spectrum-Dialog-buttonGroup--noFooter"
|
class="spectrum-ButtonGroup spectrum-Dialog-buttonGroup spectrum-Dialog-buttonGroup--noFooter"
|
||||||
>
|
>
|
||||||
<slot name="footer" />
|
<slot name="footer" />
|
||||||
|
|
||||||
{#if showSecondaryButton && secondaryButtonText && secondaryAction}
|
{#if showSecondaryButton && secondaryButtonText && secondaryAction}
|
||||||
<div class="secondary-action">
|
<div class="secondary-action">
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
export let noHorizPadding = false
|
export let noHorizPadding = false
|
||||||
export let quiet = false
|
export let quiet = false
|
||||||
export let emphasized = false
|
export let emphasized = false
|
||||||
|
export let onTop = false
|
||||||
export let size = "M"
|
export let size = "M"
|
||||||
|
|
||||||
let thisSelected = undefined
|
let thisSelected = undefined
|
||||||
|
@ -75,6 +76,7 @@
|
||||||
bind:this={container}
|
bind:this={container}
|
||||||
class:spectrum-Tabs--quiet={quiet}
|
class:spectrum-Tabs--quiet={quiet}
|
||||||
class:noHorizPadding
|
class:noHorizPadding
|
||||||
|
class:onTop
|
||||||
class:spectrum-Tabs--vertical={vertical}
|
class:spectrum-Tabs--vertical={vertical}
|
||||||
class:spectrum-Tabs--horizontal={!vertical}
|
class:spectrum-Tabs--horizontal={!vertical}
|
||||||
class="spectrum-Tabs spectrum-Tabs--size{size}"
|
class="spectrum-Tabs spectrum-Tabs--size{size}"
|
||||||
|
@ -122,4 +124,7 @@
|
||||||
.noPadding {
|
.noPadding {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.onTop {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -74,11 +74,11 @@ filterTests(["smoke", "all"], () => {
|
||||||
.contains("Update role")
|
.contains("Update role")
|
||||||
.click({ force: true })
|
.click({ force: true })
|
||||||
})
|
})
|
||||||
cy.reload({ timeout: 5000 })
|
cy.reload()
|
||||||
cy.wait(1000)
|
cy.wait(1000)
|
||||||
}
|
}
|
||||||
// Confirm roles exist within Configure roles table
|
// Confirm roles exist within Configure roles table
|
||||||
cy.get(interact.SPECTRUM_TABLE, { timeout: 2000 })
|
cy.get(interact.SPECTRUM_TABLE, { timeout: 20000 })
|
||||||
.eq(0)
|
.eq(0)
|
||||||
.within(assginedRoles => {
|
.within(assginedRoles => {
|
||||||
expect(assginedRoles).to.contain("Admin")
|
expect(assginedRoles).to.contain("Admin")
|
||||||
|
@ -180,7 +180,7 @@ filterTests(["smoke", "all"], () => {
|
||||||
cy.reload()
|
cy.reload()
|
||||||
|
|
||||||
// Confirm details have been saved
|
// Confirm details have been saved
|
||||||
cy.get(interact.FIELD, { timeout: 1000 }).eq(1).within(() => {
|
cy.get(interact.FIELD, { timeout: 20000 }).eq(1).within(() => {
|
||||||
cy.get(interact.SPECTRUM_TEXTFIELD_INPUT).should('have.value', "bb")
|
cy.get(interact.SPECTRUM_TEXTFIELD_INPUT).should('have.value', "bb")
|
||||||
})
|
})
|
||||||
cy.get(interact.FIELD, { timeout: 1000 }).eq(2).within(() => {
|
cy.get(interact.FIELD, { timeout: 1000 }).eq(2).within(() => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import filterTests from "../../support/filterTests"
|
import filterTests from "../../support/filterTests"
|
||||||
|
|
||||||
filterTests(['all'], () => {
|
filterTests(['all'], () => {
|
||||||
context("Datasource Wizard", () => {
|
xcontext("Datasource Wizard", () => {
|
||||||
if (Cypress.env("TEST_ENV")) {
|
if (Cypress.env("TEST_ENV")) {
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.login()
|
cy.login()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import filterTests from "../../support/filterTests"
|
import filterTests from "../../support/filterTests"
|
||||||
|
|
||||||
filterTests(["all"], () => {
|
filterTests(["all"], () => {
|
||||||
context("Oracle Datasource Testing", () => {
|
xcontext("Oracle Datasource Testing", () => {
|
||||||
if (Cypress.env("TEST_ENV")) {
|
if (Cypress.env("TEST_ENV")) {
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.login()
|
cy.login()
|
||||||
|
|
|
@ -162,7 +162,7 @@ filterTests(["all"], () => {
|
||||||
switchSchema("randomText")
|
switchSchema("randomText")
|
||||||
|
|
||||||
// No tables displayed
|
// No tables displayed
|
||||||
cy.get(".spectrum-Body", { timeout: 20000 }).eq(2).should("contain", "No tables found")
|
cy.get(".spectrum-Body", { timeout: 10000 }).eq(2, { timeout: 10000 }).should("contain", "No tables found")
|
||||||
|
|
||||||
// Previously created query should be visible
|
// Previously created query should be visible
|
||||||
cy.get(".spectrum-Table").should("contain", queryName)
|
cy.get(".spectrum-Table").should("contain", queryName)
|
||||||
|
|
|
@ -14,7 +14,7 @@ filterTests(["smoke", "all"], () => {
|
||||||
// Select REST data source
|
// Select REST data source
|
||||||
cy.selectExternalDatasource(datasource)
|
cy.selectExternalDatasource(datasource)
|
||||||
// Enter incorrect api & attempt to send query
|
// Enter incorrect api & attempt to send query
|
||||||
cy.get(".spectrum-Button", { timeout: 500 }).contains("Add query").click({ force: true })
|
cy.get(".query-buttons", { timeout: 1000 }).contains("Add query").click({ force: true })
|
||||||
cy.intercept("**/preview").as("queryError")
|
cy.intercept("**/preview").as("queryError")
|
||||||
cy.get("input").clear().type("random text")
|
cy.get("input").clear().type("random text")
|
||||||
cy.get(".spectrum-Button").contains("Send").click({ force: true })
|
cy.get(".spectrum-Button").contains("Send").click({ force: true })
|
||||||
|
|
|
@ -457,8 +457,8 @@ Cypress.Commands.add("createTable", (tableName, initialTable) => {
|
||||||
cy.get(".spectrum-ButtonGroup").contains("Create").click()
|
cy.get(".spectrum-ButtonGroup").contains("Create").click()
|
||||||
})
|
})
|
||||||
// Ensure modal has closed and table is created
|
// Ensure modal has closed and table is created
|
||||||
cy.get(".spectrum-Modal").should("not.exist")
|
cy.get(".spectrum-Modal", { timeout: 2000 }).should("not.exist")
|
||||||
cy.get(".spectrum-Tabs-content", { timeout: 1000 }).should(
|
cy.get(".spectrum-Tabs-content", { timeout: 2000 }).should(
|
||||||
"contain",
|
"contain",
|
||||||
tableName
|
tableName
|
||||||
)
|
)
|
||||||
|
@ -637,30 +637,32 @@ Cypress.Commands.add(
|
||||||
(datasourceNames, accessLevelLabel) => {
|
(datasourceNames, accessLevelLabel) => {
|
||||||
cy.contains("Design").click()
|
cy.contains("Design").click()
|
||||||
cy.get(".spectrum-Button").contains("Add screen").click({ force: true })
|
cy.get(".spectrum-Button").contains("Add screen").click({ force: true })
|
||||||
cy.get(".spectrum-Modal").within(() => {
|
cy.get(".spectrum-Dialog-grid").within(() => {
|
||||||
cy.get(".item").contains("Autogenerated screens").click()
|
cy.get("[data-cy='autogenerated-screens']").click()
|
||||||
|
cy.intercept("**/api/datasources").as("autoScreens")
|
||||||
cy.get(".spectrum-Button").contains("Continue").click({ force: true })
|
cy.get(".spectrum-Button").contains("Continue").click({ force: true })
|
||||||
|
cy.wait("@autoScreens")
|
||||||
|
cy.wait(5000)
|
||||||
})
|
})
|
||||||
cy.get(".spectrum-Modal [data-cy='data-source-modal']", {
|
cy.get("[data-cy='autogenerated-screens']").should("not.exist")
|
||||||
timeout: 500,
|
cy.get("[data-cy='data-source-modal']", { timeout: 10000 }).within(() => {
|
||||||
}).within(() => {
|
|
||||||
for (let i = 0; i < datasourceNames.length; i++) {
|
for (let i = 0; i < datasourceNames.length; i++) {
|
||||||
cy.wait(500)
|
cy.get(".data-source-entry")
|
||||||
cy.get(".data-source-entry").contains(datasourceNames[i]).click()
|
.contains(datasourceNames[i], { timeout: 20000 })
|
||||||
//Ensure the check mark is visible
|
.click({ force: true })
|
||||||
|
// Ensure the check mark is visible
|
||||||
cy.get(".data-source-entry")
|
cy.get(".data-source-entry")
|
||||||
.contains(datasourceNames[i])
|
.contains(datasourceNames[i])
|
||||||
.get(".data-source-check")
|
.get(".data-source-check", { timeout: 20000 })
|
||||||
.should("exist")
|
.should("exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
cy.get(".spectrum-Button").contains("Confirm").click({ force: true })
|
cy.get(".spectrum-Button").contains("Confirm").click({ force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
cy.get(".spectrum-Modal").within(() => {
|
cy.get(".spectrum-Modal", { timeout: 10000 }).within(() => {
|
||||||
if (accessLevelLabel) {
|
if (accessLevelLabel) {
|
||||||
cy.get(".spectrum-Picker-label").click()
|
cy.get(".spectrum-Picker-label", { timeout: 10000 }).click()
|
||||||
cy.wait(500)
|
|
||||||
cy.contains(accessLevelLabel).click()
|
cy.contains(accessLevelLabel).click()
|
||||||
}
|
}
|
||||||
cy.get(".spectrum-Button").contains("Done").click({ force: true })
|
cy.get(".spectrum-Button").contains("Done").click({ force: true })
|
||||||
|
@ -915,8 +917,9 @@ Cypress.Commands.add("createRestQuery", (method, restUrl, queryPrettyName) => {
|
||||||
Cypress.Commands.add("closeModal", () => {
|
Cypress.Commands.add("closeModal", () => {
|
||||||
cy.get(".spectrum-Modal", { timeout: 2000 }).within(() => {
|
cy.get(".spectrum-Modal", { timeout: 2000 }).within(() => {
|
||||||
cy.get(".close-icon").click()
|
cy.get(".close-icon").click()
|
||||||
cy.wait(1000) // Wait for modal to close
|
|
||||||
})
|
})
|
||||||
|
// Confirm modal has closed
|
||||||
|
cy.get(".spectrum-Modal", { timeout: 10000 }).should("not.exist")
|
||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Commands.add("expandBudibaseConnection", () => {
|
Cypress.Commands.add("expandBudibaseConnection", () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "1.3.4-alpha.2",
|
"version": "1.3.15-alpha.3",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -69,10 +69,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "1.3.4-alpha.2",
|
"@budibase/bbui": "1.3.15-alpha.3",
|
||||||
"@budibase/client": "1.3.4-alpha.2",
|
"@budibase/client": "1.3.15-alpha.3",
|
||||||
"@budibase/frontend-core": "1.3.4-alpha.2",
|
"@budibase/frontend-core": "1.3.15-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.4-alpha.2",
|
"@budibase/string-templates": "1.3.15-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",
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
"@babel/runtime": "^7.13.10",
|
"@babel/runtime": "^7.13.10",
|
||||||
"@rollup/plugin-replace": "^2.4.2",
|
"@rollup/plugin-replace": "^2.4.2",
|
||||||
"@roxi/routify": "2.18.5",
|
"@roxi/routify": "2.18.5",
|
||||||
"@sveltejs/vite-plugin-svelte": "1.0.0-next.19",
|
"@sveltejs/vite-plugin-svelte": "1.0.1",
|
||||||
"@testing-library/jest-dom": "^5.11.10",
|
"@testing-library/jest-dom": "^5.11.10",
|
||||||
"@testing-library/svelte": "^3.0.0",
|
"@testing-library/svelte": "^3.0.0",
|
||||||
"babel-jest": "^26.6.3",
|
"babel-jest": "^26.6.3",
|
||||||
|
@ -118,7 +118,7 @@
|
||||||
"ts-node": "^10.4.0",
|
"ts-node": "^10.4.0",
|
||||||
"tsconfig-paths": "4.0.0",
|
"tsconfig-paths": "4.0.0",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.5.5",
|
||||||
"vite": "^2.1.5"
|
"vite": "^3.0.8"
|
||||||
},
|
},
|
||||||
"gitHead": "115189f72a850bfb52b65ec61d932531bf327072"
|
"gitHead": "115189f72a850bfb52b65ec61d932531bf327072"
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ function prepareData(config) {
|
||||||
ds => ds.source === config.type
|
ds => ds.source === config.type
|
||||||
).length
|
).length
|
||||||
|
|
||||||
let baseName = IntegrationNames[config.type]
|
let baseName = IntegrationNames[config.type] || config.name
|
||||||
let name =
|
let name =
|
||||||
existingTypeCount === 0 ? baseName : `${baseName}-${existingTypeCount + 1}`
|
existingTypeCount === 0 ? baseName : `${baseName}-${existingTypeCount + 1}`
|
||||||
|
|
||||||
|
|
|
@ -90,13 +90,21 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
// Fetch component definitions.
|
// Fetch component definitions.
|
||||||
// Allow errors to propagate.
|
// Allow errors to propagate.
|
||||||
let components = await API.fetchComponentLibDefinitions(application.appId)
|
const components = await API.fetchComponentLibDefinitions(
|
||||||
|
application.appId
|
||||||
|
)
|
||||||
|
|
||||||
|
// Filter out custom component keys so we can flag them
|
||||||
|
const customComponents = Object.keys(components).filter(name =>
|
||||||
|
name.startsWith("plugin/")
|
||||||
|
)
|
||||||
|
|
||||||
// Reset store state
|
// Reset store state
|
||||||
store.update(state => ({
|
store.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
libraries: application.componentLibraries,
|
libraries: application.componentLibraries,
|
||||||
components,
|
components,
|
||||||
|
customComponents,
|
||||||
clientFeatures: {
|
clientFeatures: {
|
||||||
...INITIAL_FRONTEND_STATE.clientFeatures,
|
...INITIAL_FRONTEND_STATE.clientFeatures,
|
||||||
...components.features,
|
...components.features,
|
||||||
|
@ -116,6 +124,7 @@ export const getFrontendStore = () => {
|
||||||
version: application.version,
|
version: application.version,
|
||||||
revertableVersion: application.revertableVersion,
|
revertableVersion: application.revertableVersion,
|
||||||
navigation: application.navigation || {},
|
navigation: application.navigation || {},
|
||||||
|
usedPlugins: application.usedPlugins || [],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Initialise backend stores
|
// Initialise backend stores
|
||||||
|
@ -189,9 +198,18 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
save: async screen => {
|
save: async screen => {
|
||||||
|
const state = get(store)
|
||||||
const creatingNewScreen = screen._id === undefined
|
const creatingNewScreen = screen._id === undefined
|
||||||
const savedScreen = await API.saveScreen(screen)
|
const savedScreen = await API.saveScreen(screen)
|
||||||
const routesResponse = await API.fetchAppRoutes()
|
const routesResponse = await API.fetchAppRoutes()
|
||||||
|
let usedPlugins = state.usedPlugins
|
||||||
|
|
||||||
|
// If plugins changed we need to fetch the latest app metadata
|
||||||
|
if (savedScreen.pluginAdded) {
|
||||||
|
const { application } = await API.fetchAppPackage(state.appId)
|
||||||
|
usedPlugins = application.usedPlugins || []
|
||||||
|
}
|
||||||
|
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
// Update screen object
|
// Update screen object
|
||||||
const idx = state.screens.findIndex(x => x._id === savedScreen._id)
|
const idx = state.screens.findIndex(x => x._id === savedScreen._id)
|
||||||
|
@ -210,6 +228,9 @@ export const getFrontendStore = () => {
|
||||||
// Update routes
|
// Update routes
|
||||||
state.routes = routesResponse.routes
|
state.routes = routesResponse.routes
|
||||||
|
|
||||||
|
// Update used plugins
|
||||||
|
state.usedPlugins = usedPlugins
|
||||||
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
return savedScreen
|
return savedScreen
|
||||||
|
@ -378,9 +399,6 @@ export const getFrontendStore = () => {
|
||||||
if (!componentName) {
|
if (!componentName) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
if (!componentName.startsWith("@budibase")) {
|
|
||||||
componentName = `@budibase/standard-components/${componentName}`
|
|
||||||
}
|
|
||||||
return get(store).components[componentName]
|
return get(store).components[componentName]
|
||||||
},
|
},
|
||||||
createInstance: (componentName, presetProps) => {
|
createInstance: (componentName, presetProps) => {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Select, Input, Label } from "@budibase/bbui"
|
import { Button, Select, Input, Label } from "@budibase/bbui"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { onMount, createEventDispatcher } from "svelte"
|
||||||
|
import { flags } from "stores/backend"
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
|
@ -29,11 +30,16 @@
|
||||||
label: "Every Night at Midnight",
|
label: "Every Night at Midnight",
|
||||||
value: "0 0 * * *",
|
value: "0 0 * * *",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: "Every Budibase Reboot",
|
|
||||||
value: "@reboot",
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (!$flags.cloud) {
|
||||||
|
CRON_EXPRESSIONS.push({
|
||||||
|
label: "Every Budibase Reboot",
|
||||||
|
value: "@reboot",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="block-field">
|
<div class="block-field">
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
customQueryIconColor,
|
customQueryIconColor,
|
||||||
customQueryText,
|
customQueryText,
|
||||||
} from "helpers/data/utils"
|
} from "helpers/data/utils"
|
||||||
import ICONS from "./icons"
|
import { getIcon } from "./icons"
|
||||||
import { notifications } from "@budibase/bbui"
|
import { notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
let openDataSources = []
|
let openDataSources = []
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
>
|
>
|
||||||
<div class="datasource-icon" slot="icon">
|
<div class="datasource-icon" slot="icon">
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={ICONS[datasource.source]}
|
this={getIcon(datasource.source, datasource.schema)}
|
||||||
height="18"
|
height="18"
|
||||||
width="18"
|
width="18"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
notifications,
|
notifications,
|
||||||
Modal,
|
Modal,
|
||||||
Table,
|
Table,
|
||||||
|
Toggle,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { datasources, integrations, tables } from "stores/backend"
|
import { datasources, integrations, tables } from "stores/backend"
|
||||||
import CreateEditRelationship from "components/backend/Datasources/CreateEditRelationship.svelte"
|
import CreateEditRelationship from "components/backend/Datasources/CreateEditRelationship.svelte"
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
import ArrayRenderer from "components/common/renderers/ArrayRenderer.svelte"
|
import ArrayRenderer from "components/common/renderers/ArrayRenderer.svelte"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
|
import ValuesList from "components/common/ValuesList.svelte"
|
||||||
|
|
||||||
export let datasource
|
export let datasource
|
||||||
export let save
|
export let save
|
||||||
|
@ -31,6 +33,8 @@
|
||||||
let createExternalTableModal
|
let createExternalTableModal
|
||||||
let selectedFromRelationship, selectedToRelationship
|
let selectedFromRelationship, selectedToRelationship
|
||||||
let confirmDialog
|
let confirmDialog
|
||||||
|
let specificTables = null
|
||||||
|
let requireSpecificTables = false
|
||||||
|
|
||||||
$: integration = datasource && $integrations[datasource.source]
|
$: integration = datasource && $integrations[datasource.source]
|
||||||
$: plusTables = datasource?.plus
|
$: plusTables = datasource?.plus
|
||||||
|
@ -87,7 +91,7 @@
|
||||||
|
|
||||||
async function updateDatasourceSchema() {
|
async function updateDatasourceSchema() {
|
||||||
try {
|
try {
|
||||||
await datasources.updateSchema(datasource)
|
await datasources.updateSchema(datasource, specificTables)
|
||||||
notifications.success(`Datasource ${name} tables updated successfully.`)
|
notifications.success(`Datasource ${name} tables updated successfully.`)
|
||||||
await tables.fetch()
|
await tables.fetch()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -150,6 +154,19 @@
|
||||||
warning={false}
|
warning={false}
|
||||||
title="Confirm table fetch"
|
title="Confirm table fetch"
|
||||||
>
|
>
|
||||||
|
<Toggle
|
||||||
|
bind:value={requireSpecificTables}
|
||||||
|
on:change={e => {
|
||||||
|
requireSpecificTables = e.detail
|
||||||
|
specificTables = null
|
||||||
|
}}
|
||||||
|
thin
|
||||||
|
text="Fetch listed tables only (one per line)"
|
||||||
|
/>
|
||||||
|
{#if requireSpecificTables}
|
||||||
|
<ValuesList label="" bind:values={specificTables} />
|
||||||
|
{/if}
|
||||||
|
<br />
|
||||||
<Body>
|
<Body>
|
||||||
If you have fetched tables from this database before, this action may
|
If you have fetched tables from this database before, this action may
|
||||||
overwrite any changes you made after your initial fetch.
|
overwrite any changes you made after your initial fetch.
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import { Heading, Detail } from "@budibase/bbui"
|
||||||
|
import { getIcon } from "../icons"
|
||||||
|
|
||||||
|
export let integration
|
||||||
|
export let integrationType
|
||||||
|
export let schema
|
||||||
|
|
||||||
|
let dispatcher = createEventDispatcher()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class:selected={integration.type === integrationType}
|
||||||
|
on:click={() => dispatcher("selected", integrationType)}
|
||||||
|
class="item hoverable"
|
||||||
|
>
|
||||||
|
<div class="item-body" class:with-type={!!schema.type}>
|
||||||
|
<svelte:component
|
||||||
|
this={getIcon(integrationType, schema)}
|
||||||
|
height="20"
|
||||||
|
width="20"
|
||||||
|
/>
|
||||||
|
<div class="text">
|
||||||
|
<Heading size="XXS">{schema.friendlyName}</Heading>
|
||||||
|
{#if schema.type}
|
||||||
|
<Detail size="S">{schema.type || ""}</Detail>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.item {
|
||||||
|
cursor: pointer;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--spectrum-alias-grid-margin-xsmall);
|
||||||
|
padding: var(--spectrum-alias-item-padding-s)
|
||||||
|
var(--spectrum-alias-item-padding-m);
|
||||||
|
background: var(--spectrum-alias-background-color-secondary);
|
||||||
|
transition: background 0.13s ease-out;
|
||||||
|
border: solid var(--spectrum-alias-border-color);
|
||||||
|
border-radius: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
.item:hover,
|
||||||
|
.item.selected {
|
||||||
|
background: var(--spectrum-alias-background-color-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.item-body.with-type {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.item-body.with-type :global(svg) {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<script>
|
||||||
|
export let width = "100"
|
||||||
|
export let height = "100"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{width}
|
||||||
|
{height}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 18.43 17.62"
|
||||||
|
xml:space="preserve"
|
||||||
|
>
|
||||||
|
<style type="text/css">
|
||||||
|
.custom-st0 {
|
||||||
|
fill: var(
|
||||||
|
--spectrum-heading-xxs-text-color,
|
||||||
|
var(--spectrum-alias-heading-text-color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<ellipse
|
||||||
|
id="Ellipse_9514"
|
||||||
|
class="custom-st0"
|
||||||
|
cx="9.14"
|
||||||
|
cy="2.88"
|
||||||
|
rx="8"
|
||||||
|
ry="2.5"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
id="Path_8355"
|
||||||
|
class="custom-st0"
|
||||||
|
d="M7.64,12.88c0-0.48,0.06-0.95,0.17-1.41c-2.53-0.16-5.92-0.76-6.67-1.95v4.36
|
||||||
|
c0,1.34,3.39,2.43,7.63,2.49C8.03,15.36,7.63,14.13,7.64,12.88z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
id="Path_8356"
|
||||||
|
class="custom-st0"
|
||||||
|
d="M13.64,6.88c1.25,0,2.47,0.39,3.48,1.12c0.01-0.04,0.02-0.08,0.02-0.12V4.51
|
||||||
|
c-1.22,1.55-5.53,2-8,2s-7.11-0.58-8-2v3.36c0,1.28,3.09,2.33,7.06,2.48C9.18,8.24,11.3,6.88,13.64,6.88z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
id="Path_8353"
|
||||||
|
class="custom-st0"
|
||||||
|
d="M10.32,14.42c-0.56-0.56-0.56-1.47,0-2.03l1.24-1.24l-0.01-0.01c-0.25-0.25-0.25-0.65,0-0.9l0,0
|
||||||
|
L12,9.79c0.25-0.25,0.65-0.25,0.9,0c0,0,0,0,0,0l0,0l0.45,0.45l1.53-1.53c0.09-0.09,0.24-0.09,0.34,0l0.34,0.34
|
||||||
|
c0.09,0.09,0.09,0.24,0,0.34l-1.53,1.53l1.35,1.35l1.53-1.53c0.09-0.09,0.24-0.09,0.34,0l0.34,0.34c0.09,0.09,0.09,0.24,0,0.34
|
||||||
|
l-1.53,1.53l0.45,0.45c0.25,0.25,0.25,0.65,0,0.9l0,0l-0.45,0.45c-0.25,0.25-0.65,0.25-0.9,0l0,0l-0.01-0.01l-1.24,1.24
|
||||||
|
c-0.56,0.56-1.47,0.56-2.03,0l0,0L10.32,14.42z"
|
||||||
|
/>
|
||||||
|
</svg>
|
|
@ -15,8 +15,9 @@ import GoogleSheets from "./GoogleSheets.svelte"
|
||||||
import Firebase from "./Firebase.svelte"
|
import Firebase from "./Firebase.svelte"
|
||||||
import Redis from "./Redis.svelte"
|
import Redis from "./Redis.svelte"
|
||||||
import Snowflake from "./Snowflake.svelte"
|
import Snowflake from "./Snowflake.svelte"
|
||||||
|
import Custom from "./Custom.svelte"
|
||||||
|
|
||||||
export default {
|
const ICONS = {
|
||||||
BUDIBASE: Budibase,
|
BUDIBASE: Budibase,
|
||||||
POSTGRES: Postgres,
|
POSTGRES: Postgres,
|
||||||
DYNAMODB: DynamoDB,
|
DYNAMODB: DynamoDB,
|
||||||
|
@ -34,4 +35,15 @@ export default {
|
||||||
FIRESTORE: Firebase,
|
FIRESTORE: Firebase,
|
||||||
REDIS: Redis,
|
REDIS: Redis,
|
||||||
SNOWFLAKE: Snowflake,
|
SNOWFLAKE: Snowflake,
|
||||||
|
CUSTOM: Custom,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ICONS
|
||||||
|
|
||||||
|
export function getIcon(integrationType, schema) {
|
||||||
|
if (schema?.custom || !ICONS[integrationType]) {
|
||||||
|
return ICONS.CUSTOM
|
||||||
|
} else {
|
||||||
|
return ICONS[integrationType]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
import { createRestDatasource } from "builderStore/datasource"
|
import { createRestDatasource } from "builderStore/datasource"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import ImportRestQueriesModal from "./ImportRestQueriesModal.svelte"
|
import ImportRestQueriesModal from "./ImportRestQueriesModal.svelte"
|
||||||
|
import DatasourceCard from "../_components/DatasourceCard.svelte"
|
||||||
|
|
||||||
export let modal
|
export let modal
|
||||||
let integrations = {}
|
let integrations = {}
|
||||||
|
@ -27,6 +28,9 @@
|
||||||
let importModal
|
let importModal
|
||||||
|
|
||||||
$: showImportButton = false
|
$: showImportButton = false
|
||||||
|
$: customIntegrations = Object.entries(integrations).filter(
|
||||||
|
entry => entry[1].custom
|
||||||
|
)
|
||||||
|
|
||||||
checkShowImport()
|
checkShowImport()
|
||||||
|
|
||||||
|
@ -49,6 +53,9 @@
|
||||||
schema: selected.datasource,
|
schema: selected.datasource,
|
||||||
auth: selected.auth,
|
auth: selected.auth,
|
||||||
}
|
}
|
||||||
|
if (selected.friendlyName) {
|
||||||
|
integration.name = selected.friendlyName
|
||||||
|
}
|
||||||
checkShowImport()
|
checkShowImport()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,36 +157,39 @@
|
||||||
<Layout noPadding gap="XS">
|
<Layout noPadding gap="XS">
|
||||||
<Body size="S">Connect to an external data source</Body>
|
<Body size="S">Connect to an external data source</Body>
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
{#each Object.entries(integrations).filter(([key]) => key !== IntegrationTypes.INTERNAL) as [integrationType, schema]}
|
{#each Object.entries(integrations).filter(([key, val]) => key !== IntegrationTypes.INTERNAL && !val.custom) as [integrationType, schema]}
|
||||||
<div
|
<DatasourceCard
|
||||||
class:selected={integration.type === integrationType}
|
on:selected={evt => selectIntegration(evt.detail)}
|
||||||
on:click={() => selectIntegration(integrationType)}
|
{schema}
|
||||||
class="item hoverable"
|
bind:integrationType
|
||||||
>
|
{integration}
|
||||||
<div class="item-body" class:with-type={!!schema.type}>
|
/>
|
||||||
<svelte:component
|
|
||||||
this={ICONS[integrationType]}
|
|
||||||
height="20"
|
|
||||||
width="20"
|
|
||||||
/>
|
|
||||||
<div class="text">
|
|
||||||
<Heading size="XXS">{schema.friendlyName}</Heading>
|
|
||||||
{#if schema.type}
|
|
||||||
<Detail size="S">{schema.type || ""}</Detail>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
{#if customIntegrations.length > 0}
|
||||||
|
<Layout noPadding gap="XS">
|
||||||
|
<Body size="S">Custom data source</Body>
|
||||||
|
<div class="item-list">
|
||||||
|
{#each customIntegrations as [integrationType, schema]}
|
||||||
|
<DatasourceCard
|
||||||
|
on:selected={evt => selectIntegration(evt.detail)}
|
||||||
|
{schema}
|
||||||
|
bind:integrationType
|
||||||
|
{integration}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
{/if}
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.item-list {
|
.item-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
grid-template-columns: repeat(2, minmax(150px, 1fr));
|
||||||
grid-gap: var(--spectrum-alias-grid-baseline);
|
grid-gap: var(--spectrum-alias-grid-baseline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,14 @@
|
||||||
let datasource = cloneDeep(integration)
|
let datasource = cloneDeep(integration)
|
||||||
let skipFetch = false
|
let skipFetch = false
|
||||||
|
|
||||||
|
$: name =
|
||||||
|
IntegrationNames[datasource.type] || datasource.name || datasource.type
|
||||||
|
|
||||||
async function saveDatasource() {
|
async function saveDatasource() {
|
||||||
try {
|
try {
|
||||||
|
if (!datasource.name) {
|
||||||
|
datasource.name = name
|
||||||
|
}
|
||||||
const resp = await save(datasource, skipFetch)
|
const resp = await save(datasource, skipFetch)
|
||||||
$goto(`./datasource/${resp._id}`)
|
$goto(`./datasource/${resp._id}`)
|
||||||
notifications.success(`Datasource updated successfully.`)
|
notifications.success(`Datasource updated successfully.`)
|
||||||
|
@ -32,7 +38,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ModalContent
|
<ModalContent
|
||||||
title={`Connect to ${IntegrationNames[datasource.type]}`}
|
title={`Connect to ${name}`}
|
||||||
onConfirm={() => saveDatasource()}
|
onConfirm={() => saveDatasource()}
|
||||||
onCancel={() => modal.show()}
|
onCancel={() => modal.show()}
|
||||||
confirmText={datasource.plus
|
confirmText={datasource.plus
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let bindingDrawer
|
let bindingDrawer
|
||||||
let valid = true
|
let valid = true
|
||||||
|
let currentVal = value
|
||||||
|
|
||||||
$: readableValue = runtimeToReadableBinding(bindings, value)
|
$: readableValue = runtimeToReadableBinding(bindings, value)
|
||||||
$: tempValue = readableValue
|
$: tempValue = readableValue
|
||||||
|
@ -30,11 +31,17 @@
|
||||||
|
|
||||||
const saveBinding = () => {
|
const saveBinding = () => {
|
||||||
onChange(tempValue)
|
onChange(tempValue)
|
||||||
|
onBlur()
|
||||||
bindingDrawer.hide()
|
bindingDrawer.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onChange = value => {
|
const onChange = value => {
|
||||||
dispatch("change", readableToRuntimeBinding(bindings, value))
|
currentVal = readableToRuntimeBinding(bindings, value)
|
||||||
|
dispatch("change", currentVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur = () => {
|
||||||
|
dispatch("blur", currentVal)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -45,6 +52,7 @@
|
||||||
readonly={isJS}
|
readonly={isJS}
|
||||||
value={isJS ? "(JavaScript function)" : readableValue}
|
value={isJS ? "(JavaScript function)" : readableValue}
|
||||||
on:change={event => onChange(event.detail)}
|
on:change={event => onChange(event.detail)}
|
||||||
|
on:blur={onBlur}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{updateOnChange}
|
{updateOnChange}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
newBlock.inputs = {
|
newBlock.inputs = {
|
||||||
fields: Object.keys(parameters.fields).reduce((fields, key) => {
|
fields: Object.keys(parameters.fields ?? {}).reduce((fields, key) => {
|
||||||
fields[key] = "string"
|
fields[key] = "string"
|
||||||
return fields
|
return fields
|
||||||
}, {}),
|
}, {}),
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
placeholder={keyPlaceholder}
|
placeholder={keyPlaceholder}
|
||||||
readonly={readOnly}
|
readonly={readOnly}
|
||||||
bind:value={field.name}
|
bind:value={field.name}
|
||||||
on:change={changed}
|
on:blur={changed}
|
||||||
/>
|
/>
|
||||||
{#if options}
|
{#if options}
|
||||||
<Select bind:value={field.value} on:change={changed} {options} />
|
<Select bind:value={field.value} on:change={changed} {options} />
|
||||||
|
@ -115,7 +115,10 @@
|
||||||
<DrawerBindableInput
|
<DrawerBindableInput
|
||||||
{bindings}
|
{bindings}
|
||||||
placeholder="Value"
|
placeholder="Value"
|
||||||
on:change={e => (field.value = e.detail)}
|
on:blur={e => {
|
||||||
|
field.value = e.detail
|
||||||
|
changed()
|
||||||
|
}}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
allowJS={false}
|
allowJS={false}
|
||||||
|
@ -127,7 +130,7 @@
|
||||||
placeholder={valuePlaceholder}
|
placeholder={valuePlaceholder}
|
||||||
readonly={readOnly}
|
readonly={readOnly}
|
||||||
bind:value={field.value}
|
bind:value={field.value}
|
||||||
on:change={changed}
|
on:blur={changed}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if toggle}
|
{#if toggle}
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
<script>
|
<script>
|
||||||
import { ModalContent, Toggle } from "@budibase/bbui"
|
import { ModalContent, Toggle, Body } from "@budibase/bbui"
|
||||||
|
|
||||||
export let app
|
export let app
|
||||||
|
export let published
|
||||||
let excludeRows = false
|
let excludeRows = false
|
||||||
|
|
||||||
|
$: title = published ? "Export published app" : "Export latest app"
|
||||||
|
$: confirmText = published ? "Export published" : "Export latest"
|
||||||
|
|
||||||
const exportApp = () => {
|
const exportApp = () => {
|
||||||
const id = app.deployed ? app.prodId : app.devId
|
const id = published ? app.prodId : app.devId
|
||||||
const appName = encodeURIComponent(app.name)
|
const appName = encodeURIComponent(app.name)
|
||||||
window.location = `/api/backups/export?appId=${id}&appname=${appName}&excludeRows=${excludeRows}`
|
window.location = `/api/backups/export?appId=${id}&appname=${appName}&excludeRows=${excludeRows}`
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ModalContent title={"Export"} confirmText={"Export"} onConfirm={exportApp}>
|
<ModalContent {title} {confirmText} onConfirm={exportApp}>
|
||||||
|
<Body
|
||||||
|
>Apps can be exported with or without data that is within internal tables -
|
||||||
|
select this below.</Body
|
||||||
|
>
|
||||||
<Toggle text="Exclude Rows" bind:value={excludeRows} />
|
<Toggle text="Exclude Rows" bind:value={excludeRows} />
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|
|
@ -57,3 +57,10 @@ export const DefaultAppTheme = {
|
||||||
navBackground: "var(--spectrum-global-color-gray-50)",
|
navBackground: "var(--spectrum-global-color-gray-50)",
|
||||||
navTextColor: "var(--spectrum-global-color-gray-800)",
|
navTextColor: "var(--spectrum-global-color-gray-800)",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const PluginSource = {
|
||||||
|
URL: "URL",
|
||||||
|
NPM: "NPM",
|
||||||
|
GITHUB: "Github",
|
||||||
|
FILE: "File Upload",
|
||||||
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ export function buildQueryString(obj) {
|
||||||
if (str !== "") {
|
if (str !== "") {
|
||||||
str += "&"
|
str += "&"
|
||||||
}
|
}
|
||||||
str += `${key}=${value || ""}`
|
str += `${key}=${encodeURIComponent(value || "")}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str
|
return str
|
||||||
|
|
|
@ -31,7 +31,9 @@
|
||||||
class="add-button"
|
class="add-button"
|
||||||
data-cy={`new-${isExternal ? "datasource" : "table"}`}
|
data-cy={`new-${isExternal ? "datasource" : "table"}`}
|
||||||
>
|
>
|
||||||
<Icon hoverable name="AddCircle" on:click={modal.show} />
|
{#if modal}
|
||||||
|
<Icon hoverable name="AddCircle" on:click={modal.show} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|
|
@ -28,25 +28,25 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import restUtils from "helpers/data/utils"
|
import restUtils from "helpers/data/utils"
|
||||||
import {
|
import {
|
||||||
RestBodyTypes as bodyTypes,
|
|
||||||
SchemaTypeOptions,
|
|
||||||
PaginationLocations,
|
PaginationLocations,
|
||||||
PaginationTypes,
|
PaginationTypes,
|
||||||
|
RawRestBodyTypes,
|
||||||
|
RestBodyTypes as bodyTypes,
|
||||||
|
SchemaTypeOptions,
|
||||||
} from "constants/backend"
|
} from "constants/backend"
|
||||||
import JSONPreview from "components/integration/JSONPreview.svelte"
|
import JSONPreview from "components/integration/JSONPreview.svelte"
|
||||||
import AccessLevelSelect from "components/integration/AccessLevelSelect.svelte"
|
import AccessLevelSelect from "components/integration/AccessLevelSelect.svelte"
|
||||||
import DynamicVariableModal from "../../_components/DynamicVariableModal.svelte"
|
import DynamicVariableModal from "../../_components/DynamicVariableModal.svelte"
|
||||||
import Placeholder from "assets/bb-spaceship.svg"
|
import Placeholder from "assets/bb-spaceship.svg"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import { RawRestBodyTypes } from "constants/backend"
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getRestBindings,
|
getRestBindings,
|
||||||
toBindingsArray,
|
|
||||||
runtimeToReadableBinding,
|
|
||||||
readableToRuntimeBinding,
|
readableToRuntimeBinding,
|
||||||
runtimeToReadableMap,
|
|
||||||
readableToRuntimeMap,
|
readableToRuntimeMap,
|
||||||
|
runtimeToReadableBinding,
|
||||||
|
runtimeToReadableMap,
|
||||||
|
toBindingsArray,
|
||||||
} from "builderStore/dataBinding"
|
} from "builderStore/dataBinding"
|
||||||
|
|
||||||
let query, datasource
|
let query, datasource
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
$: runtimeUrlQueries = readableToRuntimeMap(mergedBindings, breakQs)
|
$: runtimeUrlQueries = readableToRuntimeMap(mergedBindings, breakQs)
|
||||||
|
|
||||||
function getSelectedQuery() {
|
function getSelectedQuery() {
|
||||||
const cloneQuery = cloneDeep(
|
return cloneDeep(
|
||||||
$queries.list.find(q => q._id === $queries.selected) || {
|
$queries.list.find(q => q._id === $queries.selected) || {
|
||||||
datasourceId: $params.selectedDatasource,
|
datasourceId: $params.selectedDatasource,
|
||||||
parameters: [],
|
parameters: [],
|
||||||
|
@ -107,7 +107,6 @@
|
||||||
queryVerb: "read",
|
queryVerb: "read",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return cloneQuery
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkQueryName(inputUrl = null) {
|
function checkQueryName(inputUrl = null) {
|
||||||
|
@ -121,14 +120,15 @@
|
||||||
if (!base) {
|
if (!base) {
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
const qs = restUtils.buildQueryString(
|
let qs = restUtils.buildQueryString(
|
||||||
runtimeToReadableMap(mergedBindings, qsObj)
|
runtimeToReadableMap(mergedBindings, qsObj)
|
||||||
)
|
)
|
||||||
let newUrl = base
|
let newUrl = base
|
||||||
if (base.includes("?")) {
|
if (base.includes("?")) {
|
||||||
newUrl = base.split("?")[0]
|
const split = base.split("?")
|
||||||
|
newUrl = split[0]
|
||||||
}
|
}
|
||||||
return qs.length > 0 ? `${newUrl}?${qs}` : newUrl
|
return qs.length === 0 ? newUrl : `${newUrl}?${qs}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildQuery() {
|
function buildQuery() {
|
||||||
|
@ -314,6 +314,25 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const paramsChanged = evt => {
|
||||||
|
breakQs = {}
|
||||||
|
for (let param of evt.detail) {
|
||||||
|
breakQs[param.name] = param.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlChanged = evt => {
|
||||||
|
breakQs = {}
|
||||||
|
const qs = evt.target.value.split("?")[1]
|
||||||
|
if (qs && qs.length > 0) {
|
||||||
|
const parts = qs.split("&")
|
||||||
|
for (let part of parts) {
|
||||||
|
const [key, value] = part.split("=")
|
||||||
|
breakQs[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
query = getSelectedQuery()
|
query = getSelectedQuery()
|
||||||
|
|
||||||
|
@ -426,7 +445,11 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="url">
|
<div class="url">
|
||||||
<Input bind:value={url} placeholder="http://www.api.com/endpoint" />
|
<Input
|
||||||
|
on:blur={urlChanged}
|
||||||
|
bind:value={url}
|
||||||
|
placeholder="http://www.api.com/endpoint"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button primary disabled={!url} on:click={runQuery}>Send</Button>
|
<Button primary disabled={!url} on:click={runQuery}>Send</Button>
|
||||||
<Button
|
<Button
|
||||||
|
@ -456,13 +479,16 @@
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="Params">
|
<Tab title="Params">
|
||||||
<KeyValueBuilder
|
{#key breakQs}
|
||||||
bind:object={breakQs}
|
<KeyValueBuilder
|
||||||
name="param"
|
on:change={paramsChanged}
|
||||||
headings
|
object={breakQs}
|
||||||
bindings={mergedBindings}
|
name="param"
|
||||||
bindingDrawerLeft="260px"
|
headings
|
||||||
/>
|
bindings={mergedBindings}
|
||||||
|
bindingDrawerLeft="260px"
|
||||||
|
/>
|
||||||
|
{/key}
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="Headers">
|
<Tab title="Headers">
|
||||||
<KeyValueBuilder
|
<KeyValueBuilder
|
||||||
|
|
|
@ -85,6 +85,8 @@
|
||||||
? [$store.componentToPaste?._id]
|
? [$store.componentToPaste?._id]
|
||||||
: [],
|
: [],
|
||||||
isBudibaseEvent: true,
|
isBudibaseEvent: true,
|
||||||
|
usedPlugins: $store.usedPlugins,
|
||||||
|
location: window.location,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the preview when required
|
// Refresh the preview when required
|
||||||
|
@ -303,7 +305,7 @@
|
||||||
<iframe
|
<iframe
|
||||||
title="componentPreview"
|
title="componentPreview"
|
||||||
bind:this={iframe}
|
bind:this={iframe}
|
||||||
src="/preview"
|
src="/app/preview"
|
||||||
class:hidden={loading || error}
|
class:hidden={loading || error}
|
||||||
class:tablet={$store.previewDevice === "tablet"}
|
class:tablet={$store.previewDevice === "tablet"}
|
||||||
class:mobile={$store.previewDevice === "mobile"}
|
class:mobile={$store.previewDevice === "mobile"}
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeyAction = async (component, key, ctrlKey = false) => {
|
const handleKeyAction = async (event, component, key, ctrlKey = false) => {
|
||||||
if (!component || !key) {
|
if (!component || !key) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,9 @@
|
||||||
const handler = keyHandlers[key]
|
const handler = keyHandlers[key]
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
return false
|
return false
|
||||||
|
} else if (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
}
|
}
|
||||||
return handler(component)
|
return handler(component)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -95,14 +98,19 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Key events are always for the selected component
|
// Key events are always for the selected component
|
||||||
return handleKeyAction($selectedComponent, e.key, e.ctrlKey || e.metaKey)
|
return await handleKeyAction(
|
||||||
|
e,
|
||||||
|
$selectedComponent,
|
||||||
|
e.key,
|
||||||
|
e.ctrlKey || e.metaKey
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleComponentMenu = async e => {
|
const handleComponentMenu = async e => {
|
||||||
// Menu events can be for any component
|
// Menu events can be for any component
|
||||||
const { id, key, ctrlKey } = e.detail
|
const { id, key, ctrlKey } = e.detail
|
||||||
const component = findComponent($selectedScreen.props, id)
|
const component = findComponent($selectedScreen.props, id)
|
||||||
return await handleKeyAction(component, key, ctrlKey)
|
return await handleKeyAction(null, component, key, ctrlKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
{#if $selectedComponent}
|
{#if $selectedComponent}
|
||||||
{#key $selectedComponent._id}
|
{#key $selectedComponent._id}
|
||||||
<Panel {title} icon={componentDefinition.icon} borderLeft>
|
<Panel {title} icon={componentDefinition?.icon} borderLeft>
|
||||||
<ComponentSettingsSection
|
<ComponentSettingsSection
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
{componentDefinition}
|
{componentDefinition}
|
||||||
|
|
|
@ -24,7 +24,11 @@
|
||||||
$: currentDefinition = store.actions.components.getDefinition(
|
$: currentDefinition = store.actions.components.getDefinition(
|
||||||
$selectedComponent?._component
|
$selectedComponent?._component
|
||||||
)
|
)
|
||||||
$: enrichedStructure = enrichStructure(structure, $store.components)
|
$: enrichedStructure = enrichStructure(
|
||||||
|
structure,
|
||||||
|
$store.components,
|
||||||
|
$store.customComponents
|
||||||
|
)
|
||||||
$: filteredStructure = filterStructure(
|
$: filteredStructure = filterStructure(
|
||||||
enrichedStructure,
|
enrichedStructure,
|
||||||
section,
|
section,
|
||||||
|
@ -46,8 +50,25 @@
|
||||||
|
|
||||||
// Parses the structure in the manifest and returns an enriched structure with
|
// Parses the structure in the manifest and returns an enriched structure with
|
||||||
// explicit categories
|
// explicit categories
|
||||||
const enrichStructure = (structure, definitions) => {
|
const enrichStructure = (structure, definitions, customComponents) => {
|
||||||
let enrichedStructure = []
|
let enrichedStructure = []
|
||||||
|
|
||||||
|
// Add custom components category
|
||||||
|
if (customComponents?.length) {
|
||||||
|
enrichedStructure.push({
|
||||||
|
name: "Plugins",
|
||||||
|
isCategory: true,
|
||||||
|
children: customComponents
|
||||||
|
.map(x => ({
|
||||||
|
...definitions[x],
|
||||||
|
name: definitions[x].friendlyName || definitions[x].name,
|
||||||
|
}))
|
||||||
|
.sort((a, b) => {
|
||||||
|
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
structure.forEach(item => {
|
structure.forEach(item => {
|
||||||
if (typeof item === "string") {
|
if (typeof item === "string") {
|
||||||
const def = definitions[`@budibase/standard-components/${item}`]
|
const def = definitions[`@budibase/standard-components/${item}`]
|
||||||
|
@ -65,6 +86,7 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return enrichedStructure
|
return enrichedStructure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +247,7 @@
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
height: 100%;
|
height: calc(100% - 60px);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
},
|
},
|
||||||
{ title: "Auth", href: "/builder/portal/manage/auth" },
|
{ title: "Auth", href: "/builder/portal/manage/auth" },
|
||||||
{ title: "Email", href: "/builder/portal/manage/email" },
|
{ title: "Email", href: "/builder/portal/manage/email" },
|
||||||
|
{ title: "Plugins", href: "/builder/portal/manage/plugins" },
|
||||||
|
|
||||||
{
|
{
|
||||||
title: "Organisation",
|
title: "Organisation",
|
||||||
href: "/builder/portal/settings/organisation",
|
href: "/builder/portal/settings/organisation",
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||||
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
||||||
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
|
||||||
|
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
|
@ -33,7 +32,6 @@
|
||||||
let selectedApp
|
let selectedApp
|
||||||
let creationModal
|
let creationModal
|
||||||
let updatingModal
|
let updatingModal
|
||||||
let exportModal
|
|
||||||
let creatingApp = false
|
let creatingApp = false
|
||||||
let loaded = $apps?.length || $templates?.length
|
let loaded = $apps?.length || $templates?.length
|
||||||
let searchTerm = ""
|
let searchTerm = ""
|
||||||
|
@ -407,10 +405,6 @@
|
||||||
<UpdateAppModal app={selectedApp} />
|
<UpdateAppModal app={selectedApp} />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Modal bind:this={exportModal} padding={false} width="600px">
|
|
||||||
<ExportAppModal app={selectedApp} />
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.appTable {
|
.appTable {
|
||||||
border-top: var(--border-light);
|
border-top: var(--border-light);
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
ModalContent,
|
||||||
|
Label,
|
||||||
|
Input,
|
||||||
|
Select,
|
||||||
|
Dropzone,
|
||||||
|
Body,
|
||||||
|
notifications,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
|
||||||
|
import { plugins } from "stores/portal"
|
||||||
|
import { PluginSource } from "constants"
|
||||||
|
|
||||||
|
function opt(name, optional) {
|
||||||
|
if (optional) {
|
||||||
|
return { name, optional }
|
||||||
|
}
|
||||||
|
return { name }
|
||||||
|
}
|
||||||
|
|
||||||
|
let authOptions = {
|
||||||
|
[PluginSource.URL]: [opt("URL"), opt("Headers", true)],
|
||||||
|
[PluginSource.NPM]: [opt("URL")],
|
||||||
|
[PluginSource.GITHUB]: [opt("URL"), opt("Github Token", true)],
|
||||||
|
[PluginSource.FILE]: [opt("File Upload")],
|
||||||
|
}
|
||||||
|
let file
|
||||||
|
let source = PluginSource.URL
|
||||||
|
let dynamicValues = {}
|
||||||
|
|
||||||
|
let validation
|
||||||
|
$: validation = source === "File Upload" ? file : dynamicValues["URL"]
|
||||||
|
|
||||||
|
function infoMessage(optionName) {
|
||||||
|
switch (optionName) {
|
||||||
|
case PluginSource.URL:
|
||||||
|
return "Please specify a URL which directs to a built plugin TAR archive. You can provide headers if authentication is required."
|
||||||
|
case PluginSource.NPM:
|
||||||
|
return "Please specify the URL to a public NPM package which contains the built version of the plugin you wish to install."
|
||||||
|
case PluginSource.GITHUB:
|
||||||
|
return "Please specify the URL to a Github repository which contains built plugin releases. If this is a private repo you can provide a token to access it."
|
||||||
|
case PluginSource.FILE:
|
||||||
|
return "Please provide a built plugin TAR archive. You can build a plugin locally using the Budibase CLI."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
try {
|
||||||
|
if (source === PluginSource.FILE) {
|
||||||
|
await plugins.uploadPlugin(file)
|
||||||
|
} else {
|
||||||
|
const url = dynamicValues["URL"]
|
||||||
|
let auth =
|
||||||
|
source === PluginSource.GITHUB
|
||||||
|
? dynamicValues["Github Token"]
|
||||||
|
: source === PluginSource.URL
|
||||||
|
? dynamicValues["Headers"]
|
||||||
|
: undefined
|
||||||
|
await plugins.createPlugin(source, url, auth)
|
||||||
|
}
|
||||||
|
notifications.success("Plugin added successfully.")
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err?.message ? err.message : JSON.stringify(err)
|
||||||
|
notifications.error(`Failed to add plugin: ${msg}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ModalContent
|
||||||
|
confirmText={"Save"}
|
||||||
|
onConfirm={save}
|
||||||
|
disabled={!validation}
|
||||||
|
size="M"
|
||||||
|
title="Add new plugin"
|
||||||
|
>
|
||||||
|
<div class="form-row">
|
||||||
|
<Label size="M">Source</Label>
|
||||||
|
<Select
|
||||||
|
placeholder={null}
|
||||||
|
bind:value={source}
|
||||||
|
options={Object.values(PluginSource)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Body size="S">{infoMessage(source)}</Body>
|
||||||
|
{#each authOptions[source] as option}
|
||||||
|
{#if option.name === PluginSource.FILE}
|
||||||
|
<div class="form-row">
|
||||||
|
<Label size="M">{option.name}</Label>
|
||||||
|
<Dropzone
|
||||||
|
gallery={false}
|
||||||
|
value={[file]}
|
||||||
|
on:change={e => {
|
||||||
|
if (!e.detail || e.detail.length === 0) {
|
||||||
|
file = null
|
||||||
|
} else {
|
||||||
|
file = e.detail[0]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="form-row">
|
||||||
|
<div>
|
||||||
|
<Label size="M">{option.name}</Label>
|
||||||
|
{#if option.optional}
|
||||||
|
<Label size="S" muted><i>Optional</i></Label>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if option.name === "Headers"}
|
||||||
|
<KeyValueBuilder bind:object={dynamicValues[option.name]} />
|
||||||
|
{:else}
|
||||||
|
<Input bind:value={dynamicValues[option.name]} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</ModalContent>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 60px 1fr;
|
||||||
|
grid-gap: var(--spacing-l);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script>
|
||||||
|
import { Body, ModalContent, notifications } from "@budibase/bbui"
|
||||||
|
import { plugins } from "stores/portal"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let plugin
|
||||||
|
|
||||||
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
async function deletePlugin() {
|
||||||
|
try {
|
||||||
|
await plugins.deletePlugin(plugin._id)
|
||||||
|
notifications.success(`Plugin ${plugin?.name} deleted`)
|
||||||
|
dispatch("deleted")
|
||||||
|
} catch (error) {
|
||||||
|
const msg = error?.message ? error.message : JSON.stringify(error)
|
||||||
|
notifications.error(`Error deleting plugin: ${msg}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ModalContent
|
||||||
|
warning
|
||||||
|
onConfirm={deletePlugin}
|
||||||
|
title="Delete Plugin"
|
||||||
|
confirmText="Delete plugin"
|
||||||
|
cancelText="Cancel"
|
||||||
|
showCloseIcon={false}
|
||||||
|
>
|
||||||
|
<Body>
|
||||||
|
Are you sure you want to delete <strong>{plugin?.name}</strong>
|
||||||
|
</Body>
|
||||||
|
</ModalContent>
|
|
@ -0,0 +1,145 @@
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
Icon,
|
||||||
|
Body,
|
||||||
|
Modal,
|
||||||
|
ModalContent,
|
||||||
|
Button,
|
||||||
|
Label,
|
||||||
|
Input,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import DeletePluginModal from "../_components/DeletePluginModal.svelte"
|
||||||
|
|
||||||
|
export let plugin
|
||||||
|
|
||||||
|
let detailsModal
|
||||||
|
let deleteModal
|
||||||
|
|
||||||
|
let icon =
|
||||||
|
plugin.schema.type === "component"
|
||||||
|
? plugin.schema.schema.icon || "Book"
|
||||||
|
: plugin.schema.schema.icon || "Beaker"
|
||||||
|
|
||||||
|
function pluginDeleted() {
|
||||||
|
if (detailsModal) {
|
||||||
|
detailsModal.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="row" on:click={() => detailsModal.show()}>
|
||||||
|
<div class="title">
|
||||||
|
<div class="name">
|
||||||
|
<div>
|
||||||
|
<Icon size="M" name={icon} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Body
|
||||||
|
size="S"
|
||||||
|
color="var(--spectrum-global-color-gray-900)"
|
||||||
|
weight="800"
|
||||||
|
>
|
||||||
|
{plugin.name}
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="desktop">{plugin.version}</div>
|
||||||
|
<div class="desktop">
|
||||||
|
{plugin.schema.type.charAt(0).toUpperCase() + plugin.schema.type.slice(1)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Icon name="ChevronRight" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Modal bind:this={detailsModal}>
|
||||||
|
<ModalContent
|
||||||
|
size="M"
|
||||||
|
title="Plugin details"
|
||||||
|
showConfirmButton={false}
|
||||||
|
showCancelButton={false}
|
||||||
|
>
|
||||||
|
<div class="details-row">
|
||||||
|
<Label size="M">Name</Label>
|
||||||
|
<Input disabled value={plugin.name} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="details-row">
|
||||||
|
<Label size="M">Type</Label>
|
||||||
|
<Input
|
||||||
|
disabled
|
||||||
|
value={plugin.schema.type.charAt(0).toUpperCase() +
|
||||||
|
plugin.schema.type.slice(1)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="details-row">
|
||||||
|
<Label size="M">Source</Label>
|
||||||
|
<Input disabled value={plugin.source || "N/A"} />
|
||||||
|
</div>
|
||||||
|
<div class="details-row">
|
||||||
|
<Label size="M">Version</Label>
|
||||||
|
<Input disabled value={plugin.version} />
|
||||||
|
</div>
|
||||||
|
<div class="details-row">
|
||||||
|
<Label size="M">License</Label>
|
||||||
|
<Input disabled value={plugin.package.license} />
|
||||||
|
</div>
|
||||||
|
<div class="details-row">
|
||||||
|
<Label size="M">Author</Label>
|
||||||
|
<Input disabled value={plugin.package.author || "N/A"} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer" slot="footer">
|
||||||
|
<Button newStyles on:click={deleteModal.show()} warning>Delete</Button>
|
||||||
|
</div>
|
||||||
|
</ModalContent>
|
||||||
|
|
||||||
|
<Modal bind:this={deleteModal}>
|
||||||
|
<DeletePluginModal {plugin} on:deleted={pluginDeleted} />
|
||||||
|
</Modal>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 110px 140px 20px;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--background);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0 16px;
|
||||||
|
height: 56px;
|
||||||
|
background: var(--spectrum-global-color-gray-50);
|
||||||
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
|
transition: background 130ms ease-out;
|
||||||
|
}
|
||||||
|
.row:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: var(--spectrum-global-color-gray-75);
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
grid-gap: var(--spacing-m);
|
||||||
|
grid-template-columns: 75px 75px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 60px 1fr;
|
||||||
|
grid-gap: var(--spacing-l) var(--spacing-l);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.desktop {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-l);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,95 @@
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
Layout,
|
||||||
|
Heading,
|
||||||
|
Body,
|
||||||
|
Button,
|
||||||
|
Select,
|
||||||
|
Divider,
|
||||||
|
Modal,
|
||||||
|
Search,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { plugins } from "stores/portal"
|
||||||
|
import PluginRow from "./_components/PluginRow.svelte"
|
||||||
|
import AddPluginModal from "./_components/AddPluginModal.svelte"
|
||||||
|
|
||||||
|
let modal
|
||||||
|
let searchTerm = ""
|
||||||
|
let filter = "all"
|
||||||
|
let filterOptions = [
|
||||||
|
{ label: "All plugins", value: "all" },
|
||||||
|
{ label: "Components", value: "component" },
|
||||||
|
{ label: "Datasources", value: "datasource" },
|
||||||
|
]
|
||||||
|
|
||||||
|
$: filteredPlugins = $plugins
|
||||||
|
.filter(plugin => {
|
||||||
|
return filter === "all" || plugin.schema.type === filter
|
||||||
|
})
|
||||||
|
.filter(plugin => {
|
||||||
|
return (
|
||||||
|
!searchTerm ||
|
||||||
|
plugin?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
await plugins.load()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Layout noPadding>
|
||||||
|
<Layout gap="XS" noPadding>
|
||||||
|
<Heading size="M">Plugins</Heading>
|
||||||
|
<Body>Add your own custom datasources and components</Body>
|
||||||
|
</Layout>
|
||||||
|
<Divider size="S" />
|
||||||
|
<Layout noPadding>
|
||||||
|
<div class="controls">
|
||||||
|
<div>
|
||||||
|
<Button on:click={modal.show} newStyles cta icon={"Add"}>
|
||||||
|
Add plugin
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="filters">
|
||||||
|
<div class="select">
|
||||||
|
<Select
|
||||||
|
bind:value={filter}
|
||||||
|
placeholder={null}
|
||||||
|
options={filterOptions}
|
||||||
|
autoWidth
|
||||||
|
quiet
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Search bind:value={searchTerm} placeholder="Search plugins" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if filteredPlugins?.length}
|
||||||
|
<Layout noPadding gap="S">
|
||||||
|
{#each filteredPlugins as plugin (plugin._id)}
|
||||||
|
<PluginRow {plugin} />
|
||||||
|
{/each}
|
||||||
|
</Layout>
|
||||||
|
{/if}
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<Modal bind:this={modal}>
|
||||||
|
<AddPluginModal />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.filters {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-xl);
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.controls :global(.spectrum-Search) {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -16,6 +16,7 @@
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Icon,
|
Icon,
|
||||||
Helpers,
|
Helpers,
|
||||||
|
Modal,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import OverviewTab from "../_components/OverviewTab.svelte"
|
import OverviewTab from "../_components/OverviewTab.svelte"
|
||||||
import SettingsTab from "../_components/SettingsTab.svelte"
|
import SettingsTab from "../_components/SettingsTab.svelte"
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
import EditableIcon from "components/common/EditableIcon.svelte"
|
import EditableIcon from "components/common/EditableIcon.svelte"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
import HistoryTab from "components/portal/overview/automation/HistoryTab.svelte"
|
import HistoryTab from "components/portal/overview/automation/HistoryTab.svelte"
|
||||||
|
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
||||||
import { checkIncomingDeploymentStatus } from "components/deploy/utils"
|
import { checkIncomingDeploymentStatus } from "components/deploy/utils"
|
||||||
import { onDestroy, onMount } from "svelte"
|
import { onDestroy, onMount } from "svelte"
|
||||||
|
|
||||||
|
@ -38,7 +40,9 @@
|
||||||
let loaded = false
|
let loaded = false
|
||||||
let deletionModal
|
let deletionModal
|
||||||
let unpublishModal
|
let unpublishModal
|
||||||
|
let exportModal
|
||||||
let appName = ""
|
let appName = ""
|
||||||
|
let published
|
||||||
|
|
||||||
// App
|
// App
|
||||||
$: filteredApps = $apps.filter(app => app.devId === application)
|
$: filteredApps = $apps.filter(app => app.devId === application)
|
||||||
|
@ -140,11 +144,9 @@
|
||||||
notifications.success("App ID copied to clipboard.")
|
notifications.success("App ID copied to clipboard.")
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportApp = (app, opts = { published: false }) => {
|
const exportApp = opts => {
|
||||||
const appName = encodeURIComponent(app.name)
|
published = opts.published
|
||||||
const id = opts?.published ? app.prodId : app.devId
|
exportModal.show()
|
||||||
// always export the development version
|
|
||||||
window.location = `/api/backups/export?appId=${id}&appname=${appName}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const unpublishApp = app => {
|
const unpublishApp = app => {
|
||||||
|
@ -206,6 +208,10 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<Modal bind:this={exportModal} padding={false} width="600px">
|
||||||
|
<ExportAppModal app={selectedApp} {published} />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<span class="overview-wrap">
|
<span class="overview-wrap">
|
||||||
<Page wide noPadding>
|
<Page wide noPadding>
|
||||||
{#await promise}
|
{#await promise}
|
||||||
|
@ -269,14 +275,14 @@
|
||||||
<Icon hoverable name="More" />
|
<Icon hoverable name="More" />
|
||||||
</span>
|
</span>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
on:click={() => exportApp(selectedApp, { published: false })}
|
on:click={() => exportApp({ published: false })}
|
||||||
icon="DownloadFromCloud"
|
icon="DownloadFromCloud"
|
||||||
>
|
>
|
||||||
Export latest
|
Export latest
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{#if isPublished}
|
{#if isPublished}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
on:click={() => exportApp(selectedApp, { published: true })}
|
on:click={() => exportApp({ published: true })}
|
||||||
icon="DownloadFromCloudOutline"
|
icon="DownloadFromCloudOutline"
|
||||||
>
|
>
|
||||||
Export published
|
Export published
|
||||||
|
|
|
@ -88,14 +88,14 @@
|
||||||
<Heading size="S">Information</Heading>
|
<Heading size="S">Information</Heading>
|
||||||
<Body size="S">Here you can update your logo and organization name.</Body>
|
<Body size="S">Here you can update your logo and organization name.</Body>
|
||||||
</Layout>
|
</Layout>
|
||||||
<div class="fields">
|
<div className="fields">
|
||||||
<div class="field">
|
<div className="field">
|
||||||
<Label size="L">Org. name</Label>
|
<Label size="L">Org. name</Label>
|
||||||
<Input thin bind:value={$values.company} />
|
<Input thin bind:value={$values.company} />
|
||||||
</div>
|
</div>
|
||||||
<div class="field logo">
|
<div className="field logo">
|
||||||
<Label size="L">Logo</Label>
|
<Label size="L">Logo</Label>
|
||||||
<div class="file">
|
<div className="file">
|
||||||
<Dropzone
|
<Dropzone
|
||||||
value={[$values.logo]}
|
value={[$values.logo]}
|
||||||
on:change={e => {
|
on:change={e => {
|
||||||
|
@ -115,8 +115,8 @@
|
||||||
<Heading size="S">Platform</Heading>
|
<Heading size="S">Platform</Heading>
|
||||||
<Body size="S">Here you can set up general platform settings.</Body>
|
<Body size="S">Here you can set up general platform settings.</Body>
|
||||||
</Layout>
|
</Layout>
|
||||||
<div class="fields">
|
<div className="fields">
|
||||||
<div class="field">
|
<div className="field">
|
||||||
<Label
|
<Label
|
||||||
size="L"
|
size="L"
|
||||||
tooltip={"Update the Platform URL to match your Budibase web URL. This keeps email templates and authentication configs up to date."}
|
tooltip={"Update the Platform URL to match your Budibase web URL. This keeps email templates and authentication configs up to date."}
|
||||||
|
@ -150,15 +150,18 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: var(--spacing-m);
|
grid-gap: var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.field {
|
.field {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 100px 1fr;
|
grid-template-columns: 100px 1fr;
|
||||||
grid-gap: var(--spacing-l);
|
grid-gap: var(--spacing-l);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file {
|
.file {
|
||||||
max-width: 30ch;
|
max-width: 30ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,8 +62,11 @@ export function createDatasourcesStore() {
|
||||||
unselect: () => {
|
unselect: () => {
|
||||||
update(state => ({ ...state, selected: null }))
|
update(state => ({ ...state, selected: null }))
|
||||||
},
|
},
|
||||||
updateSchema: async datasource => {
|
updateSchema: async (datasource, tablesFilter) => {
|
||||||
const response = await API.buildDatasourceSchema(datasource?._id)
|
const response = await API.buildDatasourceSchema({
|
||||||
|
datasourceId: datasource?._id,
|
||||||
|
tablesFilter,
|
||||||
|
})
|
||||||
return await updateDatasource(response)
|
return await updateDatasource(response)
|
||||||
},
|
},
|
||||||
save: async (body, fetchSchema = false) => {
|
save: async (body, fetchSchema = false) => {
|
||||||
|
|
|
@ -8,3 +8,4 @@ export { oidc } from "./oidc"
|
||||||
export { templates } from "./templates"
|
export { templates } from "./templates"
|
||||||
export { licensing } from "./licensing"
|
export { licensing } from "./licensing"
|
||||||
export { groups } from "./groups"
|
export { groups } from "./groups"
|
||||||
|
export { plugins } from "./plugins"
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
import { API } from "api"
|
||||||
|
import { PluginSource } from "constants"
|
||||||
|
|
||||||
|
export function createPluginsStore() {
|
||||||
|
const { subscribe, set, update } = writable([])
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
const plugins = await API.getPlugins()
|
||||||
|
set(plugins)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deletePlugin(pluginId) {
|
||||||
|
await API.deletePlugin(pluginId)
|
||||||
|
update(state => {
|
||||||
|
state = state.filter(existing => existing._id !== pluginId)
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createPlugin(source, url, auth = null) {
|
||||||
|
let pluginData = {
|
||||||
|
source,
|
||||||
|
url,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (source) {
|
||||||
|
case PluginSource.URL:
|
||||||
|
pluginData.headers = auth
|
||||||
|
break
|
||||||
|
case PluginSource.GITHUB:
|
||||||
|
pluginData.githubToken = auth
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await API.createPlugin(pluginData)
|
||||||
|
|
||||||
|
let newPlugin = res.plugins[0]
|
||||||
|
update(state => {
|
||||||
|
const currentIdx = state.findIndex(plugin => plugin._id === newPlugin._id)
|
||||||
|
if (currentIdx >= 0) {
|
||||||
|
state.splice(currentIdx, 1, newPlugin)
|
||||||
|
} else {
|
||||||
|
state.push(newPlugin)
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadPlugin(file) {
|
||||||
|
if (!file) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let data = new FormData()
|
||||||
|
data.append("file", file)
|
||||||
|
let resp = await API.uploadPlugin(data)
|
||||||
|
let newPlugin = resp.plugins[0]
|
||||||
|
update(state => {
|
||||||
|
const currentIdx = state.findIndex(plugin => plugin._id === newPlugin._id)
|
||||||
|
if (currentIdx >= 0) {
|
||||||
|
state.splice(currentIdx, 1, newPlugin)
|
||||||
|
} else {
|
||||||
|
state.push(newPlugin)
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
load,
|
||||||
|
createPlugin,
|
||||||
|
deletePlugin,
|
||||||
|
uploadPlugin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const plugins = createPluginsStore()
|
|
@ -1,15 +1,23 @@
|
||||||
import { svelte } from "@sveltejs/vite-plugin-svelte"
|
import { svelte } from "@sveltejs/vite-plugin-svelte"
|
||||||
import replace from "@rollup/plugin-replace"
|
import replace from "@rollup/plugin-replace"
|
||||||
|
import { defineConfig, loadEnv } from "vite"
|
||||||
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|
||||||
export default ({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
const isProduction = mode === "production"
|
const isProduction = mode === "production"
|
||||||
|
const env = loadEnv(mode, process.cwd())
|
||||||
return {
|
return {
|
||||||
server: {
|
server: {
|
||||||
fs: {
|
fs: {
|
||||||
strict: false,
|
strict: false,
|
||||||
},
|
},
|
||||||
|
hmr: {
|
||||||
|
protocol: env.VITE_HMR_PROTOCOL || "ws",
|
||||||
|
clientPort: env.VITE_HMR_CLIENT_PORT || 3000,
|
||||||
|
path: env.VITE_HMR_PATH || "/",
|
||||||
|
},
|
||||||
|
port: 3000,
|
||||||
},
|
},
|
||||||
base: "/builder/",
|
base: "/builder/",
|
||||||
build: {
|
build: {
|
||||||
|
@ -79,4 +87,4 @@ export default ({ mode }) => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
|
@ -967,6 +967,11 @@
|
||||||
debug "^3.1.0"
|
debug "^3.1.0"
|
||||||
lodash.once "^4.1.1"
|
lodash.once "^4.1.1"
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64@0.14.54":
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
|
||||||
|
integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
|
||||||
|
|
||||||
"@hapi/hoek@^9.0.0":
|
"@hapi/hoek@^9.0.0":
|
||||||
version "9.2.1"
|
version "9.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17"
|
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17"
|
||||||
|
@ -1215,10 +1220,10 @@
|
||||||
estree-walker "^1.0.1"
|
estree-walker "^1.0.1"
|
||||||
picomatch "^2.2.2"
|
picomatch "^2.2.2"
|
||||||
|
|
||||||
"@rollup/pluginutils@^4.1.1":
|
"@rollup/pluginutils@^4.2.1":
|
||||||
version "4.1.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec"
|
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
||||||
integrity sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==
|
integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
estree-walker "^2.0.1"
|
estree-walker "^2.0.1"
|
||||||
picomatch "^2.2.2"
|
picomatch "^2.2.2"
|
||||||
|
@ -1350,17 +1355,17 @@
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-4.3.0.tgz#03ddf67d3aa8a9a4cb0edbbd259465c9ced7e70d"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-4.3.0.tgz#03ddf67d3aa8a9a4cb0edbbd259465c9ced7e70d"
|
||||||
integrity sha512-ZQ2XAhgu4G9yBeXQNDAz07Z8oZNnMt5o9vzf/mpBA7Teb/JI+8qXp2wt8D245SzmtNlFkG/bzRYvQc0scgZeCQ==
|
integrity sha512-ZQ2XAhgu4G9yBeXQNDAz07Z8oZNnMt5o9vzf/mpBA7Teb/JI+8qXp2wt8D245SzmtNlFkG/bzRYvQc0scgZeCQ==
|
||||||
|
|
||||||
"@sveltejs/vite-plugin-svelte@1.0.0-next.19":
|
"@sveltejs/vite-plugin-svelte@1.0.1":
|
||||||
version "1.0.0-next.19"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.19.tgz#9646abc2cd1982146db4bb341aafdb5f32f19dd2"
|
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.1.tgz#7f468f03c933fcdfc60d4773671c73f33b9ef4d6"
|
||||||
integrity sha512-q9hHkMzodScwDq64pNaWhekpj97vWg3wO9T0rqd8bC2EsrBQs2uD1qMJvDqlNd63AbO2uSJMGo+TQ0Xt2xgyYg==
|
integrity sha512-PorCgUounn0VXcpeJu+hOweZODKmGuLHsLomwqSj+p26IwjjGffmYQfVHtiTWq+NqaUuuHWWG7vPge6UFw4Aeg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@rollup/pluginutils" "^4.1.1"
|
"@rollup/pluginutils" "^4.2.1"
|
||||||
debug "^4.3.2"
|
debug "^4.3.4"
|
||||||
kleur "^4.1.4"
|
deepmerge "^4.2.2"
|
||||||
magic-string "^0.25.7"
|
kleur "^4.1.5"
|
||||||
require-relative "^0.8.7"
|
magic-string "^0.26.2"
|
||||||
svelte-hmr "^0.14.7"
|
svelte-hmr "^0.14.12"
|
||||||
|
|
||||||
"@testing-library/dom@^7.0.3":
|
"@testing-library/dom@^7.0.3":
|
||||||
version "7.31.2"
|
version "7.31.2"
|
||||||
|
@ -2493,6 +2498,13 @@ debug@^3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "^2.1.1"
|
ms "^2.1.1"
|
||||||
|
|
||||||
|
debug@^4.3.4:
|
||||||
|
version "4.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||||
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
|
dependencies:
|
||||||
|
ms "2.1.2"
|
||||||
|
|
||||||
decamelize@^1.2.0:
|
decamelize@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||||
|
@ -2655,113 +2667,132 @@ error-ex@^1.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-arrayish "^0.2.1"
|
is-arrayish "^0.2.1"
|
||||||
|
|
||||||
esbuild-android-arm64@0.13.14:
|
esbuild-android-64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.14.tgz#c85083ece26be3d67e6c720e088968a98409e023"
|
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
|
||||||
integrity sha512-Q+Xhfp827r+ma8/DJgpMRUbDZfefsk13oePFEXEIJ4gxFbNv5+vyiYXYuKm43/+++EJXpnaYmEnu4hAKbAWYbA==
|
integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
|
||||||
|
|
||||||
esbuild-darwin-64@0.13.14:
|
esbuild-android-arm64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.14.tgz#8e4e237ad847cc54a1d3a5caee26a746b9f0b81f"
|
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
|
||||||
integrity sha512-YmOhRns6QBNSjpVdTahi/yZ8dscx9ai7a6OY6z5ACgOuQuaQ2Qk2qgJ0/siZ6LgD0gJFMV8UINFV5oky5TFNQQ==
|
integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
|
||||||
|
|
||||||
esbuild-darwin-arm64@0.13.14:
|
esbuild-darwin-64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.14.tgz#b3b5ebd40b2cb06ee0f6fb342dd4bdcca54ad273"
|
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
|
||||||
integrity sha512-Lp00VTli2jqZghSa68fx3fEFCPsO1hK59RMo1PRap5RUjhf55OmaZTZYnCDI0FVlCtt+gBwX5qwFt4lc6tI1xg==
|
integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
|
||||||
|
|
||||||
esbuild-freebsd-64@0.13.14:
|
esbuild-darwin-arm64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.14.tgz#175ecb2fa8141428cf70ea2d5f4c27534bad53e0"
|
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
|
||||||
integrity sha512-BKosI3jtvTfnmsCW37B1TyxMUjkRWKqopR0CE9AF2ratdpkxdR24Vpe3gLKNyWiZ7BE96/SO5/YfhbPUzY8wKw==
|
integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
|
||||||
|
|
||||||
esbuild-freebsd-arm64@0.13.14:
|
esbuild-freebsd-64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.14.tgz#a7d64e41d1fa581f8db7775e5200f18e67d70c4d"
|
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
|
||||||
integrity sha512-yd2uh0yf+fWv5114+SYTl4/1oDWtr4nN5Op+PGxAkMqHfYfLjFKpcxwCo/QOS/0NWqPVE8O41IYZlFhbEN2B8Q==
|
integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
|
||||||
|
|
||||||
esbuild-linux-32@0.13.14:
|
esbuild-freebsd-arm64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.14.tgz#14bdd4f6b6cfd35c65c835894651ba335c2117da"
|
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
|
||||||
integrity sha512-a8rOnS1oWSfkkYWXoD2yXNV4BdbDKA7PNVQ1klqkY9SoSApL7io66w5H44mTLsfyw7G6Z2vLlaLI2nz9MMAowA==
|
integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
|
||||||
|
|
||||||
esbuild-linux-64@0.13.14:
|
esbuild-linux-32@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.14.tgz#7fd56851b2982fdd0cd8447ee9858c2c5711708a"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
|
||||||
integrity sha512-yPZSoMs9W2MC3Dw+6kflKt5FfQm6Dicex9dGIr1OlHRsn3Hm7yGMUTctlkW53KknnZdOdcdd5upxvbxqymczVQ==
|
integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
|
||||||
|
|
||||||
esbuild-linux-arm64@0.13.14:
|
esbuild-linux-64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.14.tgz#a55634d70679ba509adeafd68eebb9fd1ec5af6c"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
|
||||||
integrity sha512-Lvo391ln9PzC334e+jJ2S0Rt0cxP47eoH5gFyv/E8HhOnEJTvm7A+RRnMjjHnejELacTTfYgFGQYPjLsi/jObQ==
|
integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
|
||||||
|
|
||||||
esbuild-linux-arm@0.13.14:
|
esbuild-linux-arm64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.14.tgz#bb96a99677e608b31ff61f37564326d38e846ca2"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
|
||||||
integrity sha512-8chZE4pkKRvJ/M/iwsNQ1KqsRg2RyU5eT/x2flNt/f8F2TVrDreR7I0HEeCR50wLla3B1C3wTIOzQBmjuc6uWg==
|
integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
|
||||||
|
|
||||||
esbuild-linux-mips64le@0.13.14:
|
esbuild-linux-arm@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.14.tgz#6a55362a8fd1e593dea2ecc41877beed8b8184b9"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
|
||||||
integrity sha512-MZhgxbmrWbpY3TOE029O6l5tokG9+Yoj2hW7vdit/d/VnmneqeGrSHADuDL6qXM8L5jaCiaivb4VhsyVCpdAbQ==
|
integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
|
||||||
|
|
||||||
esbuild-linux-ppc64le@0.13.14:
|
esbuild-linux-mips64le@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.14.tgz#9e0048587ece0a7f184ab147f20d077098045e7f"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
|
||||||
integrity sha512-un7KMwS7fX1Un6BjfSZxTT8L5cV/8Uf4SAhM7WYy2XF8o8TI+uRxxD03svZnRNIPsN2J5cl6qV4n7Iwz+yhhVw==
|
integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
|
||||||
|
|
||||||
esbuild-netbsd-64@0.13.14:
|
esbuild-linux-ppc64le@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.14.tgz#dcab16a4bbcfa16e2e8535dadc5f64fdc891c63b"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
|
||||||
integrity sha512-5ekKx/YbOmmlTeNxBjh38Uh5TGn5C4uyqN17i67k18pS3J+U2hTVD7rCxcFcRS1AjNWumkVL3jWqYXadFwMS0Q==
|
integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
|
||||||
|
|
||||||
esbuild-openbsd-64@0.13.14:
|
esbuild-linux-riscv64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.14.tgz#3c7453b155ebb68dc34d5aec3bd6505337bdda08"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
|
||||||
integrity sha512-9bzvwewHjct2Cv5XcVoE1yW5YTW12Sk838EYfA46abgnhxGoFSD1mFcaztp5HHC43AsF+hQxbSFG/RilONARUA==
|
integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
|
||||||
|
|
||||||
esbuild-sunos-64@0.13.14:
|
esbuild-linux-s390x@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.14.tgz#85addf5fef6b5db154a955d4f2e88953359d75ce"
|
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
|
||||||
integrity sha512-mjMrZB76M6FmoiTvj/RGWilrioR7gVwtFBRVugr9qLarXMIU1W/pQx+ieEOtflrW61xo8w1fcxyHsVVGRvoQ0w==
|
integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
|
||||||
|
|
||||||
esbuild-windows-32@0.13.14:
|
esbuild-netbsd-64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.14.tgz#f77f98f30a5c636c44db2428ecdf9bcbbaedb1a7"
|
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
|
||||||
integrity sha512-GZa6mrx2rgfbH/5uHg0Rdw50TuOKbdoKCpEBitzmG5tsXBdce+cOL+iFO5joZc6fDVCLW3Y6tjxmSXRk/v20Hg==
|
integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
|
||||||
|
|
||||||
esbuild-windows-64@0.13.14:
|
esbuild-openbsd-64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.14.tgz#bc778674c40d65150d12385e0f23eb3a0badbd0d"
|
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
|
||||||
integrity sha512-Lsgqah24bT7ClHjLp/Pj3A9wxjhIAJyWQcrOV4jqXAFikmrp2CspA8IkJgw7HFjx6QrJuhpcKVbCAe/xw0i2yw==
|
integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
|
||||||
|
|
||||||
esbuild-windows-arm64@0.13.14:
|
esbuild-sunos-64@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.14.tgz#91a8dad35ab2c4dd27cd83860742955b25a354d7"
|
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
|
||||||
integrity sha512-KP8FHVlWGhM7nzYtURsGnskXb/cBCPTfj0gOKfjKq2tHtYnhDZywsUG57nk7TKhhK0fL11LcejHG3LRW9RF/9A==
|
integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
|
||||||
|
|
||||||
esbuild@^0.13.2:
|
esbuild-windows-32@0.14.54:
|
||||||
version "0.13.14"
|
version "0.14.54"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.14.tgz#98a3f7f42809abdc2b57c84565d0f713382dc1a5"
|
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
|
||||||
integrity sha512-xu4D+1ji9x53ocuomcY+KOrwAnWzhBu/wTEjpdgZ8I1c8i5vboYIeigMdzgY1UowYBKa2vZgVgUB32bu7gkxeg==
|
integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
|
||||||
|
|
||||||
|
esbuild-windows-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
|
||||||
|
integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
|
||||||
|
|
||||||
|
esbuild-windows-arm64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
|
||||||
|
integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
|
||||||
|
|
||||||
|
esbuild@^0.14.47:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
|
||||||
|
integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
esbuild-android-arm64 "0.13.14"
|
"@esbuild/linux-loong64" "0.14.54"
|
||||||
esbuild-darwin-64 "0.13.14"
|
esbuild-android-64 "0.14.54"
|
||||||
esbuild-darwin-arm64 "0.13.14"
|
esbuild-android-arm64 "0.14.54"
|
||||||
esbuild-freebsd-64 "0.13.14"
|
esbuild-darwin-64 "0.14.54"
|
||||||
esbuild-freebsd-arm64 "0.13.14"
|
esbuild-darwin-arm64 "0.14.54"
|
||||||
esbuild-linux-32 "0.13.14"
|
esbuild-freebsd-64 "0.14.54"
|
||||||
esbuild-linux-64 "0.13.14"
|
esbuild-freebsd-arm64 "0.14.54"
|
||||||
esbuild-linux-arm "0.13.14"
|
esbuild-linux-32 "0.14.54"
|
||||||
esbuild-linux-arm64 "0.13.14"
|
esbuild-linux-64 "0.14.54"
|
||||||
esbuild-linux-mips64le "0.13.14"
|
esbuild-linux-arm "0.14.54"
|
||||||
esbuild-linux-ppc64le "0.13.14"
|
esbuild-linux-arm64 "0.14.54"
|
||||||
esbuild-netbsd-64 "0.13.14"
|
esbuild-linux-mips64le "0.14.54"
|
||||||
esbuild-openbsd-64 "0.13.14"
|
esbuild-linux-ppc64le "0.14.54"
|
||||||
esbuild-sunos-64 "0.13.14"
|
esbuild-linux-riscv64 "0.14.54"
|
||||||
esbuild-windows-32 "0.13.14"
|
esbuild-linux-s390x "0.14.54"
|
||||||
esbuild-windows-64 "0.13.14"
|
esbuild-netbsd-64 "0.14.54"
|
||||||
esbuild-windows-arm64 "0.13.14"
|
esbuild-openbsd-64 "0.14.54"
|
||||||
|
esbuild-sunos-64 "0.14.54"
|
||||||
|
esbuild-windows-32 "0.14.54"
|
||||||
|
esbuild-windows-64 "0.14.54"
|
||||||
|
esbuild-windows-arm64 "0.14.54"
|
||||||
|
|
||||||
escalade@^3.1.1:
|
escalade@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
|
@ -3519,6 +3550,13 @@ is-core-module@^2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
|
|
||||||
|
is-core-module@^2.9.0:
|
||||||
|
version "2.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
|
||||||
|
integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
|
||||||
|
dependencies:
|
||||||
|
has "^1.0.3"
|
||||||
|
|
||||||
is-data-descriptor@^0.1.4:
|
is-data-descriptor@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
||||||
|
@ -4285,10 +4323,10 @@ kleur@^3.0.3:
|
||||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
||||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||||
|
|
||||||
kleur@^4.1.4:
|
kleur@^4.1.5:
|
||||||
version "4.1.4"
|
version "4.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d"
|
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
|
||||||
integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==
|
integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
|
||||||
|
|
||||||
lazy-ass@1.6.0, lazy-ass@^1.6.0:
|
lazy-ass@1.6.0, lazy-ass@^1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
|
@ -4425,6 +4463,13 @@ magic-string@^0.25.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
sourcemap-codec "^1.4.4"
|
sourcemap-codec "^1.4.4"
|
||||||
|
|
||||||
|
magic-string@^0.26.2:
|
||||||
|
version "0.26.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.2.tgz#5331700e4158cd6befda738bb6b0c7b93c0d4432"
|
||||||
|
integrity sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==
|
||||||
|
dependencies:
|
||||||
|
sourcemap-codec "^1.4.8"
|
||||||
|
|
||||||
make-dir@^3.0.0:
|
make-dir@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
|
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
|
||||||
|
@ -4615,10 +4660,10 @@ nanoid@^2.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
||||||
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
|
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
|
||||||
|
|
||||||
nanoid@^3.1.30:
|
nanoid@^3.3.4:
|
||||||
version "3.1.30"
|
version "3.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||||
integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==
|
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||||
|
|
||||||
nanomatch@^1.2.9:
|
nanomatch@^1.2.9:
|
||||||
version "1.2.13"
|
version "1.2.13"
|
||||||
|
@ -4887,7 +4932,7 @@ path-key@^3.0.0, path-key@^3.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||||
|
|
||||||
path-parse@^1.0.6:
|
path-parse@^1.0.6, path-parse@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||||
|
@ -4948,14 +4993,14 @@ posix-character-classes@^0.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||||
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
|
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
|
||||||
|
|
||||||
postcss@^8.3.8:
|
postcss@^8.4.16:
|
||||||
version "8.3.11"
|
version "8.4.16"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858"
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
|
||||||
integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA==
|
integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.1.30"
|
nanoid "^3.3.4"
|
||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
source-map-js "^0.6.2"
|
source-map-js "^1.0.2"
|
||||||
|
|
||||||
posthog-js@1.4.5:
|
posthog-js@1.4.5:
|
||||||
version "1.4.5"
|
version "1.4.5"
|
||||||
|
@ -5184,11 +5229,6 @@ require-main-filename@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||||
|
|
||||||
require-relative@^0.8.7:
|
|
||||||
version "0.8.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de"
|
|
||||||
integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=
|
|
||||||
|
|
||||||
resolve-cwd@^3.0.0:
|
resolve-cwd@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
|
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
|
||||||
|
@ -5206,7 +5246,7 @@ resolve-url@^0.2.1:
|
||||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||||
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
||||||
|
|
||||||
resolve@^1.10.0, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0:
|
resolve@^1.10.0, resolve@^1.14.2, resolve@^1.18.1:
|
||||||
version "1.20.0"
|
version "1.20.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||||
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||||
|
@ -5214,6 +5254,15 @@ resolve@^1.10.0, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0:
|
||||||
is-core-module "^2.2.0"
|
is-core-module "^2.2.0"
|
||||||
path-parse "^1.0.6"
|
path-parse "^1.0.6"
|
||||||
|
|
||||||
|
resolve@^1.22.1:
|
||||||
|
version "1.22.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||||
|
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||||
|
dependencies:
|
||||||
|
is-core-module "^2.9.0"
|
||||||
|
path-parse "^1.0.7"
|
||||||
|
supports-preserve-symlinks-flag "^1.0.0"
|
||||||
|
|
||||||
restore-cursor@^3.1.0:
|
restore-cursor@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
|
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
|
||||||
|
@ -5262,7 +5311,14 @@ rollup-pluginutils@^2.8.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
estree-walker "^0.6.1"
|
estree-walker "^0.6.1"
|
||||||
|
|
||||||
rollup@^2.44.0, rollup@^2.57.0:
|
"rollup@>=2.75.6 <2.77.0 || ~2.77.0":
|
||||||
|
version "2.77.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.3.tgz#8f00418d3a2740036e15deb653bed1a90ee0cc12"
|
||||||
|
integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
rollup@^2.44.0:
|
||||||
version "2.60.0"
|
version "2.60.0"
|
||||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.60.0.tgz#4ee60ab7bdd0356763f87d7099f413e5460fc193"
|
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.60.0.tgz#4ee60ab7bdd0356763f87d7099f413e5460fc193"
|
||||||
integrity sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==
|
integrity sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==
|
||||||
|
@ -5475,10 +5531,10 @@ snapdragon@^0.8.1:
|
||||||
source-map-resolve "^0.5.0"
|
source-map-resolve "^0.5.0"
|
||||||
use "^3.1.0"
|
use "^3.1.0"
|
||||||
|
|
||||||
source-map-js@^0.6.2:
|
source-map-js@^1.0.2:
|
||||||
version "0.6.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||||
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
|
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||||
|
|
||||||
source-map-resolve@^0.5.0:
|
source-map-resolve@^0.5.0:
|
||||||
version "0.5.3"
|
version "0.5.3"
|
||||||
|
@ -5527,7 +5583,7 @@ source-map@^0.7.3:
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||||
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
||||||
|
|
||||||
sourcemap-codec@^1.4.4:
|
sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8:
|
||||||
version "1.4.8"
|
version "1.4.8"
|
||||||
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||||
|
@ -5707,15 +5763,20 @@ supports-hyperlinks@^2.0.0:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
supports-color "^7.0.0"
|
supports-color "^7.0.0"
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||||
|
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||||
|
|
||||||
svelte-dnd-action@^0.9.8:
|
svelte-dnd-action@^0.9.8:
|
||||||
version "0.9.12"
|
version "0.9.12"
|
||||||
resolved "https://registry.yarnpkg.com/svelte-dnd-action/-/svelte-dnd-action-0.9.12.tgz#78cf33097986488c6d069eca517af473cd998730"
|
resolved "https://registry.yarnpkg.com/svelte-dnd-action/-/svelte-dnd-action-0.9.12.tgz#78cf33097986488c6d069eca517af473cd998730"
|
||||||
integrity sha512-GlXIB3/56IMR5A0+qUx+FX7Q7n8uCAIeuYdgSBmn9iOlxWc+mgM8P1kNwAKCMSTdQ4IQETVQILNgWVY1KIFzsg==
|
integrity sha512-GlXIB3/56IMR5A0+qUx+FX7Q7n8uCAIeuYdgSBmn9iOlxWc+mgM8P1kNwAKCMSTdQ4IQETVQILNgWVY1KIFzsg==
|
||||||
|
|
||||||
svelte-hmr@^0.14.7:
|
svelte-hmr@^0.14.12:
|
||||||
version "0.14.7"
|
version "0.14.12"
|
||||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.7.tgz#7fa8261c7b225d9409f0a86f3b9ea5c3ca6f6607"
|
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.12.tgz#a127aec02f1896500b10148b2d4d21ddde39973f"
|
||||||
integrity sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==
|
integrity sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==
|
||||||
|
|
||||||
svelte-jester@^1.3.2:
|
svelte-jester@^1.3.2:
|
||||||
version "1.8.2"
|
version "1.8.2"
|
||||||
|
@ -6081,15 +6142,15 @@ verror@1.10.0:
|
||||||
core-util-is "1.0.2"
|
core-util-is "1.0.2"
|
||||||
extsprintf "^1.2.0"
|
extsprintf "^1.2.0"
|
||||||
|
|
||||||
vite@^2.1.5:
|
vite@^3.0.8:
|
||||||
version "2.6.14"
|
version "3.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-2.6.14.tgz#35c09a15e4df823410819a2a239ab11efb186271"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.8.tgz#aa095ad8e3e5da46d9ec7e878f262678965d6531"
|
||||||
integrity sha512-2HA9xGyi+EhY2MXo0+A2dRsqsAG3eFNEVIo12olkWhOmc8LfiM+eMdrXf+Ruje9gdXgvSqjLI9freec1RUM5EA==
|
integrity sha512-AOZ4eN7mrkJiOLuw8IA7piS4IdOQyQCA81GxGsAQvAZzMRi9ZwGB3TOaYsj4uLAWK46T5L4AfQ6InNGlxX30IQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.13.2"
|
esbuild "^0.14.47"
|
||||||
postcss "^8.3.8"
|
postcss "^8.4.16"
|
||||||
resolve "^1.20.0"
|
resolve "^1.22.1"
|
||||||
rollup "^2.57.0"
|
rollup ">=2.75.6 <2.77.0 || ~2.77.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/cli",
|
"name": "@budibase/cli",
|
||||||
"version": "1.3.4-alpha.2",
|
"version": "1.3.15-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,14 +26,18 @@
|
||||||
"outputPath": "build"
|
"outputPath": "build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/backend-core": "1.3.4-alpha.2",
|
"@budibase/backend-core": "1.3.15-alpha.3",
|
||||||
|
"@budibase/string-templates": "1.3.15-alpha.3",
|
||||||
|
"@budibase/types": "1.3.15-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",
|
||||||
"commander": "7.1.0",
|
"commander": "7.1.0",
|
||||||
"docker-compose": "0.23.6",
|
"docker-compose": "0.23.6",
|
||||||
"dotenv": "16.0.1",
|
"dotenv": "16.0.1",
|
||||||
|
"download": "8.0.0",
|
||||||
"inquirer": "8.0.0",
|
"inquirer": "8.0.0",
|
||||||
|
"joi": "17.6.0",
|
||||||
"lookpath": "1.1.0",
|
"lookpath": "1.1.0",
|
||||||
"node-fetch": "2",
|
"node-fetch": "2",
|
||||||
"pkg": "5.7.0",
|
"pkg": "5.7.0",
|
||||||
|
|
|
@ -3,6 +3,7 @@ exports.CommandWords = {
|
||||||
HOSTING: "hosting",
|
HOSTING: "hosting",
|
||||||
ANALYTICS: "analytics",
|
ANALYTICS: "analytics",
|
||||||
HELP: "help",
|
HELP: "help",
|
||||||
|
PLUGIN: "plugins",
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.InitTypes = {
|
exports.InitTypes = {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
process.env.NO_JS = "1"
|
|
@ -0,0 +1,27 @@
|
||||||
|
const util = require("util")
|
||||||
|
const exec = util.promisify(require("child_process").exec)
|
||||||
|
|
||||||
|
exports.exec = async (command, dir = "./") => {
|
||||||
|
const { stdout } = await exec(command, { cwd: dir })
|
||||||
|
return stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.utilityInstalled = async utilName => {
|
||||||
|
try {
|
||||||
|
await exports.exec(`${utilName} --version`)
|
||||||
|
return true
|
||||||
|
} catch (err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.runPkgCommand = async (command, dir = "./") => {
|
||||||
|
const yarn = await exports.utilityInstalled("yarn")
|
||||||
|
const npm = await exports.utilityInstalled("npm")
|
||||||
|
if (!yarn && !npm) {
|
||||||
|
throw new Error("Must have yarn or npm installed to run build.")
|
||||||
|
}
|
||||||
|
const npmCmd = command === "install" ? `npm ${command}` : `npm run ${command}`
|
||||||
|
const cmd = yarn ? `yarn ${command}` : npmCmd
|
||||||
|
await exports.exec(cmd, dir)
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
require("./prebuilds")
|
require("./prebuilds")
|
||||||
|
require("./environment")
|
||||||
const { getCommands } = require("./options")
|
const { getCommands } = require("./options")
|
||||||
const { Command } = require("commander")
|
const { Command } = require("commander")
|
||||||
const { getHelpDescription } = require("./utils")
|
const { getHelpDescription } = require("./utils")
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
const analytics = require("./analytics")
|
const analytics = require("./analytics")
|
||||||
const hosting = require("./hosting")
|
const hosting = require("./hosting")
|
||||||
const backups = require("./backups")
|
const backups = require("./backups")
|
||||||
|
const plugins = require("./plugins")
|
||||||
|
|
||||||
exports.getCommands = () => {
|
exports.getCommands = () => {
|
||||||
return [hosting.command, analytics.command, backups.command]
|
return [hosting.command, analytics.command, backups.command, plugins.command]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
const Command = require("../structures/Command")
|
||||||
|
const { CommandWords } = require("../constants")
|
||||||
|
const { getSkeleton, fleshOutSkeleton } = require("./skeleton")
|
||||||
|
const questions = require("../questions")
|
||||||
|
const fs = require("fs")
|
||||||
|
const { PLUGIN_TYPE_ARR } = require("@budibase/types")
|
||||||
|
const { validate } = require("@budibase/backend-core/plugins")
|
||||||
|
const { runPkgCommand } = require("../exec")
|
||||||
|
const { join } = require("path")
|
||||||
|
const { success, error, info } = require("../utils")
|
||||||
|
|
||||||
|
function checkInPlugin() {
|
||||||
|
if (!fs.existsSync("package.json")) {
|
||||||
|
throw new Error(
|
||||||
|
"Please run in a plugin directory - must contain package.json"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!fs.existsSync("schema.json")) {
|
||||||
|
throw new Error(
|
||||||
|
"Please run in a plugin directory - must contain schema.json"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init(opts) {
|
||||||
|
const type = opts["init"] || opts
|
||||||
|
if (!type || !PLUGIN_TYPE_ARR.includes(type)) {
|
||||||
|
console.log(
|
||||||
|
error(
|
||||||
|
"Please provide a type to init, either 'component' or 'datasource'."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(info("Lets get some details about your new plugin:"))
|
||||||
|
const name = await questions.string("Name", `budibase-${type}`)
|
||||||
|
if (fs.existsSync(name)) {
|
||||||
|
console.log(
|
||||||
|
error("Directory by plugin name already exists, pick a new name.")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const desc = await questions.string(
|
||||||
|
"Description",
|
||||||
|
`An amazing Budibase ${type}!`
|
||||||
|
)
|
||||||
|
const version = await questions.string("Version", "1.0.0")
|
||||||
|
// get the skeleton
|
||||||
|
console.log(info("Retrieving project..."))
|
||||||
|
await getSkeleton(type, name)
|
||||||
|
await fleshOutSkeleton(type, name, desc, version)
|
||||||
|
console.log(info("Installing dependencies..."))
|
||||||
|
await runPkgCommand("install", join(process.cwd(), name))
|
||||||
|
console.log(info(`Plugin created in directory "${name}"`))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verify() {
|
||||||
|
// will throw errors if not acceptable
|
||||||
|
checkInPlugin()
|
||||||
|
console.log(info("Verifying plugin..."))
|
||||||
|
const schema = fs.readFileSync("schema.json", "utf8")
|
||||||
|
const pkg = fs.readFileSync("package.json", "utf8")
|
||||||
|
let name, version
|
||||||
|
try {
|
||||||
|
const schemaJson = JSON.parse(schema)
|
||||||
|
const pkgJson = JSON.parse(pkg)
|
||||||
|
if (!pkgJson.name || !pkgJson.version || !pkgJson.description) {
|
||||||
|
throw new Error(
|
||||||
|
"package.json is missing one of 'name', 'version' or 'description'."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
name = pkgJson.name
|
||||||
|
version = pkgJson.version
|
||||||
|
validate(schemaJson)
|
||||||
|
return { name, version }
|
||||||
|
} catch (err) {
|
||||||
|
if (err && err.message && err.message.includes("not valid JSON")) {
|
||||||
|
console.log(error(`schema.json is not valid JSON: ${err.message}`))
|
||||||
|
} else {
|
||||||
|
console.log(error(`Invalid schema/package.json: ${err.message}`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function build() {
|
||||||
|
const verified = await verify()
|
||||||
|
if (!verified.name) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(success("Verified!"))
|
||||||
|
console.log(info("Building plugin..."))
|
||||||
|
await runPkgCommand("build")
|
||||||
|
const output = join("dist", `${verified.name}-${verified.version}.tar.gz`)
|
||||||
|
console.log(success(`Build complete - output in: ${output}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function watch() {
|
||||||
|
const verified = await verify()
|
||||||
|
if (!verified.name) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const output = join("dist", `${verified.name}-${verified.version}.tar.gz`)
|
||||||
|
console.log(info(`Watching - build in: ${output}`))
|
||||||
|
try {
|
||||||
|
await runPkgCommand("watch")
|
||||||
|
} catch (err) {
|
||||||
|
// always errors when user escapes
|
||||||
|
console.log(success("Watch exited."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = new Command(`${CommandWords.PLUGIN}`)
|
||||||
|
.addHelp(
|
||||||
|
"Custom plugins for Budibase, init, build and verify your components and datasources with this tool."
|
||||||
|
)
|
||||||
|
.addSubOption(
|
||||||
|
"--init [type]",
|
||||||
|
"Init a new plugin project, with a type of either component or datasource.",
|
||||||
|
init
|
||||||
|
)
|
||||||
|
.addSubOption(
|
||||||
|
"--build",
|
||||||
|
"Build your plugin, this will verify and produce a final tarball for your project.",
|
||||||
|
build
|
||||||
|
)
|
||||||
|
.addSubOption(
|
||||||
|
"--watch",
|
||||||
|
"Automatically build any changes to your plugin.",
|
||||||
|
watch
|
||||||
|
)
|
||||||
|
|
||||||
|
exports.command = command
|
|
@ -0,0 +1,60 @@
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
const download = require("download")
|
||||||
|
const fs = require("fs")
|
||||||
|
const os = require("os")
|
||||||
|
const { join } = require("path")
|
||||||
|
const tar = require("tar")
|
||||||
|
const { processStringSync } = require("@budibase/string-templates")
|
||||||
|
|
||||||
|
const HBS_FILES = ["package.json.hbs", "schema.json.hbs", "README.md.hbs"]
|
||||||
|
|
||||||
|
async function getSkeletonUrl(type) {
|
||||||
|
const resp = await fetch(
|
||||||
|
"https://api.github.com/repos/budibase/budibase-skeleton/releases/latest"
|
||||||
|
)
|
||||||
|
if (resp.status >= 300) {
|
||||||
|
throw new Error("Failed to retrieve skeleton metadata")
|
||||||
|
}
|
||||||
|
const json = await resp.json()
|
||||||
|
for (let asset of json["assets"]) {
|
||||||
|
if (asset.name && asset.name.includes(type)) {
|
||||||
|
return asset["browser_download_url"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error("No skeleton found in latest release.")
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getSkeleton = async (type, name) => {
|
||||||
|
const url = await getSkeletonUrl(type)
|
||||||
|
const tarballFile = join(os.tmpdir(), "skeleton.tar.gz")
|
||||||
|
|
||||||
|
// download the full skeleton tarball
|
||||||
|
fs.writeFileSync(tarballFile, await download(url))
|
||||||
|
fs.mkdirSync(name)
|
||||||
|
// extract it and get what we need
|
||||||
|
await tar.extract({
|
||||||
|
file: tarballFile,
|
||||||
|
C: name,
|
||||||
|
})
|
||||||
|
// clear up
|
||||||
|
fs.rmSync(tarballFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.fleshOutSkeleton = async (type, name, description, version) => {
|
||||||
|
for (let file of HBS_FILES) {
|
||||||
|
const oldFile = join(name, file),
|
||||||
|
newFile = join(name, file.substring(0, file.length - 4))
|
||||||
|
const hbsContents = fs.readFileSync(oldFile, "utf8")
|
||||||
|
if (!hbsContents) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const output = processStringSync(hbsContents, {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
version,
|
||||||
|
})
|
||||||
|
// write the updated file and remove the HBS file
|
||||||
|
fs.writeFileSync(newFile, output)
|
||||||
|
fs.rmSync(oldFile)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
const os = require("os")
|
const os = require("os")
|
||||||
const { join } = require("path")
|
const { join } = require("path")
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
|
const { error } = require("./utils")
|
||||||
const PREBUILDS = "prebuilds"
|
const PREBUILDS = "prebuilds"
|
||||||
const ARCH = `${os.platform()}-${os.arch()}`
|
const ARCH = `${os.platform()}-${os.arch()}`
|
||||||
const PREBUILD_DIR = join(process.execPath, "..", PREBUILDS, ARCH)
|
const PREBUILD_DIR = join(process.execPath, "..", PREBUILDS, ARCH)
|
||||||
|
|
||||||
checkForBinaries()
|
// running as built CLI pkg bundle
|
||||||
|
if (!process.argv[0].includes("node")) {
|
||||||
|
checkForBinaries()
|
||||||
|
}
|
||||||
|
|
||||||
function checkForBinaries() {
|
function checkForBinaries() {
|
||||||
const readDir = join(__filename, "..", "..", PREBUILDS, ARCH)
|
const readDir = join(__filename, "..", "..", PREBUILDS, ARCH)
|
||||||
|
@ -22,7 +26,15 @@ function checkForBinaries() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup(evt) {
|
||||||
|
if (evt && evt.errno) {
|
||||||
|
console.error(
|
||||||
|
error(
|
||||||
|
"Failed to run CLI command - please report with the following message:"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
console.error(error(evt))
|
||||||
|
}
|
||||||
if (fs.existsSync(PREBUILD_DIR)) {
|
if (fs.existsSync(PREBUILD_DIR)) {
|
||||||
fs.rmSync(PREBUILD_DIR, { recursive: true })
|
fs.rmSync(PREBUILD_DIR, { recursive: true })
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/client",
|
"name": "@budibase/client",
|
||||||
"version": "1.3.4-alpha.2",
|
"version": "1.3.15-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.4-alpha.2",
|
"@budibase/bbui": "1.3.15-alpha.3",
|
||||||
"@budibase/frontend-core": "1.3.4-alpha.2",
|
"@budibase/frontend-core": "1.3.15-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.4-alpha.2",
|
"@budibase/string-templates": "1.3.15-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",
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
"sanitize-html": "^2.7.0",
|
"sanitize-html": "^2.7.0",
|
||||||
"screenfull": "^6.0.1",
|
"screenfull": "^6.0.1",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
|
"socket.io-client": "^4.5.1",
|
||||||
"svelte": "^3.49.0",
|
"svelte": "^3.49.0",
|
||||||
"svelte-apexcharts": "^1.0.2",
|
"svelte-apexcharts": "^1.0.2",
|
||||||
"svelte-flatpickr": "^3.1.0",
|
"svelte-flatpickr": "^3.1.0",
|
||||||
|
|
|
@ -89,6 +89,14 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
{#if $builderStore.usedPlugins?.length}
|
||||||
|
{#each $builderStore.usedPlugins as plugin (plugin.hash)}
|
||||||
|
<script src={`/plugins/${plugin.jsUrl}?r=${plugin.hash || ""}`}></script>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
{#if dataLoaded}
|
{#if dataLoaded}
|
||||||
<div
|
<div
|
||||||
id="spectrum-root"
|
id="spectrum-root"
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext, setContext, onMount, onDestroy } from "svelte"
|
import { getContext, setContext, onMount, onDestroy } from "svelte"
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import * as AppComponents from "components/app"
|
|
||||||
import Router from "./Router.svelte"
|
|
||||||
import {
|
import {
|
||||||
enrichProps,
|
enrichProps,
|
||||||
propsAreSame,
|
propsAreSame,
|
||||||
|
@ -127,7 +125,9 @@
|
||||||
// Empty components are those which accept children but do not have any.
|
// Empty components are those which accept children but do not have any.
|
||||||
// Empty states can be shown for these components, but can be disabled
|
// Empty states can be shown for these components, but can be disabled
|
||||||
// in the component manifest.
|
// in the component manifest.
|
||||||
$: empty = interactive && !children.length && hasChildren
|
$: empty =
|
||||||
|
(interactive && !children.length && hasChildren) ||
|
||||||
|
hasMissingRequiredSettings
|
||||||
$: emptyState = empty && showEmptyState
|
$: emptyState = empty && showEmptyState
|
||||||
|
|
||||||
// Enrich component settings
|
// Enrich component settings
|
||||||
|
@ -165,14 +165,14 @@
|
||||||
missingRequiredSettings,
|
missingRequiredSettings,
|
||||||
})
|
})
|
||||||
|
|
||||||
const initialise = instance => {
|
const initialise = (instance, force = false) => {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we're processing a new instance
|
// Ensure we're processing a new instance
|
||||||
const instanceKey = Helpers.hashString(JSON.stringify(instance))
|
const instanceKey = Helpers.hashString(JSON.stringify(instance))
|
||||||
if (instanceKey === lastInstanceKey) {
|
if (instanceKey === lastInstanceKey && !force) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
lastInstanceKey = instanceKey
|
lastInstanceKey = instanceKey
|
||||||
|
@ -180,7 +180,7 @@
|
||||||
|
|
||||||
// Pull definition and constructor
|
// Pull definition and constructor
|
||||||
const component = instance._component
|
const component = instance._component
|
||||||
constructor = getComponentConstructor(component)
|
constructor = componentStore.actions.getComponentConstructor(component)
|
||||||
definition = componentStore.actions.getComponentDefinition(component)
|
definition = componentStore.actions.getComponentDefinition(component)
|
||||||
if (!definition) {
|
if (!definition) {
|
||||||
return
|
return
|
||||||
|
@ -237,16 +237,6 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the component constructor for the specified component
|
|
||||||
const getComponentConstructor = component => {
|
|
||||||
const split = component?.split("/")
|
|
||||||
const name = split?.[split.length - 1]
|
|
||||||
if (name === "screenslot" && !insideScreenslot) {
|
|
||||||
return Router
|
|
||||||
}
|
|
||||||
return AppComponents[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSettingsDefinitionMap = settingsDefinition => {
|
const getSettingsDefinitionMap = settingsDefinition => {
|
||||||
let map = {}
|
let map = {}
|
||||||
settingsDefinition?.forEach(setting => {
|
settingsDefinition?.forEach(setting => {
|
||||||
|
@ -419,9 +409,11 @@
|
||||||
!componentStore.actions.isComponentRegistered(id)
|
!componentStore.actions.isComponentRegistered(id)
|
||||||
) {
|
) {
|
||||||
componentStore.actions.registerInstance(id, {
|
componentStore.actions.registerInstance(id, {
|
||||||
|
component: instance._component,
|
||||||
getSettings: () => cachedSettings,
|
getSettings: () => cachedSettings,
|
||||||
getRawSettings: () => ({ ...staticSettings, ...dynamicSettings }),
|
getRawSettings: () => ({ ...staticSettings, ...dynamicSettings }),
|
||||||
getDataContext: () => get(context),
|
getDataContext: () => get(context),
|
||||||
|
reload: () => initialise(instance, true),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,28 +2,25 @@
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { builderStore } from "stores"
|
import { builderStore } from "stores"
|
||||||
|
|
||||||
const { styleable } = getContext("sdk")
|
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
|
||||||
$: requiredSetting = $component.missingRequiredSettings?.[0]
|
$: requiredSetting = $component.missingRequiredSettings?.[0]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $builderStore.inBuilder && requiredSetting}
|
{#if $builderStore.inBuilder && requiredSetting}
|
||||||
<div use:styleable={$component.styles}>
|
<div class="component-placeholder">
|
||||||
<div class="component-placeholder">
|
<span>
|
||||||
<span>
|
Add the <mark>{requiredSetting.label}</mark> setting to start using your component
|
||||||
Add the <mark>{requiredSetting.label}</mark> setting to start using your
|
-
|
||||||
component -
|
</span>
|
||||||
</span>
|
<span
|
||||||
<span
|
class="spectrum-Link"
|
||||||
class="spectrum-Link"
|
on:click={() => {
|
||||||
on:click={() => {
|
builderStore.actions.highlightSetting(requiredSetting.key)
|
||||||
builderStore.actions.highlightSetting(requiredSetting.key)
|
}}
|
||||||
}}
|
>
|
||||||
>
|
Show me
|
||||||
Show me
|
</span>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { ProgressCircle, Pagination } from "@budibase/bbui"
|
import { ProgressCircle, Pagination } from "@budibase/bbui"
|
||||||
import Placeholder from "./Placeholder.svelte"
|
|
||||||
import { fetchData, LuceneUtils } from "@budibase/frontend-core"
|
import { fetchData, LuceneUtils } from "@budibase/frontend-core"
|
||||||
|
|
||||||
export let dataSource
|
export let dataSource
|
||||||
|
@ -133,11 +132,7 @@
|
||||||
<ProgressCircle />
|
<ProgressCircle />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
{#if $component.emptyState}
|
<slot />
|
||||||
<Placeholder />
|
|
||||||
{:else}
|
|
||||||
<slot />
|
|
||||||
{/if}
|
|
||||||
{#if paginate && $fetch.supportsPagination}
|
{#if paginate && $fetch.supportsPagination}
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
<Pagination
|
<Pagination
|
||||||
|
|
|
@ -19,7 +19,10 @@
|
||||||
label="Active screen"
|
label="Active screen"
|
||||||
value={$screenStore.activeScreen?.routing.route}
|
value={$screenStore.activeScreen?.routing.route}
|
||||||
/>
|
/>
|
||||||
<DevToolsStat label="Components" value={$componentStore.mountedComponents} />
|
<DevToolsStat
|
||||||
|
label="Components"
|
||||||
|
value={$componentStore.mountedComponentCount}
|
||||||
|
/>
|
||||||
<DevToolsStat label="User" value={$authStore.email} />
|
<DevToolsStat label="User" value={$authStore.email} />
|
||||||
<DevToolsStat label="Role" value={$authStore.roleId} />
|
<DevToolsStat label="Role" value={$authStore.roleId} />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
import ClientApp from "./components/ClientApp.svelte"
|
import ClientApp from "./components/ClientApp.svelte"
|
||||||
import { builderStore, appStore, devToolsStore, blockStore } from "./stores"
|
import {
|
||||||
|
builderStore,
|
||||||
|
appStore,
|
||||||
|
devToolsStore,
|
||||||
|
blockStore,
|
||||||
|
componentStore,
|
||||||
|
} from "./stores"
|
||||||
import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-rollup.js"
|
import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-rollup.js"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
|
import { initWebsocket } from "./websocket.js"
|
||||||
|
|
||||||
|
// Provide svelte and svelte/internal as globals for custom components
|
||||||
|
import * as svelte from "svelte"
|
||||||
|
import * as internal from "svelte/internal"
|
||||||
|
window.svelte_internal = internal
|
||||||
|
window.svelte = svelte
|
||||||
|
|
||||||
// Initialise spectrum icons
|
// Initialise spectrum icons
|
||||||
loadSpectrumIcons()
|
loadSpectrumIcons()
|
||||||
|
@ -21,6 +34,8 @@ const loadBudibase = () => {
|
||||||
previewDevice: window["##BUDIBASE_PREVIEW_DEVICE##"],
|
previewDevice: window["##BUDIBASE_PREVIEW_DEVICE##"],
|
||||||
navigation: window["##BUDIBASE_PREVIEW_NAVIGATION##"],
|
navigation: window["##BUDIBASE_PREVIEW_NAVIGATION##"],
|
||||||
hiddenComponentIds: window["##BUDIBASE_HIDDEN_COMPONENT_IDS##"],
|
hiddenComponentIds: window["##BUDIBASE_HIDDEN_COMPONENT_IDS##"],
|
||||||
|
usedPlugins: window["##BUDIBASE_USED_PLUGINS##"],
|
||||||
|
location: window["##BUDIBASE_LOCATION##"],
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set app ID - this window flag is set by both the preview and the real
|
// Set app ID - this window flag is set by both the preview and the real
|
||||||
|
@ -43,6 +58,21 @@ const loadBudibase = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register any custom components
|
||||||
|
if (window["##BUDIBASE_CUSTOM_COMPONENTS##"]) {
|
||||||
|
window["##BUDIBASE_CUSTOM_COMPONENTS##"].forEach(component => {
|
||||||
|
componentStore.actions.registerCustomComponent(component)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a callback available for custom component bundles to register
|
||||||
|
// themselves at runtime
|
||||||
|
window.registerCustomComponent =
|
||||||
|
componentStore.actions.registerCustomComponent
|
||||||
|
|
||||||
|
// Initialise websocket
|
||||||
|
initWebsocket()
|
||||||
|
|
||||||
// Create app if one hasn't been created yet
|
// Create app if one hasn't been created yet
|
||||||
if (!app) {
|
if (!app) {
|
||||||
app = new ClientApp({
|
app = new ClientApp({
|
||||||
|
|
|
@ -19,6 +19,7 @@ const createBuilderStore = () => {
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
navigation: null,
|
navigation: null,
|
||||||
hiddenComponentIds: [],
|
hiddenComponentIds: [],
|
||||||
|
usedPlugins: null,
|
||||||
|
|
||||||
// Legacy - allow the builder to specify a layout
|
// Legacy - allow the builder to specify a layout
|
||||||
layout: null,
|
layout: null,
|
||||||
|
@ -87,6 +88,20 @@ const createBuilderStore = () => {
|
||||||
ejectBlock: (id, definition) => {
|
ejectBlock: (id, definition) => {
|
||||||
dispatchEvent("eject-block", { id, definition })
|
dispatchEvent("eject-block", { id, definition })
|
||||||
},
|
},
|
||||||
|
updateUsedPlugin: (name, hash) => {
|
||||||
|
// Check if we used this plugin
|
||||||
|
const used = get(store)?.usedPlugins?.find(x => x.name === name)
|
||||||
|
if (used) {
|
||||||
|
store.update(state => {
|
||||||
|
state.usedPlugins = state.usedPlugins.filter(x => x.name !== name)
|
||||||
|
state.usedPlugins.push({
|
||||||
|
...used,
|
||||||
|
hash,
|
||||||
|
})
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...store,
|
...store,
|
||||||
|
|
|
@ -4,9 +4,17 @@ import { findComponentById, findComponentPathById } from "../utils/components"
|
||||||
import { devToolsStore } from "./devTools"
|
import { devToolsStore } from "./devTools"
|
||||||
import { screenStore } from "./screens"
|
import { screenStore } from "./screens"
|
||||||
import { builderStore } from "./builder"
|
import { builderStore } from "./builder"
|
||||||
|
import Router from "../components/Router.svelte"
|
||||||
|
import * as AppComponents from "../components/app/index.js"
|
||||||
|
|
||||||
|
const budibasePrefix = "@budibase/standard-components/"
|
||||||
|
|
||||||
const createComponentStore = () => {
|
const createComponentStore = () => {
|
||||||
const store = writable({})
|
const store = writable({
|
||||||
|
customComponentManifest: {},
|
||||||
|
customComponentMap: {},
|
||||||
|
mountedComponents: {},
|
||||||
|
})
|
||||||
|
|
||||||
const derivedStore = derived(
|
const derivedStore = derived(
|
||||||
[store, builderStore, devToolsStore, screenStore],
|
[store, builderStore, devToolsStore, screenStore],
|
||||||
|
@ -25,41 +33,65 @@ const createComponentStore = () => {
|
||||||
asset = $screenState.activeScreen
|
asset = $screenState.activeScreen
|
||||||
}
|
}
|
||||||
const component = findComponentById(asset?.props, selectedComponentId)
|
const component = findComponentById(asset?.props, selectedComponentId)
|
||||||
const prefix = "@budibase/standard-components/"
|
const definition = getComponentDefinition(component?._component)
|
||||||
const type = component?._component?.replace(prefix, "")
|
|
||||||
const definition = type ? Manifest[type] : null
|
|
||||||
|
|
||||||
// Derive the selected component path
|
// Derive the selected component path
|
||||||
const path =
|
const path =
|
||||||
findComponentPathById(asset?.props, selectedComponentId) || []
|
findComponentPathById(asset?.props, selectedComponentId) || []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedComponentInstance: $store[selectedComponentId],
|
customComponentManifest: $store.customComponentManifest,
|
||||||
|
selectedComponentInstance:
|
||||||
|
$store.mountedComponents[selectedComponentId],
|
||||||
selectedComponent: component,
|
selectedComponent: component,
|
||||||
selectedComponentDefinition: definition,
|
selectedComponentDefinition: definition,
|
||||||
selectedComponentPath: path?.map(component => component._id),
|
selectedComponentPath: path?.map(component => component._id),
|
||||||
mountedComponents: Object.keys($store).length,
|
mountedComponentCount: Object.keys($store.mountedComponents).length,
|
||||||
currentAsset: asset,
|
currentAsset: asset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const registerInstance = (id, instance) => {
|
const registerInstance = (id, instance) => {
|
||||||
store.update(state => ({
|
store.update(state => {
|
||||||
...state,
|
// If this is a custom component, flag it so we can reload this component
|
||||||
[id]: instance,
|
// later if required
|
||||||
}))
|
const component = instance.component
|
||||||
|
if (component?.startsWith("plugin")) {
|
||||||
|
if (!state.customComponentMap[component]) {
|
||||||
|
state.customComponentMap[component] = [id]
|
||||||
|
} else {
|
||||||
|
state.customComponentMap[component].push(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register to mounted components
|
||||||
|
state.mountedComponents[id] = instance
|
||||||
|
return state
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const unregisterInstance = id => {
|
const unregisterInstance = id => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
delete state[id]
|
// Remove from custom component map if required
|
||||||
|
const component = state.mountedComponents[id]?.instance?.component
|
||||||
|
let customComponentMap = state.customComponentMap
|
||||||
|
if (component?.startsWith("plugin")) {
|
||||||
|
customComponentMap[component] = customComponentMap[component].filter(
|
||||||
|
x => {
|
||||||
|
return x !== id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from mounted components
|
||||||
|
delete state.mountedComponents[id]
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const isComponentRegistered = id => {
|
const isComponentRegistered = id => {
|
||||||
return get(store)[id] != null
|
return get(store).mountedComponents[id] != null
|
||||||
}
|
}
|
||||||
|
|
||||||
const getComponentById = id => {
|
const getComponentById = id => {
|
||||||
|
@ -68,9 +100,66 @@ const createComponentStore = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getComponentDefinition = type => {
|
const getComponentDefinition = type => {
|
||||||
const prefix = "@budibase/standard-components/"
|
if (!type) {
|
||||||
type = type?.replace(prefix, "")
|
return null
|
||||||
return type ? Manifest[type] : null
|
}
|
||||||
|
|
||||||
|
// Screenslot is an edge case
|
||||||
|
if (type === "screenslot") {
|
||||||
|
type = `${budibasePrefix}${type}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle built-in components
|
||||||
|
if (type.startsWith(budibasePrefix)) {
|
||||||
|
type = type.replace(budibasePrefix, "")
|
||||||
|
return type ? Manifest[type] : null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle custom components
|
||||||
|
const { customComponentManifest } = get(store)
|
||||||
|
return customComponentManifest?.[type]?.schema?.schema
|
||||||
|
}
|
||||||
|
|
||||||
|
const getComponentConstructor = type => {
|
||||||
|
if (!type) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (type === "screenslot") {
|
||||||
|
return Router
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle budibase components
|
||||||
|
if (type.startsWith(budibasePrefix)) {
|
||||||
|
const split = type.split("/")
|
||||||
|
const name = split[split.length - 1]
|
||||||
|
return AppComponents[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle custom components
|
||||||
|
const { customComponentManifest } = get(store)
|
||||||
|
return customComponentManifest?.[type]?.Component
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerCustomComponent = ({ Component, schema, version }) => {
|
||||||
|
if (!Component || !schema?.schema?.name || !version) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const component = `plugin/${schema.schema.name}`
|
||||||
|
store.update(state => {
|
||||||
|
state.customComponentManifest[component] = {
|
||||||
|
Component,
|
||||||
|
schema,
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
|
||||||
|
// Reload any mounted instances of this custom component
|
||||||
|
const state = get(store)
|
||||||
|
if (state.customComponentMap[component]?.length) {
|
||||||
|
state.customComponentMap[component].forEach(id => {
|
||||||
|
state.mountedComponents[id]?.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -81,6 +170,8 @@ const createComponentStore = () => {
|
||||||
isComponentRegistered,
|
isComponentRegistered,
|
||||||
getComponentById,
|
getComponentById,
|
||||||
getComponentDefinition,
|
getComponentDefinition,
|
||||||
|
getComponentConstructor,
|
||||||
|
registerCustomComponent,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { builderStore } from "./stores/index.js"
|
||||||
|
import { get } from "svelte/store"
|
||||||
|
import { io } from "socket.io-client"
|
||||||
|
|
||||||
|
export const initWebsocket = () => {
|
||||||
|
const { inBuilder, location } = get(builderStore)
|
||||||
|
|
||||||
|
// Only connect when we're inside the builder preview, for now
|
||||||
|
if (!inBuilder || !location) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise connection
|
||||||
|
const tls = location.protocol === "https:"
|
||||||
|
const proto = tls ? "wss:" : "ws:"
|
||||||
|
const host = location.hostname
|
||||||
|
const port = location.port || (tls ? 443 : 80)
|
||||||
|
const socket = io(`${proto}//${host}:${port}`, {
|
||||||
|
path: "/socket/client",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Event handlers
|
||||||
|
socket.on("plugin-update", data => {
|
||||||
|
builderStore.actions.updateUsedPlugin(data.name, data.hash)
|
||||||
|
})
|
||||||
|
}
|
|
@ -113,6 +113,11 @@
|
||||||
estree-walker "^1.0.1"
|
estree-walker "^1.0.1"
|
||||||
picomatch "^2.2.2"
|
picomatch "^2.2.2"
|
||||||
|
|
||||||
|
"@socket.io/component-emitter@~3.1.0":
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
|
||||||
|
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
|
||||||
|
|
||||||
"@spectrum-css/button@^3.0.3":
|
"@spectrum-css/button@^3.0.3":
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84"
|
resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84"
|
||||||
|
@ -469,6 +474,13 @@ dayjs@^1.10.5:
|
||||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.8.tgz#267df4bc6276fcb33c04a6735287e3f429abec41"
|
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.8.tgz#267df4bc6276fcb33c04a6735287e3f429abec41"
|
||||||
integrity sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow==
|
integrity sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow==
|
||||||
|
|
||||||
|
debug@~4.3.1, debug@~4.3.2:
|
||||||
|
version "4.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||||
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
|
dependencies:
|
||||||
|
ms "2.1.2"
|
||||||
|
|
||||||
deepmerge@^4.2.2:
|
deepmerge@^4.2.2:
|
||||||
version "4.2.2"
|
version "4.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||||
|
@ -536,6 +548,22 @@ emojis-list@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
|
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
|
||||||
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
|
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
|
||||||
|
|
||||||
|
engine.io-client@~6.2.1:
|
||||||
|
version "6.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.2.2.tgz#c6c5243167f5943dcd9c4abee1bfc634aa2cbdd0"
|
||||||
|
integrity sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
engine.io-parser "~5.0.3"
|
||||||
|
ws "~8.2.3"
|
||||||
|
xmlhttprequest-ssl "~2.0.0"
|
||||||
|
|
||||||
|
engine.io-parser@~5.0.3:
|
||||||
|
version "5.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0"
|
||||||
|
integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==
|
||||||
|
|
||||||
entities@^2.0.0:
|
entities@^2.0.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
||||||
|
@ -824,6 +852,11 @@ minimist@^1.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||||
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||||
|
|
||||||
|
ms@2.1.2:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||||
|
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
|
||||||
nanoid@^2.1.0:
|
nanoid@^2.1.0:
|
||||||
version "2.1.11"
|
version "2.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
||||||
|
@ -1389,6 +1422,24 @@ slash@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
|
socket.io-client@^4.5.1:
|
||||||
|
version "4.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.5.1.tgz#cab8da71976a300d3090414e28c2203a47884d84"
|
||||||
|
integrity sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.2"
|
||||||
|
engine.io-client "~6.2.1"
|
||||||
|
socket.io-parser "~4.2.0"
|
||||||
|
|
||||||
|
socket.io-parser@~4.2.0:
|
||||||
|
version "4.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5"
|
||||||
|
integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
|
||||||
source-map-js@^1.0.1, source-map-js@^1.0.2:
|
source-map-js@^1.0.1, source-map-js@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||||
|
@ -1598,6 +1649,16 @@ wrappy@1:
|
||||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||||
|
|
||||||
|
ws@~8.2.3:
|
||||||
|
version "8.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
|
||||||
|
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@~2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"
|
||||||
|
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==
|
||||||
|
|
||||||
y18n@^5.0.5:
|
y18n@^5.0.5:
|
||||||
version "5.0.8"
|
version "5.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/frontend-core",
|
"name": "@budibase/frontend-core",
|
||||||
"version": "1.3.4-alpha.2",
|
"version": "1.3.15-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.4-alpha.2",
|
"@budibase/bbui": "1.3.15-alpha.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"svelte": "^3.46.2"
|
"svelte": "^3.46.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,14 @@ export const buildDatasourceEndpoints = API => ({
|
||||||
/**
|
/**
|
||||||
* Prompts the server to build the schema for a datasource.
|
* Prompts the server to build the schema for a datasource.
|
||||||
* @param datasourceId the datasource ID to build the schema for
|
* @param datasourceId the datasource ID to build the schema for
|
||||||
|
* @param tablesFilter list of specific table names to be build the schema
|
||||||
*/
|
*/
|
||||||
buildDatasourceSchema: async datasourceId => {
|
buildDatasourceSchema: async ({ datasourceId, tablesFilter }) => {
|
||||||
return await API.post({
|
return await API.post({
|
||||||
url: `/api/datasources/${datasourceId}/schema`,
|
url: `/api/datasources/${datasourceId}/schema`,
|
||||||
|
body: {
|
||||||
|
tablesFilter,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { buildSelfEndpoints } from "./self"
|
||||||
import { buildViewEndpoints } from "./views"
|
import { buildViewEndpoints } from "./views"
|
||||||
import { buildLicensingEndpoints } from "./licensing"
|
import { buildLicensingEndpoints } from "./licensing"
|
||||||
import { buildGroupsEndpoints } from "./groups"
|
import { buildGroupsEndpoints } from "./groups"
|
||||||
|
import { buildPluginEndpoints } from "./plugins"
|
||||||
|
|
||||||
const defaultAPIClientConfig = {
|
const defaultAPIClientConfig = {
|
||||||
/**
|
/**
|
||||||
|
@ -243,5 +244,6 @@ export const createAPIClient = config => {
|
||||||
...buildSelfEndpoints(API),
|
...buildSelfEndpoints(API),
|
||||||
...buildLicensingEndpoints(API),
|
...buildLicensingEndpoints(API),
|
||||||
...buildGroupsEndpoints(API),
|
...buildGroupsEndpoints(API),
|
||||||
|
...buildPluginEndpoints(API),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
export const buildPluginEndpoints = API => ({
|
||||||
|
/**
|
||||||
|
* Uploads a plugin tarball bundle
|
||||||
|
* @param data the plugin tarball bundle to upload
|
||||||
|
*/
|
||||||
|
uploadPlugin: async data => {
|
||||||
|
return await API.post({
|
||||||
|
url: `/api/plugin/upload`,
|
||||||
|
body: data,
|
||||||
|
json: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a plugin from URL, Github or NPM
|
||||||
|
*/
|
||||||
|
createPlugin: async data => {
|
||||||
|
return await API.post({
|
||||||
|
url: `/api/plugin`,
|
||||||
|
body: data,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of all plugins
|
||||||
|
*/
|
||||||
|
getPlugins: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/plugin",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a plugin.
|
||||||
|
* @param pluginId the ID of the plugin to delete
|
||||||
|
*
|
||||||
|
* * @param pluginId the revision of the plugin to delete
|
||||||
|
*/
|
||||||
|
deletePlugin: async pluginId => {
|
||||||
|
return await API.delete({
|
||||||
|
url: `/api/plugin/${pluginId}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
|
@ -80,6 +80,19 @@ const cleanupQuery = query => {
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a numeric prefix on field names designed to give fields uniqueness
|
||||||
|
*/
|
||||||
|
const removeKeyNumbering = key => {
|
||||||
|
if (typeof key === "string" && key.match(/\d[0-9]*:/g) != null) {
|
||||||
|
const parts = key.split(":")
|
||||||
|
parts.shift()
|
||||||
|
return parts.join(":")
|
||||||
|
} else {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a lucene JSON query from the filter structure generated in the builder
|
* Builds a lucene JSON query from the filter structure generated in the builder
|
||||||
* @param filter the builder filter structure
|
* @param filter the builder filter structure
|
||||||
|
@ -194,7 +207,7 @@ export const runLuceneQuery = (docs, query) => {
|
||||||
const filters = Object.entries(query[type] || {})
|
const filters = Object.entries(query[type] || {})
|
||||||
for (let i = 0; i < filters.length; i++) {
|
for (let i = 0; i < filters.length; i++) {
|
||||||
const [key, testValue] = filters[i]
|
const [key, testValue] = filters[i]
|
||||||
const docValue = Helpers.deepGet(doc, key)
|
const docValue = Helpers.deepGet(doc, removeKeyNumbering(key))
|
||||||
if (failFn(docValue, testValue)) {
|
if (failFn(docValue, testValue)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ module MongoMock {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
mongodb.ObjectID = require("mongodb").ObjectID
|
mongodb.ObjectID = jest.requireActual("mongodb").ObjectID
|
||||||
|
|
||||||
module.exports = mongodb
|
module.exports = mongodb
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "1.3.4-alpha.2",
|
"version": "1.3.15-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.4-alpha.2",
|
"@budibase/backend-core": "1.3.15-alpha.3",
|
||||||
"@budibase/client": "1.3.4-alpha.2",
|
"@budibase/client": "1.3.15-alpha.3",
|
||||||
"@budibase/pro": "1.3.4-alpha.2",
|
"@budibase/pro": "1.3.15-alpha.3",
|
||||||
"@budibase/string-templates": "1.3.4-alpha.2",
|
"@budibase/string-templates": "1.3.15-alpha.3",
|
||||||
"@budibase/types": "1.3.4-alpha.2",
|
"@budibase/types": "1.3.15-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",
|
||||||
|
@ -95,6 +95,7 @@
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"bull": "4.8.5",
|
"bull": "4.8.5",
|
||||||
"chmodr": "1.2.0",
|
"chmodr": "1.2.0",
|
||||||
|
"chokidar": "3.5.3",
|
||||||
"csvtojson": "2.0.10",
|
"csvtojson": "2.0.10",
|
||||||
"curlconverter": "3.21.0",
|
"curlconverter": "3.21.0",
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
|
@ -138,8 +139,10 @@
|
||||||
"redis": "4",
|
"redis": "4",
|
||||||
"server-destroy": "1.0.1",
|
"server-destroy": "1.0.1",
|
||||||
"snowflake-promise": "^4.5.0",
|
"snowflake-promise": "^4.5.0",
|
||||||
|
"socket.io": "^4.5.1",
|
||||||
"svelte": "3.49.0",
|
"svelte": "3.49.0",
|
||||||
"swagger-parser": "10.0.3",
|
"swagger-parser": "10.0.3",
|
||||||
|
"tar": "6.1.11",
|
||||||
"to-json-schema": "0.2.5",
|
"to-json-schema": "0.2.5",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"validate.js": "0.13.1",
|
"validate.js": "0.13.1",
|
||||||
|
|
|
@ -58,6 +58,7 @@ async function init() {
|
||||||
DEPLOYMENT_ENVIRONMENT: "development",
|
DEPLOYMENT_ENVIRONMENT: "development",
|
||||||
BB_ADMIN_USER_EMAIL: "",
|
BB_ADMIN_USER_EMAIL: "",
|
||||||
BB_ADMIN_USER_PASSWORD: "",
|
BB_ADMIN_USER_PASSWORD: "",
|
||||||
|
PLUGINS_DIR: "",
|
||||||
}
|
}
|
||||||
let envFile = ""
|
let envFile = ""
|
||||||
Object.keys(envFileJson).forEach(key => {
|
Object.keys(envFileJson).forEach(key => {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue