Merge branch 'chore/npmless-builds' into chore/esbuild
This commit is contained in:
commit
f426ba1ac3
|
@ -1,36 +1,25 @@
|
|||
name: Budibase CI
|
||||
|
||||
on:
|
||||
# Trigger the workflow on push or pull request,
|
||||
# but only for the master branch
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
on:
|
||||
# Trigger the workflow on push or pull request,
|
||||
# but only for the master branch
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BRANCH: ${{ github.event.pull_request.head.ref }}
|
||||
BASE_BRANCH: ${{ github.event.pull_request.base.ref}}
|
||||
PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
- run: yarn
|
||||
- run: yarn lint
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -38,8 +27,20 @@ jobs:
|
|||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
- name: Install Pro
|
||||
run: yarn install:pro $BRANCH $BASE_BRANCH
|
||||
- run: yarn
|
||||
- run: yarn lint
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
- run: yarn
|
||||
- run: yarn bootstrap
|
||||
- run: yarn build
|
||||
|
@ -48,16 +49,17 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
- name: Install Pro
|
||||
run: yarn install:pro $BRANCH $BASE_BRANCH
|
||||
- run: yarn
|
||||
- run: yarn bootstrap
|
||||
- run: yarn build
|
||||
- run: yarn test
|
||||
- run: yarn test --ignore=@budibase/pro
|
||||
- uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
|
||||
|
@ -68,26 +70,28 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
- name: Install Pro
|
||||
run: yarn install:pro $BRANCH $BASE_BRANCH
|
||||
- run: yarn
|
||||
- run: yarn bootstrap
|
||||
- run: yarn test:pro
|
||||
- run: yarn test --scope=@budibase/pro
|
||||
|
||||
integration-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
- name: Install Pro
|
||||
run: yarn install:pro $BRANCH $BASE_BRANCH
|
||||
- run: yarn && yarn bootstrap && yarn build
|
||||
- run: |
|
||||
cd qa-core
|
||||
|
@ -96,3 +100,24 @@ jobs:
|
|||
env:
|
||||
BB_ADMIN_USER_EMAIL: admin
|
||||
BB_ADMIN_USER_PASSWORD: admin
|
||||
|
||||
check-pro-submodule:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
fetch-depth: 0
|
||||
- name: Check submodule
|
||||
run: |
|
||||
cd packages/pro
|
||||
git fetch
|
||||
if ! git merge-base --is-ancestor $(git log -n 1 --pretty=format:%H) origin/develop; then
|
||||
echo "Current commit has not been merged to develop"
|
||||
echo "Refer to the pro repo to merge your changes: https://github.com/Budibase/budibase-pro/blob/develop/docs/getting_started.md"
|
||||
exit 1
|
||||
else
|
||||
echo "All good, the submodule had been merged!"
|
||||
fi
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
name: Budibase Prerelease
|
||||
concurrency: release-prerelease
|
||||
|
||||
on:
|
||||
push:
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- '.aws/**'
|
||||
- '.github/**'
|
||||
- 'charts/**'
|
||||
- 'packages/**'
|
||||
- 'scripts/**'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
workflow_dispatch:
|
||||
- ".aws/**"
|
||||
- ".github/**"
|
||||
- "charts/**"
|
||||
- "packages/**"
|
||||
- "scripts/**"
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
# Posthog token used by ui at build time
|
||||
|
@ -24,35 +24,35 @@ env:
|
|||
INTERCOM_TOKEN: ${{ secrets.INTERCOM_TOKEN }}
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
FEATURE_PREVIEW_URL: https://budirelease.live
|
||||
|
||||
|
||||
jobs:
|
||||
release-images:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Fail if branch is not develop
|
||||
if: github.ref != 'refs/heads/develop'
|
||||
run: |
|
||||
if: github.ref != 'refs/heads/develop'
|
||||
run: |
|
||||
echo "Ref is not develop, you must run this job from develop."
|
||||
exit 1
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Install Pro
|
||||
run: yarn install:pro develop
|
||||
|
||||
- run: yarn
|
||||
- run: yarn
|
||||
- run: yarn bootstrap
|
||||
- run: yarn build
|
||||
- run: yarn build:sdk
|
||||
# - run: yarn test
|
||||
# - run: yarn test
|
||||
|
||||
- name: Publish budibase packages to NPM
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: |
|
||||
run: |
|
||||
# setup the username and email.
|
||||
git config --global user.name "Budibase Staging Release Bot"
|
||||
git config --global user.email "<>"
|
||||
|
@ -60,7 +60,7 @@ jobs:
|
|||
yarn release:develop
|
||||
|
||||
- name: Build/release Docker images
|
||||
run: |
|
||||
run: |
|
||||
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
|
||||
yarn build:docker:develop
|
||||
env:
|
||||
|
|
|
@ -2,55 +2,55 @@ name: Budibase Release
|
|||
concurrency: release
|
||||
|
||||
on:
|
||||
push:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- '.aws/**'
|
||||
- '.github/**'
|
||||
- 'charts/**'
|
||||
- 'packages/**'
|
||||
- 'scripts/**'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
versioning:
|
||||
type: choice
|
||||
description: "Versioning type: patch, minor, major"
|
||||
default: patch
|
||||
options:
|
||||
- patch
|
||||
- minor
|
||||
- major
|
||||
required: true
|
||||
- ".aws/**"
|
||||
- ".github/**"
|
||||
- "charts/**"
|
||||
- "packages/**"
|
||||
- "scripts/**"
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
versioning:
|
||||
type: choice
|
||||
description: "Versioning type: patch, minor, major"
|
||||
default: patch
|
||||
options:
|
||||
- patch
|
||||
- minor
|
||||
- major
|
||||
required: true
|
||||
|
||||
env:
|
||||
# Posthog token used by ui at build time
|
||||
# Posthog token used by ui at build time
|
||||
POSTHOG_TOKEN: phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||
INTERCOM_TOKEN: ${{ secrets.INTERCOM_TOKEN }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
|
||||
jobs:
|
||||
release-images:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fail if branch is not master
|
||||
if: github.ref != 'refs/heads/master'
|
||||
run: |
|
||||
if: github.ref != 'refs/heads/master'
|
||||
run: |
|
||||
echo "Ref is not master, you must run this job from master."
|
||||
exit 1
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Install Pro
|
||||
run: yarn install:pro master
|
||||
|
||||
- run: yarn
|
||||
- run: yarn bootstrap
|
||||
- run: yarn lint
|
||||
|
@ -68,12 +68,12 @@ jobs:
|
|||
echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} >> .npmrc
|
||||
yarn release
|
||||
|
||||
- name: 'Get Previous tag'
|
||||
- name: "Get Previous tag"
|
||||
id: previoustag
|
||||
uses: "WyriHaximus/github-action-get-previous-tag@v1"
|
||||
|
||||
- name: Build/release Docker images
|
||||
run: |
|
||||
run: |
|
||||
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
|
||||
yarn build:docker
|
||||
env:
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "packages/pro"]
|
||||
path = packages/pro
|
||||
url = git@github.com:Budibase/budibase-pro.git
|
|
@ -0,0 +1,4 @@
|
|||
# .husky/post-checkout
|
||||
# ...
|
||||
|
||||
git config submodule.recurse true
|
|
@ -1,13 +1,17 @@
|
|||
## Dev Environment on Debian 11
|
||||
|
||||
### Install NVM & Node 14
|
||||
|
||||
NVM documentation: https://github.com/nvm-sh/nvm#installing-and-updating
|
||||
|
||||
Install NVM
|
||||
|
||||
```
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
||||
```
|
||||
|
||||
Install Node 14
|
||||
|
||||
```
|
||||
nvm install 14
|
||||
```
|
||||
|
@ -17,13 +21,16 @@ nvm install 14
|
|||
```
|
||||
npm install -g yarn jest lerna
|
||||
```
|
||||
|
||||
### Install Docker and Docker Compose
|
||||
|
||||
```
|
||||
apt install docker.io
|
||||
pip3 install docker-compose
|
||||
```
|
||||
|
||||
### Clone the repo
|
||||
|
||||
```
|
||||
git clone https://github.com/Budibase/budibase.git
|
||||
```
|
||||
|
@ -44,10 +51,13 @@ This setup process was tested on Debian 11 (bullseye) with version numbers show
|
|||
cd budibase
|
||||
yarn setup
|
||||
```
|
||||
|
||||
The yarn setup command runs several build steps i.e.
|
||||
|
||||
```
|
||||
node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev
|
||||
```
|
||||
|
||||
So this command will actually run the application in dev mode. It creates .env files under `./packages/server` and `./packages/worker` and runs docker containers for each service via docker-compose.
|
||||
|
||||
The dev version will be available on port 10000 i.e.
|
||||
|
@ -55,6 +65,7 @@ The dev version will be available on port 10000 i.e.
|
|||
http://127.0.0.1:10000/builder/admin
|
||||
|
||||
### File descriptor issues with Vite and Chrome in Linux
|
||||
|
||||
If your dev environment stalls forever, with some network requests stuck in flight, it's likely that Chrome is trying to open more file descriptors than your system allows.
|
||||
To fix this, apply the following tweaks.
|
||||
|
||||
|
@ -62,4 +73,4 @@ Debian based distros:
|
|||
Add `* - nofile 65536` to `/etc/security/limits.conf`.
|
||||
|
||||
Arch:
|
||||
Add `DefaultLimitNOFILE=65536` to `/etc/systemd/system.conf`.
|
||||
Add `DefaultLimitNOFILE=65536` to `/etc/systemd/system.conf`.
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
|
||||
Install instructions [here](https://brew.sh/)
|
||||
|
||||
| **NOTE**: If you are working on a M1 Apple Silicon which is running Z shell, you could need to add
|
||||
`eval $(/opt/homebrew/bin/brew shellenv)` line to your `.zshrc`. This will make your zsh to find the apps you install
|
||||
| **NOTE**: If you are working on a M1 Apple Silicon which is running Z shell, you could need to add
|
||||
`eval $(/opt/homebrew/bin/brew shellenv)` line to your `.zshrc`. This will make your zsh to find the apps you install
|
||||
through brew.
|
||||
|
||||
|
||||
### Install Node
|
||||
|
||||
Budibase requires a recent version of node 14:
|
||||
|
||||
```
|
||||
brew install node npm
|
||||
node -v
|
||||
|
@ -22,12 +22,15 @@ node -v
|
|||
```
|
||||
npm install -g yarn jest lerna
|
||||
```
|
||||
|
||||
### Install Docker and Docker Compose
|
||||
|
||||
```
|
||||
brew install docker docker-compose
|
||||
```
|
||||
|
||||
### Clone the repo
|
||||
|
||||
```
|
||||
git clone https://github.com/Budibase/budibase.git
|
||||
```
|
||||
|
@ -48,10 +51,13 @@ This setup process was tested on Mac OSX 12 (Monterey) with version numbers show
|
|||
cd budibase
|
||||
yarn setup
|
||||
```
|
||||
|
||||
The yarn setup command runs several build steps i.e.
|
||||
|
||||
```
|
||||
node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev
|
||||
```
|
||||
|
||||
So this command will actually run the application in dev mode. It creates .env files under `./packages/server` and `./packages/worker` and runs docker containers for each service via docker-compose.
|
||||
|
||||
The dev version will be available on port 10000 i.e.
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
## Dev Environment on Windows 10/11 (WSL2)
|
||||
|
||||
|
||||
### Install WSL with Ubuntu LTS
|
||||
|
||||
Enable WSL 2 on Windows 10/11 for docker support.
|
||||
|
||||
```
|
||||
wsl --set-default-version 2
|
||||
```
|
||||
|
||||
Install Ubuntu LTS.
|
||||
|
||||
```
|
||||
wsl --install Ubuntu
|
||||
```
|
||||
|
@ -16,6 +18,7 @@ Or follow the instruction here:
|
|||
https://learn.microsoft.com/en-us/windows/wsl/install
|
||||
|
||||
### Install Docker in windows
|
||||
|
||||
Download the installer from docker and install it.
|
||||
|
||||
Check this url for more detailed instructions:
|
||||
|
@ -24,18 +27,21 @@ https://docs.docker.com/desktop/install/windows-install/
|
|||
You should follow the next steps from within the Ubuntu terminal.
|
||||
|
||||
### Install NVM & Node 14
|
||||
|
||||
NVM documentation: https://github.com/nvm-sh/nvm#installing-and-updating
|
||||
|
||||
Install NVM
|
||||
|
||||
```
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
||||
```
|
||||
|
||||
Install Node 14
|
||||
|
||||
```
|
||||
nvm install 14
|
||||
```
|
||||
|
||||
|
||||
### Install npm requirements
|
||||
|
||||
```
|
||||
|
@ -43,6 +49,7 @@ npm install -g yarn jest lerna
|
|||
```
|
||||
|
||||
### Clone the repo
|
||||
|
||||
```
|
||||
git clone https://github.com/Budibase/budibase.git
|
||||
```
|
||||
|
@ -63,10 +70,13 @@ This setup process was tested on Windows 11 with version numbers show below. You
|
|||
cd budibase
|
||||
yarn setup
|
||||
```
|
||||
|
||||
The yarn setup command runs several build steps i.e.
|
||||
|
||||
```
|
||||
node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev
|
||||
```
|
||||
|
||||
So this command will actually run the application in dev mode. It creates .env files under `./packages/server` and `./packages/worker` and runs docker containers for each service via docker-compose.
|
||||
|
||||
The dev version will be available on port 10000 i.e.
|
||||
|
@ -74,8 +84,9 @@ The dev version will be available on port 10000 i.e.
|
|||
http://127.0.0.1:10000/builder/admin
|
||||
|
||||
### Working with the code
|
||||
|
||||
Here are the instructions to work on the application from within Visual Studio Code (in Windows) through the WSL. All the commands and files are within the Ubuntu system and it should run as if you were working on a Linux machine.
|
||||
|
||||
https://code.visualstudio.com/docs/remote/wsl
|
||||
|
||||
Note you will be able to run the application from within the WSL terminal and you will be able to access the application from the a browser in Windows.
|
||||
Note you will be able to run the application from within the WSL terminal and you will be able to access the application from the a browser in Windows.
|
||||
|
|
18
lerna.json
18
lerna.json
|
@ -1,8 +1,22 @@
|
|||
{
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/backend-core",
|
||||
"packages/bbui",
|
||||
"packages/builder",
|
||||
"packages/cli",
|
||||
"packages/client",
|
||||
"packages/frontend-core",
|
||||
"packages/sdk",
|
||||
"packages/server",
|
||||
"packages/shared-core",
|
||||
"packages/string-templates",
|
||||
"packages/types",
|
||||
"packages/worker",
|
||||
"packages/pro/packages/pro"
|
||||
],
|
||||
"useWorkspaces": true,
|
||||
"packages": ["packages/*"],
|
||||
"command": {
|
||||
"publish": {
|
||||
"ignoreChanges": [
|
||||
|
|
30
package.json
30
package.json
|
@ -11,7 +11,7 @@
|
|||
"eslint": "^7.28.0",
|
||||
"eslint-plugin-cypress": "^2.11.3",
|
||||
"eslint-plugin-svelte3": "^3.2.0",
|
||||
"husky": "^7.0.1",
|
||||
"husky": "^8.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"kill-port": "^1.6.1",
|
||||
"lerna": "^6.6.1",
|
||||
|
@ -24,18 +24,16 @@
|
|||
"typescript": "4.7.3"
|
||||
},
|
||||
"scripts": {
|
||||
"setup": "node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev",
|
||||
"bootstrap": "lerna link && ./scripts/link-dependencies.sh",
|
||||
"setup": "git config submodule.recurse true && git submodule update && node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev",
|
||||
"bootstrap": "./scripts/bootstrap.sh && lerna link && ./scripts/link-dependencies.sh",
|
||||
"build": "lerna run --stream build",
|
||||
"build:dev": "lerna run --stream prebuild && tsc --build --watch --preserveWatchOutput",
|
||||
"build:dev": "lerna run --stream prebuild && yarn nx run-many --target=build --output-style=dynamic --watch --preserveWatchOutput",
|
||||
"backend:bootstrap": "./scripts/scopeBackend.sh && yarn run bootstrap",
|
||||
"backend:build": "./scripts/scopeBackend.sh 'lerna run --stream build'",
|
||||
"build:sdk": "lerna run --stream build:sdk",
|
||||
"deps:circular": "madge packages/server/dist/index.js packages/worker/src/index.ts packages/backend-core/dist/src/index.js packages/cli/src/index.js --circular",
|
||||
"release": "lerna publish ${RELEASE_VERSION_TYPE:-patch} --yes --force-publish && yarn release:pro",
|
||||
"release:develop": "lerna publish prerelease --yes --force-publish --dist-tag develop --exact && yarn release:pro:develop",
|
||||
"release:pro": "bash scripts/pro/release.sh",
|
||||
"release:pro:develop": "bash scripts/pro/release.sh develop",
|
||||
"restore": "yarn run clean && yarn run bootstrap && yarn run build",
|
||||
"nuke": "yarn run nuke:packages && yarn run nuke:docker",
|
||||
"nuke:packages": "yarn run restore",
|
||||
|
@ -49,7 +47,6 @@
|
|||
"dev:server": "yarn run kill-server && lerna run --stream --parallel dev:builder --concurrency 1 --scope @budibase/backend-core --scope @budibase/worker --scope @budibase/server",
|
||||
"dev:built": "yarn run kill-all && cd packages/server && yarn dev:stack:up && cd ../../ && lerna run --stream --parallel dev:built",
|
||||
"test": "lerna run --stream test --stream",
|
||||
"test:pro": "bash scripts/pro/test.sh",
|
||||
"lint:eslint": "eslint packages && eslint qa-core",
|
||||
"lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --check \"qa-core/**/*.{js,ts,svelte}\"",
|
||||
"lint": "yarn run lint:eslint && yarn run lint:prettier",
|
||||
|
@ -86,12 +83,25 @@
|
|||
"mode:account": "yarn mode:cloud && yarn env:account:enable",
|
||||
"security:audit": "node scripts/audit.js",
|
||||
"postinstall": "husky install",
|
||||
"install:pro": "bash scripts/pro/install.sh",
|
||||
"dep:clean": "yarn clean && yarn bootstrap"
|
||||
"dep:clean": "yarn clean -y && yarn bootstrap",
|
||||
"submodules:load": "git submodule init && git submodule update && yarn && yarn bootstrap",
|
||||
"submodules:unload": "git submodule deinit --all && yarn && yarn bootstrap"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*"
|
||||
"packages/backend-core",
|
||||
"packages/bbui",
|
||||
"packages/builder",
|
||||
"packages/cli",
|
||||
"packages/client",
|
||||
"packages/frontend-core",
|
||||
"packages/sdk",
|
||||
"packages/server",
|
||||
"packages/shared-core",
|
||||
"packages/string-templates",
|
||||
"packages/types",
|
||||
"packages/worker",
|
||||
"packages/pro/packages/pro"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -15,8 +15,6 @@
|
|||
"prebuild": "rimraf dist/",
|
||||
"prepack": "cp package.json dist",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"build:pro": "../../scripts/pro/build.sh",
|
||||
"postbuild": "yarn run build:pro",
|
||||
"build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput",
|
||||
"test": "bash scripts/test.sh",
|
||||
"test:watch": "jest --watchAll"
|
||||
|
@ -24,7 +22,7 @@
|
|||
"dependencies": {
|
||||
"@budibase/nano": "10.1.2",
|
||||
"@budibase/pouchdb-replication-stream": "1.2.10",
|
||||
"@budibase/types": "2.5.6-alpha.28",
|
||||
"@budibase/types": "2.5.6-alpha.42",
|
||||
"@shopify/jest-koa-mocks": "5.0.1",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-cloudfront-sign": "2.2.0",
|
||||
|
@ -47,6 +45,8 @@
|
|||
"passport-jwt": "4.0.0",
|
||||
"passport-local": "1.0.0",
|
||||
"passport-oauth2-refresh": "^2.1.0",
|
||||
"pino": "8.11.0",
|
||||
"pino-http": "8.3.3",
|
||||
"posthog-node": "1.3.0",
|
||||
"pouchdb": "7.3.0",
|
||||
"pouchdb-find": "7.2.2",
|
||||
|
@ -80,7 +80,6 @@
|
|||
"jest-serial-runner": "^1.2.1",
|
||||
"koa": "2.13.4",
|
||||
"nodemon": "2.0.16",
|
||||
"pino": "7.11.0",
|
||||
"pino-pretty": "10.0.0",
|
||||
"pouchdb-adapter-memory": "7.2.2",
|
||||
"timekeeper": "2.2.0",
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
Event,
|
||||
LicenseActivatedEvent,
|
||||
LicensePlanChangedEvent,
|
||||
LicenseTierChangedEvent,
|
||||
PlanType,
|
||||
Account,
|
||||
LicensePortalOpenedEvent,
|
||||
|
@ -11,22 +10,22 @@ import {
|
|||
LicenseCheckoutOpenedEvent,
|
||||
LicensePaymentFailedEvent,
|
||||
LicensePaymentRecoveredEvent,
|
||||
PriceDuration,
|
||||
} from "@budibase/types"
|
||||
|
||||
async function tierChanged(account: Account, from: number, to: number) {
|
||||
const properties: LicenseTierChangedEvent = {
|
||||
accountId: account.accountId,
|
||||
to,
|
||||
from,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_TIER_CHANGED, properties)
|
||||
}
|
||||
|
||||
async function planChanged(account: Account, from: PlanType, to: PlanType) {
|
||||
async function planChanged(
|
||||
account: Account,
|
||||
from: PlanType,
|
||||
to: PlanType,
|
||||
quantity: number | undefined,
|
||||
duration: PriceDuration | undefined
|
||||
) {
|
||||
const properties: LicensePlanChangedEvent = {
|
||||
accountId: account.accountId,
|
||||
to,
|
||||
from,
|
||||
quantity,
|
||||
duration,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_PLAN_CHANGED, properties)
|
||||
}
|
||||
|
@ -74,7 +73,6 @@ async function paymentRecovered(account: Account) {
|
|||
}
|
||||
|
||||
export default {
|
||||
tierChanged,
|
||||
planChanged,
|
||||
activated,
|
||||
checkoutOpened,
|
||||
|
|
|
@ -123,7 +123,6 @@ beforeAll(async () => {
|
|||
jest.spyOn(events.plugin, "imported")
|
||||
jest.spyOn(events.plugin, "deleted")
|
||||
|
||||
jest.spyOn(events.license, "tierChanged")
|
||||
jest.spyOn(events.license, "planChanged")
|
||||
jest.spyOn(events.license, "activated")
|
||||
jest.spyOn(events.license, "checkoutOpened")
|
||||
|
|
|
@ -7,16 +7,29 @@ import {
|
|||
PlanType,
|
||||
PriceDuration,
|
||||
PurchasedPlan,
|
||||
PurchasedPrice,
|
||||
Quotas,
|
||||
Subscription,
|
||||
} from "@budibase/types"
|
||||
|
||||
export function price(): PurchasedPrice {
|
||||
return {
|
||||
amount: 10000,
|
||||
amountMonthly: 10000,
|
||||
currency: "usd",
|
||||
duration: PriceDuration.MONTHLY,
|
||||
priceId: "price_123",
|
||||
dayPasses: undefined,
|
||||
isPerUser: true,
|
||||
}
|
||||
}
|
||||
|
||||
export const plan = (type: PlanType = PlanType.FREE): PurchasedPlan => {
|
||||
return {
|
||||
type,
|
||||
usesInvoicing: false,
|
||||
minUsers: 1,
|
||||
model: PlanModel.PER_USER,
|
||||
price: price(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
"@budibase/types": ["../types/src"]
|
||||
}
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../types" }
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
]
|
||||
}
|
||||
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,8 +38,8 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
||||
"@budibase/shared-core": "2.5.6-alpha.28",
|
||||
"@budibase/string-templates": "2.5.6-alpha.28",
|
||||
"@budibase/shared-core": "2.5.6-alpha.42",
|
||||
"@budibase/string-templates": "2.5.6-alpha.42",
|
||||
"@spectrum-css/accordion": "3.0.24",
|
||||
"@spectrum-css/actionbutton": "1.0.1",
|
||||
"@spectrum-css/actiongroup": "1.0.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -58,11 +58,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.5.6-alpha.28",
|
||||
"@budibase/client": "2.5.6-alpha.28",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.28",
|
||||
"@budibase/shared-core": "2.5.6-alpha.28",
|
||||
"@budibase/string-templates": "2.5.6-alpha.28",
|
||||
"@budibase/bbui": "2.5.6-alpha.42",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.42",
|
||||
"@budibase/shared-core": "2.5.6-alpha.42",
|
||||
"@budibase/string-templates": "2.5.6-alpha.42",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
|
|
|
@ -134,6 +134,7 @@ export const getFrontendStore = () => {
|
|||
previousTopNavPath: {},
|
||||
version: application.version,
|
||||
revertableVersion: application.revertableVersion,
|
||||
upgradableVersion: application.upgradableVersion,
|
||||
navigation: application.navigation || {},
|
||||
usedPlugins: application.usedPlugins || [],
|
||||
}))
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
} from "@budibase/bbui"
|
||||
import { store } from "builderStore"
|
||||
import { API } from "api"
|
||||
import clientPackage from "@budibase/client/package.json"
|
||||
|
||||
export function show() {
|
||||
updateModal.show()
|
||||
|
@ -25,9 +24,9 @@
|
|||
|
||||
$: appId = $store.appId
|
||||
$: updateAvailable =
|
||||
clientPackage.version &&
|
||||
$store.upgradableVersion &&
|
||||
$store.version &&
|
||||
clientPackage.version !== $store.version
|
||||
$store.upgradableVersion !== $store.version
|
||||
$: revertAvailable = $store.revertableVersion != null
|
||||
|
||||
const refreshAppPackage = async () => {
|
||||
|
@ -46,7 +45,7 @@
|
|||
// Don't wait for the async refresh, since this causes modal flashing
|
||||
refreshAppPackage()
|
||||
notifications.success(
|
||||
`App updated successfully to version ${clientPackage.version}`
|
||||
`App updated successfully to version ${$store.upgradableVersion}`
|
||||
)
|
||||
} catch (err) {
|
||||
notifications.error(`Error updating app: ${err}`)
|
||||
|
@ -91,7 +90,7 @@
|
|||
{#if updateAvailable}
|
||||
<Body size="S">
|
||||
This app is currently using version <b>{$store.version}</b>, but version
|
||||
<b>{clientPackage.version}</b> is available. Updates can contain new features,
|
||||
<b>{$store.upgradableVersion}</b> is available. Updates can contain new features,
|
||||
performance improvements and bug fixes.
|
||||
</Body>
|
||||
{:else}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
onMount(() => {
|
||||
unlimited = isUnlimited()
|
||||
percentage = getPercentage()
|
||||
if (warnWhenFull && percentage === 100) {
|
||||
if (warnWhenFull && percentage >= 100) {
|
||||
showWarning = true
|
||||
}
|
||||
})
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<Panel title={$selectedLayout?.name} icon="Experience" borderLeft>
|
||||
<Panel title={$selectedLayout?.name} icon="Experience" borderLeft wide>
|
||||
<Layout paddingX="L" paddingY="XL" gap="S">
|
||||
<Banner type="warning" showCloseButton={false}>
|
||||
Custom layouts are being deprecated. They will be removed in a future
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<Panel borderLeft title="Navigation" icon="InfoOutline">
|
||||
<Panel borderLeft title="Navigation" icon="InfoOutline" wide>
|
||||
<Layout paddingX="L" paddingY="XL" gap="S">
|
||||
{#if $selectedScreen.layoutId}
|
||||
<Banner
|
||||
|
|
|
@ -149,6 +149,7 @@
|
|||
title={$selectedScreen.routing.route}
|
||||
icon={$selectedScreen.routing.route === "/" ? "Home" : "WebPage"}
|
||||
borderLeft
|
||||
wide
|
||||
>
|
||||
<Layout gap="S" paddingX="L" paddingY="XL">
|
||||
{#if $selectedScreen.layoutId}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { Body, Layout } from "@budibase/bbui"
|
||||
</script>
|
||||
|
||||
<Panel borderLeft title="Theme" icon="InfoOutline">
|
||||
<Panel borderLeft title="Theme" icon="InfoOutline" wide>
|
||||
<Layout paddingX="L" paddingY="XL">
|
||||
<Body size="S">
|
||||
Your theme is set across all the screens within your app.
|
||||
|
|
|
@ -43,12 +43,18 @@
|
|||
}
|
||||
|
||||
$: quotaUsage = $licensing.quotaUsage
|
||||
|
||||
$: license = $auth.user?.license
|
||||
$: plan = license?.plan
|
||||
$: usesInvoicing = plan?.usesInvoicing
|
||||
|
||||
$: accountPortalAccess = $auth?.user?.accountPortalAccess
|
||||
$: quotaReset = quotaUsage?.quotaReset
|
||||
$: canManagePlan =
|
||||
($admin.cloud && accountPortalAccess) || (!$admin.cloud && $auth.isAdmin)
|
||||
|
||||
$: showButton = !usesInvoicing && accountPortalAccess
|
||||
|
||||
const setMonthlyUsage = () => {
|
||||
monthlyUsage = []
|
||||
if (quotaUsage.monthly) {
|
||||
|
@ -121,7 +127,7 @@
|
|||
const setTextRows = () => {
|
||||
textRows = []
|
||||
|
||||
if (cancelAt) {
|
||||
if (cancelAt && !usesInvoicing) {
|
||||
textRows.push({ message: "Subscription has been cancelled" })
|
||||
textRows.push({
|
||||
message: `${getDaysRemaining(cancelAt)} days remaining`,
|
||||
|
@ -213,7 +219,7 @@
|
|||
description="YOUR CURRENT PLAN"
|
||||
title={planTitle()}
|
||||
{primaryActionText}
|
||||
primaryAction={accountPortalAccess ? goToAccountPortal : undefined}
|
||||
primaryAction={showButton ? goToAccountPortal : undefined}
|
||||
{textRows}
|
||||
>
|
||||
<div class="content">
|
||||
|
@ -224,33 +230,23 @@
|
|||
<Usage {usage} warnWhenFull={WARN_USAGE.includes(usage.name)} />
|
||||
</div>
|
||||
{/each}
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="S">Monthly limits</Heading>
|
||||
<div class="detail">
|
||||
<TooltipWrapper tooltip={new Date(quotaReset)}>
|
||||
<Detail size="M">
|
||||
Resets in {daysRemainingInMonth} days
|
||||
</Detail>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</Layout>
|
||||
<Layout noPadding gap="M">
|
||||
{#each monthlyUsage as usage}
|
||||
<Usage {usage} warnWhenFull={WARN_USAGE.includes(usage.name)} />
|
||||
{/each}
|
||||
</Layout>
|
||||
</Layout>
|
||||
</div>
|
||||
|
||||
{#if monthlyUsage.length}
|
||||
<div class="column">
|
||||
<Layout noPadding gap="M">
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="S">Monthly limits</Heading>
|
||||
<div class="detail">
|
||||
<TooltipWrapper tooltip={new Date(quotaReset)}>
|
||||
<Detail size="M">
|
||||
Resets in {daysRemainingInMonth} days
|
||||
</Detail>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</Layout>
|
||||
<Layout noPadding gap="M">
|
||||
{#each monthlyUsage as usage}
|
||||
<Usage
|
||||
{usage}
|
||||
warnWhenFull={WARN_USAGE.includes(usage.name)}
|
||||
/>
|
||||
{/each}
|
||||
</Layout>
|
||||
</Layout>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</DashCard>
|
||||
</Layout>
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
<Heading>Backups</Heading>
|
||||
{#if !$licensing.backupsEnabled}
|
||||
<Tags>
|
||||
<Tag icon="LockClosed">Pro plan</Tag>
|
||||
<Tag icon="LockClosed">Premium</Tag>
|
||||
</Tags>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { store } from "builderStore"
|
||||
import clientPackage from "@budibase/client/package.json"
|
||||
import { processStringSync } from "@budibase/string-templates"
|
||||
import { users, auth, apps, groups, overview } from "stores/portal"
|
||||
import { fetchData } from "@budibase/frontend-core"
|
||||
|
@ -40,7 +39,7 @@
|
|||
},
|
||||
},
|
||||
})
|
||||
$: updateAvailable = clientPackage.version !== $store.version
|
||||
$: updateAvailable = $store.upgradableVersion !== $store.version
|
||||
$: isPublished = app?.status === AppStatus.DEPLOYED
|
||||
$: appEditorId = !app?.updatedBy ? $auth.user._id : app?.updatedBy
|
||||
$: appEditorText = appEditor?.firstName || appEditor?.email
|
||||
|
@ -172,8 +171,8 @@
|
|||
<Heading size="XS">{$store.version}</Heading>
|
||||
{#if updateAvailable}
|
||||
<div class="version-status">
|
||||
New version <strong>{clientPackage.version}</strong> is available
|
||||
-
|
||||
New version <strong>{$store.upgradableVersion}</strong> is
|
||||
available -
|
||||
<Link
|
||||
on:click={() => {
|
||||
$goto("./version")
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
<script>
|
||||
import { Layout, Heading, Body, Divider, Button } from "@budibase/bbui"
|
||||
import { store } from "builderStore"
|
||||
import clientPackage from "@budibase/client/package.json"
|
||||
import VersionModal from "components/deploy/VersionModal.svelte"
|
||||
|
||||
let versionModal
|
||||
|
||||
$: updateAvailable = clientPackage.version !== $store.version
|
||||
$: updateAvailable = $store.upgradableVersion !== $store.version
|
||||
</script>
|
||||
|
||||
<Layout noPadding>
|
||||
|
@ -18,7 +17,7 @@
|
|||
{#if updateAvailable}
|
||||
<Body>
|
||||
The app is currently using version <strong>{$store.version}</strong>
|
||||
but version <strong>{clientPackage.version}</strong> is available.
|
||||
but version <strong>{$store.upgradableVersion}</strong> is available.
|
||||
<br />
|
||||
Updates can contain new features, performance improvements and bug fixes.
|
||||
</Body>
|
||||
|
|
|
@ -378,7 +378,7 @@
|
|||
</div>
|
||||
{#if !$licensing.enforceableSSO}
|
||||
<Tags>
|
||||
<Tag icon="LockClosed">Enterprise plan</Tag>
|
||||
<Tag icon="LockClosed">Enterprise</Tag>
|
||||
</Tags>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -213,7 +213,7 @@
|
|||
{/if}
|
||||
{#if isCloud && !brandingEnabled}
|
||||
<Tags>
|
||||
<Tag icon="LockClosed">Pro</Tag>
|
||||
<Tag icon="LockClosed">Premium</Tag>
|
||||
</Tags>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
<Heading size="M">Groups</Heading>
|
||||
{#if !$licensing.groupsEnabled}
|
||||
<Tags>
|
||||
<Tag icon="LockClosed">Pro plan</Tag>
|
||||
<Tag icon="LockClosed">Business</Tag>
|
||||
</Tags>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
$: invalidEmails = []
|
||||
|
||||
$: userCount = $licensing.userCount + userEmails.length
|
||||
$: willExceed = userCount > $licensing.userLimit
|
||||
$: willExceed = licensing.willExceedUserLimit(userCount)
|
||||
|
||||
$: importDisabled =
|
||||
!userEmails.length || !validEmails(userEmails) || !usersRole || willExceed
|
||||
|
|
|
@ -114,11 +114,13 @@ export function createUsersStore() {
|
|||
const getUserRole = ({ admin, builder }) =>
|
||||
admin?.global ? "admin" : builder?.global ? "developer" : "appUser"
|
||||
|
||||
const refreshUsage = fn => async args => {
|
||||
const response = await fn(args)
|
||||
await licensing.setQuotaUsage()
|
||||
return response
|
||||
}
|
||||
const refreshUsage =
|
||||
fn =>
|
||||
async (...args) => {
|
||||
const response = await fn(...args)
|
||||
await licensing.setQuotaUsage()
|
||||
return response
|
||||
}
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
@ -133,7 +135,7 @@ export function createUsersStore() {
|
|||
updateInvite,
|
||||
getUserCountByApp,
|
||||
// any operation that adds or deletes users
|
||||
acceptInvite: refreshUsage(acceptInvite),
|
||||
acceptInvite,
|
||||
create: refreshUsage(create),
|
||||
save: refreshUsage(save),
|
||||
bulkDelete: refreshUsage(bulkDelete),
|
||||
|
|
|
@ -13,9 +13,5 @@
|
|||
},
|
||||
"ts-node": {
|
||||
"require": ["tsconfig-paths/register"]
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../types" },
|
||||
{ "path": "../backend-core" },
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
|
@ -29,9 +29,9 @@
|
|||
"outputPath": "build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.5.6-alpha.28",
|
||||
"@budibase/string-templates": "2.5.6-alpha.28",
|
||||
"@budibase/types": "2.5.6-alpha.28",
|
||||
"@budibase/backend-core": "2.5.6-alpha.42",
|
||||
"@budibase/string-templates": "2.5.6-alpha.42",
|
||||
"@budibase/types": "2.5.6-alpha.42",
|
||||
"axios": "0.21.2",
|
||||
"chalk": "4.1.0",
|
||||
"cli-progress": "3.11.2",
|
||||
|
|
|
@ -5225,36 +5225,5 @@
|
|||
"type": "schema",
|
||||
"suffix": "repeater"
|
||||
}
|
||||
},
|
||||
"spreadsheet": {
|
||||
"name": "Spreadsheet",
|
||||
"icon": "ViewGrid",
|
||||
"settings": [
|
||||
{
|
||||
"key": "table",
|
||||
"type": "table",
|
||||
"label": "Table"
|
||||
},
|
||||
{
|
||||
"type": "filter",
|
||||
"label": "Filtering",
|
||||
"key": "filter"
|
||||
},
|
||||
{
|
||||
"type": "field/sortable",
|
||||
"label": "Sort Column",
|
||||
"key": "sortColumn"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Sort Order",
|
||||
"key": "sortOrder",
|
||||
"options": [
|
||||
"Ascending",
|
||||
"Descending"
|
||||
],
|
||||
"defaultValue": "Ascending"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.5.6-alpha.28",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.28",
|
||||
"@budibase/shared-core": "2.5.6-alpha.28",
|
||||
"@budibase/string-templates": "2.5.6-alpha.28",
|
||||
"@budibase/types": "2.5.6-alpha.28",
|
||||
"@budibase/bbui": "2.5.6-alpha.42",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.42",
|
||||
"@budibase/shared-core": "2.5.6-alpha.42",
|
||||
"@budibase/string-templates": "2.5.6-alpha.42",
|
||||
"@budibase/types": "2.5.6-alpha.42",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "@budibase/frontend-core",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Budibase frontend core libraries used in builder and client",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.5.6-alpha.28",
|
||||
"@budibase/shared-core": "2.5.6-alpha.28",
|
||||
"@budibase/bbui": "2.5.6-alpha.42",
|
||||
"@budibase/shared-core": "2.5.6-alpha.42",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash": "^4.17.21",
|
||||
"socket.io-client": "^4.6.1",
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
export let updateValue = rows.actions.updateValue
|
||||
export let invertX = false
|
||||
export let invertY = false
|
||||
export let contentLines = 1
|
||||
|
||||
const emptyError = writable(null)
|
||||
|
||||
|
@ -84,5 +85,7 @@
|
|||
{readonly}
|
||||
{invertY}
|
||||
{invertX}
|
||||
{contentLines}
|
||||
/>
|
||||
<slot />
|
||||
</GridCell>
|
||||
|
|
|
@ -117,6 +117,9 @@
|
|||
.cell.error {
|
||||
--cell-color: var(--spectrum-global-color-red-500);
|
||||
}
|
||||
.cell.readonly {
|
||||
--cell-color: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
.cell:not(.focused) {
|
||||
user-select: none;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
$: sortedBy = column.name === $sort.column
|
||||
$: canMoveLeft = orderable && idx > 0
|
||||
$: canMoveRight = orderable && idx < $renderedColumns.length - 1
|
||||
$: ascendingLabel = column.schema?.type === "number" ? "low-high" : "A-Z"
|
||||
$: descendingLabel = column.schema?.type === "number" ? "high-low" : "Z-A"
|
||||
|
||||
const editColumn = () => {
|
||||
dispatch("edit-column", column.schema)
|
||||
|
@ -179,14 +181,14 @@
|
|||
on:click={sortAscending}
|
||||
disabled={column.name === $sort.column && $sort.order === "ascending"}
|
||||
>
|
||||
Sort A-Z
|
||||
Sort {ascendingLabel}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="SortOrderDown"
|
||||
on:click={sortDescending}
|
||||
disabled={column.name === $sort.column && $sort.order === "descending"}
|
||||
>
|
||||
Sort Z-A
|
||||
Sort {descendingLabel}
|
||||
</MenuItem>
|
||||
<MenuItem disabled={!canMoveLeft} icon="ChevronLeft" on:click={moveLeft}>
|
||||
Move left
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { onMount, tick } from "svelte"
|
||||
import { clickOutside } from "@budibase/bbui"
|
||||
|
||||
export let value
|
||||
export let focused = false
|
||||
|
@ -60,6 +61,7 @@
|
|||
on:change={handleChange}
|
||||
on:wheel|stopPropagation
|
||||
spellcheck="false"
|
||||
use:clickOutside={close}
|
||||
/>
|
||||
{:else}
|
||||
<div class="long-form-cell" on:click={editable ? open : null} class:editable>
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
import TextCell from "./TextCell.svelte"
|
||||
|
||||
export let api
|
||||
export let onChange
|
||||
|
||||
const numberOnChange = value => {
|
||||
const float = parseFloat(value)
|
||||
const newValue = isNaN(float) ? null : float
|
||||
onChange(newValue)
|
||||
}
|
||||
</script>
|
||||
|
||||
<TextCell {...$$props} bind:api type="number" />
|
||||
<TextCell {...$$props} onChange={numberOnChange} bind:api type="number" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { Icon } from "@budibase/bbui"
|
||||
import { Icon, clickOutside } from "@budibase/bbui"
|
||||
import { getColor } from "../lib/utils"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
|||
export let api
|
||||
export let invertX = false
|
||||
export let invertY = false
|
||||
export let contentLines = 1
|
||||
|
||||
let isOpen = false
|
||||
let focusedOptionIdx = null
|
||||
|
@ -86,7 +87,11 @@
|
|||
class:open
|
||||
on:click|self={editable ? open : null}
|
||||
>
|
||||
<div class="values" on:click={editable ? open : null}>
|
||||
<div
|
||||
class="values"
|
||||
class:wrap={contentLines > 1}
|
||||
on:click={editable ? open : null}
|
||||
>
|
||||
{#each values as val}
|
||||
{@const color = getOptionColor(val)}
|
||||
{#if color}
|
||||
|
@ -113,6 +118,7 @@
|
|||
class:invertX
|
||||
class:invertY
|
||||
on:wheel={e => e.stopPropagation()}
|
||||
use:clickOutside={close}
|
||||
>
|
||||
{#each options as option, idx}
|
||||
{@const color = getOptionColor(option)}
|
||||
|
@ -160,6 +166,9 @@
|
|||
grid-row-gap: var(--cell-padding);
|
||||
overflow: hidden;
|
||||
padding: var(--cell-padding);
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.values.wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.text {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<script>
|
||||
import { getColor } from "../lib/utils"
|
||||
import { onMount, getContext } from "svelte"
|
||||
import { Icon, Input, ProgressCircle } from "@budibase/bbui"
|
||||
import { Icon, Input, ProgressCircle, clickOutside } from "@budibase/bbui"
|
||||
import { debounce } from "../../../utils/utils"
|
||||
|
||||
export let value
|
||||
|
@ -29,6 +29,7 @@
|
|||
export let onChange
|
||||
export let invertX = false
|
||||
export let invertY = false
|
||||
export let contentLines = 1
|
||||
|
||||
const { API, dispatch } = getContext("grid")
|
||||
const color = getColor(0)
|
||||
|
@ -243,7 +244,11 @@
|
|||
|
||||
<div class="wrapper" class:editable class:focused style="--color:{color};">
|
||||
<div class="container">
|
||||
<div class="values" on:wheel={e => (focused ? e.stopPropagation() : null)}>
|
||||
<div
|
||||
class="values"
|
||||
class:wrap={editable || contentLines > 1}
|
||||
on:wheel={e => (focused ? e.stopPropagation() : null)}
|
||||
>
|
||||
{#each value || [] as relationship, idx}
|
||||
{#if relationship.primaryDisplay}
|
||||
<div class="badge">
|
||||
|
@ -279,7 +284,13 @@
|
|||
</div>
|
||||
|
||||
{#if isOpen}
|
||||
<div class="dropdown" class:invertX class:invertY on:wheel|stopPropagation>
|
||||
<div
|
||||
class="dropdown"
|
||||
class:invertX
|
||||
class:invertY
|
||||
on:wheel|stopPropagation
|
||||
use:clickOutside={close}
|
||||
>
|
||||
<div class="search">
|
||||
<Input
|
||||
autofocus
|
||||
|
@ -376,6 +387,9 @@
|
|||
grid-row-gap: var(--cell-padding);
|
||||
overflow: hidden;
|
||||
padding: var(--cell-padding);
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.values.wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.count {
|
||||
|
|
|
@ -3,16 +3,13 @@
|
|||
import { ActionButton, Popover, Select } from "@budibase/bbui"
|
||||
|
||||
const { sort, columns, stickyColumn } = getContext("grid")
|
||||
const orderOptions = [
|
||||
{ label: "A-Z", value: "ascending" },
|
||||
{ label: "Z-A", value: "descending" },
|
||||
]
|
||||
|
||||
let open = false
|
||||
let anchor
|
||||
|
||||
$: columnOptions = getColumnOptions($stickyColumn, $columns)
|
||||
$: checkValidSortColumn($sort.column, $stickyColumn, $columns)
|
||||
$: orderOptions = getOrderOptions($sort.column, columnOptions)
|
||||
|
||||
const getColumnOptions = (stickyColumn, columns) => {
|
||||
let options = []
|
||||
|
@ -20,6 +17,7 @@
|
|||
options.push({
|
||||
label: stickyColumn.label || stickyColumn.name,
|
||||
value: stickyColumn.name,
|
||||
type: stickyColumn.schema?.type,
|
||||
})
|
||||
}
|
||||
return [
|
||||
|
@ -27,10 +25,25 @@
|
|||
...columns.map(col => ({
|
||||
label: col.label || col.name,
|
||||
value: col.name,
|
||||
type: col.schema?.type,
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
||||
const getOrderOptions = (column, columnOptions) => {
|
||||
const type = columnOptions.find(col => col.value === column)?.type
|
||||
return [
|
||||
{
|
||||
label: type === "number" ? "Low-high" : "A-Z",
|
||||
value: "ascending",
|
||||
},
|
||||
{
|
||||
label: type === "number" ? "High-low" : "Z-A",
|
||||
value: "descending",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const updateSortColumn = e => {
|
||||
sort.update(state => ({
|
||||
...state,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
selectedCellMap,
|
||||
focusedRow,
|
||||
columnHorizontalInversionIndex,
|
||||
contentLines,
|
||||
} = getContext("grid")
|
||||
|
||||
$: rowSelected = !!$selectedRows[row._id]
|
||||
|
@ -44,6 +45,7 @@
|
|||
focused={$focusedCellId === cellId}
|
||||
selectedUser={$selectedCellMap[cellId]}
|
||||
width={column.width}
|
||||
contentLines={$contentLines}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<script>
|
||||
export let keybind
|
||||
export let padded = false
|
||||
export let overlay = false
|
||||
|
||||
$: parsedKeys = parseKeys(keybind)
|
||||
|
||||
const parseKeys = keybind => {
|
||||
return keybind?.split("+").map(key => {
|
||||
if (key.toLowerCase() === "ctrl") {
|
||||
return navigator.platform.startsWith("Mac") ? "⌘" : key
|
||||
} else if (key.toLowerCase() === "enter") {
|
||||
return "↵"
|
||||
}
|
||||
return key
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="keys" class:padded class:overlay>
|
||||
{#each parsedKeys as key}
|
||||
<div class="key">
|
||||
{key}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.keys {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 3px;
|
||||
}
|
||||
.keys.padded {
|
||||
padding: var(--cell-padding);
|
||||
}
|
||||
.key {
|
||||
padding: 2px 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background-color: var(--spectrum-global-color-gray-200);
|
||||
color: var(--spectrum-global-color-gray-700);
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.overlay .key {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: #eee;
|
||||
}
|
||||
</style>
|
|
@ -7,6 +7,7 @@
|
|||
import { GutterWidth } from "../lib/constants"
|
||||
import { NewRowID } from "../lib/constants"
|
||||
import GutterCell from "../cells/GutterCell.svelte"
|
||||
import KeyboardShortcut from "./KeyboardShortcut.svelte"
|
||||
|
||||
const {
|
||||
hoveredRowId,
|
||||
|
@ -27,13 +28,14 @@
|
|||
columnHorizontalInversionIndex,
|
||||
} = getContext("grid")
|
||||
|
||||
let visible = false
|
||||
let isAdding = false
|
||||
let newRow = {}
|
||||
let offset = 0
|
||||
|
||||
$: firstColumn = $stickyColumn || $renderedColumns[0]
|
||||
$: width = GutterWidth + ($stickyColumn?.width || 0)
|
||||
$: $tableId, (isAdding = false)
|
||||
$: $tableId, (visible = false)
|
||||
$: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows)
|
||||
|
||||
const shouldInvertY = (offset, inversionIndex, rows) => {
|
||||
|
@ -45,7 +47,8 @@
|
|||
|
||||
const addRow = async () => {
|
||||
// Blur the active cell and tick to let final value updates propagate
|
||||
$focusedCellAPI?.blur()
|
||||
isAdding = true
|
||||
$focusedCellId = null
|
||||
await tick()
|
||||
|
||||
// Create row
|
||||
|
@ -60,17 +63,19 @@
|
|||
$focusedCellId = `${savedRow._id}-${firstColumn.name}`
|
||||
}
|
||||
}
|
||||
isAdding = false
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
isAdding = false
|
||||
visible = false
|
||||
$focusedCellId = null
|
||||
$hoveredRowId = null
|
||||
document.removeEventListener("keydown", handleKeyPress)
|
||||
}
|
||||
|
||||
const startAdding = async () => {
|
||||
if (isAdding) {
|
||||
if (visible) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -95,7 +100,7 @@
|
|||
|
||||
// Update state and select initial cell
|
||||
newRow = {}
|
||||
isAdding = true
|
||||
visible = true
|
||||
$hoveredRowId = NewRowID
|
||||
if (firstColumn) {
|
||||
$focusedCellId = `${NewRowID}-${firstColumn.name}`
|
||||
|
@ -115,7 +120,7 @@
|
|||
}
|
||||
|
||||
const handleKeyPress = e => {
|
||||
if (!isAdding) {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
|
@ -137,7 +142,7 @@
|
|||
</script>
|
||||
|
||||
<!-- Only show new row functionality if we have any columns -->
|
||||
{#if isAdding}
|
||||
{#if visible}
|
||||
<div
|
||||
class="container"
|
||||
class:floating={offset > 0}
|
||||
|
@ -148,6 +153,9 @@
|
|||
<div class="sticky-column" transition:fade={{ duration: 130 }}>
|
||||
<GutterCell on:expand={addViaModal} rowHovered>
|
||||
<Icon name="Add" color="var(--spectrum-global-color-gray-500)" />
|
||||
{#if isAdding}
|
||||
<div in:fade={{ duration: 130 }} class="loading-overlay" />
|
||||
{/if}
|
||||
</GutterCell>
|
||||
{#if $stickyColumn}
|
||||
{@const cellId = `${NewRowID}-${$stickyColumn.name}`}
|
||||
|
@ -161,7 +169,14 @@
|
|||
{updateValue}
|
||||
rowIdx={0}
|
||||
{invertY}
|
||||
/>
|
||||
>
|
||||
{#if $stickyColumn?.schema?.autocolumn}
|
||||
<div class="readonly-overlay">Can't edit auto column</div>
|
||||
{/if}
|
||||
{#if isAdding}
|
||||
<div in:fade={{ duration: 130 }} class="loading-overlay" />
|
||||
{/if}
|
||||
</DataCell>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="normal-columns" transition:fade={{ duration: 130 }}>
|
||||
|
@ -181,15 +196,32 @@
|
|||
rowIdx={0}
|
||||
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
||||
{invertY}
|
||||
/>
|
||||
>
|
||||
{#if column?.schema?.autocolumn}
|
||||
<div class="readonly-overlay">Can't edit auto column</div>
|
||||
{/if}
|
||||
{#if isAdding}
|
||||
<div in:fade={{ duration: 130 }} class="loading-overlay" />
|
||||
{/if}
|
||||
</DataCell>
|
||||
{/key}
|
||||
{/each}
|
||||
</div>
|
||||
</GridScrollWrapper>
|
||||
</div>
|
||||
<div class="buttons" transition:fade={{ duration: 130 }}>
|
||||
<Button size="M" cta on:click={addRow}>Save</Button>
|
||||
<Button size="M" secondary newStyles on:click={clear}>Cancel</Button>
|
||||
<Button size="M" cta on:click={addRow} disabled={isAdding}>
|
||||
<div class="button-with-keys">
|
||||
Save
|
||||
<KeyboardShortcut overlay keybind="Ctrl+Enter" />
|
||||
</div>
|
||||
</Button>
|
||||
<Button size="M" secondary newStyles on:click={clear}>
|
||||
<div class="button-with-keys">
|
||||
Cancel
|
||||
<KeyboardShortcut overlay keybind="Esc" />
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -240,6 +272,14 @@
|
|||
top: calc(var(--row-height) + var(--offset) + 24px);
|
||||
left: var(--gutter-width);
|
||||
}
|
||||
.button-with-keys {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
.button-with-keys :global(> div) {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
/* Sticky column styles */
|
||||
.sticky-column {
|
||||
|
@ -262,4 +302,33 @@
|
|||
width: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Readonly cell overlay */
|
||||
.readonly-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: var(--row-height);
|
||||
width: 100%;
|
||||
padding: var(--cell-padding);
|
||||
font-style: italic;
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
z-index: 1;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Overlay while row is being added */
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: var(--row-height);
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
background: var(--spectrum-global-color-gray-400);
|
||||
opacity: 0.25;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import HeaderCell from "../cells/HeaderCell.svelte"
|
||||
import { GutterWidth, BlankRowID } from "../lib/constants"
|
||||
import GutterCell from "../cells/GutterCell.svelte"
|
||||
import KeyboardShortcut from "./KeyboardShortcut.svelte"
|
||||
|
||||
const {
|
||||
rows,
|
||||
|
@ -21,6 +22,7 @@
|
|||
focusedRow,
|
||||
scrollLeft,
|
||||
dispatch,
|
||||
contentLines,
|
||||
} = getContext("grid")
|
||||
|
||||
$: rowCount = $rows.length
|
||||
|
@ -85,6 +87,7 @@
|
|||
selectedUser={$selectedCellMap[cellId]}
|
||||
width={$stickyColumn.width}
|
||||
column={$stickyColumn}
|
||||
contentLines={$contentLines}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -103,7 +106,9 @@
|
|||
<GridCell
|
||||
width={$stickyColumn.width}
|
||||
highlighted={$hoveredRowId === BlankRowID}
|
||||
/>
|
||||
>
|
||||
<KeyboardShortcut padded keybind="Ctrl+Enter" />
|
||||
</GridCell>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -15,8 +15,22 @@
|
|||
selectedRows,
|
||||
} = getContext("grid")
|
||||
|
||||
const ignoredOriginSelectors = [
|
||||
".spectrum-Modal",
|
||||
"#builder-side-panel-container",
|
||||
]
|
||||
|
||||
// Global key listener which intercepts all key events
|
||||
const handleKeyDown = e => {
|
||||
// Avoid processing events sourced from certain origins
|
||||
if (e.target?.closest) {
|
||||
for (let selector of ignoredOriginSelectors) {
|
||||
if (e.target.closest(selector)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing selected avoid processing further key presses
|
||||
if (!$focusedCellId) {
|
||||
if (e.key === "Tab" || e.key?.startsWith("Arrow")) {
|
||||
|
@ -60,11 +74,6 @@
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid processing events sourced from modals
|
||||
if (e.target?.closest?.(".spectrum-Modal")) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
|
||||
// Handle the key ourselves
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 26d3a26c1e5b0fbfd6fc5614b30934352b8cf5ae
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/sdk",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Budibase Public API SDK",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
|
|
|
@ -20,9 +20,9 @@ const baseConfig: Config.InitialProjectOptions = {
|
|||
}
|
||||
|
||||
// add pro sources if they exist
|
||||
if (fs.existsSync("../../../budibase-pro")) {
|
||||
baseConfig.moduleNameMapper["@budibase/pro"] =
|
||||
"<rootDir>/../../../budibase-pro/packages/pro/src"
|
||||
if (fs.existsSync("../pro/packages")) {
|
||||
baseConfig.moduleNameMapper!["@budibase/pro"] =
|
||||
"<rootDir>/../pro/packages/pro/src"
|
||||
}
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"watch": ["src", "../backend-core", "../../../budibase-pro/packages/pro"],
|
||||
"watch": ["src", "../backend-core", "../pro/packages/pro"],
|
||||
"ext": "js,ts,json",
|
||||
"ignore": [
|
||||
"src/**/*.spec.ts",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -46,12 +46,12 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "2.5.6-alpha.28",
|
||||
"@budibase/client": "2.5.6-alpha.28",
|
||||
"@budibase/pro": "2.5.6-alpha.28",
|
||||
"@budibase/shared-core": "2.5.6-alpha.28",
|
||||
"@budibase/string-templates": "2.5.6-alpha.28",
|
||||
"@budibase/types": "2.5.6-alpha.28",
|
||||
"@budibase/backend-core": "2.5.6-alpha.42",
|
||||
"@budibase/client": "2.5.6-alpha.42",
|
||||
"@budibase/pro": "2.5.6-alpha.42",
|
||||
"@budibase/shared-core": "2.5.6-alpha.42",
|
||||
"@budibase/string-templates": "2.5.6-alpha.42",
|
||||
"@budibase/types": "2.5.6-alpha.42",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
|
@ -223,7 +223,7 @@ export async function fetchAppPackage(ctx: UserCtx) {
|
|||
)
|
||||
|
||||
ctx.body = {
|
||||
application,
|
||||
application: { ...application, upgradableVersion: envCore.VERSION },
|
||||
screens,
|
||||
layouts,
|
||||
clientLibPath,
|
||||
|
|
|
@ -12,7 +12,15 @@ import { getIntegration } from "../../integrations"
|
|||
import { getDatasourceAndQuery } from "./row/utils"
|
||||
import { invalidateDynamicVariables } from "../../threads/utils"
|
||||
import { db as dbCore, context, events } from "@budibase/backend-core"
|
||||
import { UserCtx, Datasource, Row } from "@budibase/types"
|
||||
import {
|
||||
UserCtx,
|
||||
Datasource,
|
||||
Row,
|
||||
CreateDatasourceResponse,
|
||||
UpdateDatasourceResponse,
|
||||
UpdateDatasourceRequest,
|
||||
CreateDatasourceRequest,
|
||||
} from "@budibase/types"
|
||||
import sdk from "../../sdk"
|
||||
|
||||
export async function fetch(ctx: UserCtx) {
|
||||
|
@ -146,7 +154,7 @@ async function invalidateVariables(
|
|||
await invalidateDynamicVariables(toInvalidate)
|
||||
}
|
||||
|
||||
export async function update(ctx: UserCtx) {
|
||||
export async function update(ctx: UserCtx<any, UpdateDatasourceResponse>) {
|
||||
const db = context.getAppDB()
|
||||
const datasourceId = ctx.params.datasourceId
|
||||
let datasource = await sdk.datasources.get(datasourceId)
|
||||
|
@ -187,15 +195,17 @@ export async function update(ctx: UserCtx) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function save(ctx: UserCtx) {
|
||||
export async function save(
|
||||
ctx: UserCtx<CreateDatasourceRequest, CreateDatasourceResponse>
|
||||
) {
|
||||
const db = context.getAppDB()
|
||||
const plus = ctx.request.body.datasource.plus
|
||||
const fetchSchema = ctx.request.body.fetchSchema
|
||||
|
||||
const datasource = {
|
||||
_id: generateDatasourceID({ plus }),
|
||||
type: plus ? DocumentType.DATASOURCE_PLUS : DocumentType.DATASOURCE,
|
||||
...ctx.request.body.datasource,
|
||||
type: plus ? DocumentType.DATASOURCE_PLUS : DocumentType.DATASOURCE,
|
||||
}
|
||||
|
||||
let schemaError = null
|
||||
|
@ -218,7 +228,7 @@ export async function save(ctx: UserCtx) {
|
|||
}
|
||||
}
|
||||
|
||||
const response: any = {
|
||||
const response: CreateDatasourceResponse = {
|
||||
datasource: await sdk.datasources.removeSecretSingle(datasource),
|
||||
}
|
||||
if (schemaError) {
|
||||
|
|
|
@ -27,6 +27,7 @@ export const isProdAppID = dbCore.isProdAppID
|
|||
export const USER_METDATA_PREFIX = `${DocumentType.ROW}${SEPARATOR}${dbCore.InternalTable.USER_METADATA}${SEPARATOR}`
|
||||
export const LINK_USER_METADATA_PREFIX = `${DocumentType.LINK}${SEPARATOR}${dbCore.InternalTable.USER_METADATA}${SEPARATOR}`
|
||||
export const TABLE_ROW_PREFIX = `${DocumentType.ROW}${SEPARATOR}${DocumentType.TABLE}`
|
||||
export const AUTOMATION_LOG_PREFIX = `${DocumentType.AUTOMATION_LOG}${SEPARATOR}`
|
||||
export const ViewName = dbCore.ViewName
|
||||
export const InternalTables = dbCore.InternalTable
|
||||
export const UNICODE_MAX = dbCore.UNICODE_MAX
|
||||
|
|
|
@ -349,7 +349,7 @@ describe("row api - postgres", () => {
|
|||
},
|
||||
plus: true,
|
||||
source: "POSTGRES",
|
||||
type: "datasource",
|
||||
type: "datasource_plus",
|
||||
_id: expect.any(String),
|
||||
_rev: expect.any(String),
|
||||
createdAt: expect.any(String),
|
||||
|
|
|
@ -3,6 +3,7 @@ import { budibaseTempDir } from "../../../utilities/budibaseDir"
|
|||
import { streamFile, createTempFolder } from "../../../utilities/fileSystem"
|
||||
import { ObjectStoreBuckets } from "../../../constants"
|
||||
import {
|
||||
AUTOMATION_LOG_PREFIX,
|
||||
LINK_USER_METADATA_PREFIX,
|
||||
TABLE_ROW_PREFIX,
|
||||
USER_METDATA_PREFIX,
|
||||
|
@ -20,11 +21,15 @@ const uuid = require("uuid/v4")
|
|||
const tar = require("tar")
|
||||
const MemoryStream = require("memorystream")
|
||||
|
||||
type ExportOpts = {
|
||||
interface DBDumpOpts {
|
||||
filter?: any
|
||||
exportPath?: string
|
||||
}
|
||||
|
||||
interface ExportOpts extends DBDumpOpts {
|
||||
tar?: boolean
|
||||
excludeRows?: boolean
|
||||
excludeLogs?: boolean
|
||||
}
|
||||
|
||||
function tarFilesToTmp(tmpDir: string, files: string[]) {
|
||||
|
@ -49,7 +54,7 @@ function tarFilesToTmp(tmpDir: string, files: string[]) {
|
|||
* a filter function or the name of the export.
|
||||
* @return {*} either a readable stream or a string
|
||||
*/
|
||||
export async function exportDB(dbName: string, opts: ExportOpts = {}) {
|
||||
export async function exportDB(dbName: string, opts: DBDumpOpts = {}) {
|
||||
const exportOpts = {
|
||||
filter: opts?.filter,
|
||||
batch_size: 1000,
|
||||
|
@ -76,11 +81,14 @@ export async function exportDB(dbName: string, opts: ExportOpts = {}) {
|
|||
})
|
||||
}
|
||||
|
||||
function defineFilter(excludeRows?: boolean) {
|
||||
function defineFilter(excludeRows?: boolean, excludeLogs?: boolean) {
|
||||
const ids = [USER_METDATA_PREFIX, LINK_USER_METADATA_PREFIX]
|
||||
if (excludeRows) {
|
||||
ids.push(TABLE_ROW_PREFIX)
|
||||
}
|
||||
if (excludeLogs) {
|
||||
ids.push(AUTOMATION_LOG_PREFIX)
|
||||
}
|
||||
return (doc: any) =>
|
||||
!ids.map(key => doc._id.includes(key)).reduce((prev, curr) => prev || curr)
|
||||
}
|
||||
|
@ -130,8 +138,7 @@ export async function exportApp(appId: string, config?: ExportOpts) {
|
|||
// enforce an export of app DB to the tmp path
|
||||
const dbPath = join(tmpPath, DB_EXPORT_FILE)
|
||||
await exportDB(appId, {
|
||||
...config,
|
||||
filter: defineFilter(config?.excludeRows),
|
||||
filter: defineFilter(config?.excludeRows, config?.excludeLogs),
|
||||
exportPath: dbPath,
|
||||
})
|
||||
// if tar requested, return where the tarball is
|
||||
|
@ -155,6 +162,10 @@ export async function exportApp(appId: string, config?: ExportOpts) {
|
|||
* @returns {*} a readable stream of the backup which is written in real time
|
||||
*/
|
||||
export async function streamExportApp(appId: string, excludeRows: boolean) {
|
||||
const tmpPath = await exportApp(appId, { excludeRows, tar: true })
|
||||
const tmpPath = await exportApp(appId, {
|
||||
excludeRows,
|
||||
excludeLogs: true,
|
||||
tar: true,
|
||||
})
|
||||
return streamFile(tmpPath)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"@budibase/backend-core": ["../backend-core/src"],
|
||||
"@budibase/backend-core/*": ["../backend-core/*"],
|
||||
"@budibase/shared-core": ["../shared-core/src"],
|
||||
"@budibase/pro": ["../../../budibase-pro/packages/pro/src"]
|
||||
"@budibase/pro": ["../pro/packages/pro/src"]
|
||||
}
|
||||
},
|
||||
"ts-node": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/shared-core",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Shared data utils",
|
||||
"main": "dist/cjs/src/index.js",
|
||||
"types": "dist/mjs/src/index.d.ts",
|
||||
|
@ -20,7 +20,7 @@
|
|||
"dev:builder": "yarn prebuild && concurrently \"tsc -p tsconfig.build.json --watch\" \"tsc -p tsconfig-cjs.build.json --watch\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/types": "2.5.6-alpha.28"
|
||||
"@budibase/types": "2.5.6-alpha.42"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^7.6.0",
|
||||
|
|
|
@ -6,6 +6,5 @@
|
|||
"paths": {
|
||||
"@budibase/types": ["../types/src"]
|
||||
}
|
||||
},
|
||||
"references": [{ "path": "../types" }]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/types",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Budibase types",
|
||||
"main": "dist/cjs/index.js",
|
||||
"types": "dist/mjs/index.d.ts",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { QuotaUsage } from "../../documents"
|
||||
import { LicenseOverrides, QuotaUsage } from "../../documents"
|
||||
import { PlanType } from "../../sdk"
|
||||
|
||||
export interface GetLicenseRequest {
|
||||
// All fields should be optional to cater for
|
||||
|
@ -20,3 +21,8 @@ export interface QuotaTriggeredRequest {
|
|||
export interface LicenseActivateRequest {
|
||||
installVersion?: string
|
||||
}
|
||||
|
||||
export interface UpdateLicenseRequest {
|
||||
planType?: PlanType
|
||||
overrides?: LicenseOverrides
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Datasource } from "../../../documents"
|
||||
|
||||
export interface CreateDatasourceResponse {
|
||||
datasource: Datasource
|
||||
error?: any
|
||||
}
|
||||
|
||||
export interface UpdateDatasourceResponse {
|
||||
datasource: Datasource
|
||||
}
|
||||
|
||||
export interface CreateDatasourceRequest {
|
||||
datasource: Datasource
|
||||
fetchSchema?: boolean
|
||||
}
|
||||
|
||||
export interface UpdateDatasourceRequest extends Datasource {
|
||||
datasource: Datasource
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
export * from "./backup"
|
||||
export * from "./datasource"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Feature, Hosting, License, PlanType, Quotas } from "../../sdk"
|
||||
import { DeepPartial } from "../../shared"
|
||||
import { QuotaUsage } from "../global"
|
||||
|
||||
export interface CreateAccount {
|
||||
|
@ -25,7 +26,7 @@ export const isCreatePasswordAccount = (
|
|||
|
||||
export interface LicenseOverrides {
|
||||
features?: Feature[]
|
||||
quotas?: Quotas
|
||||
quotas?: DeepPartial<Quotas>
|
||||
}
|
||||
|
||||
export interface Account extends CreateAccount {
|
||||
|
@ -38,6 +39,7 @@ export interface Account extends CreateAccount {
|
|||
// licensing
|
||||
tier: string // deprecated
|
||||
planType?: PlanType
|
||||
/** @deprecated */
|
||||
planTier?: number
|
||||
license?: License
|
||||
installId?: string
|
||||
|
@ -46,6 +48,7 @@ export interface Account extends CreateAccount {
|
|||
stripeCustomerId?: string
|
||||
licenseKey?: string
|
||||
licenseKeyActivatedAt?: number
|
||||
licenseRequestedAt?: number
|
||||
licenseOverrides?: LicenseOverrides
|
||||
quotaUsage?: QuotaUsage
|
||||
}
|
||||
|
|
|
@ -42,3 +42,10 @@ export interface PaginationValues {
|
|||
page: string | number | null
|
||||
limit: number | null
|
||||
}
|
||||
|
||||
export interface PreviewQueryRequest extends Omit<Query, "parameters"> {
|
||||
parameters: {}
|
||||
flags?: {
|
||||
urlName?: boolean
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,6 @@ export enum Event {
|
|||
|
||||
// LICENSE
|
||||
LICENSE_PLAN_CHANGED = "license:plan:changed",
|
||||
LICENSE_TIER_CHANGED = "license:tier:changed",
|
||||
LICENSE_ACTIVATED = "license:activated",
|
||||
LICENSE_PAYMENT_FAILED = "license:payment:failed",
|
||||
LICENSE_PAYMENT_RECOVERED = "license:payment:recovered",
|
||||
|
@ -328,7 +327,6 @@ export const AuditedEventFriendlyName: Record<Event, string | undefined> = {
|
|||
|
||||
// LICENSE - NOT AUDITED
|
||||
[Event.LICENSE_PLAN_CHANGED]: undefined,
|
||||
[Event.LICENSE_TIER_CHANGED]: undefined,
|
||||
[Event.LICENSE_ACTIVATED]: undefined,
|
||||
[Event.LICENSE_PAYMENT_FAILED]: undefined,
|
||||
[Event.LICENSE_PAYMENT_RECOVERED]: undefined,
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { PlanType } from "../licensing"
|
||||
|
||||
export interface LicenseTierChangedEvent {
|
||||
accountId: string
|
||||
from: number
|
||||
to: number
|
||||
}
|
||||
import { PlanType, PriceDuration } from "../licensing"
|
||||
|
||||
export interface LicensePlanChangedEvent {
|
||||
accountId: string
|
||||
from: PlanType
|
||||
to: PlanType
|
||||
// may not be on historical events
|
||||
// free plans won't have a duration
|
||||
duration: PriceDuration | undefined
|
||||
// may not be on historical events
|
||||
// free plans won't have a quantity
|
||||
quantity: number | undefined
|
||||
}
|
||||
|
||||
export interface LicenseActivatedEvent {
|
||||
|
|
|
@ -17,7 +17,6 @@ export enum PriceDuration {
|
|||
export interface AvailablePlan {
|
||||
type: PlanType
|
||||
maxUsers: number
|
||||
minUsers: number
|
||||
prices: AvailablePrice[]
|
||||
}
|
||||
|
||||
|
@ -38,7 +37,6 @@ export interface PurchasedPlan {
|
|||
type: PlanType
|
||||
model: PlanModel
|
||||
usesInvoicing: boolean
|
||||
minUsers: number
|
||||
price?: PurchasedPrice
|
||||
}
|
||||
|
||||
|
|
|
@ -55,12 +55,6 @@ export const isConstantQuota = (
|
|||
return quotaType === QuotaType.CONSTANT
|
||||
}
|
||||
|
||||
export interface Minimums {
|
||||
users: number
|
||||
}
|
||||
|
||||
export type PlanMinimums = { [key in PlanType]: Minimums }
|
||||
|
||||
export type PlanQuotas = { [key in PlanType]: Quotas | undefined }
|
||||
|
||||
export type MonthlyQuotas = {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from "./typeUtils"
|
|
@ -0,0 +1,3 @@
|
|||
export type DeepPartial<T> = {
|
||||
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
|
||||
}
|
|
@ -20,11 +20,11 @@ const config: Config.InitialOptions = {
|
|||
}
|
||||
|
||||
// add pro sources if they exist
|
||||
if (fs.existsSync("../../../budibase-pro")) {
|
||||
config.moduleNameMapper["@budibase/pro/(.*)"] =
|
||||
"<rootDir>/../../../budibase-pro/packages/pro/$1"
|
||||
config.moduleNameMapper["@budibase/pro"] =
|
||||
"<rootDir>/../../../budibase-pro/packages/pro/src"
|
||||
if (fs.existsSync("../pro/packages")) {
|
||||
config.moduleNameMapper!["@budibase/pro/(.*)"] =
|
||||
"<rootDir>/../pro/packages/pro/$1"
|
||||
config.moduleNameMapper!["@budibase/pro"] =
|
||||
"<rootDir>/../pro/packages/pro/src"
|
||||
}
|
||||
|
||||
export default config
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"watch": ["src", "../backend-core", "../../../budibase-pro/packages/pro"],
|
||||
"watch": ["src", "../backend-core", "../pro/packages/pro"],
|
||||
"ext": "js,ts,json",
|
||||
"ignore": [
|
||||
"src/**/*.spec.ts",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.5.6-alpha.28",
|
||||
"version": "2.5.6-alpha.42",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -39,10 +39,10 @@
|
|||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.5.6-alpha.28",
|
||||
"@budibase/pro": "2.5.6-alpha.28",
|
||||
"@budibase/string-templates": "2.5.6-alpha.28",
|
||||
"@budibase/types": "2.5.6-alpha.28",
|
||||
"@budibase/backend-core": "2.5.6-alpha.42",
|
||||
"@budibase/pro": "2.5.6-alpha.42",
|
||||
"@budibase/string-templates": "2.5.6-alpha.42",
|
||||
"@budibase/types": "2.5.6-alpha.42",
|
||||
"@koa/router": "8.0.8",
|
||||
"@sentry/node": "6.17.7",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
|
|
|
@ -424,7 +424,9 @@ export const inviteAccept = async (
|
|||
if (err.code === ErrorCode.USAGE_LIMIT_EXCEEDED) {
|
||||
// explicitly re-throw limit exceeded errors
|
||||
ctx.throw(400, err)
|
||||
return
|
||||
}
|
||||
console.warn("Error inviting user", err)
|
||||
ctx.throw(400, "Unable to create new user, invitation invalid.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Account, AccountMetadata } from "@budibase/types"
|
||||
import { Account, AccountMetadata, Ctx } from "@budibase/types"
|
||||
import * as accounts from "../../../sdk/accounts"
|
||||
|
||||
export const save = async (ctx: any) => {
|
||||
export const save = async (ctx: Ctx<Account, AccountMetadata>) => {
|
||||
const account = ctx.request.body as Account
|
||||
let metadata: AccountMetadata = {
|
||||
_id: accounts.metadata.formatAccountMetadataId(account.accountId),
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
cellspacing="0"
|
||||
>
|
||||
<img
|
||||
width="32px"
|
||||
width="32"
|
||||
height="32"
|
||||
style="margin-right:16px; vertical-align: middle;"
|
||||
alt="Budibase Logo"
|
||||
src="https://i.imgur.com/Xhdt1YP.png"
|
||||
|
|
|
@ -18,8 +18,17 @@ export const saveMetadata = async (
|
|||
if (existing) {
|
||||
metadata._rev = existing._rev
|
||||
}
|
||||
const res = await db.put(metadata)
|
||||
metadata._rev = res.rev
|
||||
try {
|
||||
const res = await db.put(metadata)
|
||||
metadata._rev = res.rev
|
||||
} catch (e: any) {
|
||||
// account can be updated frequently
|
||||
// ignore 409
|
||||
if (e.status !== 409) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
return metadata
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"@budibase/types": ["../types/src"],
|
||||
"@budibase/backend-core": ["../backend-core/src"],
|
||||
"@budibase/backend-core/*": ["../backend-core/*"],
|
||||
"@budibase/pro": ["../../../budibase-pro/packages/pro/src"]
|
||||
"@budibase/pro": ["../pro/packages/pro/src"]
|
||||
}
|
||||
},
|
||||
"ts-node": {
|
||||
|
|
|
@ -8,8 +8,10 @@ function init() {
|
|||
const envFileJson = {
|
||||
BUDIBASE_URL: "http://localhost:10000",
|
||||
ACCOUNT_PORTAL_URL: "http://localhost:10001",
|
||||
ACCOUNT_PORTAL_API_KEY: "budibase",
|
||||
BB_ADMIN_USER_EMAIL: "admin",
|
||||
BB_ADMIN_USER_PASSWORD: "admin",
|
||||
LOG_LEVEL: "info",
|
||||
}
|
||||
let envFile = ""
|
||||
Object.keys(envFileJson).forEach(key => {
|
||||
|
|
|
@ -8,6 +8,7 @@ interface ApiOptions {
|
|||
method?: APIMethod
|
||||
body?: object
|
||||
headers?: HeadersInit | undefined
|
||||
internal?: boolean
|
||||
}
|
||||
|
||||
export default class AccountInternalAPIClient {
|
||||
|
@ -18,6 +19,9 @@ export default class AccountInternalAPIClient {
|
|||
if (!env.ACCOUNT_PORTAL_URL) {
|
||||
throw new Error("Must set ACCOUNT_PORTAL_URL env var")
|
||||
}
|
||||
if (!env.ACCOUNT_PORTAL_API_KEY) {
|
||||
throw new Error("Must set ACCOUNT_PORTAL_API_KEY env var")
|
||||
}
|
||||
this.host = `${env.ACCOUNT_PORTAL_URL}`
|
||||
this.state = state
|
||||
}
|
||||
|
@ -39,6 +43,13 @@ export default class AccountInternalAPIClient {
|
|||
credentials: "include",
|
||||
}
|
||||
|
||||
if (options.internal) {
|
||||
requestOptions.headers = {
|
||||
...requestOptions.headers,
|
||||
...{ "x-budibase-api-key": env.ACCOUNT_PORTAL_API_KEY },
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const response = await fetch(`${this.host}${url}`, requestOptions)
|
||||
|
||||
|
@ -50,15 +61,20 @@ export default class AccountInternalAPIClient {
|
|||
body = await response.text()
|
||||
}
|
||||
|
||||
const message = `${method} ${url} - ${response.status}
|
||||
Response body: ${JSON.stringify(body)}
|
||||
Request body: ${requestOptions.body}`
|
||||
const data = {
|
||||
request: requestOptions.body,
|
||||
response: body,
|
||||
}
|
||||
const message = `${method} ${url} - ${response.status}`
|
||||
|
||||
if (response.status > 499) {
|
||||
console.error(message)
|
||||
console.error(message, data)
|
||||
} else if (response.status >= 400) {
|
||||
console.warn(message)
|
||||
console.warn(message, data)
|
||||
} else {
|
||||
console.debug(message, data)
|
||||
}
|
||||
|
||||
return [response, body]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import AccountInternalAPIClient from "../AccountInternalAPIClient"
|
||||
import { Account, UpdateLicenseRequest } from "@budibase/types"
|
||||
import { Response } from "node-fetch"
|
||||
|
||||
export default class LicenseAPI {
|
||||
client: AccountInternalAPIClient
|
||||
|
@ -6,4 +8,18 @@ export default class LicenseAPI {
|
|||
constructor(client: AccountInternalAPIClient) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
async updateLicense(
|
||||
accountId: string,
|
||||
body: UpdateLicenseRequest
|
||||
): Promise<[Response, Account]> {
|
||||
const [response, json] = await this.client.put(
|
||||
`/api/accounts/${accountId}/license`,
|
||||
{
|
||||
body,
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
return [response, json]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,23 @@ if (!LOADED) {
|
|||
const env = {
|
||||
BUDIBASE_URL: process.env.BUDIBASE_URL,
|
||||
ACCOUNT_PORTAL_URL: process.env.ACCOUNT_PORTAL_URL,
|
||||
ACCOUNT_PORTAL_API_KEY: process.env.ACCOUNT_PORTAL_API_KEY,
|
||||
BB_ADMIN_USER_EMAIL: process.env.BB_ADMIN_USER_EMAIL,
|
||||
BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD,
|
||||
POSTGRES_HOST: process.env.POSTGRES_HOST,
|
||||
POSTGRES_PORT: process.env.POSTGRES_PORT,
|
||||
POSTGRES_DB: process.env.POSTGRES_DB,
|
||||
POSTGRES_USER: process.env.POSTGRES_USER,
|
||||
POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD,
|
||||
MONGODB_CONNECTION_STRING: process.env.MONGODB_CONNECTION_STRING,
|
||||
MONGODB_DB: process.env.MONGODB_DB,
|
||||
REST_API_BASE_URL: process.env.REST_API_BASE_URL,
|
||||
REST_API_KEY: process.env.REST_API_KEY,
|
||||
MARIADB_HOST: process.env.MARIADB_HOST,
|
||||
MARIADB_PORT: process.env.MARIADB_PORT,
|
||||
MARIADB_DB: process.env.MARIADB_DB,
|
||||
MARIADB_USER: process.env.MARIADB_USER,
|
||||
MARIADB_PASSWORD: process.env.MARIADB_PASSWORD,
|
||||
}
|
||||
|
||||
export = env
|
||||
|
|
|
@ -7,6 +7,10 @@ import ScreenAPI from "./apis/ScreenAPI"
|
|||
import SelfAPI from "./apis/SelfAPI"
|
||||
import TableAPI from "./apis/TableAPI"
|
||||
import UserAPI from "./apis/UserAPI"
|
||||
import DatasourcesAPI from "./apis/DatasourcesAPI"
|
||||
import IntegrationsAPI from "./apis/IntegrationsAPI"
|
||||
import QueriesAPI from "./apis/QueriesAPI"
|
||||
import PermissionsAPI from "./apis/PermissionsAPI"
|
||||
import BudibaseInternalAPIClient from "./BudibaseInternalAPIClient"
|
||||
import { State } from "../../types"
|
||||
|
||||
|
@ -22,6 +26,10 @@ export default class BudibaseInternalAPI {
|
|||
self: SelfAPI
|
||||
tables: TableAPI
|
||||
users: UserAPI
|
||||
datasources: DatasourcesAPI
|
||||
integrations: IntegrationsAPI
|
||||
queries: QueriesAPI
|
||||
permissions: PermissionsAPI
|
||||
|
||||
constructor(state: State) {
|
||||
this.client = new BudibaseInternalAPIClient(state)
|
||||
|
@ -35,5 +43,9 @@ export default class BudibaseInternalAPI {
|
|||
this.self = new SelfAPI(this.client)
|
||||
this.tables = new TableAPI(this.client)
|
||||
this.users = new UserAPI(this.client)
|
||||
this.datasources = new DatasourcesAPI(this.client)
|
||||
this.integrations = new IntegrationsAPI(this.client)
|
||||
this.queries = new QueriesAPI(this.client)
|
||||
this.permissions = new PermissionsAPI(this.client)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ class BudibaseInternalAPIClient {
|
|||
if (!env.BUDIBASE_URL) {
|
||||
throw new Error("Must set BUDIBASE_URL env var")
|
||||
}
|
||||
this.host = `${env.ACCOUNT_PORTAL_URL}/api`
|
||||
this.host = `${env.BUDIBASE_URL}/api`
|
||||
this.state = state
|
||||
}
|
||||
|
@ -53,14 +52,18 @@ class BudibaseInternalAPIClient {
|
|||
body = await response.text()
|
||||
}
|
||||
|
||||
const message = `${method} ${url} - ${response.status}
|
||||
Response body: ${JSON.stringify(body)}
|
||||
Request body: ${requestOptions.body}`
|
||||
const data = {
|
||||
request: requestOptions.body,
|
||||
response: body,
|
||||
}
|
||||
const message = `${method} ${url} - ${response.status}`
|
||||
|
||||
if (response.status > 499) {
|
||||
console.error(message)
|
||||
console.error(message, data)
|
||||
} else if (response.status >= 400) {
|
||||
console.warn(message)
|
||||
console.warn(message, data)
|
||||
} else {
|
||||
console.debug(message, data)
|
||||
}
|
||||
|
||||
return [response, body]
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
import { Response } from "node-fetch"
|
||||
import {
|
||||
Datasource,
|
||||
CreateDatasourceResponse,
|
||||
UpdateDatasourceResponse,
|
||||
} from "@budibase/types"
|
||||
import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient"
|
||||
|
||||
export default class DatasourcesAPI {
|
||||
client: BudibaseInternalAPIClient
|
||||
|
||||
constructor(client: BudibaseInternalAPIClient) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
async getIntegrations(): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.get(`/integrations`)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
const integrationsCount = Object.keys(json).length
|
||||
expect(integrationsCount).toBe(16)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async getAll(): Promise<[Response, Datasource[]]> {
|
||||
const [response, json] = await this.client.get(`/datasources`)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
expect(json.length).toBeGreaterThan(0)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async getTable(dataSourceId: string): Promise<[Response, Datasource]> {
|
||||
const [response, json] = await this.client.get(
|
||||
`/datasources/${dataSourceId}`
|
||||
)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
expect(json._id).toEqual(dataSourceId)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async add(body: any): Promise<[Response, CreateDatasourceResponse]> {
|
||||
const [response, json] = await this.client.post(`/datasources`, { body })
|
||||
expect(response).toHaveStatusCode(200)
|
||||
expect(json.datasource._id).toBeDefined()
|
||||
expect(json.datasource._rev).toBeDefined()
|
||||
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async update(body: any): Promise<[Response, UpdateDatasourceResponse]> {
|
||||
const [response, json] = await this.client.put(`/datasources/${body._id}`, {
|
||||
body,
|
||||
})
|
||||
expect(response).toHaveStatusCode(200)
|
||||
expect(json.datasource._id).toBeDefined()
|
||||
expect(json.datasource._rev).toBeDefined()
|
||||
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async previewQuery(body: any): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.post(`/queries/preview`, {
|
||||
body,
|
||||
})
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async saveQuery(body: any): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.post(`/queries`, {
|
||||
body,
|
||||
})
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async getQuery(queryId: string): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.get(`/queries/${queryId}`)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async getQueryPermissions(queryId: string): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.get(`/permissions/${queryId}`)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async delete(dataSourceId: string, revId: string): Promise<Response> {
|
||||
const [response, json] = await this.client.del(
|
||||
`/datasources/${dataSourceId}/${revId}`
|
||||
)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return response
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { Response } from "node-fetch"
|
||||
import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient"
|
||||
|
||||
export default class IntegrationsAPI {
|
||||
client: BudibaseInternalAPIClient
|
||||
|
||||
constructor(client: BudibaseInternalAPIClient) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
async getAll(): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.get(`/integrations`)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
const integrationsCount = Object.keys(json).length
|
||||
expect(integrationsCount).toBeGreaterThan(0)
|
||||
return [response, json]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { Response } from "node-fetch"
|
||||
import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient"
|
||||
|
||||
export default class PermissionsAPI {
|
||||
client: BudibaseInternalAPIClient
|
||||
|
||||
constructor(client: BudibaseInternalAPIClient) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
async getAll(id: string): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.get(`/permissions/${id}`)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import { Response } from "node-fetch"
|
||||
import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient"
|
||||
import { PreviewQueryRequest, Query } from "@budibase/types"
|
||||
|
||||
export default class DatasourcesAPI {
|
||||
client: BudibaseInternalAPIClient
|
||||
|
||||
constructor(client: BudibaseInternalAPIClient) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
async preview(body: PreviewQueryRequest): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.post(`/queries/preview`, {
|
||||
body,
|
||||
})
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async save(body: Query): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.post(`/queries`, {
|
||||
body,
|
||||
})
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
|
||||
async get(queryId: string): Promise<[Response, any]> {
|
||||
const [response, json] = await this.client.get(`/queries/${queryId}`)
|
||||
expect(response).toHaveStatusCode(200)
|
||||
return [response, json]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// Add information about the data source to the fixtures file from 1password
|
||||
export const mongoDB = () => {
|
||||
return {
|
||||
datasource: {
|
||||
name: "MongoDB",
|
||||
source: "MONGODB",
|
||||
type: "datasource",
|
||||
config: {
|
||||
connectionString: process.env.MONGODB_CONNECTION_STRING,
|
||||
db: process.env.MONGODB_DB,
|
||||
},
|
||||
},
|
||||
|
||||
fetchSchema: false,
|
||||
}
|
||||
}
|
||||
|
||||
export const postgresSQL = () => {
|
||||
return {
|
||||
datasource: {
|
||||
name: "PostgresSQL",
|
||||
plus: true,
|
||||
source: "POSTGRES",
|
||||
type: "datasource",
|
||||
config: {
|
||||
database: process.env.POSTGRES_DB,
|
||||
host: process.env.POSTGRES_HOST,
|
||||
password: process.env.POSTGRES_PASSWORD,
|
||||
port: process.env.POSTGRES_PORT,
|
||||
schema: "public",
|
||||
user: process.env.POSTGRES_USER,
|
||||
},
|
||||
},
|
||||
fetchSchema: true,
|
||||
}
|
||||
}
|
||||
export const mariaDB = () => {
|
||||
return {
|
||||
datasource: {
|
||||
name: "MariaDB",
|
||||
plus: true,
|
||||
source: "MYSQL",
|
||||
type: "datasource",
|
||||
config: {
|
||||
database: process.env.MARIADB_DB,
|
||||
host: process.env.MARIADB_HOST,
|
||||
password: process.env.MARIADB_PASSWORD,
|
||||
port: process.env.MARIADB_PORT,
|
||||
schema: "public",
|
||||
user: process.env.MARIADB_USER,
|
||||
},
|
||||
},
|
||||
fetchSchema: true,
|
||||
}
|
||||
}
|
||||
|
||||
export const restAPI = () => {
|
||||
return {
|
||||
datasource: {
|
||||
name: "RestAPI",
|
||||
source: "REST",
|
||||
type: "datasource",
|
||||
config: {
|
||||
defaultHeaders: {},
|
||||
rejectUnauthorized: true,
|
||||
url: process.env.REST_API_BASE_URL,
|
||||
},
|
||||
},
|
||||
fetchSchema: false,
|
||||
}
|
||||
}
|
|
@ -4,3 +4,5 @@ export * as rows from "./rows"
|
|||
export * as screens from "./screens"
|
||||
export * as tables from "./tables"
|
||||
export * as users from "./users"
|
||||
export * as datasources from "./datasources"
|
||||
export * as queries from "./queries"
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
import { PreviewQueryRequest } from "@budibase/types"
|
||||
|
||||
const query = (datasourceId: string, fields: any): any => {
|
||||
return {
|
||||
datasourceId: datasourceId,
|
||||
fields: fields,
|
||||
name: "Query 1",
|
||||
parameters: {},
|
||||
queryVerb: "read",
|
||||
schema: {},
|
||||
transformer: "return data",
|
||||
}
|
||||
}
|
||||
|
||||
export const mariaDB = (datasourceId: string): PreviewQueryRequest => {
|
||||
const fields = {
|
||||
sql: "SELECT * FROM employees LIMIT 10;",
|
||||
}
|
||||
return query(datasourceId, fields)
|
||||
}
|
||||
|
||||
export const mongoDB = (datasourceId: string): PreviewQueryRequest => {
|
||||
const fields = {
|
||||
extra: {
|
||||
collection: "movies",
|
||||
actionType: "find",
|
||||
},
|
||||
json: "",
|
||||
}
|
||||
return query(datasourceId, fields)
|
||||
}
|
||||
|
||||
export const postgres = (datasourceId: string): PreviewQueryRequest => {
|
||||
const fields = {
|
||||
sql: "SELECT * FROM customers;",
|
||||
}
|
||||
return query(datasourceId, fields)
|
||||
}
|
||||
|
||||
export const expectedSchemaFields = {
|
||||
mariaDB: {
|
||||
birth_date: "string",
|
||||
emp_no: "number",
|
||||
first_name: "string",
|
||||
gender: "string",
|
||||
hire_date: "string",
|
||||
last_name: "string",
|
||||
},
|
||||
mongoDB: {
|
||||
directors: "array",
|
||||
genres: "array",
|
||||
image: "string",
|
||||
plot: "string",
|
||||
rank: "number",
|
||||
rating: "number",
|
||||
release_date: "string",
|
||||
running_time_secs: "number",
|
||||
title: "string",
|
||||
year: "number",
|
||||
_id: "json",
|
||||
},
|
||||
postgres: {
|
||||
address: "string",
|
||||
city: "string",
|
||||
company_name: "string",
|
||||
contact_name: "string",
|
||||
contact_title: "string",
|
||||
country: "string",
|
||||
customer_id: "string",
|
||||
fax: "string",
|
||||
phone: "string",
|
||||
postal_code: "string",
|
||||
region: "string",
|
||||
},
|
||||
restAPI: {
|
||||
abilities: "array",
|
||||
base_experience: "number",
|
||||
forms: "array",
|
||||
game_indices: "array",
|
||||
height: "number",
|
||||
held_items: "array",
|
||||
id: "number",
|
||||
is_default: "string",
|
||||
location_area_encounters: "string",
|
||||
moves: "array",
|
||||
name: "string",
|
||||
order: "number",
|
||||
past_types: "array",
|
||||
species: "json",
|
||||
sprites: "json",
|
||||
stats: "array",
|
||||
types: "array",
|
||||
weight: "number",
|
||||
},
|
||||
}
|
||||
|
||||
const request = (datasourceId: string, fields: any, flags: any): any => {
|
||||
return {
|
||||
datasourceId: datasourceId,
|
||||
fields: fields,
|
||||
flags: flags,
|
||||
name: "Query 1",
|
||||
parameters: {},
|
||||
queryVerb: "read",
|
||||
schema: {},
|
||||
transformer: "return data",
|
||||
}
|
||||
}
|
||||
export const restAPI = (datasourceId: string): PreviewQueryRequest => {
|
||||
const fields = {
|
||||
authConfigId: null,
|
||||
bodyType: "none",
|
||||
disabledHeaders: {},
|
||||
headers: {},
|
||||
pagination: {},
|
||||
path: `${process.env.REST_API_BASE_URL}/pokemon/ditto`,
|
||||
queryString: "",
|
||||
}
|
||||
const flags = {
|
||||
urlName: true,
|
||||
}
|
||||
return request(datasourceId, fields, flags)
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import TestConfiguration from "../../config/TestConfiguration"
|
||||
import * as fixtures from "../../fixtures"
|
||||
|
||||
describe("Internal API - Data Sources", () => {
|
||||
const config = new TestConfiguration()
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.beforeAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await config.afterAll()
|
||||
})
|
||||
|
||||
it("Create an app with a data source", async () => {
|
||||
// Create app
|
||||
await config.createApp()
|
||||
|
||||
// Create Screen
|
||||
const roleArray = ["BASIC", "POWER", "ADMIN", "PUBLIC"]
|
||||
for (let role in roleArray) {
|
||||
const [response, screen] = await config.api.screens.create(
|
||||
fixtures.screens.generateScreen(roleArray[role])
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,69 @@
|
|||
import TestConfiguration from "../../config/TestConfiguration"
|
||||
import * as fixtures from "../../fixtures"
|
||||
import { Query } from "@budibase/types"
|
||||
|
||||
describe("Internal API - Data Sources: MariaDB", () => {
|
||||
const config = new TestConfiguration()
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.beforeAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await config.afterAll()
|
||||
})
|
||||
|
||||
it("Create an app with a data source - MariaDB", async () => {
|
||||
// Create app
|
||||
await config.createApp()
|
||||
|
||||
// Get all integrations
|
||||
await config.api.integrations.getAll()
|
||||
|
||||
// Add data source
|
||||
const [dataSourceResponse, dataSourceJson] =
|
||||
await config.api.datasources.add(fixtures.datasources.mariaDB())
|
||||
|
||||
// Update data source
|
||||
const newDataSourceInfo = {
|
||||
...dataSourceJson.datasource,
|
||||
name: "MariaDB2",
|
||||
}
|
||||
const [updatedDataSourceResponse, updatedDataSourceJson] =
|
||||
await config.api.datasources.update(newDataSourceInfo)
|
||||
|
||||
// Query data source
|
||||
const [queryResponse, queryJson] = await config.api.queries.preview(
|
||||
fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!)
|
||||
)
|
||||
|
||||
expect(queryJson.rows.length).toEqual(10)
|
||||
expect(queryJson.schemaFields).toEqual(
|
||||
fixtures.queries.expectedSchemaFields.mariaDB
|
||||
)
|
||||
|
||||
// Save query
|
||||
const datasourcetoSave: Query = {
|
||||
...fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!),
|
||||
parameters: [],
|
||||
}
|
||||
|
||||
const [saveQueryResponse, saveQueryJson] = await config.api.queries.save(
|
||||
datasourcetoSave
|
||||
)
|
||||
// Get Query
|
||||
const [getQueryResponse, getQueryJson] = await config.api.queries.get(
|
||||
<string>saveQueryJson._id
|
||||
)
|
||||
|
||||
// Get Query permissions
|
||||
const [getQueryPermissionsResponse, getQueryPermissionsJson] =
|
||||
await config.api.permissions.getAll(saveQueryJson._id!)
|
||||
|
||||
// Delete data source
|
||||
const deleteResponse = await config.api.datasources.delete(
|
||||
updatedDataSourceJson.datasource._id!,
|
||||
updatedDataSourceJson.datasource._rev!
|
||||
)
|
||||
})
|
||||
})
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue