1
0
Fork 0
mirror of synced 2024-07-09 00:06:05 +12:00

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: on:
workflow_dispatch: workflow_dispatch:
env:
POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }}
INTERCOM_TOKEN: ${{ secrets.INTERCOM_TOKEN }}
POSTHOG_URL: ${{ secrets.POSTHOG_URL }}
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -15,31 +10,60 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch_depth: 0
- uses: actions/setup-node@v1
with:
node-version: 14.x
- run: yarn
- run: yarn bootstrap
- name: Configure AWS Credentials - name: Tag and release Docker images (Self Host)
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)
run: | run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD 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: env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }} 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: on:
push: push:
branches: branches:
- master - test
env: env:
POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }} POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }}
@ -57,4 +57,33 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }} DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }}
BUDIBASE_RELEASE_VERSION: ${{ steps.previoustag.outputs.tag }} 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://github.com/Budibase/budibase
- https://budibase.com - https://budibase.com
type: application type: application
version: 0.2.6 version: 1.0.0
appVersion: 1.0.10 appVersion: 1.0.20
dependencies: dependencies:
- name: couchdb - name: couchdb
version: 3.3.4 version: 3.3.4

View file

@ -50,6 +50,14 @@ static_resources:
route: route:
cluster: app-service cluster: app-service
- match:
safe_regex:
google_re2: {}
regex: "/api/.*/export"
route:
timeout: 0s
cluster: app-service
- match: { path: "/api/deploy" } - match: { path: "/api/deploy" }
route: route:
timeout: 60s 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", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View file

@ -23,8 +23,8 @@
"build": "lerna run build", "build": "lerna run build",
"publishdev": "lerna run publishdev", "publishdev": "lerna run publishdev",
"publishnpm": "yarn build && lerna publish --force-publish", "publishnpm": "yarn build && lerna publish --force-publish",
"release": "yarn build && lerna publish patch --yes --force-publish", "release": "lerna publish patch --yes --force-publish",
"release:develop": "yarn build && lerna publish prerelease --yes --force-publish --dist-tag develop", "release:develop": "lerna publish prerelease --yes --force-publish --dist-tag develop",
"restore": "yarn run clean && yarn run bootstrap && yarn run build", "restore": "yarn run clean && yarn run bootstrap && yarn run build",
"nuke": "yarn run nuke:packages && yarn run nuke:docker", "nuke": "yarn run nuke:packages && yarn run nuke:docker",
"nuke:packages": "yarn run restore", "nuke:packages": "yarn run restore",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,7 +4,6 @@
Layout, Layout,
Detail, Detail,
Button, Button,
ButtonGroup,
Input, Input,
Select, Select,
Modal, Modal,
@ -43,6 +42,7 @@
let cloud = $admin.cloud let cloud = $admin.cloud
let appName = "" let appName = ""
let creatingFromTemplate = false let creatingFromTemplate = false
$: enrichedApps = enrichApps($apps, $auth.user, sortBy) $: enrichedApps = enrichApps($apps, $auth.user, sortBy)
$: filteredApps = enrichedApps.filter(app => $: filteredApps = enrichedApps.filter(app =>
app?.name?.toLowerCase().includes(searchTerm.toLowerCase()) app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
@ -280,99 +280,104 @@
</script> </script>
<Page wide> <Page wide>
<Layout noPadding> <Layout noPadding gap="XL">
<div class="title"> <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} {#if cloud}
<Button secondary on:click={initiateAppsExport}>Export apps</Button> <Button icon="Export" quiet secondary on:click={initiateAppsExport}>
Export apps
</Button>
{/if} {/if}
<Button icon="Import" quiet secondary on:click={initiateAppImport} <Button icon="Import" quiet secondary on:click={initiateAppImport}>
>Import app</Button Import app
> </Button>
<Button icon="Add" cta on:click={initiateAppCreation}>Create app</Button <Button icon="Add" cta on:click={initiateAppCreation}>
> Create app
</ButtonGroup> </Button>
</div>
</div> </div>
<div class="title-text"> <Layout noPadding gap="S">
<Body size="S">Manage your apps and get a head start with templates</Body> <Detail size="L">Quick start templates</Detail>
</div> <div class="grid">
<Detail>Quick Start Templates</Detail> {#each $templates as item}
<div class="grid"> <div
{#each $templates as item} on:click={() => {
<div template = item
on:click={() => { creationModal.show()
template = item creatingApp = true
creationModal.show() }}
creatingApp = true class="template-card"
}} >
class="template-card" <div class="card-body">
> <div style="color: {item.background}" class="iconAlign">
<div class="card-body"> <svg
<div style="color: {item.background}" class="iconAlign"> width="26px"
<svg height="26px"
width="26px" class="spectrum-Icon"
height="26px" style="color:{item.background};"
class="spectrum-Icon" focusable="false"
style="color:{item.background};" >
focusable="false" <use xlink:href="#spectrum-icon-18-{item.icon}" />
> </svg>
<use xlink:href="#spectrum-icon-18-{item.icon}" /> </div>
</svg> <div class="iconAlign">
</div> <Body weight="900" size="S">{item.name}</Body>
<div class="iconAlign"> <div style="font-size: 10px;">
<Body weight="900" size="S">{item.name}</Body> <Body size="S">{item.category.toUpperCase()}</Body>
<div style="font-size: 10px;"> </div>
<Body size="S">{item.category.toUpperCase()}</Body>
</div> </div>
</div> </div>
</div> </div>
</div>
{/each}
</div>
{#if loaded && enrichedApps.length}
<div class="title">
<Detail>My Apps</Detail>
</div>
<div class="filter">
<div class="select">
<Select
quiet
autoWidth
bind:value={sortBy}
placeholder={null}
options={[
{ label: "Sort by name", value: "name" },
{ label: "Sort by recently updated", value: "updated" },
{ 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 class="appTable">
{#each filteredApps as app (app.appId)}
<AppRow
{releaseLock}
{editIcon}
{app}
{unpublishApp}
{viewApp}
{editApp}
{exportApp}
{deleteApp}
{updateApp}
/>
{/each} {/each}
</div> </div>
</Layout>
{#if loaded && enrichedApps.length}
<Layout noPadding gap="S">
<div class="title">
<Detail size="L">My apps</Detail>
<div class="filter">
<Select
quiet
autoWidth
bind:value={sortBy}
placeholder={null}
options={[
{ label: "Sort by name", value: "name" },
{ label: "Sort by recently updated", value: "updated" },
{ label: "Sort by status", value: "status" },
]}
/>
<Search placeholder="Search" bind:value={searchTerm} />
</div>
</div>
<div class="appTable">
{#each filteredApps as app (app.appId)}
<AppRow
{releaseLock}
{editIcon}
{app}
{unpublishApp}
{viewApp}
{editApp}
{exportApp}
{deleteApp}
{updateApp}
/>
{/each}
</div>
</Layout>
{/if} {/if}
{#if !enrichedApps.length && !creatingApp && loaded} {#if !enrichedApps.length && !creatingApp && loaded}
<div class="empty-wrapper"> <div class="empty-wrapper">
<Modal inline> <Modal inline>
@ -380,6 +385,7 @@
</Modal> </Modal>
</div> </div>
{/if} {/if}
{#if creatingFromTemplate} {#if creatingFromTemplate}
<div class="empty-wrapper"> <div class="empty-wrapper">
<p>Creating your Budibase app from your selected template...</p> <p>Creating your Budibase app from your selected template...</p>
@ -427,68 +433,61 @@
<ChooseIconModal app={selectedApp} bind:this={iconModal} /> <ChooseIconModal app={selectedApp} bind:this={iconModal} />
<style> <style>
.title, .title {
.filter {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
gap: 5px; gap: var(--spacing-xl);
flex-wrap: wrap;
} }
.buttons {
@media only screen and (max-width: 560px) { display: flex;
.title { flex-direction: row;
flex-direction: column; justify-content: flex-start;
align-items: flex-start; align-items: center;
} gap: var(--spacing-xl);
.grid { flex-wrap: wrap;
grid-template-columns: repeat(2, 1fr); }
@media (max-width: 640px) {
.buttons {
flex-direction: row-reverse;
justify-content: flex-end;
} }
} }
.iconAlign { .filter {
padding: 0 0 0 var(--spacing-m); display: flex;
display: inline-block; flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-xl);
}
.grid {
display: grid;
grid-gap: var(--spacing-xl);
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
} }
.template-card { .template-card {
height: 80px; height: 80px;
width: 270px;
border-radius: var(--border-radius-s); border-radius: var(--border-radius-s);
margin-bottom: var(--spacing-m);
border: 1px solid var(--spectrum-global-color-gray-300); border: 1px solid var(--spectrum-global-color-gray-300);
cursor: pointer; cursor: pointer;
display: flex; display: flex;
} }
.title-text { .template-card:hover {
margin-top: calc(var(--spacing-xl) * -1); background: var(--spectrum-alias-background-color-tertiary);
} }
.card-body { .card-body {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 12px; padding: 12px;
} }
.iconAlign {
.grid { padding: 0 0 0 var(--spacing-m);
display: grid; display: inline-block;
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;
} }
.appTable { .appTable {
@ -511,6 +510,12 @@
.appTable :global(> div) { .appTable :global(> div) {
border-bottom: var(--border-light); border-bottom: var(--border-light);
} }
@media (max-width: 640px) {
.appTable {
grid-template-columns: 1fr auto;
}
}
.empty-wrapper { .empty-wrapper {
flex: 1 1 auto; flex: 1 1 auto;
height: 100%; height: 100%;
@ -519,20 +524,4 @@
justify-content: center; justify-content: center;
align-items: 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> </style>

View file

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

View file

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

View file

@ -1,8 +1,9 @@
<script> <script>
import { setContext, getContext } from "svelte" import { setContext, getContext, onMount } from "svelte"
import Router, { querystring } from "svelte-spa-router" import Router, { querystring } from "svelte-spa-router"
import { routeStore } from "stores" import { routeStore, stateStore } from "stores"
import Screen from "./Screen.svelte" import Screen from "./Screen.svelte"
import { get } from "svelte/store"
const { styleable } = getContext("sdk") const { styleable } = getContext("sdk")
const component = getContext("component") const component = getContext("component")
@ -17,15 +18,17 @@
} }
// Keep query params up to date // Keep query params up to date
$: { $: routeStore.actions.setQueryParams(parseQueryString($querystring))
const parseQueryString = query => {
let queryParams = {} let queryParams = {}
if ($querystring) { if (query) {
const urlSearchParams = new URLSearchParams($querystring) const urlSearchParams = new URLSearchParams(query)
for (const [key, value] of urlSearchParams) { for (const [key, value] of urlSearchParams) {
queryParams[key] = value queryParams[key] = value
} }
} }
routeStore.actions.setQueryParams(queryParams) return queryParams
} }
const getRouterConfig = routes => { const getRouterConfig = routes => {
@ -42,6 +45,19 @@
const onRouteLoading = ({ detail }) => { const onRouteLoading = ({ detail }) => {
routeStore.actions.setActiveRoute(detail.route) 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> </script>
{#key config.id} {#key config.id}

View file

@ -4,6 +4,7 @@
dataSourceStore, dataSourceStore,
notificationStore, notificationStore,
routeStore, routeStore,
stateStore,
} from "stores" } from "stores"
import { Modal, ModalContent, ActionButton } from "@budibase/bbui" import { Modal, ModalContent, ActionButton } from "@budibase/bbui"
import { onDestroy } from "svelte" import { onDestroy } from "svelte"
@ -12,12 +13,13 @@
NOTIFICATION: "notification", NOTIFICATION: "notification",
CLOSE_SCREEN_MODAL: "close-screen-modal", CLOSE_SCREEN_MODAL: "close-screen-modal",
INVALIDATE_DATASOURCE: "invalidate-datasource", INVALIDATE_DATASOURCE: "invalidate-datasource",
UPDATE_STATE: "update-state",
} }
let iframe let iframe
let listenersAttached = false let listenersAttached = false
const invalidateDataSource = event => { const proxyInvalidation = event => {
const { dataSourceId } = event.detail const { dataSourceId } = event.detail
dataSourceStore.actions.invalidateDataSource(dataSourceId) dataSourceStore.actions.invalidateDataSource(dataSourceId)
} }
@ -27,14 +29,28 @@
notificationStore.actions.send(message, type, icon) 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) { function receiveMessage(message) {
const handlers = { const handlers = {
[MessageTypes.NOTIFICATION]: () => { [MessageTypes.NOTIFICATION]: () => {
proxyNotification(message.data) proxyNotification(message.data)
}, },
[MessageTypes.CLOSE_SCREEN_MODAL]: peekStore.actions.hidePeek, [MessageTypes.CLOSE_SCREEN_MODAL]: () => {
peekStore.actions.hidePeek()
},
[MessageTypes.INVALIDATE_DATASOURCE]: () => { [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 = { const initialState = {
showPeek: false, showPeek: false,
@ -14,7 +15,10 @@ const createPeekStore = () => {
let href = url let href = url
let external = !url.startsWith("/") let external = !url.startsWith("/")
if (!external) { 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({ store.set({
showPeek: true, showPeek: true,

View file

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

View file

@ -146,6 +146,15 @@ const updateStateHandler = action => {
} else if (type === "delete") { } else if (type === "delete") {
stateStore.actions.deleteValue(key) 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 = { const handlerMap = {

View file

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

View file

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

View file

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

View file

@ -7,6 +7,7 @@ const newid = require("../db/newid")
const { updateEntityMetadata } = require("../utilities") const { updateEntityMetadata } = require("../utilities")
const { MetadataTypes } = require("../constants") const { MetadataTypes } = require("../constants")
const { getDeployedAppID } = require("@budibase/auth/db") const { getDeployedAppID } = require("@budibase/auth/db")
const { cloneDeep } = require("lodash/fp")
const WH_STEP_ID = definitions.WEBHOOK.stepId const WH_STEP_ID = definitions.WEBHOOK.stepId
const CRON_STEP_ID = definitions.CRON.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 // end the repetition and the job itself
exports.disableAllCrons = async appId => { exports.disableAllCrons = async appId => {
const promises = [] const promises = []

View file

@ -6,13 +6,14 @@ import {
RestQueryFields as RestQuery, RestQueryFields as RestQuery,
AuthType, AuthType,
BasicAuthConfig, BasicAuthConfig,
BearerAuthConfig BearerAuthConfig,
} from "../definitions/datasource" } from "../definitions/datasource"
import { IntegrationBase } from "./base/IntegrationBase" import { IntegrationBase } from "./base/IntegrationBase"
const BodyTypes = { const BodyTypes = {
NONE: "none", NONE: "none",
FORM_DATA: "form", FORM_DATA: "form",
XML: "xml",
ENCODED: "encoded", ENCODED: "encoded",
JSON: "json", JSON: "json",
TEXT: "text", TEXT: "text",
@ -45,6 +46,9 @@ module RestModule {
const fetch = require("node-fetch") const fetch = require("node-fetch")
const { formatBytes } = require("../utilities") const { formatBytes } = require("../utilities")
const { performance } = require("perf_hooks") const { performance } = require("perf_hooks")
const FormData = require("form-data")
const { URLSearchParams } = require("url")
const { parseStringPromise: xmlParser, Builder: XmlBuilder } = require("xml2js")
const SCHEMA: Integration = { const SCHEMA: Integration = {
docs: "https://github.com/node-fetch/node-fetch", docs: "https://github.com/node-fetch/node-fetch",
@ -110,15 +114,38 @@ module RestModule {
async parseResponse(response: any) { async parseResponse(response: any) {
let data, raw, headers let data, raw, headers
const contentType = response.headers.get("content-type") const contentType = response.headers.get("content-type") || ""
if (contentType && contentType.indexOf("application/json") !== -1) { try {
data = await response.json() if (contentType.includes("application/json")) {
raw = JSON.stringify(data) data = await response.json()
} else { raw = JSON.stringify(data)
data = await response.text() } else if (
raw = data 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
}
} catch (err) {
throw "Failed to parse response body."
} }
const size = formatBytes(response.headers.get("content-length") || Buffer.byteLength(raw, "utf8")) const size = formatBytes(
response.headers.get("content-length") || Buffer.byteLength(raw, "utf8")
)
const time = `${Math.round(performance.now() - this.startTimeMs)}ms` const time = `${Math.round(performance.now() - this.startTimeMs)}ms`
headers = response.headers.raw() headers = response.headers.raw()
for (let [key, value] of Object.entries(headers)) { for (let [key, value] of Object.entries(headers)) {
@ -150,7 +177,59 @@ module RestModule {
return complete return complete
} }
getAuthHeaders(authConfigId: string): { [key: string]: any }{ 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 = {} let headers: any = {}
if (this.config.authConfigs && authConfigId) { if (this.config.authConfigs && authConfigId) {
@ -180,7 +259,16 @@ module RestModule {
} }
async _req(query: RestQuery) { 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) const authHeaders = this.getAuthHeaders(authConfigId)
this.headers = { this.headers = {
@ -197,18 +285,9 @@ module RestModule {
} }
} }
let json let input: any = { method, headers: this.headers }
if (bodyType === BodyTypes.JSON && requestBody) { if (requestBody) {
try { input = this.addBody(bodyType, requestBody, input)
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)
} }
this.startTimeMs = performance.now() this.startTimeMs = performance.now()

View file

@ -14,6 +14,11 @@ const fetch = require("node-fetch")
const RestIntegration = require("../rest") const RestIntegration = require("../rest")
const { AuthType } = require("../rest") const { AuthType } = require("../rest")
const HEADERS = {
"Accept": "application/json",
"Content-Type": "application/json"
}
class TestConfiguration { class TestConfiguration {
constructor(config = {}) { constructor(config = {}) {
this.integration = new RestIntegration.integration(config) this.integration = new RestIntegration.integration(config)
@ -35,9 +40,7 @@ describe("REST Integration", () => {
const query = { const query = {
path: "api", path: "api",
queryString: "test=1", queryString: "test=1",
headers: { headers: HEADERS,
Accept: "application/json",
},
bodyType: "json", bodyType: "json",
requestBody: JSON.stringify({ requestBody: JSON.stringify({
name: "test", name: "test",
@ -47,9 +50,7 @@ describe("REST Integration", () => {
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, { expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
method: "POST", method: "POST",
body: '{"name":"test"}', body: '{"name":"test"}',
headers: { headers: HEADERS,
Accept: "application/json",
},
}) })
}) })
@ -86,9 +87,7 @@ describe("REST Integration", () => {
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, { expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
method: "PUT", method: "PUT",
body: '{"name":"test"}', body: '{"name":"test"}',
headers: { headers: HEADERS,
Accept: "application/json",
},
}) })
}) })
@ -107,13 +106,98 @@ describe("REST Integration", () => {
const response = await config.integration.delete(query) const response = await config.integration.delete(query)
expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, { expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
method: "DELETE", method: "DELETE",
headers: { headers: HEADERS,
Accept: "application/json",
},
body: '{"name":"test"}', 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", () => { describe("authentication", () => {
const basicAuth = { const basicAuth = {
_id: "c59c14bd1898a43baa08da68959b24686", _id: "c59c14bd1898a43baa08da68959b24686",

View file

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

View file

@ -1,6 +1,4 @@
// when thread starts, make sure it is recorded require("./utils").threadSetup()
const env = require("../environment")
env.setInThread()
const ScriptRunner = require("../utilities/scriptRunner") const ScriptRunner = require("../utilities/scriptRunner")
const { integrations } = require("../integrations") 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", "name": "@budibase/string-templates",
"version": "1.0.19-alpha.3", "version": "1.0.27-alpha.1",
"description": "Handlebars wrapper for Budibase templating.", "description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs", "main": "src/index.cjs",
"module": "dist/bundle.mjs", "module": "dist/bundle.mjs",

View file

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