Merge branch 'cheeks-lab-day-eject-blocks' of github.com:Budibase/budibase into form-block
This commit is contained in:
commit
c873a4d965
|
@ -102,4 +102,6 @@ packages/builder/cypress/reports
|
|||
stats.html
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
*.tsbuildinfo
|
||||
budibase-component
|
||||
budibase-datasource
|
||||
|
|
|
@ -124,11 +124,15 @@ spec:
|
|||
value: {{ .Values.globals.tenantFeatureFlags | quote }}
|
||||
{{ if .Values.globals.bbAdminUserEmail }}
|
||||
- name: BB_ADMIN_USER_EMAIL
|
||||
value: { { .Values.globals.bbAdminUserEmail | quote } }
|
||||
value: {{ .Values.globals.bbAdminUserEmail | quote }}
|
||||
{{ end }}
|
||||
{{ if .Values.globals.bbAdminUserPassword }}
|
||||
- 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 }}
|
||||
{{ if .Values.services.apps.nodeDebug }}
|
||||
- name: NODE_DEBUG
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
"dependencies": {
|
||||
"bulma": "^0.9.3",
|
||||
"next": "12.1.0",
|
||||
"node-fetch": "^3.2.2",
|
||||
"node-sass": "^7.0.1",
|
||||
"node-fetch": "^3.2.10",
|
||||
"sass": "^1.52.3",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-notifications-component": "^3.4.1"
|
||||
|
@ -24,4 +24,4 @@
|
|||
"eslint-config-next": "12.1.0",
|
||||
"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"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.2.tgz#16d33fbe32ca7c6ca1ca8ba5dfea1dd885c59f04"
|
||||
integrity sha512-Cwhq1JFIoon15wcIkFzubVNFE5GvXGV82pKf4knXXjvGmn7RJKcypeuqcVNZMGDZsAFWyIRya/anwAJr7TWJ7w==
|
||||
node-fetch@^3.2.10:
|
||||
version "3.2.10"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8"
|
||||
integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
|
|
|
@ -22,4 +22,7 @@ BUDIBASE_ENVIRONMENT=PRODUCTION
|
|||
|
||||
# An admin user can be automatically created initially if these are set
|
||||
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}
|
||||
BB_ADMIN_USER_EMAIL: ${BB_ADMIN_USER_EMAIL}
|
||||
BB_ADMIN_USER_PASSWORD: ${BB_ADMIN_USER_PASSWORD}
|
||||
PLUGINS_DIR: ${PLUGINS_DIR}
|
||||
depends_on:
|
||||
- worker-service
|
||||
- redis-service
|
||||
# volumes:
|
||||
# - /some/path/to/plugins:/plugins
|
||||
|
||||
worker-service:
|
||||
restart: unless-stopped
|
||||
|
|
|
@ -22,4 +22,7 @@ BUDIBASE_ENVIRONMENT=PRODUCTION
|
|||
|
||||
# An admin user can be automatically created initially if these are set
|
||||
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;
|
||||
}
|
||||
|
||||
location /preview {
|
||||
proxy_pass http://{{ address }}:4001;
|
||||
}
|
||||
|
||||
location /builder {
|
||||
proxy_pass http://{{ address }}:3000;
|
||||
rewrite ^/builder(.*)$ /builder/$1 break;
|
||||
|
@ -84,6 +80,20 @@ http {
|
|||
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 / {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
|
|
@ -88,10 +88,6 @@ http {
|
|||
proxy_pass http://$apps:4002;
|
||||
}
|
||||
|
||||
location /preview {
|
||||
proxy_pass http://$apps:4002;
|
||||
}
|
||||
|
||||
location = / {
|
||||
proxy_pass http://$apps:4002;
|
||||
}
|
||||
|
@ -162,6 +158,15 @@ http {
|
|||
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 / {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
|
|
@ -4,9 +4,9 @@ echo ${TARGETBUILD} > /buildtarget.txt
|
|||
if [[ "${TARGETBUILD}" = "aas" ]]; then
|
||||
# Azure AppService uses /home for persisent data & SSH on port 2222
|
||||
DATA_DIR=/home
|
||||
mkdir -p $DATA_DIR/{search,minio,couchdb}
|
||||
mkdir -p $DATA_DIR/couchdb/{dbs,views}
|
||||
chown -R couchdb:couchdb $DATA_DIR/couchdb/
|
||||
mkdir -p $DATA_DIR/{search,minio,couch}
|
||||
mkdir -p $DATA_DIR/couch/{dbs,views}
|
||||
chown -R couchdb:couchdb $DATA_DIR/couch/
|
||||
apt update
|
||||
apt-get install -y openssh-server
|
||||
sed -i "s/#Port 22/Port 2222/" /etc/ssh/sshd_config
|
||||
|
@ -16,5 +16,4 @@ if [[ "${TARGETBUILD}" = "aas" ]]; then
|
|||
else
|
||||
sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini
|
||||
sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini
|
||||
|
||||
fi
|
|
@ -1,5 +1,5 @@
|
|||
; CouchDB Configuration Settings
|
||||
|
||||
[couchdb]
|
||||
database_dir = DATA_DIR/couchdb/dbs
|
||||
view_index_dir = DATA_DIR/couchdb/views
|
||||
database_dir = DATA_DIR/couch/dbs
|
||||
view_index_dir = DATA_DIR/couch/views
|
||||
|
|
|
@ -66,6 +66,15 @@ server {
|
|||
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 / {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
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
|
||||
|
||||
# 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}/search
|
||||
chown -R couchdb:couchdb ${DATA_DIR}/couchdb
|
||||
chown -R couchdb:couchdb ${DATA_DIR}/couch
|
||||
redis-server --requirepass $REDIS_PASSWORD &
|
||||
/opt/clouseau/bin/clouseau &
|
||||
/minio/minio server ${DATA_DIR}/minio &
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "1.3.4-alpha.2",
|
||||
"version": "1.3.15-alpha.3",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"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",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -20,7 +20,8 @@
|
|||
"test:watch": "jest --watchAll"
|
||||
},
|
||||
"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",
|
||||
"aws-sdk": "2.1030.0",
|
||||
"bcrypt": "5.0.1",
|
||||
|
@ -60,7 +61,6 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@shopify/jest-koa-mocks": "3.1.5",
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/koa": "2.0.52",
|
||||
"@types/lodash": "4.14.180",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
...require("./src/plugin"),
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { dangerousGetDB, closeDB } from "."
|
||||
import { DocumentType } from "./constants"
|
||||
|
||||
class Replication {
|
||||
source: any
|
||||
|
@ -53,6 +54,14 @@ class 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
|
||||
*/
|
||||
|
@ -60,6 +69,7 @@ class Replication {
|
|||
await this.target.destroy()
|
||||
// Recreate the DB again
|
||||
this.target = dangerousGetDB(this.target.name)
|
||||
// take the opportunity to remove deleted tombstones
|
||||
await this.replicate()
|
||||
}
|
||||
|
||||
|
|
|
@ -254,7 +254,16 @@ export async function getAllApps({ dev, all, idsOnly, efficient }: any = {}) {
|
|||
return false
|
||||
})
|
||||
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) =>
|
||||
// skip setup otherwise databases could be re-created
|
||||
|
|
|
@ -50,6 +50,7 @@ const env = {
|
|||
GLOBAL_BUCKET_NAME: process.env.GLOBAL_BUCKET_NAME || "global",
|
||||
GLOBAL_CLOUD_BUCKET_NAME:
|
||||
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,
|
||||
DISABLE_DEVELOPER_LICENSE: process.env.DISABLE_DEVELOPER_LICENSE,
|
||||
DEFAULT_LICENSE: process.env.DEFAULT_LICENSE,
|
||||
|
|
|
@ -18,6 +18,7 @@ import * as dbConstants from "./db/constants"
|
|||
import logging from "./logging"
|
||||
import pino from "./pino"
|
||||
import * as middleware from "./middleware"
|
||||
import plugins from "./plugin"
|
||||
|
||||
// mimic the outer package exports
|
||||
import * as db from "./pkg/db"
|
||||
|
@ -56,6 +57,7 @@ const core = {
|
|||
errors,
|
||||
logging,
|
||||
roles,
|
||||
plugins,
|
||||
...pino,
|
||||
...errorClasses,
|
||||
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.
|
||||
|
@ -172,6 +176,14 @@ export const streamUpload = async (
|
|||
const objectStore = ObjectStore(bucketName)
|
||||
await makeSureBucketExists(objectStore, bucketName)
|
||||
|
||||
// Set content type for certain known extensions
|
||||
if (filename?.endsWith(".js")) {
|
||||
extra = {
|
||||
...extra,
|
||||
ContentType: "application/javascript",
|
||||
}
|
||||
}
|
||||
|
||||
const params = {
|
||||
Bucket: sanitizeBucket(bucketName),
|
||||
Key: sanitizeKey(filename),
|
||||
|
@ -295,9 +307,13 @@ export const uploadDirectory = async (
|
|||
return files
|
||||
}
|
||||
|
||||
exports.downloadTarballDirect = async (url: string, path: string) => {
|
||||
exports.downloadTarballDirect = async (
|
||||
url: string,
|
||||
path: string,
|
||||
headers = {}
|
||||
) => {
|
||||
path = sanitizeKey(path)
|
||||
const response = await fetch(url)
|
||||
const response = await fetch(url, { headers })
|
||||
if (!response.ok) {
|
||||
throw new Error(`unexpected response ${response.statusText}`)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ exports.ObjectStoreBuckets = {
|
|||
TEMPLATES: env.TEMPLATES_BUCKET_NAME,
|
||||
GLOBAL: env.GLOBAL_BUCKET_NAME,
|
||||
GLOBAL_CLOUD: env.GLOBAL_CLOUD_BUCKET_NAME,
|
||||
PLUGINS: env.PLUGIN_BUCKET_NAME,
|
||||
}
|
||||
|
||||
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"
|
||||
tar "^6.1.11"
|
||||
|
||||
"@shopify/jest-koa-mocks@3.1.5":
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@shopify/jest-koa-mocks/-/jest-koa-mocks-3.1.5.tgz#11f77ccfbcaf35cf5ee2c6108a286e61e6bea084"
|
||||
integrity sha512-gQ3/7ELerv00TWO37AGFX5mT9CsFCS+3/UbKMuoIlKEU0QH2OX8BV9WBf/EKw7adCDNlxss0lqV6J8kf5pgr4A==
|
||||
"@shopify/jest-koa-mocks@5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@shopify/jest-koa-mocks/-/jest-koa-mocks-5.0.1.tgz#fba490b6b7985fbb571eb9974897d396a3642e94"
|
||||
integrity sha512-4YskS9q8+TEHNoyopmuoy2XyhInyqeOl7CF5ShJs19sm6m0EA/jGGvgf/osv2PeTfuf42/L2G9CzWUSg49yTSg==
|
||||
dependencies:
|
||||
koa "^2.13.4"
|
||||
node-mocks-http "^1.5.8"
|
||||
node-mocks-http "^1.11.0"
|
||||
|
||||
"@sideway/address@^4.1.3":
|
||||
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"
|
||||
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
|
||||
|
||||
node-mocks-http@^1.5.8:
|
||||
node-mocks-http@^1.11.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.11.0.tgz#defc0febf6b935f08245397d47534a8de592996e"
|
||||
integrity sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw==
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"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",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,7 +38,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
|
||||
"@budibase/string-templates": "1.3.4-alpha.2",
|
||||
"@budibase/string-templates": "1.3.15-alpha.3",
|
||||
"@spectrum-css/actionbutton": "^1.0.1",
|
||||
"@spectrum-css/actiongroup": "^1.0.1",
|
||||
"@spectrum-css/avatar": "^3.0.2",
|
||||
|
|
|
@ -4,10 +4,15 @@
|
|||
|
||||
export let size = "M"
|
||||
export let tooltip = ""
|
||||
export let muted
|
||||
</script>
|
||||
|
||||
<TooltipWrapper {tooltip} {size}>
|
||||
<label for="" class={`spectrum-FieldLabel spectrum-FieldLabel--size${size}`}>
|
||||
<label
|
||||
class:muted
|
||||
for=""
|
||||
class={`spectrum-FieldLabel spectrum-FieldLabel--size${size}`}
|
||||
>
|
||||
<slot />
|
||||
</label>
|
||||
</TooltipWrapper>
|
||||
|
@ -17,4 +22,8 @@
|
|||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.muted {
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
export let secondaryAction = undefined
|
||||
export let secondaryButtonWarning = false
|
||||
export let dataCy = null
|
||||
|
||||
const { hide, cancel } = getContext(Context.Modal)
|
||||
let loading = false
|
||||
$: confirmDisabled = disabled || loading
|
||||
|
@ -88,12 +87,11 @@
|
|||
<section class="spectrum-Dialog-content content-grid">
|
||||
<slot />
|
||||
</section>
|
||||
{#if showCancelButton || showConfirmButton}
|
||||
{#if showCancelButton || showConfirmButton || $$slots.footer}
|
||||
<div
|
||||
class="spectrum-ButtonGroup spectrum-Dialog-buttonGroup spectrum-Dialog-buttonGroup--noFooter"
|
||||
>
|
||||
<slot name="footer" />
|
||||
|
||||
{#if showSecondaryButton && secondaryButtonText && secondaryAction}
|
||||
<div class="secondary-action">
|
||||
<Button
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
export let noHorizPadding = false
|
||||
export let quiet = false
|
||||
export let emphasized = false
|
||||
export let onTop = false
|
||||
export let size = "M"
|
||||
|
||||
let thisSelected = undefined
|
||||
|
@ -75,6 +76,7 @@
|
|||
bind:this={container}
|
||||
class:spectrum-Tabs--quiet={quiet}
|
||||
class:noHorizPadding
|
||||
class:onTop
|
||||
class:spectrum-Tabs--vertical={vertical}
|
||||
class:spectrum-Tabs--horizontal={!vertical}
|
||||
class="spectrum-Tabs spectrum-Tabs--size{size}"
|
||||
|
@ -122,4 +124,7 @@
|
|||
.noPadding {
|
||||
margin: 0;
|
||||
}
|
||||
.onTop {
|
||||
z-index: 100;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -74,11 +74,11 @@ filterTests(["smoke", "all"], () => {
|
|||
.contains("Update role")
|
||||
.click({ force: true })
|
||||
})
|
||||
cy.reload({ timeout: 5000 })
|
||||
cy.reload()
|
||||
cy.wait(1000)
|
||||
}
|
||||
// Confirm roles exist within Configure roles table
|
||||
cy.get(interact.SPECTRUM_TABLE, { timeout: 2000 })
|
||||
cy.get(interact.SPECTRUM_TABLE, { timeout: 20000 })
|
||||
.eq(0)
|
||||
.within(assginedRoles => {
|
||||
expect(assginedRoles).to.contain("Admin")
|
||||
|
@ -180,7 +180,7 @@ filterTests(["smoke", "all"], () => {
|
|||
cy.reload()
|
||||
|
||||
// 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.FIELD, { timeout: 1000 }).eq(2).within(() => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import filterTests from "../../support/filterTests"
|
||||
|
||||
filterTests(['all'], () => {
|
||||
context("Datasource Wizard", () => {
|
||||
xcontext("Datasource Wizard", () => {
|
||||
if (Cypress.env("TEST_ENV")) {
|
||||
before(() => {
|
||||
cy.login()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import filterTests from "../../support/filterTests"
|
||||
|
||||
filterTests(["all"], () => {
|
||||
context("Oracle Datasource Testing", () => {
|
||||
xcontext("Oracle Datasource Testing", () => {
|
||||
if (Cypress.env("TEST_ENV")) {
|
||||
before(() => {
|
||||
cy.login()
|
||||
|
|
|
@ -162,7 +162,7 @@ filterTests(["all"], () => {
|
|||
switchSchema("randomText")
|
||||
|
||||
// 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
|
||||
cy.get(".spectrum-Table").should("contain", queryName)
|
||||
|
|
|
@ -14,7 +14,7 @@ filterTests(["smoke", "all"], () => {
|
|||
// Select REST data source
|
||||
cy.selectExternalDatasource(datasource)
|
||||
// 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.get("input").clear().type("random text")
|
||||
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()
|
||||
})
|
||||
// Ensure modal has closed and table is created
|
||||
cy.get(".spectrum-Modal").should("not.exist")
|
||||
cy.get(".spectrum-Tabs-content", { timeout: 1000 }).should(
|
||||
cy.get(".spectrum-Modal", { timeout: 2000 }).should("not.exist")
|
||||
cy.get(".spectrum-Tabs-content", { timeout: 2000 }).should(
|
||||
"contain",
|
||||
tableName
|
||||
)
|
||||
|
@ -637,30 +637,32 @@ Cypress.Commands.add(
|
|||
(datasourceNames, accessLevelLabel) => {
|
||||
cy.contains("Design").click()
|
||||
cy.get(".spectrum-Button").contains("Add screen").click({ force: true })
|
||||
cy.get(".spectrum-Modal").within(() => {
|
||||
cy.get(".item").contains("Autogenerated screens").click()
|
||||
cy.get(".spectrum-Dialog-grid").within(() => {
|
||||
cy.get("[data-cy='autogenerated-screens']").click()
|
||||
cy.intercept("**/api/datasources").as("autoScreens")
|
||||
cy.get(".spectrum-Button").contains("Continue").click({ force: true })
|
||||
cy.wait("@autoScreens")
|
||||
cy.wait(5000)
|
||||
})
|
||||
cy.get(".spectrum-Modal [data-cy='data-source-modal']", {
|
||||
timeout: 500,
|
||||
}).within(() => {
|
||||
cy.get("[data-cy='autogenerated-screens']").should("not.exist")
|
||||
cy.get("[data-cy='data-source-modal']", { timeout: 10000 }).within(() => {
|
||||
for (let i = 0; i < datasourceNames.length; i++) {
|
||||
cy.wait(500)
|
||||
cy.get(".data-source-entry").contains(datasourceNames[i]).click()
|
||||
//Ensure the check mark is visible
|
||||
cy.get(".data-source-entry")
|
||||
.contains(datasourceNames[i], { timeout: 20000 })
|
||||
.click({ force: true })
|
||||
// Ensure the check mark is visible
|
||||
cy.get(".data-source-entry")
|
||||
.contains(datasourceNames[i])
|
||||
.get(".data-source-check")
|
||||
.get(".data-source-check", { timeout: 20000 })
|
||||
.should("exist")
|
||||
}
|
||||
|
||||
cy.get(".spectrum-Button").contains("Confirm").click({ force: true })
|
||||
})
|
||||
|
||||
cy.get(".spectrum-Modal").within(() => {
|
||||
cy.get(".spectrum-Modal", { timeout: 10000 }).within(() => {
|
||||
if (accessLevelLabel) {
|
||||
cy.get(".spectrum-Picker-label").click()
|
||||
cy.wait(500)
|
||||
cy.get(".spectrum-Picker-label", { timeout: 10000 }).click()
|
||||
cy.contains(accessLevelLabel).click()
|
||||
}
|
||||
cy.get(".spectrum-Button").contains("Done").click({ force: true })
|
||||
|
@ -915,8 +917,9 @@ Cypress.Commands.add("createRestQuery", (method, restUrl, queryPrettyName) => {
|
|||
Cypress.Commands.add("closeModal", () => {
|
||||
cy.get(".spectrum-Modal", { timeout: 2000 }).within(() => {
|
||||
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", () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "1.3.4-alpha.2",
|
||||
"version": "1.3.15-alpha.3",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -69,10 +69,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.3.4-alpha.2",
|
||||
"@budibase/client": "1.3.4-alpha.2",
|
||||
"@budibase/frontend-core": "1.3.4-alpha.2",
|
||||
"@budibase/string-templates": "1.3.4-alpha.2",
|
||||
"@budibase/bbui": "1.3.15-alpha.3",
|
||||
"@budibase/client": "1.3.15-alpha.3",
|
||||
"@budibase/frontend-core": "1.3.15-alpha.3",
|
||||
"@budibase/string-templates": "1.3.15-alpha.3",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
@ -96,7 +96,7 @@
|
|||
"@babel/runtime": "^7.13.10",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@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/svelte": "^3.0.0",
|
||||
"babel-jest": "^26.6.3",
|
||||
|
@ -118,7 +118,7 @@
|
|||
"ts-node": "^10.4.0",
|
||||
"tsconfig-paths": "4.0.0",
|
||||
"typescript": "^4.5.5",
|
||||
"vite": "^2.1.5"
|
||||
"vite": "^3.0.8"
|
||||
},
|
||||
"gitHead": "115189f72a850bfb52b65ec61d932531bf327072"
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ function prepareData(config) {
|
|||
ds => ds.source === config.type
|
||||
).length
|
||||
|
||||
let baseName = IntegrationNames[config.type]
|
||||
let baseName = IntegrationNames[config.type] || config.name
|
||||
let name =
|
||||
existingTypeCount === 0 ? baseName : `${baseName}-${existingTypeCount + 1}`
|
||||
|
||||
|
|
|
@ -90,13 +90,21 @@ export const getFrontendStore = () => {
|
|||
|
||||
// Fetch component definitions.
|
||||
// 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
|
||||
store.update(state => ({
|
||||
...state,
|
||||
libraries: application.componentLibraries,
|
||||
components,
|
||||
customComponents,
|
||||
clientFeatures: {
|
||||
...INITIAL_FRONTEND_STATE.clientFeatures,
|
||||
...components.features,
|
||||
|
@ -116,6 +124,7 @@ export const getFrontendStore = () => {
|
|||
version: application.version,
|
||||
revertableVersion: application.revertableVersion,
|
||||
navigation: application.navigation || {},
|
||||
usedPlugins: application.usedPlugins || [],
|
||||
}))
|
||||
|
||||
// Initialise backend stores
|
||||
|
@ -189,9 +198,18 @@ export const getFrontendStore = () => {
|
|||
})
|
||||
},
|
||||
save: async screen => {
|
||||
const state = get(store)
|
||||
const creatingNewScreen = screen._id === undefined
|
||||
const savedScreen = await API.saveScreen(screen)
|
||||
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 => {
|
||||
// Update screen object
|
||||
const idx = state.screens.findIndex(x => x._id === savedScreen._id)
|
||||
|
@ -210,6 +228,9 @@ export const getFrontendStore = () => {
|
|||
// Update routes
|
||||
state.routes = routesResponse.routes
|
||||
|
||||
// Update used plugins
|
||||
state.usedPlugins = usedPlugins
|
||||
|
||||
return state
|
||||
})
|
||||
return savedScreen
|
||||
|
@ -378,9 +399,6 @@ export const getFrontendStore = () => {
|
|||
if (!componentName) {
|
||||
return null
|
||||
}
|
||||
if (!componentName.startsWith("@budibase")) {
|
||||
componentName = `@budibase/standard-components/${componentName}`
|
||||
}
|
||||
return get(store).components[componentName]
|
||||
},
|
||||
createInstance: (componentName, presetProps) => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
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()
|
||||
|
||||
export let value
|
||||
|
@ -29,11 +30,16 @@
|
|||
label: "Every Night at Midnight",
|
||||
value: "0 0 * * *",
|
||||
},
|
||||
{
|
||||
label: "Every Budibase Reboot",
|
||||
value: "@reboot",
|
||||
},
|
||||
]
|
||||
|
||||
onMount(() => {
|
||||
if (!$flags.cloud) {
|
||||
CRON_EXPRESSIONS.push({
|
||||
label: "Every Budibase Reboot",
|
||||
value: "@reboot",
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="block-field">
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
customQueryIconColor,
|
||||
customQueryText,
|
||||
} from "helpers/data/utils"
|
||||
import ICONS from "./icons"
|
||||
import { getIcon } from "./icons"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
|
||||
let openDataSources = []
|
||||
|
@ -124,7 +124,7 @@
|
|||
>
|
||||
<div class="datasource-icon" slot="icon">
|
||||
<svelte:component
|
||||
this={ICONS[datasource.source]}
|
||||
this={getIcon(datasource.source, datasource.schema)}
|
||||
height="18"
|
||||
width="18"
|
||||
/>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
notifications,
|
||||
Modal,
|
||||
Table,
|
||||
Toggle,
|
||||
} from "@budibase/bbui"
|
||||
import { datasources, integrations, tables } from "stores/backend"
|
||||
import CreateEditRelationship from "components/backend/Datasources/CreateEditRelationship.svelte"
|
||||
|
@ -15,6 +16,7 @@
|
|||
import ArrayRenderer from "components/common/renderers/ArrayRenderer.svelte"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import { goto } from "@roxi/routify"
|
||||
import ValuesList from "components/common/ValuesList.svelte"
|
||||
|
||||
export let datasource
|
||||
export let save
|
||||
|
@ -31,6 +33,8 @@
|
|||
let createExternalTableModal
|
||||
let selectedFromRelationship, selectedToRelationship
|
||||
let confirmDialog
|
||||
let specificTables = null
|
||||
let requireSpecificTables = false
|
||||
|
||||
$: integration = datasource && $integrations[datasource.source]
|
||||
$: plusTables = datasource?.plus
|
||||
|
@ -87,7 +91,7 @@
|
|||
|
||||
async function updateDatasourceSchema() {
|
||||
try {
|
||||
await datasources.updateSchema(datasource)
|
||||
await datasources.updateSchema(datasource, specificTables)
|
||||
notifications.success(`Datasource ${name} tables updated successfully.`)
|
||||
await tables.fetch()
|
||||
} catch (error) {
|
||||
|
@ -150,6 +154,19 @@
|
|||
warning={false}
|
||||
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>
|
||||
If you have fetched tables from this database before, this action may
|
||||
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 Redis from "./Redis.svelte"
|
||||
import Snowflake from "./Snowflake.svelte"
|
||||
import Custom from "./Custom.svelte"
|
||||
|
||||
export default {
|
||||
const ICONS = {
|
||||
BUDIBASE: Budibase,
|
||||
POSTGRES: Postgres,
|
||||
DYNAMODB: DynamoDB,
|
||||
|
@ -34,4 +35,15 @@ export default {
|
|||
FIRESTORE: Firebase,
|
||||
REDIS: Redis,
|
||||
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 { goto } from "@roxi/routify"
|
||||
import ImportRestQueriesModal from "./ImportRestQueriesModal.svelte"
|
||||
import DatasourceCard from "../_components/DatasourceCard.svelte"
|
||||
|
||||
export let modal
|
||||
let integrations = {}
|
||||
|
@ -27,6 +28,9 @@
|
|||
let importModal
|
||||
|
||||
$: showImportButton = false
|
||||
$: customIntegrations = Object.entries(integrations).filter(
|
||||
entry => entry[1].custom
|
||||
)
|
||||
|
||||
checkShowImport()
|
||||
|
||||
|
@ -49,6 +53,9 @@
|
|||
schema: selected.datasource,
|
||||
auth: selected.auth,
|
||||
}
|
||||
if (selected.friendlyName) {
|
||||
integration.name = selected.friendlyName
|
||||
}
|
||||
checkShowImport()
|
||||
}
|
||||
|
||||
|
@ -150,36 +157,39 @@
|
|||
<Layout noPadding gap="XS">
|
||||
<Body size="S">Connect to an external data source</Body>
|
||||
<div class="item-list">
|
||||
{#each Object.entries(integrations).filter(([key]) => key !== IntegrationTypes.INTERNAL) as [integrationType, schema]}
|
||||
<div
|
||||
class:selected={integration.type === integrationType}
|
||||
on:click={() => selectIntegration(integrationType)}
|
||||
class="item hoverable"
|
||||
>
|
||||
<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 Object.entries(integrations).filter(([key, val]) => key !== IntegrationTypes.INTERNAL && !val.custom) as [integrationType, schema]}
|
||||
<DatasourceCard
|
||||
on:selected={evt => selectIntegration(evt.detail)}
|
||||
{schema}
|
||||
bind:integrationType
|
||||
{integration}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</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>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.item-list {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,14 @@
|
|||
let datasource = cloneDeep(integration)
|
||||
let skipFetch = false
|
||||
|
||||
$: name =
|
||||
IntegrationNames[datasource.type] || datasource.name || datasource.type
|
||||
|
||||
async function saveDatasource() {
|
||||
try {
|
||||
if (!datasource.name) {
|
||||
datasource.name = name
|
||||
}
|
||||
const resp = await save(datasource, skipFetch)
|
||||
$goto(`./datasource/${resp._id}`)
|
||||
notifications.success(`Datasource updated successfully.`)
|
||||
|
@ -32,7 +38,7 @@
|
|||
</script>
|
||||
|
||||
<ModalContent
|
||||
title={`Connect to ${IntegrationNames[datasource.type]}`}
|
||||
title={`Connect to ${name}`}
|
||||
onConfirm={() => saveDatasource()}
|
||||
onCancel={() => modal.show()}
|
||||
confirmText={datasource.plus
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
const dispatch = createEventDispatcher()
|
||||
let bindingDrawer
|
||||
let valid = true
|
||||
let currentVal = value
|
||||
|
||||
$: readableValue = runtimeToReadableBinding(bindings, value)
|
||||
$: tempValue = readableValue
|
||||
|
@ -30,11 +31,17 @@
|
|||
|
||||
const saveBinding = () => {
|
||||
onChange(tempValue)
|
||||
onBlur()
|
||||
bindingDrawer.hide()
|
||||
}
|
||||
|
||||
const onChange = value => {
|
||||
dispatch("change", readableToRuntimeBinding(bindings, value))
|
||||
currentVal = readableToRuntimeBinding(bindings, value)
|
||||
dispatch("change", currentVal)
|
||||
}
|
||||
|
||||
const onBlur = () => {
|
||||
dispatch("blur", currentVal)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -45,6 +52,7 @@
|
|||
readonly={isJS}
|
||||
value={isJS ? "(JavaScript function)" : readableValue}
|
||||
on:change={event => onChange(event.detail)}
|
||||
on:blur={onBlur}
|
||||
{placeholder}
|
||||
{updateOnChange}
|
||||
/>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
)
|
||||
|
||||
newBlock.inputs = {
|
||||
fields: Object.keys(parameters.fields).reduce((fields, key) => {
|
||||
fields: Object.keys(parameters.fields ?? {}).reduce((fields, key) => {
|
||||
fields[key] = "string"
|
||||
return fields
|
||||
}, {}),
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
placeholder={keyPlaceholder}
|
||||
readonly={readOnly}
|
||||
bind:value={field.name}
|
||||
on:change={changed}
|
||||
on:blur={changed}
|
||||
/>
|
||||
{#if options}
|
||||
<Select bind:value={field.value} on:change={changed} {options} />
|
||||
|
@ -115,7 +115,10 @@
|
|||
<DrawerBindableInput
|
||||
{bindings}
|
||||
placeholder="Value"
|
||||
on:change={e => (field.value = e.detail)}
|
||||
on:blur={e => {
|
||||
field.value = e.detail
|
||||
changed()
|
||||
}}
|
||||
disabled={readOnly}
|
||||
value={field.value}
|
||||
allowJS={false}
|
||||
|
@ -127,7 +130,7 @@
|
|||
placeholder={valuePlaceholder}
|
||||
readonly={readOnly}
|
||||
bind:value={field.value}
|
||||
on:change={changed}
|
||||
on:blur={changed}
|
||||
/>
|
||||
{/if}
|
||||
{#if toggle}
|
||||
|
|
|
@ -1,16 +1,24 @@
|
|||
<script>
|
||||
import { ModalContent, Toggle } from "@budibase/bbui"
|
||||
import { ModalContent, Toggle, Body } from "@budibase/bbui"
|
||||
|
||||
export let app
|
||||
export let published
|
||||
let excludeRows = false
|
||||
|
||||
$: title = published ? "Export published app" : "Export latest app"
|
||||
$: confirmText = published ? "Export published" : "Export latest"
|
||||
|
||||
const exportApp = () => {
|
||||
const id = app.deployed ? app.prodId : app.devId
|
||||
const id = published ? app.prodId : app.devId
|
||||
const appName = encodeURIComponent(app.name)
|
||||
window.location = `/api/backups/export?appId=${id}&appname=${appName}&excludeRows=${excludeRows}`
|
||||
}
|
||||
</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} />
|
||||
</ModalContent>
|
||||
|
|
|
@ -57,3 +57,10 @@ export const DefaultAppTheme = {
|
|||
navBackground: "var(--spectrum-global-color-gray-50)",
|
||||
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 !== "") {
|
||||
str += "&"
|
||||
}
|
||||
str += `${key}=${value || ""}`
|
||||
str += `${key}=${encodeURIComponent(value || "")}`
|
||||
}
|
||||
}
|
||||
return str
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
class="add-button"
|
||||
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 class="content">
|
||||
|
|
|
@ -28,25 +28,25 @@
|
|||
import { onMount } from "svelte"
|
||||
import restUtils from "helpers/data/utils"
|
||||
import {
|
||||
RestBodyTypes as bodyTypes,
|
||||
SchemaTypeOptions,
|
||||
PaginationLocations,
|
||||
PaginationTypes,
|
||||
RawRestBodyTypes,
|
||||
RestBodyTypes as bodyTypes,
|
||||
SchemaTypeOptions,
|
||||
} from "constants/backend"
|
||||
import JSONPreview from "components/integration/JSONPreview.svelte"
|
||||
import AccessLevelSelect from "components/integration/AccessLevelSelect.svelte"
|
||||
import DynamicVariableModal from "../../_components/DynamicVariableModal.svelte"
|
||||
import Placeholder from "assets/bb-spaceship.svg"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { RawRestBodyTypes } from "constants/backend"
|
||||
|
||||
import {
|
||||
getRestBindings,
|
||||
toBindingsArray,
|
||||
runtimeToReadableBinding,
|
||||
readableToRuntimeBinding,
|
||||
runtimeToReadableMap,
|
||||
readableToRuntimeMap,
|
||||
runtimeToReadableBinding,
|
||||
runtimeToReadableMap,
|
||||
toBindingsArray,
|
||||
} from "builderStore/dataBinding"
|
||||
|
||||
let query, datasource
|
||||
|
@ -95,7 +95,7 @@
|
|||
$: runtimeUrlQueries = readableToRuntimeMap(mergedBindings, breakQs)
|
||||
|
||||
function getSelectedQuery() {
|
||||
const cloneQuery = cloneDeep(
|
||||
return cloneDeep(
|
||||
$queries.list.find(q => q._id === $queries.selected) || {
|
||||
datasourceId: $params.selectedDatasource,
|
||||
parameters: [],
|
||||
|
@ -107,7 +107,6 @@
|
|||
queryVerb: "read",
|
||||
}
|
||||
)
|
||||
return cloneQuery
|
||||
}
|
||||
|
||||
function checkQueryName(inputUrl = null) {
|
||||
|
@ -121,14 +120,15 @@
|
|||
if (!base) {
|
||||
return base
|
||||
}
|
||||
const qs = restUtils.buildQueryString(
|
||||
let qs = restUtils.buildQueryString(
|
||||
runtimeToReadableMap(mergedBindings, qsObj)
|
||||
)
|
||||
let newUrl = base
|
||||
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() {
|
||||
|
@ -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 () => {
|
||||
query = getSelectedQuery()
|
||||
|
||||
|
@ -426,7 +445,11 @@
|
|||
/>
|
||||
</div>
|
||||
<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>
|
||||
<Button primary disabled={!url} on:click={runQuery}>Send</Button>
|
||||
<Button
|
||||
|
@ -456,13 +479,16 @@
|
|||
/>
|
||||
</Tab>
|
||||
<Tab title="Params">
|
||||
<KeyValueBuilder
|
||||
bind:object={breakQs}
|
||||
name="param"
|
||||
headings
|
||||
bindings={mergedBindings}
|
||||
bindingDrawerLeft="260px"
|
||||
/>
|
||||
{#key breakQs}
|
||||
<KeyValueBuilder
|
||||
on:change={paramsChanged}
|
||||
object={breakQs}
|
||||
name="param"
|
||||
headings
|
||||
bindings={mergedBindings}
|
||||
bindingDrawerLeft="260px"
|
||||
/>
|
||||
{/key}
|
||||
</Tab>
|
||||
<Tab title="Headers">
|
||||
<KeyValueBuilder
|
||||
|
|
|
@ -85,6 +85,8 @@
|
|||
? [$store.componentToPaste?._id]
|
||||
: [],
|
||||
isBudibaseEvent: true,
|
||||
usedPlugins: $store.usedPlugins,
|
||||
location: window.location,
|
||||
}
|
||||
|
||||
// Refresh the preview when required
|
||||
|
@ -303,7 +305,7 @@
|
|||
<iframe
|
||||
title="componentPreview"
|
||||
bind:this={iframe}
|
||||
src="/preview"
|
||||
src="/app/preview"
|
||||
class:hidden={loading || error}
|
||||
class:tablet={$store.previewDevice === "tablet"}
|
||||
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) {
|
||||
return false
|
||||
}
|
||||
|
@ -76,6 +76,9 @@
|
|||
const handler = keyHandlers[key]
|
||||
if (!handler) {
|
||||
return false
|
||||
} else if (event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
return handler(component)
|
||||
} catch (error) {
|
||||
|
@ -95,14 +98,19 @@
|
|||
return
|
||||
}
|
||||
// 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 => {
|
||||
// Menu events can be for any component
|
||||
const { id, key, ctrlKey } = e.detail
|
||||
const component = findComponent($selectedScreen.props, id)
|
||||
return await handleKeyAction(component, key, ctrlKey)
|
||||
return await handleKeyAction(null, component, key, ctrlKey)
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
{#if $selectedComponent}
|
||||
{#key $selectedComponent._id}
|
||||
<Panel {title} icon={componentDefinition.icon} borderLeft>
|
||||
<Panel {title} icon={componentDefinition?.icon} borderLeft>
|
||||
<ComponentSettingsSection
|
||||
{componentInstance}
|
||||
{componentDefinition}
|
||||
|
|
|
@ -24,7 +24,11 @@
|
|||
$: currentDefinition = store.actions.components.getDefinition(
|
||||
$selectedComponent?._component
|
||||
)
|
||||
$: enrichedStructure = enrichStructure(structure, $store.components)
|
||||
$: enrichedStructure = enrichStructure(
|
||||
structure,
|
||||
$store.components,
|
||||
$store.customComponents
|
||||
)
|
||||
$: filteredStructure = filterStructure(
|
||||
enrichedStructure,
|
||||
section,
|
||||
|
@ -46,8 +50,25 @@
|
|||
|
||||
// Parses the structure in the manifest and returns an enriched structure with
|
||||
// explicit categories
|
||||
const enrichStructure = (structure, definitions) => {
|
||||
const enrichStructure = (structure, definitions, customComponents) => {
|
||||
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 => {
|
||||
if (typeof item === "string") {
|
||||
const def = definitions[`@budibase/standard-components/${item}`]
|
||||
|
@ -65,6 +86,7 @@
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
return enrichedStructure
|
||||
}
|
||||
|
||||
|
@ -225,7 +247,7 @@
|
|||
position: fixed;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
height: calc(100% - 60px);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
},
|
||||
{ title: "Auth", href: "/builder/portal/manage/auth" },
|
||||
{ title: "Email", href: "/builder/portal/manage/email" },
|
||||
{ title: "Plugins", href: "/builder/portal/manage/plugins" },
|
||||
|
||||
{
|
||||
title: "Organisation",
|
||||
href: "/builder/portal/settings/organisation",
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import Spinner from "components/common/Spinner.svelte"
|
||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
||||
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
||||
|
||||
import { store, automationStore } from "builderStore"
|
||||
import { API } from "api"
|
||||
|
@ -33,7 +32,6 @@
|
|||
let selectedApp
|
||||
let creationModal
|
||||
let updatingModal
|
||||
let exportModal
|
||||
let creatingApp = false
|
||||
let loaded = $apps?.length || $templates?.length
|
||||
let searchTerm = ""
|
||||
|
@ -407,10 +405,6 @@
|
|||
<UpdateAppModal app={selectedApp} />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={exportModal} padding={false} width="600px">
|
||||
<ExportAppModal app={selectedApp} />
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.appTable {
|
||||
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,
|
||||
Icon,
|
||||
Helpers,
|
||||
Modal,
|
||||
} from "@budibase/bbui"
|
||||
import OverviewTab from "../_components/OverviewTab.svelte"
|
||||
import SettingsTab from "../_components/SettingsTab.svelte"
|
||||
|
@ -29,6 +30,7 @@
|
|||
import EditableIcon from "components/common/EditableIcon.svelte"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import HistoryTab from "components/portal/overview/automation/HistoryTab.svelte"
|
||||
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
||||
import { checkIncomingDeploymentStatus } from "components/deploy/utils"
|
||||
import { onDestroy, onMount } from "svelte"
|
||||
|
||||
|
@ -38,7 +40,9 @@
|
|||
let loaded = false
|
||||
let deletionModal
|
||||
let unpublishModal
|
||||
let exportModal
|
||||
let appName = ""
|
||||
let published
|
||||
|
||||
// App
|
||||
$: filteredApps = $apps.filter(app => app.devId === application)
|
||||
|
@ -140,11 +144,9 @@
|
|||
notifications.success("App ID copied to clipboard.")
|
||||
}
|
||||
|
||||
const exportApp = (app, opts = { published: false }) => {
|
||||
const appName = encodeURIComponent(app.name)
|
||||
const id = opts?.published ? app.prodId : app.devId
|
||||
// always export the development version
|
||||
window.location = `/api/backups/export?appId=${id}&appname=${appName}`
|
||||
const exportApp = opts => {
|
||||
published = opts.published
|
||||
exportModal.show()
|
||||
}
|
||||
|
||||
const unpublishApp = app => {
|
||||
|
@ -206,6 +208,10 @@
|
|||
})
|
||||
</script>
|
||||
|
||||
<Modal bind:this={exportModal} padding={false} width="600px">
|
||||
<ExportAppModal app={selectedApp} {published} />
|
||||
</Modal>
|
||||
|
||||
<span class="overview-wrap">
|
||||
<Page wide noPadding>
|
||||
{#await promise}
|
||||
|
@ -269,14 +275,14 @@
|
|||
<Icon hoverable name="More" />
|
||||
</span>
|
||||
<MenuItem
|
||||
on:click={() => exportApp(selectedApp, { published: false })}
|
||||
on:click={() => exportApp({ published: false })}
|
||||
icon="DownloadFromCloud"
|
||||
>
|
||||
Export latest
|
||||
</MenuItem>
|
||||
{#if isPublished}
|
||||
<MenuItem
|
||||
on:click={() => exportApp(selectedApp, { published: true })}
|
||||
on:click={() => exportApp({ published: true })}
|
||||
icon="DownloadFromCloudOutline"
|
||||
>
|
||||
Export published
|
||||
|
|
|
@ -88,14 +88,14 @@
|
|||
<Heading size="S">Information</Heading>
|
||||
<Body size="S">Here you can update your logo and organization name.</Body>
|
||||
</Layout>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<div className="fields">
|
||||
<div className="field">
|
||||
<Label size="L">Org. name</Label>
|
||||
<Input thin bind:value={$values.company} />
|
||||
</div>
|
||||
<div class="field logo">
|
||||
<div className="field logo">
|
||||
<Label size="L">Logo</Label>
|
||||
<div class="file">
|
||||
<div className="file">
|
||||
<Dropzone
|
||||
value={[$values.logo]}
|
||||
on:change={e => {
|
||||
|
@ -115,8 +115,8 @@
|
|||
<Heading size="S">Platform</Heading>
|
||||
<Body size="S">Here you can set up general platform settings.</Body>
|
||||
</Layout>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<div className="fields">
|
||||
<div className="field">
|
||||
<Label
|
||||
size="L"
|
||||
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;
|
||||
grid-gap: var(--spacing-m);
|
||||
}
|
||||
|
||||
.field {
|
||||
display: grid;
|
||||
grid-template-columns: 100px 1fr;
|
||||
grid-gap: var(--spacing-l);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file {
|
||||
max-width: 30ch;
|
||||
}
|
||||
|
||||
.logo {
|
||||
align-items: start;
|
||||
}
|
||||
|
|
|
@ -62,8 +62,11 @@ export function createDatasourcesStore() {
|
|||
unselect: () => {
|
||||
update(state => ({ ...state, selected: null }))
|
||||
},
|
||||
updateSchema: async datasource => {
|
||||
const response = await API.buildDatasourceSchema(datasource?._id)
|
||||
updateSchema: async (datasource, tablesFilter) => {
|
||||
const response = await API.buildDatasourceSchema({
|
||||
datasourceId: datasource?._id,
|
||||
tablesFilter,
|
||||
})
|
||||
return await updateDatasource(response)
|
||||
},
|
||||
save: async (body, fetchSchema = false) => {
|
||||
|
|
|
@ -8,3 +8,4 @@ export { oidc } from "./oidc"
|
|||
export { templates } from "./templates"
|
||||
export { licensing } from "./licensing"
|
||||
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 replace from "@rollup/plugin-replace"
|
||||
import { defineConfig, loadEnv } from "vite"
|
||||
|
||||
import path from "path"
|
||||
|
||||
export default ({ mode }) => {
|
||||
export default defineConfig(({ mode }) => {
|
||||
const isProduction = mode === "production"
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
return {
|
||||
server: {
|
||||
fs: {
|
||||
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/",
|
||||
build: {
|
||||
|
@ -79,4 +87,4 @@ export default ({ mode }) => {
|
|||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -967,6 +967,11 @@
|
|||
debug "^3.1.0"
|
||||
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":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17"
|
||||
|
@ -1215,10 +1220,10 @@
|
|||
estree-walker "^1.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@rollup/pluginutils@^4.1.1":
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec"
|
||||
integrity sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==
|
||||
"@rollup/pluginutils@^4.2.1":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
||||
integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
|
||||
dependencies:
|
||||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
@ -1350,17 +1355,17 @@
|
|||
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-4.3.0.tgz#03ddf67d3aa8a9a4cb0edbbd259465c9ced7e70d"
|
||||
integrity sha512-ZQ2XAhgu4G9yBeXQNDAz07Z8oZNnMt5o9vzf/mpBA7Teb/JI+8qXp2wt8D245SzmtNlFkG/bzRYvQc0scgZeCQ==
|
||||
|
||||
"@sveltejs/vite-plugin-svelte@1.0.0-next.19":
|
||||
version "1.0.0-next.19"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.19.tgz#9646abc2cd1982146db4bb341aafdb5f32f19dd2"
|
||||
integrity sha512-q9hHkMzodScwDq64pNaWhekpj97vWg3wO9T0rqd8bC2EsrBQs2uD1qMJvDqlNd63AbO2uSJMGo+TQ0Xt2xgyYg==
|
||||
"@sveltejs/vite-plugin-svelte@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.1.tgz#7f468f03c933fcdfc60d4773671c73f33b9ef4d6"
|
||||
integrity sha512-PorCgUounn0VXcpeJu+hOweZODKmGuLHsLomwqSj+p26IwjjGffmYQfVHtiTWq+NqaUuuHWWG7vPge6UFw4Aeg==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^4.1.1"
|
||||
debug "^4.3.2"
|
||||
kleur "^4.1.4"
|
||||
magic-string "^0.25.7"
|
||||
require-relative "^0.8.7"
|
||||
svelte-hmr "^0.14.7"
|
||||
"@rollup/pluginutils" "^4.2.1"
|
||||
debug "^4.3.4"
|
||||
deepmerge "^4.2.2"
|
||||
kleur "^4.1.5"
|
||||
magic-string "^0.26.2"
|
||||
svelte-hmr "^0.14.12"
|
||||
|
||||
"@testing-library/dom@^7.0.3":
|
||||
version "7.31.2"
|
||||
|
@ -2493,6 +2498,13 @@ debug@^3.1.0:
|
|||
dependencies:
|
||||
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:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
|
@ -2655,113 +2667,132 @@ error-ex@^1.3.1:
|
|||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
esbuild-android-arm64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.14.tgz#c85083ece26be3d67e6c720e088968a98409e023"
|
||||
integrity sha512-Q+Xhfp827r+ma8/DJgpMRUbDZfefsk13oePFEXEIJ4gxFbNv5+vyiYXYuKm43/+++EJXpnaYmEnu4hAKbAWYbA==
|
||||
esbuild-android-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
|
||||
integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
|
||||
|
||||
esbuild-darwin-64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.14.tgz#8e4e237ad847cc54a1d3a5caee26a746b9f0b81f"
|
||||
integrity sha512-YmOhRns6QBNSjpVdTahi/yZ8dscx9ai7a6OY6z5ACgOuQuaQ2Qk2qgJ0/siZ6LgD0gJFMV8UINFV5oky5TFNQQ==
|
||||
esbuild-android-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
|
||||
integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
|
||||
|
||||
esbuild-darwin-arm64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.14.tgz#b3b5ebd40b2cb06ee0f6fb342dd4bdcca54ad273"
|
||||
integrity sha512-Lp00VTli2jqZghSa68fx3fEFCPsO1hK59RMo1PRap5RUjhf55OmaZTZYnCDI0FVlCtt+gBwX5qwFt4lc6tI1xg==
|
||||
esbuild-darwin-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
|
||||
integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
|
||||
|
||||
esbuild-freebsd-64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.14.tgz#175ecb2fa8141428cf70ea2d5f4c27534bad53e0"
|
||||
integrity sha512-BKosI3jtvTfnmsCW37B1TyxMUjkRWKqopR0CE9AF2ratdpkxdR24Vpe3gLKNyWiZ7BE96/SO5/YfhbPUzY8wKw==
|
||||
esbuild-darwin-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
|
||||
integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
|
||||
|
||||
esbuild-freebsd-arm64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.14.tgz#a7d64e41d1fa581f8db7775e5200f18e67d70c4d"
|
||||
integrity sha512-yd2uh0yf+fWv5114+SYTl4/1oDWtr4nN5Op+PGxAkMqHfYfLjFKpcxwCo/QOS/0NWqPVE8O41IYZlFhbEN2B8Q==
|
||||
esbuild-freebsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
|
||||
integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
|
||||
|
||||
esbuild-linux-32@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.14.tgz#14bdd4f6b6cfd35c65c835894651ba335c2117da"
|
||||
integrity sha512-a8rOnS1oWSfkkYWXoD2yXNV4BdbDKA7PNVQ1klqkY9SoSApL7io66w5H44mTLsfyw7G6Z2vLlaLI2nz9MMAowA==
|
||||
esbuild-freebsd-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
|
||||
integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
|
||||
|
||||
esbuild-linux-64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.14.tgz#7fd56851b2982fdd0cd8447ee9858c2c5711708a"
|
||||
integrity sha512-yPZSoMs9W2MC3Dw+6kflKt5FfQm6Dicex9dGIr1OlHRsn3Hm7yGMUTctlkW53KknnZdOdcdd5upxvbxqymczVQ==
|
||||
esbuild-linux-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
|
||||
integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
|
||||
|
||||
esbuild-linux-arm64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.14.tgz#a55634d70679ba509adeafd68eebb9fd1ec5af6c"
|
||||
integrity sha512-Lvo391ln9PzC334e+jJ2S0Rt0cxP47eoH5gFyv/E8HhOnEJTvm7A+RRnMjjHnejELacTTfYgFGQYPjLsi/jObQ==
|
||||
esbuild-linux-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
|
||||
integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
|
||||
|
||||
esbuild-linux-arm@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.14.tgz#bb96a99677e608b31ff61f37564326d38e846ca2"
|
||||
integrity sha512-8chZE4pkKRvJ/M/iwsNQ1KqsRg2RyU5eT/x2flNt/f8F2TVrDreR7I0HEeCR50wLla3B1C3wTIOzQBmjuc6uWg==
|
||||
esbuild-linux-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
|
||||
integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
|
||||
|
||||
esbuild-linux-mips64le@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.14.tgz#6a55362a8fd1e593dea2ecc41877beed8b8184b9"
|
||||
integrity sha512-MZhgxbmrWbpY3TOE029O6l5tokG9+Yoj2hW7vdit/d/VnmneqeGrSHADuDL6qXM8L5jaCiaivb4VhsyVCpdAbQ==
|
||||
esbuild-linux-arm@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
|
||||
integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
|
||||
|
||||
esbuild-linux-ppc64le@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.14.tgz#9e0048587ece0a7f184ab147f20d077098045e7f"
|
||||
integrity sha512-un7KMwS7fX1Un6BjfSZxTT8L5cV/8Uf4SAhM7WYy2XF8o8TI+uRxxD03svZnRNIPsN2J5cl6qV4n7Iwz+yhhVw==
|
||||
esbuild-linux-mips64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
|
||||
integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
|
||||
|
||||
esbuild-netbsd-64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.14.tgz#dcab16a4bbcfa16e2e8535dadc5f64fdc891c63b"
|
||||
integrity sha512-5ekKx/YbOmmlTeNxBjh38Uh5TGn5C4uyqN17i67k18pS3J+U2hTVD7rCxcFcRS1AjNWumkVL3jWqYXadFwMS0Q==
|
||||
esbuild-linux-ppc64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
|
||||
integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
|
||||
|
||||
esbuild-openbsd-64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.14.tgz#3c7453b155ebb68dc34d5aec3bd6505337bdda08"
|
||||
integrity sha512-9bzvwewHjct2Cv5XcVoE1yW5YTW12Sk838EYfA46abgnhxGoFSD1mFcaztp5HHC43AsF+hQxbSFG/RilONARUA==
|
||||
esbuild-linux-riscv64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
|
||||
integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
|
||||
|
||||
esbuild-sunos-64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.14.tgz#85addf5fef6b5db154a955d4f2e88953359d75ce"
|
||||
integrity sha512-mjMrZB76M6FmoiTvj/RGWilrioR7gVwtFBRVugr9qLarXMIU1W/pQx+ieEOtflrW61xo8w1fcxyHsVVGRvoQ0w==
|
||||
esbuild-linux-s390x@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
|
||||
integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
|
||||
|
||||
esbuild-windows-32@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.14.tgz#f77f98f30a5c636c44db2428ecdf9bcbbaedb1a7"
|
||||
integrity sha512-GZa6mrx2rgfbH/5uHg0Rdw50TuOKbdoKCpEBitzmG5tsXBdce+cOL+iFO5joZc6fDVCLW3Y6tjxmSXRk/v20Hg==
|
||||
esbuild-netbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
|
||||
integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
|
||||
|
||||
esbuild-windows-64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.14.tgz#bc778674c40d65150d12385e0f23eb3a0badbd0d"
|
||||
integrity sha512-Lsgqah24bT7ClHjLp/Pj3A9wxjhIAJyWQcrOV4jqXAFikmrp2CspA8IkJgw7HFjx6QrJuhpcKVbCAe/xw0i2yw==
|
||||
esbuild-openbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
|
||||
integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
|
||||
|
||||
esbuild-windows-arm64@0.13.14:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.14.tgz#91a8dad35ab2c4dd27cd83860742955b25a354d7"
|
||||
integrity sha512-KP8FHVlWGhM7nzYtURsGnskXb/cBCPTfj0gOKfjKq2tHtYnhDZywsUG57nk7TKhhK0fL11LcejHG3LRW9RF/9A==
|
||||
esbuild-sunos-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
|
||||
integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
|
||||
|
||||
esbuild@^0.13.2:
|
||||
version "0.13.14"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.14.tgz#98a3f7f42809abdc2b57c84565d0f713382dc1a5"
|
||||
integrity sha512-xu4D+1ji9x53ocuomcY+KOrwAnWzhBu/wTEjpdgZ8I1c8i5vboYIeigMdzgY1UowYBKa2vZgVgUB32bu7gkxeg==
|
||||
esbuild-windows-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
|
||||
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:
|
||||
esbuild-android-arm64 "0.13.14"
|
||||
esbuild-darwin-64 "0.13.14"
|
||||
esbuild-darwin-arm64 "0.13.14"
|
||||
esbuild-freebsd-64 "0.13.14"
|
||||
esbuild-freebsd-arm64 "0.13.14"
|
||||
esbuild-linux-32 "0.13.14"
|
||||
esbuild-linux-64 "0.13.14"
|
||||
esbuild-linux-arm "0.13.14"
|
||||
esbuild-linux-arm64 "0.13.14"
|
||||
esbuild-linux-mips64le "0.13.14"
|
||||
esbuild-linux-ppc64le "0.13.14"
|
||||
esbuild-netbsd-64 "0.13.14"
|
||||
esbuild-openbsd-64 "0.13.14"
|
||||
esbuild-sunos-64 "0.13.14"
|
||||
esbuild-windows-32 "0.13.14"
|
||||
esbuild-windows-64 "0.13.14"
|
||||
esbuild-windows-arm64 "0.13.14"
|
||||
"@esbuild/linux-loong64" "0.14.54"
|
||||
esbuild-android-64 "0.14.54"
|
||||
esbuild-android-arm64 "0.14.54"
|
||||
esbuild-darwin-64 "0.14.54"
|
||||
esbuild-darwin-arm64 "0.14.54"
|
||||
esbuild-freebsd-64 "0.14.54"
|
||||
esbuild-freebsd-arm64 "0.14.54"
|
||||
esbuild-linux-32 "0.14.54"
|
||||
esbuild-linux-64 "0.14.54"
|
||||
esbuild-linux-arm "0.14.54"
|
||||
esbuild-linux-arm64 "0.14.54"
|
||||
esbuild-linux-mips64le "0.14.54"
|
||||
esbuild-linux-ppc64le "0.14.54"
|
||||
esbuild-linux-riscv64 "0.14.54"
|
||||
esbuild-linux-s390x "0.14.54"
|
||||
esbuild-netbsd-64 "0.14.54"
|
||||
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:
|
||||
version "3.1.1"
|
||||
|
@ -3519,6 +3550,13 @@ is-core-module@^2.2.0:
|
|||
dependencies:
|
||||
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:
|
||||
version "0.1.4"
|
||||
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"
|
||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||
|
||||
kleur@^4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d"
|
||||
integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==
|
||||
kleur@^4.1.5:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
|
||||
integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
|
||||
|
||||
lazy-ass@1.6.0, lazy-ass@^1.6.0:
|
||||
version "1.6.0"
|
||||
|
@ -4425,6 +4463,13 @@ magic-string@^0.25.7:
|
|||
dependencies:
|
||||
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:
|
||||
version "3.1.0"
|
||||
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"
|
||||
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
|
||||
|
||||
nanoid@^3.1.30:
|
||||
version "3.1.30"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362"
|
||||
integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==
|
||||
nanoid@^3.3.4:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
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"
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
path-parse@^1.0.6:
|
||||
path-parse@^1.0.6, path-parse@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
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"
|
||||
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
|
||||
|
||||
postcss@^8.3.8:
|
||||
version "8.3.11"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858"
|
||||
integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA==
|
||||
postcss@^8.4.16:
|
||||
version "8.4.16"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
|
||||
integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
|
||||
dependencies:
|
||||
nanoid "^3.1.30"
|
||||
nanoid "^3.3.4"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^0.6.2"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
posthog-js@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"
|
||||
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:
|
||||
version "3.0.0"
|
||||
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"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||
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"
|
||||
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:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
|
||||
|
@ -5262,7 +5311,14 @@ rollup-pluginutils@^2.8.2:
|
|||
dependencies:
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.60.0.tgz#4ee60ab7bdd0356763f87d7099f413e5460fc193"
|
||||
integrity sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==
|
||||
|
@ -5475,10 +5531,10 @@ snapdragon@^0.8.1:
|
|||
source-map-resolve "^0.5.0"
|
||||
use "^3.1.0"
|
||||
|
||||
source-map-js@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
|
||||
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
||||
source-map-resolve@^0.5.0:
|
||||
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"
|
||||
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
||||
|
||||
sourcemap-codec@^1.4.4:
|
||||
sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8:
|
||||
version "1.4.8"
|
||||
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||
|
@ -5707,15 +5763,20 @@ supports-hyperlinks@^2.0.0:
|
|||
has-flag "^4.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:
|
||||
version "0.9.12"
|
||||
resolved "https://registry.yarnpkg.com/svelte-dnd-action/-/svelte-dnd-action-0.9.12.tgz#78cf33097986488c6d069eca517af473cd998730"
|
||||
integrity sha512-GlXIB3/56IMR5A0+qUx+FX7Q7n8uCAIeuYdgSBmn9iOlxWc+mgM8P1kNwAKCMSTdQ4IQETVQILNgWVY1KIFzsg==
|
||||
|
||||
svelte-hmr@^0.14.7:
|
||||
version "0.14.7"
|
||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.7.tgz#7fa8261c7b225d9409f0a86f3b9ea5c3ca6f6607"
|
||||
integrity sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==
|
||||
svelte-hmr@^0.14.12:
|
||||
version "0.14.12"
|
||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.12.tgz#a127aec02f1896500b10148b2d4d21ddde39973f"
|
||||
integrity sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==
|
||||
|
||||
svelte-jester@^1.3.2:
|
||||
version "1.8.2"
|
||||
|
@ -6081,15 +6142,15 @@ verror@1.10.0:
|
|||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
vite@^2.1.5:
|
||||
version "2.6.14"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-2.6.14.tgz#35c09a15e4df823410819a2a239ab11efb186271"
|
||||
integrity sha512-2HA9xGyi+EhY2MXo0+A2dRsqsAG3eFNEVIo12olkWhOmc8LfiM+eMdrXf+Ruje9gdXgvSqjLI9freec1RUM5EA==
|
||||
vite@^3.0.8:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.8.tgz#aa095ad8e3e5da46d9ec7e878f262678965d6531"
|
||||
integrity sha512-AOZ4eN7mrkJiOLuw8IA7piS4IdOQyQCA81GxGsAQvAZzMRi9ZwGB3TOaYsj4uLAWK46T5L4AfQ6InNGlxX30IQ==
|
||||
dependencies:
|
||||
esbuild "^0.13.2"
|
||||
postcss "^8.3.8"
|
||||
resolve "^1.20.0"
|
||||
rollup "^2.57.0"
|
||||
esbuild "^0.14.47"
|
||||
postcss "^8.4.16"
|
||||
resolve "^1.22.1"
|
||||
rollup ">=2.75.6 <2.77.0 || ~2.77.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "1.3.4-alpha.2",
|
||||
"version": "1.3.15-alpha.3",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
@ -26,14 +26,18 @@
|
|||
"outputPath": "build"
|
||||
},
|
||||
"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",
|
||||
"chalk": "4.1.0",
|
||||
"cli-progress": "3.11.2",
|
||||
"commander": "7.1.0",
|
||||
"docker-compose": "0.23.6",
|
||||
"dotenv": "16.0.1",
|
||||
"download": "8.0.0",
|
||||
"inquirer": "8.0.0",
|
||||
"joi": "17.6.0",
|
||||
"lookpath": "1.1.0",
|
||||
"node-fetch": "2",
|
||||
"pkg": "5.7.0",
|
||||
|
|
|
@ -3,6 +3,7 @@ exports.CommandWords = {
|
|||
HOSTING: "hosting",
|
||||
ANALYTICS: "analytics",
|
||||
HELP: "help",
|
||||
PLUGIN: "plugins",
|
||||
}
|
||||
|
||||
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
|
||||
require("./prebuilds")
|
||||
require("./environment")
|
||||
const { getCommands } = require("./options")
|
||||
const { Command } = require("commander")
|
||||
const { getHelpDescription } = require("./utils")
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const analytics = require("./analytics")
|
||||
const hosting = require("./hosting")
|
||||
const backups = require("./backups")
|
||||
const plugins = require("./plugins")
|
||||
|
||||
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 { join } = require("path")
|
||||
const fs = require("fs")
|
||||
const { error } = require("./utils")
|
||||
const PREBUILDS = "prebuilds"
|
||||
const ARCH = `${os.platform()}-${os.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() {
|
||||
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)) {
|
||||
fs.rmSync(PREBUILD_DIR, { recursive: true })
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "1.3.4-alpha.2",
|
||||
"version": "1.3.15-alpha.3",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,9 +19,9 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.3.4-alpha.2",
|
||||
"@budibase/frontend-core": "1.3.4-alpha.2",
|
||||
"@budibase/string-templates": "1.3.4-alpha.2",
|
||||
"@budibase/bbui": "1.3.15-alpha.3",
|
||||
"@budibase/frontend-core": "1.3.15-alpha.3",
|
||||
"@budibase/string-templates": "1.3.15-alpha.3",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
@ -39,6 +39,7 @@
|
|||
"sanitize-html": "^2.7.0",
|
||||
"screenfull": "^6.0.1",
|
||||
"shortid": "^2.2.15",
|
||||
"socket.io-client": "^4.5.1",
|
||||
"svelte": "^3.49.0",
|
||||
"svelte-apexcharts": "^1.0.2",
|
||||
"svelte-flatpickr": "^3.1.0",
|
||||
|
|
|
@ -89,6 +89,14 @@
|
|||
})
|
||||
</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}
|
||||
<div
|
||||
id="spectrum-root"
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
<script>
|
||||
import { getContext, setContext, onMount, onDestroy } from "svelte"
|
||||
import { writable, get } from "svelte/store"
|
||||
import * as AppComponents from "components/app"
|
||||
import Router from "./Router.svelte"
|
||||
import {
|
||||
enrichProps,
|
||||
propsAreSame,
|
||||
|
@ -127,7 +125,9 @@
|
|||
// Empty components are those which accept children but do not have any.
|
||||
// Empty states can be shown for these components, but can be disabled
|
||||
// in the component manifest.
|
||||
$: empty = interactive && !children.length && hasChildren
|
||||
$: empty =
|
||||
(interactive && !children.length && hasChildren) ||
|
||||
hasMissingRequiredSettings
|
||||
$: emptyState = empty && showEmptyState
|
||||
|
||||
// Enrich component settings
|
||||
|
@ -165,14 +165,14 @@
|
|||
missingRequiredSettings,
|
||||
})
|
||||
|
||||
const initialise = instance => {
|
||||
const initialise = (instance, force = false) => {
|
||||
if (instance == null) {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure we're processing a new instance
|
||||
const instanceKey = Helpers.hashString(JSON.stringify(instance))
|
||||
if (instanceKey === lastInstanceKey) {
|
||||
if (instanceKey === lastInstanceKey && !force) {
|
||||
return
|
||||
} else {
|
||||
lastInstanceKey = instanceKey
|
||||
|
@ -180,7 +180,7 @@
|
|||
|
||||
// Pull definition and constructor
|
||||
const component = instance._component
|
||||
constructor = getComponentConstructor(component)
|
||||
constructor = componentStore.actions.getComponentConstructor(component)
|
||||
definition = componentStore.actions.getComponentDefinition(component)
|
||||
if (!definition) {
|
||||
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 => {
|
||||
let map = {}
|
||||
settingsDefinition?.forEach(setting => {
|
||||
|
@ -419,9 +409,11 @@
|
|||
!componentStore.actions.isComponentRegistered(id)
|
||||
) {
|
||||
componentStore.actions.registerInstance(id, {
|
||||
component: instance._component,
|
||||
getSettings: () => cachedSettings,
|
||||
getRawSettings: () => ({ ...staticSettings, ...dynamicSettings }),
|
||||
getDataContext: () => get(context),
|
||||
reload: () => initialise(instance, true),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,28 +2,25 @@
|
|||
import { getContext } from "svelte"
|
||||
import { builderStore } from "stores"
|
||||
|
||||
const { styleable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
$: requiredSetting = $component.missingRequiredSettings?.[0]
|
||||
</script>
|
||||
|
||||
{#if $builderStore.inBuilder && requiredSetting}
|
||||
<div use:styleable={$component.styles}>
|
||||
<div class="component-placeholder">
|
||||
<span>
|
||||
Add the <mark>{requiredSetting.label}</mark> setting to start using your
|
||||
component -
|
||||
</span>
|
||||
<span
|
||||
class="spectrum-Link"
|
||||
on:click={() => {
|
||||
builderStore.actions.highlightSetting(requiredSetting.key)
|
||||
}}
|
||||
>
|
||||
Show me
|
||||
</span>
|
||||
</div>
|
||||
<div class="component-placeholder">
|
||||
<span>
|
||||
Add the <mark>{requiredSetting.label}</mark> setting to start using your component
|
||||
-
|
||||
</span>
|
||||
<span
|
||||
class="spectrum-Link"
|
||||
on:click={() => {
|
||||
builderStore.actions.highlightSetting(requiredSetting.key)
|
||||
}}
|
||||
>
|
||||
Show me
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { ProgressCircle, Pagination } from "@budibase/bbui"
|
||||
import Placeholder from "./Placeholder.svelte"
|
||||
import { fetchData, LuceneUtils } from "@budibase/frontend-core"
|
||||
|
||||
export let dataSource
|
||||
|
@ -133,11 +132,7 @@
|
|||
<ProgressCircle />
|
||||
</div>
|
||||
{:else}
|
||||
{#if $component.emptyState}
|
||||
<Placeholder />
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
<slot />
|
||||
{#if paginate && $fetch.supportsPagination}
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
label="Active screen"
|
||||
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="Role" value={$authStore.roleId} />
|
||||
</Layout>
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
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 { 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
|
||||
loadSpectrumIcons()
|
||||
|
@ -21,6 +34,8 @@ const loadBudibase = () => {
|
|||
previewDevice: window["##BUDIBASE_PREVIEW_DEVICE##"],
|
||||
navigation: window["##BUDIBASE_PREVIEW_NAVIGATION##"],
|
||||
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
|
||||
|
@ -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
|
||||
if (!app) {
|
||||
app = new ClientApp({
|
||||
|
|
|
@ -19,6 +19,7 @@ const createBuilderStore = () => {
|
|||
isDragging: false,
|
||||
navigation: null,
|
||||
hiddenComponentIds: [],
|
||||
usedPlugins: null,
|
||||
|
||||
// Legacy - allow the builder to specify a layout
|
||||
layout: null,
|
||||
|
@ -87,6 +88,20 @@ const createBuilderStore = () => {
|
|||
ejectBlock: (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 {
|
||||
...store,
|
||||
|
|
|
@ -4,9 +4,17 @@ import { findComponentById, findComponentPathById } from "../utils/components"
|
|||
import { devToolsStore } from "./devTools"
|
||||
import { screenStore } from "./screens"
|
||||
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 store = writable({})
|
||||
const store = writable({
|
||||
customComponentManifest: {},
|
||||
customComponentMap: {},
|
||||
mountedComponents: {},
|
||||
})
|
||||
|
||||
const derivedStore = derived(
|
||||
[store, builderStore, devToolsStore, screenStore],
|
||||
|
@ -25,41 +33,65 @@ const createComponentStore = () => {
|
|||
asset = $screenState.activeScreen
|
||||
}
|
||||
const component = findComponentById(asset?.props, selectedComponentId)
|
||||
const prefix = "@budibase/standard-components/"
|
||||
const type = component?._component?.replace(prefix, "")
|
||||
const definition = type ? Manifest[type] : null
|
||||
const definition = getComponentDefinition(component?._component)
|
||||
|
||||
// Derive the selected component path
|
||||
const path =
|
||||
findComponentPathById(asset?.props, selectedComponentId) || []
|
||||
|
||||
return {
|
||||
selectedComponentInstance: $store[selectedComponentId],
|
||||
customComponentManifest: $store.customComponentManifest,
|
||||
selectedComponentInstance:
|
||||
$store.mountedComponents[selectedComponentId],
|
||||
selectedComponent: component,
|
||||
selectedComponentDefinition: definition,
|
||||
selectedComponentPath: path?.map(component => component._id),
|
||||
mountedComponents: Object.keys($store).length,
|
||||
mountedComponentCount: Object.keys($store.mountedComponents).length,
|
||||
currentAsset: asset,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const registerInstance = (id, instance) => {
|
||||
store.update(state => ({
|
||||
...state,
|
||||
[id]: instance,
|
||||
}))
|
||||
store.update(state => {
|
||||
// If this is a custom component, flag it so we can reload this component
|
||||
// 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 => {
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
const isComponentRegistered = id => {
|
||||
return get(store)[id] != null
|
||||
return get(store).mountedComponents[id] != null
|
||||
}
|
||||
|
||||
const getComponentById = id => {
|
||||
|
@ -68,9 +100,66 @@ const createComponentStore = () => {
|
|||
}
|
||||
|
||||
const getComponentDefinition = type => {
|
||||
const prefix = "@budibase/standard-components/"
|
||||
type = type?.replace(prefix, "")
|
||||
return type ? Manifest[type] : null
|
||||
if (!type) {
|
||||
return 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 {
|
||||
|
@ -81,6 +170,8 @@ const createComponentStore = () => {
|
|||
isComponentRegistered,
|
||||
getComponentById,
|
||||
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"
|
||||
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":
|
||||
version "3.0.3"
|
||||
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"
|
||||
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:
|
||||
version "4.2.2"
|
||||
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"
|
||||
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:
|
||||
version "2.2.0"
|
||||
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"
|
||||
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:
|
||||
version "2.1.11"
|
||||
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"
|
||||
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:
|
||||
version "1.0.2"
|
||||
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"
|
||||
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:
|
||||
version "5.0.8"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"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",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.3.4-alpha.2",
|
||||
"@budibase/bbui": "1.3.15-alpha.3",
|
||||
"lodash": "^4.17.21",
|
||||
"svelte": "^3.46.2"
|
||||
}
|
||||
|
|
|
@ -11,10 +11,14 @@ export const buildDatasourceEndpoints = API => ({
|
|||
/**
|
||||
* Prompts the server to build the schema for a datasource.
|
||||
* @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({
|
||||
url: `/api/datasources/${datasourceId}/schema`,
|
||||
body: {
|
||||
tablesFilter,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import { buildSelfEndpoints } from "./self"
|
|||
import { buildViewEndpoints } from "./views"
|
||||
import { buildLicensingEndpoints } from "./licensing"
|
||||
import { buildGroupsEndpoints } from "./groups"
|
||||
import { buildPluginEndpoints } from "./plugins"
|
||||
|
||||
const defaultAPIClientConfig = {
|
||||
/**
|
||||
|
@ -243,5 +244,6 @@ export const createAPIClient = config => {
|
|||
...buildSelfEndpoints(API),
|
||||
...buildLicensingEndpoints(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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param filter the builder filter structure
|
||||
|
@ -194,7 +207,7 @@ export const runLuceneQuery = (docs, query) => {
|
|||
const filters = Object.entries(query[type] || {})
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
const [key, testValue] = filters[i]
|
||||
const docValue = Helpers.deepGet(doc, key)
|
||||
const docValue = Helpers.deepGet(doc, removeKeyNumbering(key))
|
||||
if (failFn(docValue, testValue)) {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ module MongoMock {
|
|||
})
|
||||
}
|
||||
|
||||
mongodb.ObjectID = require("mongodb").ObjectID
|
||||
mongodb.ObjectID = jest.requireActual("mongodb").ObjectID
|
||||
|
||||
module.exports = mongodb
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "1.3.4-alpha.2",
|
||||
"version": "1.3.15-alpha.3",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -77,11 +77,11 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "1.3.4-alpha.2",
|
||||
"@budibase/client": "1.3.4-alpha.2",
|
||||
"@budibase/pro": "1.3.4-alpha.2",
|
||||
"@budibase/string-templates": "1.3.4-alpha.2",
|
||||
"@budibase/types": "1.3.4-alpha.2",
|
||||
"@budibase/backend-core": "1.3.15-alpha.3",
|
||||
"@budibase/client": "1.3.15-alpha.3",
|
||||
"@budibase/pro": "1.3.15-alpha.3",
|
||||
"@budibase/string-templates": "1.3.15-alpha.3",
|
||||
"@budibase/types": "1.3.15-alpha.3",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
@ -95,6 +95,7 @@
|
|||
"bcryptjs": "2.4.3",
|
||||
"bull": "4.8.5",
|
||||
"chmodr": "1.2.0",
|
||||
"chokidar": "3.5.3",
|
||||
"csvtojson": "2.0.10",
|
||||
"curlconverter": "3.21.0",
|
||||
"dotenv": "8.2.0",
|
||||
|
@ -138,8 +139,10 @@
|
|||
"redis": "4",
|
||||
"server-destroy": "1.0.1",
|
||||
"snowflake-promise": "^4.5.0",
|
||||
"socket.io": "^4.5.1",
|
||||
"svelte": "3.49.0",
|
||||
"swagger-parser": "10.0.3",
|
||||
"tar": "6.1.11",
|
||||
"to-json-schema": "0.2.5",
|
||||
"uuid": "3.3.2",
|
||||
"validate.js": "0.13.1",
|
||||
|
|
|
@ -58,6 +58,7 @@ async function init() {
|
|||
DEPLOYMENT_ENVIRONMENT: "development",
|
||||
BB_ADMIN_USER_EMAIL: "",
|
||||
BB_ADMIN_USER_PASSWORD: "",
|
||||
PLUGINS_DIR: "",
|
||||
}
|
||||
let envFile = ""
|
||||
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