Merge branch 'develop' of github.com:Budibase/budibase into feature/json-backend
This commit is contained in:
commit
4cd8886e1a
|
@ -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 }}
|
||||||
|
|
|
@ -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 }}
|
|
@ -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 }}"
|
|
|
@ -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
|
|
@ -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 }}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 !
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.19-alpha.3",
|
"version": "1.0.27-alpha.1",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,3 +13,9 @@
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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" },
|
||||||
]
|
]
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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 = []
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue