Merge branch 'develop' of github.com:Budibase/budibase into feature/json-backend

This commit is contained in:
Andrew Kingston 2022-01-04 09:48:44 +00:00
commit 4cd8886e1a
42 changed files with 950 additions and 1070 deletions

61
.github/workflows/deploy-cloud.yaml vendored Normal file
View File

@ -0,0 +1,61 @@
name: Budibase Cloud Deploy
on:
workflow_dispatch:
inputs:
version:
description: Budibase release version. For example - 1.0.0
required: false
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Pull values.yaml from budibase-infra
run: |
curl -H "Authorization: token ${{ secrets.GH_PERSONAL_TOKEN }}" \
-H 'Accept: application/vnd.github.v3.raw' \
-o values.production.yaml \
-L https://api.github.com/repos/budibase/budibase-infra/contents/kubernetes/values.yaml
wc -l values.production.yaml
- name: Get the latest budibase release version
id: version
run: |
if [ -z "${{ github.event.inputs.version }}" ]; then
release_version=$(cat lerna.json | jq -r '.version')
else
release_version=${{ github.event.inputs.version }}
fi
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1
- name: Deploy to EKS
uses: craftech-io/eks-helm-deploy-action@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS__KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1
cluster-name: budibase-eks-production
config-files: values.production.yaml
chart-path: charts/budibase
namespace: budibase
values: globals.appVersion=v${{ env.RELEASE_VERSION }}
name: budibase-prod
- name: Discord Webhook Action
uses: tsickert/discord-webhook@v4.0.0
with:
webhook-url: ${{ secrets.PROD_DEPLOY_WEBHOOK_URL }}
content: "Production Deployment Complete: ${{ env.RELEASE_VERSION }} deployed to Budibase Cloud."
embed-title: ${{ env.RELEASE_VERSION }}

59
.github/workflows/deploy-preprod.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: Budibase Release Preprod
on:
workflow_dispatch:
env:
POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }}
INTERCOM_TOKEN: ${{ secrets.INTERCOM_TOKEN }}
POSTHOG_URL: ${{ secrets.POSTHOG_URL }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1
- name: 'Get Previous tag'
id: previoustag
uses: "WyriHaximus/github-action-get-previous-tag@v1"
# - name: Pull values.yaml from budibase-infra
# run: |
# curl -H "Authorization: token ${{ secrets.GH_PERSONAL_TOKEN }}" \ [c3a7a9d12]
# -H 'Accept: application/vnd.github.v3.raw' \
# -o values.preprod.yaml \
# -L https://api.github.com/repos/budibase/budibase-infra/contents/kubernetes/values.preprod.yaml
- name: Deploy to Preprod Environment
uses: deliverybot/helm@v1
with:
release: budibase-preprod
namespace: budibase
chart: charts/budibase
token: ${{ github.token }}
values: |
globals:
appVersion: ${{ steps.previoustag.outputs.tag }}
# value-files: >-
# [
# "charts/budibase/values.yaml"
# ]
env:
KUBECONFIG_FILE: '${{ secrets.PREPROD_KUBECONFIG }}'
- name: Discord Webhook Action
uses: tsickert/discord-webhook@v4.0.0
with:
webhook-url: ${{ secrets.PROD_DEPLOY_WEBHOOK_URL }}
content: "Preprod Deployment Complete: ${{ env.RELEASE_VERSION }} deployed to Budibase Pre-prod."
embed-title: ${{ env.RELEASE_VERSION }}

View File

@ -1,36 +0,0 @@
name: Budibase Release Helm Charts
on:
workflow_dispatch:
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: 'Get Previous tag'
id: previoustag
uses: "WyriHaximus/github-action-get-previous-tag@v1"
- name: Install Helm
uses: azure/setup-helm@v1
with:
version: v3.4.0
# - run: yarn release:helm
# env:
# BUDIBASE_RELEASE_VERSION: ${{ steps.previoustag.outputs.tag }}
- name: Configure Git
run: |
git config user.name "Budibase Helm Bot"
git config user.email "<>"
- name: Run chart-releaser
uses: helm/chart-releaser-action@v1.2.1
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -1,13 +1,8 @@
name: Budibase Release Docker Selfhost
name: Budibase Release Selfhost
on:
workflow_dispatch:
env:
POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }}
INTERCOM_TOKEN: ${{ secrets.INTERCOM_TOKEN }}
POSTHOG_URL: ${{ secrets.POSTHOG_URL }}
jobs:
release:
runs-on: ubuntu-latest
@ -15,31 +10,60 @@ jobs:
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v1
with:
node-version: 14.x
- run: yarn
- run: yarn bootstrap
fetch_depth: 0
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1
- name: 'Get Previous tag'
id: previoustag
uses: "WyriHaximus/github-action-get-previous-tag@v1"
- name: Build/release Docker images (Self Host)
- name: Tag and release Docker images (Self Host)
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
yarn build
yarn build:docker:selfhost
# Get latest release version
release_version=$(cat lerna.json | jq -r '.version')
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
release_tag=v$release_version
# Pull apps and worker images
docker pull budibase/apps:$release_tag
docker pull budibase/worker:$release_tag
# Tag apps and worker images
docker tag budibase/apps:$release_tag budibase/apps:$SELFHOST_TAG
docker tag budibase/worker:$release_tag budibase/worker:$SELFHOST_TAG
# Push images
docker push budibase/apps:$SELFHOST_TAG
docker push budibase/worker:$SELFHOST_TAG
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }}
BUDIBASE_RELEASE_VERSION: ${{ steps.previoustag.outputs.tag }}
SELFHOST_TAG: latest
- name: Setup Helm
uses: azure/setup-helm@v1
id: helm-install
# - name: Build and release helm chart
# run: |
# git config user.name "Budibase Helm Bot"
# git config user.email "<>"
# mv budibase-${{ env.RELEASE_VERSION }}.tgz docs
# helm repo index docs
# git checkout gh-pages
# git add -A
# git commit -m "Helm Release: ${{ env.RELEASE_VERSION }}"
# git push
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - name: Deploy
# uses: peaceiris/actions-gh-pages@v3
# with:
# github_token: ${{ secrets.GITHUB_TOKEN }}
# publish_dir: ./public
# full_commit_message: "Helm Release: ${{ env.RELEASE_VERSION }}"
- name: Perform Github Release
uses: softprops/action-gh-release@v1
with:
name: v${{ env.RELEASE_VERSION }}
tag_name: v${{ env.RELEASE_VERSION }}
generate_release_notes: true

View File

@ -3,7 +3,7 @@ name: Budibase Release
on:
push:
branches:
- master
- test
env:
POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }}
@ -57,4 +57,33 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }}
BUDIBASE_RELEASE_VERSION: ${{ steps.previoustag.outputs.tag }}
# Release to pre-prod environment
# - name: Pull values.yaml from budibase-infra
# run: |
# curl -H "Authorization: token ${{ secrets.GH_PERSONAL_TOKEN }}" \ [c3a7a9d12]
# -H 'Accept: application/vnd.github.v3.raw' \
# -o values.preprod.yaml \
# -L https://api.github.com/repos/budibase/budibase-infra/contents/kubernetes/values.preprod.yaml
# - name: Deploy to Preprod Environment
# uses: deliverybot/helm@v1
# with:
# release: budibase-preprod
# namespace: budibase
# chart: charts/budibase
# token: ${{ github.token }}
# values: |
# globals:
# appVersion: ${{ steps.previoustag.outputs.tag }}
# # value-files: >-
# # [
# # "charts/budibase/values.yaml"
# # ]
# env:
# KUBECONFIG_FILE: '${{ secrets.PREPROD_KUBECONFIG }}'
# - name: Discord Webhook Action
# uses: tsickert/discord-webhook@v4.0.0
# with:
# webhook-url: ${{ secrets.PROD_DEPLOY_WEBHOOK_URL }}
# content: "Preprod Deployment Complete: ${{ env.RELEASE_VERSION }} deployed to Budibase Pre-prod."
# embed-title: ${{ env.RELEASE_VERSION }}

View File

@ -11,8 +11,8 @@ sources:
- https://github.com/Budibase/budibase
- https://budibase.com
type: application
version: 0.2.6
appVersion: 1.0.10
version: 1.0.0
appVersion: 1.0.20
dependencies:
- name: couchdb
version: 3.3.4

View File

@ -50,6 +50,14 @@ static_resources:
route:
cluster: app-service
- match:
safe_regex:
google_re2: {}
regex: "/api/.*/export"
route:
timeout: 0s
cluster: app-service
- match: { path: "/api/deploy" }
route:
timeout: 60s

214
i18n/README.fr.md Normal file
View File

@ -0,0 +1,214 @@
<p align="center">
<a href="https://www.budibase.com">
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
</a>
</p>
<h1 align="center">
Budibase
</h1>
<h3 align="center">
La plateform low-code que vous aimerez utiliser
</h3>
<p align="center">
Budibase est une plateforme low-code open source et c'est la façon la plus facile de créer des outils internes qui améliore la productivité.
</p>
<h3 align="center">
🤖 🎨 🚀
</h3>
<br>
<p align="center">
<img alt="Budibase design ui" src="https://res.cloudinary.com/daog6scxm/image/upload/v1633524049/ui/design-ui-wide-mobile_gdaveq.jpg">
</p>
<p align="center">
<a href="https://github.com/Budibase/budibase/releases">
<img alt="GitHub toutes les releases" src="https://img.shields.io/github/downloads/Budibase/budibase/total">
</a>
<a href="https://github.com/Budibase/budibase/releases">
<img alt="GitHub release (par ordre chronologique)" src="https://img.shields.io/github/v/release/Budibase/budibase">
</a>
<a href="https://twitter.com/intent/follow?screen_name=budibase">
<img src="https://img.shields.io/twitter/follow/budibase?style=social" alt="Suivre @budibase" />
</a>
<img src="https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg" alt="Code de conduite" />
<a href="https://codecov.io/gh/Budibase/budibase">
<img src="https://codecov.io/gh/Budibase/budibase/graph/badge.svg?token=E8W2ZFXQOH"/>
</a>
</p>
<h3 align="center">
<a href="https://docs.budibase.com/getting-started">Commencer</a>
<span> · </span>
<a href="https://docs.budibase.com">Documentation</a>
<span> · </span>
<a href="https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas">Demandes d'amélioration</a>
<span> · </span>
<a href="https://github.com/Budibase/budibase/issues">Signaler un bug</a>
<span> · </span>
Support: <a href="https://github.com/Budibase/budibase/discussions">Discussions</a>
</h3>
<br /><br />
## ✨ Fontionnalités
### Construire et déployer un vrai logiciel
Contrairement à d'autres plateformes, avec Budibase vous construisez et déployez des applications one-page. Les applications Budibase sont très perfomantes et peuvent être designées de manière responsive, offrant ainsi à vos utilisateurs une expérience exceptionnelle.
<br /><br />
### Source libre et extensible
Budibase est un logiciel libre - sous licence GPL v3. Cela devrait vous rassurer sur le fait que Budibase sera toujours là. Vous pouvez également coder dans Budibase ou le forker et apporter des modifications à votre guise, ce qui en fera une expérience conviviale pour les développeurs.
<br /><br />
### Importer les données ou partir de zéro
Budibase peut tirer ses données de plusieurs sources, dont MongoDB, CouchDB, PostgreSQL, MySQL, Airtable, S3, DynamoDB ou une API REST. Et contrairement à d'autres plateformes, avec Budibase, vous pouvez partir de zéro et créer des applications métier sans aucune source de données. [Demander une nouvelle source de données](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
<p align="center">
<img alt="Budibase data" src="https://res.cloudinary.com/daog6scxm/image/upload/v1636970242/Out%20of%20beta%20launch/data_n1tlhf.png">
</p>
<br /><br />
### Concevoir et créer des applications à l'aide de composants prédéfinis.
Budibase est livré avec des composants joliment conçus et puissants que vous pouvez utiliser comme des blocs de construction pour bâtir votre interface utilisateur. Nous exposons également un grand nombre de vos options de style CSS préférées afin que vous puissiez faire preuve d'une créativité accrue. [Demander un nouveau composant](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
<p align="center">
<img alt="Budibase design" src="https://res.cloudinary.com/daog6scxm/image/upload/v1636970243/Out%20of%20beta%20launch/design-like-a-pro_qhlfeu.gif">
</p>
<br /><br />
### Automatiser les processus, intégrer d'autres outils et se connecter à des webhooks
Gagnez du temps en automatisant les processus manuels et les flux de travail. Qu'il s'agisse de se connecter à des webhooks ou d'automatiser des e-mails, il suffit de dire à Budibase ce qu'il doit faire et de le laisser travailler pour vous. Vous pouvez aisément [créer une nouvelle automatisation pour Budibase ici](https://github.com/Budibase/automations) ou [Demander une nouvelle automatisation](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
<p align="center">
<img alt="Budibase automations" src="https://res.cloudinary.com/daog6scxm/image/upload/v1636970486/Out%20of%20beta%20launch/automation_riro7u.png">
</p>
<br /><br />
### Intégration avec vos outils préférés
Budibase s'intègre à un certain nombre d'outils populaires, ce qui vous permet de créer des applications qui s'adaptent parfaitement à votre pile technologique.
<p align="center">
<img alt="Budibase integrations" src="https://res.cloudinary.com/daog6scxm/image/upload/v1636970242/Out%20of%20beta%20launch/integrations_kc7dqt.png">
</p>
<br /><br />
### Paradis des admins
Budibase est conçu pour évoluer. Avec Budibase, vous pouvez vous auto-héberger sur votre propre infrastructure et gérer globalement les utilisateurs, l'accueil, le SMTP, les applications, les groupes, l'apparence et plus encore. Vous pouvez également fournir aux utilisateurs/groupes un portail d'applications et confier la gestion des utilisateurs au responsable du groupe.
- Regardez la vidéo de promotion: https://youtu.be/xoljVpty_Kw
<br /><br /><br />
## 🏁 Commencer
<img src="https://res.cloudinary.com/daog6scxm/image/upload/v1634808888/logo/deploy_npl9za.png" />
Déployez Budibase en auto-hébergement dans votre infrastructure existante, en utilisant Docker, Kubernetes et Digital Ocean.
Ou utilisez Budibase Cloud si vous n'avez pas besoin de vous auto-héberger, et que vous souhaitez démarrer rapidement.
### [Commencer avec Budibase](https://budibase.com)
<br /><br />
## 🎓 Apprendre Budibase
La documentation Budibase [est ic](https://docs.budibase.com).
<br />
<br /><br />
## 💬 Communauté
Si vous avez une question ou si vous souhaitez discuter avec d'autres utilisateurs de Budibase et rejoindre notre communauté, veuillez vous rendre à l'adresse suivante : [Discussions Github](https://github.com/Budibase/budibase/discussions)
<br /><br /><br />
## ❗ Code de conduite
Budibase s'engage à offrir à chacun une expérience accueillante, diversifiée et exempte de harcèlement. Nous attendons de tous les membres de la communauté Budibase qu'ils se conforment aux principes de notre [**Code de conduite**](https://github.com/Budibase/budibase/blob/HEAD/.github/CODE_OF_CONDUCT.md). Merci de le lire.
<br />
<br /><br />
## 🙌 Contribuer à Budibase
Qu'il s'agisse d'ouvrir un rapport de bug ou de créer une Pull request, toute contribution est appréciée et bienvenue. Si vous envisagez de mettre en œuvre une nouvelle fonctionnalité ou de modifier l'API, veuillez d'abord créer un Issue. Nous pourrons ainsi nous assurer que votre travail n'est pas vain.
### Vous ne savez pas par où commencer ?
Un bon endroit pour commencer à contribuer, c'est ici : [Projets en cours](https://github.com/Budibase/budibase/projects/22).
### Comment le repo est-il organisé ?
Budibase est une monorepo gérée par lerna. Lerna gère la construction et la publication des paquets de Budibase. Voici, à un haut niveau, les paquets qui composent Budibase.
- [packages/builder](https://github.com/Budibase/budibase/tree/HEAD/packages/builder) - contient le code pour l'application svelte côté client du budibase builder.
- [packages/client](https://github.com/Budibase/budibase/tree/HEAD/packages/client) - Un module qui s'exécute dans le navigateur et qui est chargé de lire les définitions JSON et de créer des applications web vivantes à partir de celles-ci..
- [packages/server](https://github.com/Budibase/budibase/tree/HEAD/packages/server) - Le serveur budibase. Cette application Koa est responsable de servir le JS pour les applications builder et budibase, ainsi que de fournir l'API pour l'interaction avec la base de données et le système de fichiers.
Pour plus d'informations, voir [CONTRIBUTING.md](https://github.com/Budibase/budibase/blob/HEAD/.github/CONTRIBUTING.md)
<br /><br />
## 📝 Licence
Budibase est open source, sous licence de [GPL v3](https://www.gnu.org/licenses/gpl-3.0.en.html). Les bibliothèques du client et des composants sont sous licence [MPL](https://directory.fsf.org/wiki/License:MPL-2.0) - afin que les applications que vous créez puissent être utilisées sous licence comme vous le souhaitez.
<br /><br />
## ⭐ Stargazers dans le temps
[![Stargazers dans le temps](https://starchart.cc/Budibase/budibase.svg)](https://starchart.cc/Budibase/budibase)
Si vous rencontrez des problèmes entre les mises à jour du builder, veuillez utiliser le guide suivant [ici](https://github.com/Budibase/budibase/blob/HEAD/.github/CONTRIBUTING.md#troubleshooting) pour nettoyer votre environnement.
<br /><br />
## Contributeurs ✨
Merci à ces personnes merveilleuses ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://martinmck.com"><img src="https://avatars1.githubusercontent.com/u/11256663?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martin McKeaveney</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=shogunpurple" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=shogunpurple" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=shogunpurple" title="Tests">⚠️</a> <a href="#infra-shogunpurple" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center"><a href="http://www.michaeldrury.co.uk/"><img src="https://avatars2.githubusercontent.com/u/4407001?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Drury</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=mike12345567" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=mike12345567" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=mike12345567" title="Tests">⚠️</a> <a href="#infra-mike12345567" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center"><a href="https://github.com/aptkingston"><img src="https://avatars3.githubusercontent.com/u/9075550?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Kingston</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=aptkingston" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=aptkingston" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=aptkingston" title="Tests">⚠️</a> <a href="#design-aptkingston" title="Design">🎨</a></td>
<td align="center"><a href="https://budibase.com/"><img src="https://avatars3.githubusercontent.com/u/3524181?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Shanks</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=mjashanks" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=mjashanks" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=mjashanks" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/kevmodrome"><img src="https://avatars3.githubusercontent.com/u/534488?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Åberg Kultalahti</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=kevmodrome" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=kevmodrome" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=kevmodrome" title="Tests">⚠️</a></td>
<td align="center"><a href="https://www.budibase.com/"><img src="https://avatars2.githubusercontent.com/u/49767913?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joe</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=joebudi" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=joebudi" title="Code">💻</a> <a href="#content-joebudi" title="Content">🖋</a> <a href="#design-joebudi" title="Design">🎨</a></td>
<td align="center"><a href="https://github.com/Rory-Powell"><img src="https://avatars.githubusercontent.com/u/8755148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rory Powell</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=Rory-Powell" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=Rory-Powell" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=Rory-Powell" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/PClmnt"><img src="https://avatars.githubusercontent.com/u/5665926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Peter Clement</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=PClmnt" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=PClmnt" title="Documentation">📖</a> <a href="https://github.com/Budibase/budibase/commits?author=PClmnt" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/Conor-Mack"><img src="https://avatars1.githubusercontent.com/u/36074859?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Conor_Mack</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=Conor-Mack" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=Conor-Mack" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/pngwn"><img src="https://avatars1.githubusercontent.com/u/12937446?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pngwn</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=pngwn" title="Code">💻</a> <a href="https://github.com/Budibase/budibase/commits?author=pngwn" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/HugoLd"><img src="https://avatars0.githubusercontent.com/u/26521848?v=4?s=100" width="100px;" alt=""/><br /><sub><b>HugoLd</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=HugoLd" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/victoriasloan"><img src="https://avatars.githubusercontent.com/u/9913651?v=4?s=100" width="100px;" alt=""/><br /><sub><b>victoriasloan</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=victoriasloan" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/yashank09"><img src="https://avatars.githubusercontent.com/u/37672190?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yashank09</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=yashank09" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/SOVLOOKUP"><img src="https://avatars.githubusercontent.com/u/53158137?v=4?s=100" width="100px;" alt=""/><br /><sub><b>SOVLOOKUP</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=SOVLOOKUP" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/seoulaja"><img src="https://avatars.githubusercontent.com/u/15101654?v=4?s=100" width="100px;" alt=""/><br /><sub><b>seoulaja</b></sub></a><br /><a href="#translation-seoulaja" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/mslourens"><img src="https://avatars.githubusercontent.com/u/1907152?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Maurits Lourens</b></sub></a><br /><a href="https://github.com/Budibase/budibase/commits?author=mslourens" title="Tests">⚠️</a> <a href="https://github.com/Budibase/budibase/commits?author=mslourens" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/Rory-Powell"><img src="https://avatars.githubusercontent.com/u/8755148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rory Powell</b></sub></a><br /><a href="#infra-Rory-Powell" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/Budibase/budibase/commits?author=Rory-Powell" title="Tests">⚠️</a> <a href="https://github.com/Budibase/budibase/commits?author=Rory-Powell" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
Ce projet suit la spécification [all-contributors](https://allcontributors.org/docs/fr/overview). Les contributions de toute nature sont les bienvenues !

View File

@ -1,5 +1,5 @@
{
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"npmClient": "yarn",
"packages": [
"packages/*"

View File

@ -23,8 +23,8 @@
"build": "lerna run build",
"publishdev": "lerna run publishdev",
"publishnpm": "yarn build && lerna publish --force-publish",
"release": "yarn build && lerna publish patch --yes --force-publish",
"release:develop": "yarn build && lerna publish prerelease --yes --force-publish --dist-tag develop",
"release": "lerna publish patch --yes --force-publish",
"release:develop": "lerna publish prerelease --yes --force-publish --dist-tag 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",

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/auth",
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"description": "Authentication middlewares for budibase builder and apps",
"main": "src/index.js",
"author": "Budibase",

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.",
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"license": "MPL-2.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",

View File

@ -63,6 +63,9 @@
.gap-L {
grid-gap: var(--spectrum-alias-grid-gutter-medium);
}
.gap-XL {
grid-gap: var(--spectrum-alias-grid-gutter-large);
}
.horizontal.gap-S :global(*) + :global(*) {
margin-left: var(--spectrum-alias-grid-gutter-xsmall);
}

View File

@ -13,3 +13,9 @@
>
<slot />
</p>
<style>
p {
font-weight: 600;
}
</style>

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"license": "GPL-3.0",
"private": true,
"scripts": {
@ -65,10 +65,10 @@
}
},
"dependencies": {
"@budibase/bbui": "^1.0.19-alpha.3",
"@budibase/client": "^1.0.19-alpha.3",
"@budibase/bbui": "^1.0.27-alpha.1",
"@budibase/client": "^1.0.27-alpha.1",
"@budibase/colorpicker": "1.1.2",
"@budibase/string-templates": "^1.0.19-alpha.3",
"@budibase/string-templates": "^1.0.27-alpha.1",
"@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1",

View File

@ -8,6 +8,9 @@
name: "javascript",
json: true,
},
XML: {
name: "xml",
},
SQL: {
name: "sql",
},
@ -40,11 +43,12 @@
let editor
// Keep editor up to date with value
$: editor?.setOption("mode", mode)
$: editor?.setValue(value || "")
// Creates an instance of a code mirror editor
async function createEditor(mode, value) {
if (!CodeMirror || !textarea || editor) {
if (!CodeMirror || !textarea) {
return
}

View File

@ -4,6 +4,7 @@ import "codemirror/lib/codemirror.css"
// Modes
import "codemirror/mode/javascript/javascript"
import "codemirror/mode/sql/sql"
import "codemirror/mode/xml/xml"
import "codemirror/mode/css/css"
import "codemirror/mode/handlebars/handlebars"

View File

@ -63,12 +63,13 @@
</div>
<div>
<Button
size="S"
disabled={app.lockedOther}
on:click={() => editApp(app)}
size="S"
quiet
secondary>Open</Button
secondary
>
Open
</Button>
<ActionMenu align="right">
<Icon hoverable slot="control" name="More" />
{#if app.deployed}
@ -91,7 +92,7 @@
<MenuItem on:click={() => updateApp(app)} icon="Edit">Edit</MenuItem>
<MenuItem on:click={() => deleteApp(app)} icon="Delete">Delete</MenuItem>
{/if}
<MenuItem on:click={() => editIcon(app)} icon="Brush">Edit Icon</MenuItem>
<MenuItem on:click={() => editIcon(app)} icon="Brush">Edit icon</MenuItem>
</ActionMenu>
</div>

View File

@ -4,10 +4,11 @@
export let app
let modal
$: selectedIcon = app?.icon?.name
$: selectedIcon = app?.icon?.name || "Apps"
$: selectedColor = app?.icon?.color
let iconsList = [
"Apps",
"Actions",
"ConversionFunnel",
"App",
@ -31,7 +32,6 @@
"GraphDonut",
"GraphBarHorizontal",
"Demographic",
"Apps",
]
export const show = () => {
modal.show()
@ -68,13 +68,13 @@
>
<div class="scrollable-icons">
<div class="title-spacing">
<Label>Select an Icon</Label>
<Label>Select an icon</Label>
</div>
<div class="grid">
{#each iconsList as item}
<div
class="icon-item"
style="color: {item === selectedIcon ? selectedColor : ''}"
class:selected={item === selectedIcon}
on:click={() => (selectedIcon = item)}
>
<Icon name={item} />
@ -84,7 +84,7 @@
</div>
<div class="color-selection">
<div>
<Label>Select a Color</Label>
<Label>Select a color</Label>
</div>
<div class="color-selection-item">
<ColorPicker
@ -124,4 +124,7 @@
.icon-item {
cursor: pointer;
}
.icon-item.selected {
color: var(--spectrum-global-color-blue-600);
}
</style>

View File

@ -208,6 +208,7 @@ export const RawRestBodyTypes = {
ENCODED: "encoded",
JSON: "json",
TEXT: "text",
XML: "xml",
}
export const RestBodyTypes = [
@ -215,5 +216,6 @@ export const RestBodyTypes = [
{ name: "form-data", value: "form" },
{ name: "x-www-form-encoded", value: "encoded" },
{ name: "raw (JSON)", value: "json" },
{ name: "raw (XML)", value: "xml" },
{ name: "raw (Text)", value: "text" },
]

View File

@ -7,7 +7,11 @@
} from "components/common/CodeMirrorEditor.svelte"
const objectTypes = [RawRestBodyTypes.FORM, RawRestBodyTypes.ENCODED]
const textTypes = [RawRestBodyTypes.JSON, RawRestBodyTypes.TEXT]
const textTypes = [
RawRestBodyTypes.JSON,
RawRestBodyTypes.XML,
RawRestBodyTypes.TEXT,
]
export let query
export let bodyType
@ -25,6 +29,18 @@
query.fields.requestBody = ""
}
}
function editorMode(type) {
switch (type) {
case RawRestBodyTypes.JSON:
return EditorModes.JSON
case RawRestBodyTypes.XML:
return EditorModes.XML
default:
case RawRestBodyTypes.TEXT:
return EditorModes.Text
}
}
</script>
<div class="margin">
@ -41,9 +57,7 @@
{:else if textTypes.includes(bodyType)}
<CodeMirrorEditor
height={200}
mode={bodyType === RawRestBodyTypes.JSON
? EditorModes.JSON
: EditorModes.Text}
mode={editorMode(bodyType)}
value={query.fields.requestBody}
resize="vertical"
on:change={e => (query.fields.requestBody = e.detail)}

View File

@ -48,7 +48,7 @@
let breakQs = {},
bindings = {}
let url = ""
let saveId
let saveId, isGet
let response, schema, enabledHeaders
let datasourceType, integrationInfo, queryConfig, responseSuccess
let authConfigId
@ -58,6 +58,7 @@
$: queryConfig = integrationInfo?.query
$: url = buildUrl(url, breakQs)
$: checkQueryName(url)
$: isGet = query?.queryVerb === "read"
$: responseSuccess =
response?.info?.code >= 200 && response?.info?.code <= 206
$: authConfigs = buildAuthConfigs(datasource)
@ -262,7 +263,7 @@
<Tab title="Body">
<RadioGroup
bind:value={query.fields.bodyType}
options={bodyTypes}
options={isGet ? [bodyTypes[0]] : bodyTypes}
direction="horizontal"
getOptionLabel={option => option.name}
getOptionValue={option => option.value}

View File

@ -4,7 +4,6 @@
Layout,
Detail,
Button,
ButtonGroup,
Input,
Select,
Modal,
@ -43,6 +42,7 @@
let cloud = $admin.cloud
let appName = ""
let creatingFromTemplate = false
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
$: filteredApps = enrichedApps.filter(app =>
app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
@ -280,26 +280,32 @@
</script>
<Page wide>
<Layout noPadding>
<Layout noPadding gap="XL">
<div class="title">
<Heading size="S">Welcome to Budibase</Heading>
<Layout noPadding gap="XS">
<Heading size="M">Welcome to Budibase</Heading>
<Body size="S">
Manage your apps and get a head start with templates
</Body>
</Layout>
<ButtonGroup>
<div class="buttons">
{#if cloud}
<Button secondary on:click={initiateAppsExport}>Export apps</Button>
<Button icon="Export" quiet secondary on:click={initiateAppsExport}>
Export apps
</Button>
{/if}
<Button icon="Import" quiet secondary on:click={initiateAppImport}
>Import app</Button
>
<Button icon="Add" cta on:click={initiateAppCreation}>Create app</Button
>
</ButtonGroup>
<Button icon="Import" quiet secondary on:click={initiateAppImport}>
Import app
</Button>
<Button icon="Add" cta on:click={initiateAppCreation}>
Create app
</Button>
</div>
</div>
<div class="title-text">
<Body size="S">Manage your apps and get a head start with templates</Body>
</div>
<Detail>Quick Start Templates</Detail>
<Layout noPadding gap="S">
<Detail size="L">Quick start templates</Detail>
<div class="grid">
{#each $templates as item}
<div
@ -332,12 +338,13 @@
</div>
{/each}
</div>
</Layout>
{#if loaded && enrichedApps.length}
<Layout noPadding gap="S">
<div class="title">
<Detail>My Apps</Detail>
</div>
<Detail size="L">My apps</Detail>
<div class="filter">
<div class="select">
<Select
quiet
autoWidth
@ -349,14 +356,10 @@
{ label: "Sort by status", value: "status" },
]}
/>
<div class="desktop-search">
<Search quiet placeholder="Search" bind:value={searchTerm} />
</div>
</div>
</div>
<div class="mobile-search">
<Search placeholder="Search" bind:value={searchTerm} />
</div>
</div>
<div class="appTable">
{#each filteredApps as app (app.appId)}
<AppRow
@ -372,7 +375,9 @@
/>
{/each}
</div>
</Layout>
{/if}
{#if !enrichedApps.length && !creatingApp && loaded}
<div class="empty-wrapper">
<Modal inline>
@ -380,6 +385,7 @@
</Modal>
</div>
{/if}
{#if creatingFromTemplate}
<div class="empty-wrapper">
<p>Creating your Budibase app from your selected template...</p>
@ -427,68 +433,61 @@
<ChooseIconModal app={selectedApp} bind:this={iconModal} />
<style>
.title,
.filter {
.title {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 5px;
gap: var(--spacing-xl);
flex-wrap: wrap;
}
.buttons {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-xl);
flex-wrap: wrap;
}
@media (max-width: 640px) {
.buttons {
flex-direction: row-reverse;
justify-content: flex-end;
}
}
@media only screen and (max-width: 560px) {
.title {
flex-direction: column;
align-items: flex-start;
.filter {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-xl);
}
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
.iconAlign {
padding: 0 0 0 var(--spacing-m);
display: inline-block;
display: grid;
grid-gap: var(--spacing-xl);
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
}
.template-card {
height: 80px;
width: 270px;
border-radius: var(--border-radius-s);
margin-bottom: var(--spacing-m);
border: 1px solid var(--spectrum-global-color-gray-300);
cursor: pointer;
display: flex;
}
.title-text {
margin-top: calc(var(--spacing-xl) * -1);
.template-card:hover {
background: var(--spectrum-alias-background-color-tertiary);
}
.card-body {
display: flex;
align-items: center;
padding: 12px;
}
.grid {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
}
@media (min-width: 200px) {
}
.select {
display: grid;
grid-template-columns: auto auto;
grid-gap: 30px;
}
.filter :global(.spectrum-ActionGroup) {
flex-wrap: nowrap;
}
.mobile-search {
display: none;
.iconAlign {
padding: 0 0 0 var(--spacing-m);
display: inline-block;
}
.appTable {
@ -511,6 +510,12 @@
.appTable :global(> div) {
border-bottom: var(--border-light);
}
@media (max-width: 640px) {
.appTable {
grid-template-columns: 1fr auto;
}
}
.empty-wrapper {
flex: 1 1 auto;
height: 100%;
@ -519,20 +524,4 @@
justify-content: center;
align-items: center;
}
@media (max-width: 640px) {
.appTable {
grid-template-columns: 1fr auto;
}
.desktop-search {
display: none;
}
.mobile-search {
display: block;
}
}
.template-card:hover {
background: var(--spectrum-alias-background-color-tertiary);
}
</style>

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/client",
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
"@budibase/bbui": "^1.0.19-alpha.3",
"@budibase/bbui": "^1.0.27-alpha.1",
"@budibase/standard-components": "^0.9.139",
"@budibase/string-templates": "^1.0.19-alpha.3",
"@budibase/string-templates": "^1.0.27-alpha.1",
"regexparam": "^1.3.0",
"shortid": "^2.2.15",
"svelte-spa-router": "^3.0.5"

View File

@ -1,8 +1,9 @@
<script>
import { setContext, getContext } from "svelte"
import { setContext, getContext, onMount } from "svelte"
import Router, { querystring } from "svelte-spa-router"
import { routeStore } from "stores"
import { routeStore, stateStore } from "stores"
import Screen from "./Screen.svelte"
import { get } from "svelte/store"
const { styleable } = getContext("sdk")
const component = getContext("component")
@ -17,15 +18,17 @@
}
// Keep query params up to date
$: {
$: routeStore.actions.setQueryParams(parseQueryString($querystring))
const parseQueryString = query => {
let queryParams = {}
if ($querystring) {
const urlSearchParams = new URLSearchParams($querystring)
if (query) {
const urlSearchParams = new URLSearchParams(query)
for (const [key, value] of urlSearchParams) {
queryParams[key] = value
}
}
routeStore.actions.setQueryParams(queryParams)
return queryParams
}
const getRouterConfig = routes => {
@ -42,6 +45,19 @@
const onRouteLoading = ({ detail }) => {
routeStore.actions.setActiveRoute(detail.route)
}
// Initialise state store from query string on initial load
onMount(() => {
const queryParams = parseQueryString(get(querystring))
if (queryParams.state) {
try {
const state = JSON.parse(atob(queryParams.state))
stateStore.actions.initialise(state)
} catch (error) {
// Swallow error and do nothing
}
}
})
</script>
{#key config.id}

View File

@ -4,6 +4,7 @@
dataSourceStore,
notificationStore,
routeStore,
stateStore,
} from "stores"
import { Modal, ModalContent, ActionButton } from "@budibase/bbui"
import { onDestroy } from "svelte"
@ -12,12 +13,13 @@
NOTIFICATION: "notification",
CLOSE_SCREEN_MODAL: "close-screen-modal",
INVALIDATE_DATASOURCE: "invalidate-datasource",
UPDATE_STATE: "update-state",
}
let iframe
let listenersAttached = false
const invalidateDataSource = event => {
const proxyInvalidation = event => {
const { dataSourceId } = event.detail
dataSourceStore.actions.invalidateDataSource(dataSourceId)
}
@ -27,14 +29,28 @@
notificationStore.actions.send(message, type, icon)
}
const proxyStateUpdate = event => {
const { type, key, value, persist } = event.detail
if (type === "set") {
stateStore.actions.setValue(key, value, persist)
} else if (type === "delete") {
stateStore.actions.deleteValue(key)
}
}
function receiveMessage(message) {
const handlers = {
[MessageTypes.NOTIFICATION]: () => {
proxyNotification(message.data)
},
[MessageTypes.CLOSE_SCREEN_MODAL]: peekStore.actions.hidePeek,
[MessageTypes.CLOSE_SCREEN_MODAL]: () => {
peekStore.actions.hidePeek()
},
[MessageTypes.INVALIDATE_DATASOURCE]: () => {
invalidateDataSource(message.data)
proxyInvalidation(message.data)
},
[MessageTypes.UPDATE_STATE]: () => {
proxyStateUpdate(message.data)
},
}

View File

@ -1,4 +1,5 @@
import { writable } from "svelte/store"
import { writable, get } from "svelte/store"
import { stateStore } from "./state.js"
const initialState = {
showPeek: false,
@ -14,7 +15,10 @@ const createPeekStore = () => {
let href = url
let external = !url.startsWith("/")
if (!external) {
href = `${window.location.href.split("#")[0]}#${url}?peek=true`
const state = get(stateStore)
const serialised = encodeURIComponent(btoa(JSON.stringify(state)))
const query = `peek=true&state=${serialised}`
href = `${window.location.href.split("#")[0]}#${url}?${query}`
}
store.set({
showPeek: true,

View File

@ -1,9 +1,9 @@
import { writable, get, derived } from "svelte/store"
import { localStorageStore } from "builder/src/builderStore/store/localStorage"
import { appStore } from "./app"
const createStateStore = () => {
const localStorageKey = `${get(appStore).appId}.state`
const appId = window["##BUDIBASE_APP_ID##"] || "app"
const localStorageKey = `${appId}.state`
const persistentStore = localStorageStore(localStorageKey, {})
// Initialise the temp store to mirror the persistent store
@ -34,6 +34,9 @@ const createStateStore = () => {
})
}
// Initialises the temporary state store with a certain value
const initialise = tempStore.set
// Derive the combination of both persisted and non persisted stores
const store = derived(
[tempStore, persistentStore],
@ -47,7 +50,7 @@ const createStateStore = () => {
return {
subscribe: store.subscribe,
actions: { setValue, deleteValue },
actions: { setValue, deleteValue, initialise },
}
}

View File

@ -146,6 +146,15 @@ const updateStateHandler = action => {
} else if (type === "delete") {
stateStore.actions.deleteValue(key)
}
// Emit this as an event so that parent windows which are iframing us in
// can also update their state
if (get(routeStore).queryParams?.peek) {
window.parent.postMessage({
type: "update-state",
detail: { type, key, value, persist },
})
}
}
const handlerMap = {

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"description": "Budibase Web Server",
"main": "src/index.ts",
"repository": {
@ -70,9 +70,9 @@
"license": "GPL-3.0",
"dependencies": {
"@apidevtools/swagger-parser": "^10.0.3",
"@budibase/auth": "^1.0.19-alpha.3",
"@budibase/client": "^1.0.19-alpha.3",
"@budibase/string-templates": "^1.0.19-alpha.3",
"@budibase/auth": "^1.0.27-alpha.1",
"@budibase/client": "^1.0.27-alpha.1",
"@budibase/string-templates": "^1.0.27-alpha.1",
"@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0",
@ -90,6 +90,7 @@
"dotenv": "8.2.0",
"download": "8.0.0",
"fix-path": "3.0.0",
"form-data": "^4.0.0",
"fs-extra": "8.1.0",
"jimp": "0.16.1",
"joi": "17.2.1",
@ -126,6 +127,7 @@
"validate.js": "0.13.1",
"vm2": "^3.9.3",
"worker-farm": "^1.7.0",
"xml2js": "^0.4.23",
"yargs": "13.2.4",
"zlib": "1.0.5"
},

View File

@ -5,11 +5,15 @@ const { getAutomationParams, generateAutomationID } = require("../../db/utils")
const {
checkForWebhooks,
updateTestHistory,
removeDeprecated,
} = require("../../automations/utils")
const { deleteEntityMetadata } = require("../../utilities")
const { MetadataTypes } = require("../../constants")
const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
/*************************
* *
* BUILDER FUNCTIONS *
@ -155,17 +159,17 @@ exports.destroy = async function (ctx) {
}
exports.getActionList = async function (ctx) {
ctx.body = actions.ACTION_DEFINITIONS
ctx.body = ACTION_DEFS
}
exports.getTriggerList = async function (ctx) {
ctx.body = triggers.TRIGGER_DEFINITIONS
ctx.body = TRIGGER_DEFS
}
module.exports.getDefinitionList = async function (ctx) {
ctx.body = {
trigger: triggers.TRIGGER_DEFINITIONS,
action: actions.ACTION_DEFINITIONS,
trigger: TRIGGER_DEFS,
action: ACTION_DEFS,
}
}

View File

@ -13,12 +13,11 @@ const RequestType = {
const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH]
/**
* Note, there is some functionality in this that is not currently exposed as it
* is complex and maybe better to be opinionated here.
* GET/DELETE requests cannot handle body elements so they will not be sent if configured.
* NOTE: this functionality is deprecated - it no longer should be used.
*/
exports.definition = {
deprecated: true,
name: "Outgoing webhook",
tagline: "Send a {{inputs.requestMethod}} request",
icon: "Send",

View File

@ -7,6 +7,7 @@ const newid = require("../db/newid")
const { updateEntityMetadata } = require("../utilities")
const { MetadataTypes } = require("../constants")
const { getDeployedAppID } = require("@budibase/auth/db")
const { cloneDeep } = require("lodash/fp")
const WH_STEP_ID = definitions.WEBHOOK.stepId
const CRON_STEP_ID = definitions.CRON.stepId
@ -42,6 +43,16 @@ exports.updateTestHistory = async (appId, automation, history) => {
)
}
exports.removeDeprecated = definitions => {
const base = cloneDeep(definitions)
for (let key of Object.keys(base)) {
if (base[key].deprecated) {
delete base[key]
}
}
return base
}
// end the repetition and the job itself
exports.disableAllCrons = async appId => {
const promises = []

View File

@ -6,13 +6,14 @@ import {
RestQueryFields as RestQuery,
AuthType,
BasicAuthConfig,
BearerAuthConfig
BearerAuthConfig,
} from "../definitions/datasource"
import { IntegrationBase } from "./base/IntegrationBase"
const BodyTypes = {
NONE: "none",
FORM_DATA: "form",
XML: "xml",
ENCODED: "encoded",
JSON: "json",
TEXT: "text",
@ -45,6 +46,9 @@ module RestModule {
const fetch = require("node-fetch")
const { formatBytes } = require("../utilities")
const { performance } = require("perf_hooks")
const FormData = require("form-data")
const { URLSearchParams } = require("url")
const { parseStringPromise: xmlParser, Builder: XmlBuilder } = require("xml2js")
const SCHEMA: Integration = {
docs: "https://github.com/node-fetch/node-fetch",
@ -110,15 +114,38 @@ module RestModule {
async parseResponse(response: any) {
let data, raw, headers
const contentType = response.headers.get("content-type")
if (contentType && contentType.indexOf("application/json") !== -1) {
const contentType = response.headers.get("content-type") || ""
try {
if (contentType.includes("application/json")) {
data = await response.json()
raw = JSON.stringify(data)
} else if (
contentType.includes("text/xml") ||
contentType.includes("application/xml")
) {
const rawXml = await response.text()
data =
(await xmlParser(rawXml, {
explicitArray: false,
trim: true,
explicitRoot: false,
})) || {}
// there is only one structure, its an array, return the array so it appears as rows
const keys = Object.keys(data)
if (keys.length === 1 && Array.isArray(data[keys[0]])) {
data = data[keys[0]]
}
raw = rawXml
} else {
data = await response.text()
raw = data
}
const size = formatBytes(response.headers.get("content-length") || Buffer.byteLength(raw, "utf8"))
} catch (err) {
throw "Failed to parse response body."
}
const size = formatBytes(
response.headers.get("content-length") || Buffer.byteLength(raw, "utf8")
)
const time = `${Math.round(performance.now() - this.startTimeMs)}ms`
headers = response.headers.raw()
for (let [key, value] of Object.entries(headers)) {
@ -150,6 +177,58 @@ module RestModule {
return complete
}
addBody(bodyType: string, body: string | any, input: any) {
let error, object, string
try {
string = typeof body !== "string" ? JSON.stringify(body) : body
object = typeof body === "object" ? body : JSON.parse(body)
} catch (err) {
error = err
}
if (!input.headers) {
input.headers = {}
}
switch (bodyType) {
case BodyTypes.NONE:
break
case BodyTypes.TEXT:
// content type defaults to plaintext
input.body = string
break
case BodyTypes.ENCODED:
const params = new URLSearchParams()
for (let [key, value] of Object.entries(object)) {
params.append(key, value)
}
input.body = params
break
case BodyTypes.FORM_DATA:
const form = new FormData()
for (let [key, value] of Object.entries(object)) {
form.append(key, value)
}
input.body = form
break
case BodyTypes.XML:
if (object != null) {
string = (new XmlBuilder()).buildObject(object)
}
input.body = string
input.headers["Content-Type"] = "application/xml"
break
default:
case BodyTypes.JSON:
// if JSON error, throw it
if (error) {
throw "Invalid JSON for request body"
}
input.body = string
input.headers["Content-Type"] = "application/json"
break
}
return input
}
getAuthHeaders(authConfigId: string): { [key: string]: any } {
let headers: any = {}
@ -180,7 +259,16 @@ module RestModule {
}
async _req(query: RestQuery) {
const { path = "", queryString = "", headers = {}, method = "GET", disabledHeaders, bodyType, requestBody, authConfigId } = query
const {
path = "",
queryString = "",
headers = {},
method = "GET",
disabledHeaders,
bodyType,
requestBody,
authConfigId,
} = query
const authHeaders = this.getAuthHeaders(authConfigId)
this.headers = {
@ -197,18 +285,9 @@ module RestModule {
}
}
let json
if (bodyType === BodyTypes.JSON && requestBody) {
try {
json = JSON.parse(requestBody)
} catch (err) {
throw "Invalid JSON for request body"
}
}
const input: any = { method, headers: this.headers }
if (json && typeof json === "object" && Object.keys(json).length > 0) {
input.body = JSON.stringify(json)
let input: any = { method, headers: this.headers }
if (requestBody) {
input = this.addBody(bodyType, requestBody, input)
}
this.startTimeMs = performance.now()

View File

@ -14,6 +14,11 @@ const fetch = require("node-fetch")
const RestIntegration = require("../rest")
const { AuthType } = require("../rest")
const HEADERS = {
"Accept": "application/json",
"Content-Type": "application/json"
}
class TestConfiguration {
constructor(config = {}) {
this.integration = new RestIntegration.integration(config)
@ -35,9 +40,7 @@ describe("REST Integration", () => {
const query = {
path: "api",
queryString: "test=1",
headers: {
Accept: "application/json",
},
headers: HEADERS,
bodyType: "json",
requestBody: JSON.stringify({
name: "test",
@ -47,9 +50,7 @@ describe("REST Integration", () => {
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
method: "POST",
body: '{"name":"test"}',
headers: {
Accept: "application/json",
},
headers: HEADERS,
})
})
@ -86,9 +87,7 @@ describe("REST Integration", () => {
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
method: "PUT",
body: '{"name":"test"}',
headers: {
Accept: "application/json",
},
headers: HEADERS,
})
})
@ -107,13 +106,98 @@ describe("REST Integration", () => {
const response = await config.integration.delete(query)
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
method: "DELETE",
headers: {
Accept: "application/json",
},
headers: HEADERS,
body: '{"name":"test"}',
})
})
describe("request body", () => {
const input = { a: 1, b: 2 }
it("should allow no body", () => {
const output = config.integration.addBody("none", null, {})
expect(output.body).toBeUndefined()
expect(Object.keys(output.headers).length).toEqual(0)
})
it("should allow text body", () => {
const output = config.integration.addBody("text", "hello world", {})
expect(output.body).toEqual("hello world")
// gets added by fetch
expect(Object.keys(output.headers).length).toEqual(0)
})
it("should allow form data", () => {
const FormData = require("form-data")
const output = config.integration.addBody("form", input, {})
expect(output.body instanceof FormData).toEqual(true)
expect(output.body._valueLength).toEqual(2)
// gets added by fetch
expect(Object.keys(output.headers).length).toEqual(0)
})
it("should allow encoded form data", () => {
const { URLSearchParams } = require("url")
const output = config.integration.addBody("encoded", input, {})
expect(output.body instanceof URLSearchParams).toEqual(true)
expect(output.body.toString()).toEqual("a=1&b=2")
// gets added by fetch
expect(Object.keys(output.headers).length).toEqual(0)
})
it("should allow JSON", () => {
const output = config.integration.addBody("json", input, {})
expect(output.body).toEqual(JSON.stringify(input))
expect(output.headers["Content-Type"]).toEqual("application/json")
})
it("should allow XML", () => {
const output = config.integration.addBody("xml", input, {})
expect(output.body.includes("<a>1</a>")).toEqual(true)
expect(output.body.includes("<b>2</b>")).toEqual(true)
expect(output.headers["Content-Type"]).toEqual("application/xml")
})
})
describe("response", () => {
function buildInput(json, text, header) {
return {
status: 200,
json: json ? async () => json : undefined,
text: text ? async () => text : undefined,
headers: { get: key => key === "content-length" ? 100 : header, raw: () => ({ "content-type": header }) }
}
}
it("should be able to parse JSON response", async () => {
const input = buildInput({a: 1}, null, "application/json")
const output = await config.integration.parseResponse(input)
expect(output.data).toEqual({a: 1})
expect(output.info.code).toEqual(200)
expect(output.info.size).toEqual("100B")
expect(output.extra.raw).toEqual(JSON.stringify({a: 1}))
expect(output.extra.headers["content-type"]).toEqual("application/json")
})
it("should be able to parse text response", async () => {
const text = "hello world"
const input = buildInput(null, text, "text/plain")
const output = await config.integration.parseResponse(input)
expect(output.data).toEqual(text)
expect(output.extra.raw).toEqual(text)
expect(output.extra.headers["content-type"]).toEqual("text/plain")
})
it("should be able to parse XML response", async () => {
const text = "<root><a>1</a><b>2</b></root>"
const input = buildInput(null, text, "application/xml")
const output = await config.integration.parseResponse(input)
expect(output.data).toEqual({a: "1", b: "2"})
expect(output.extra.raw).toEqual(text)
expect(output.extra.headers["content-type"]).toEqual("application/xml")
})
})
describe("authentication", () => {
const basicAuth = {
_id: "c59c14bd1898a43baa08da68959b24686",

View File

@ -1,6 +1,5 @@
// when thread starts, make sure it is recorded
require("./utils").threadSetup()
const env = require("../environment")
env.setInThread()
const actions = require("../automations/actions")
const automationUtils = require("../automations/automationUtils")
const AutomationEmitter = require("../events/AutomationEmitter")

View File

@ -1,6 +1,4 @@
// when thread starts, make sure it is recorded
const env = require("../environment")
env.setInThread()
require("./utils").threadSetup()
const ScriptRunner = require("../utilities/scriptRunner")
const { integrations } = require("../integrations")

View File

@ -0,0 +1,13 @@
const env = require("../environment")
const CouchDB = require("../db")
const { init } = require("@budibase/auth")
exports.threadSetup = () => {
// don't run this if not threading
if (env.isTest() || env.DISABLE_THREADING) {
return
}
// when thread starts, make sure it is recorded
env.setInThread()
init(CouchDB)
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/worker",
"email": "hi@budibase.com",
"version": "1.0.19-alpha.3",
"version": "1.0.27-alpha.1",
"description": "Budibase background service",
"main": "src/index.js",
"repository": {
@ -29,8 +29,8 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
"@budibase/auth": "^1.0.19-alpha.3",
"@budibase/string-templates": "^1.0.19-alpha.3",
"@budibase/auth": "^1.0.27-alpha.1",
"@budibase/string-templates": "^1.0.27-alpha.1",
"@koa/router": "^8.0.0",
"@sentry/node": "^6.0.0",
"@techpass/passport-openidconnect": "^0.3.0",